mirror of https://gitlab.com/nakst/essence
instance callbacks; bugfixes
This commit is contained in:
parent
2b1e81b772
commit
ba4b0318e7
|
@ -495,6 +495,30 @@ void LoadSettings() {
|
|||
}
|
||||
}
|
||||
|
||||
int InstanceCallback(Instance *instance, EsMessage *message) {
|
||||
if (message->type == ES_MSG_INSTANCE_CLOSE) {
|
||||
EsAssert(!instance->closed);
|
||||
instance->closed = true;
|
||||
instance->list = nullptr;
|
||||
instance->placesView = nullptr;
|
||||
instance->breadcrumbBar = nullptr;
|
||||
instance->newFolderButton = nullptr;
|
||||
instance->status = nullptr;
|
||||
instance->blockingDialog = nullptr;
|
||||
} else if (message->type == ES_MSG_INSTANCE_DESTROY) {
|
||||
EsApplicationStartupRequest request = EsInstanceGetStartupRequest(instance);
|
||||
|
||||
if (request.flags & ES_APPLICATION_STARTUP_BACKGROUND_SERVICE) {
|
||||
// No cleanup to do.
|
||||
} else {
|
||||
InstanceDestroy(instance);
|
||||
instances.FindAndDeleteSwap(instance, true);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _start() {
|
||||
_init();
|
||||
|
||||
|
@ -514,6 +538,7 @@ void _start() {
|
|||
|
||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
||||
Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(FileManagerTitle));
|
||||
instance->callback = InstanceCallback;
|
||||
|
||||
EsApplicationStartupRequest request = EsInstanceGetStartupRequest(instance);
|
||||
|
||||
|
@ -523,26 +548,6 @@ void _start() {
|
|||
instances.Add(instance);
|
||||
InstanceCreateUI(instance);
|
||||
}
|
||||
} else if (message->type == ES_MSG_INSTANCE_CLOSE) {
|
||||
Instance *instance = message->instanceClose.instance;
|
||||
EsAssert(!instance->closed);
|
||||
instance->closed = true;
|
||||
instance->list = nullptr;
|
||||
instance->placesView = nullptr;
|
||||
instance->breadcrumbBar = nullptr;
|
||||
instance->newFolderButton = nullptr;
|
||||
instance->status = nullptr;
|
||||
instance->blockingDialog = nullptr;
|
||||
} else if (message->type == ES_MSG_INSTANCE_DESTROY) {
|
||||
Instance *instance = message->instanceDestroy.instance;
|
||||
EsApplicationStartupRequest request = EsInstanceGetStartupRequest(instance);
|
||||
|
||||
if (request.flags & ES_APPLICATION_STARTUP_BACKGROUND_SERVICE) {
|
||||
// No cleanup to do.
|
||||
} else {
|
||||
InstanceDestroy(instance);
|
||||
instances.FindAndDeleteSwap(instance, true);
|
||||
}
|
||||
} else if (message->type == ES_MSG_APPLICATION_EXIT) {
|
||||
#ifdef DEBUG_BUILD
|
||||
for (uintptr_t i = 0; i < drives.Length(); i++) {
|
||||
|
|
|
@ -298,6 +298,62 @@ void BackCommand(Instance *instance, EsElement *, EsCommand *) {
|
|||
EsWindowSwitchToolbar(instance->window, instance->fontListToolbar, ES_TRANSITION_SLIDE_DOWN);
|
||||
}
|
||||
|
||||
int InstanceCallback(Instance *instance, EsMessage *message) {
|
||||
if (message->type == ES_MSG_INSTANCE_CLOSE) {
|
||||
instance->switcher = nullptr;
|
||||
instance->fontList = nullptr;
|
||||
instance->fontSizeTextbox = nullptr;
|
||||
instance->previewTextTextbox = nullptr;
|
||||
instance->fontPreview = nullptr;
|
||||
instance->fontListToolbar = nullptr;
|
||||
instance->fontPreviewToolbar = nullptr;
|
||||
} else if (message->type == ES_MSG_INSTANCE_DESTROY) {
|
||||
SaveSettings(instance);
|
||||
EsHeapFree(instance->previewText);
|
||||
instance->fonts.Free();
|
||||
// TODO Remove the font added to the font database.
|
||||
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
|
||||
if (!message->instanceOpen.update) {
|
||||
EsFontInformation information = {};
|
||||
information.availableWeightsNormal = 1 << 4 /* regular */;
|
||||
instance->fontPreviewID = EsFontDatabaseInsertFile(&information, message->instanceOpen.file);
|
||||
// TODO Check that the font is valid.
|
||||
|
||||
EsElementDestroyContents(instance->fontPreview);
|
||||
|
||||
EsPanel *titleRow = EsPanelCreate(instance->fontPreview, ES_CELL_H_CENTER | ES_PANEL_HORIZONTAL, &styleFontInformationRow);
|
||||
EsIconDisplayCreate(titleRow, ES_FLAGS_DEFAULT, ES_STYLE_ICON_DISPLAY, ES_ICON_FONT_X_GENERIC);
|
||||
EsTextDisplayCreate(titleRow, ES_FLAGS_DEFAULT, ES_STYLE_TEXT_HEADING0, message->instanceOpen.name, message->instanceOpen.nameBytes);
|
||||
EsSpacerCreate(instance->fontPreview, ES_FLAGS_DEFAULT, 0, 0, 20);
|
||||
|
||||
int sizes[] = { 12, 18, 24, 36, 48, 60, 72, 0 };
|
||||
|
||||
for (uintptr_t i = 0; sizes[i]; i++) {
|
||||
EsPanel *row = EsPanelCreate(instance->fontPreview, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL, &styleFontInformationRow);
|
||||
char buffer[64];
|
||||
EsTextDisplayCreate(row, ES_FLAGS_DEFAULT, 0, buffer, EsStringFormat(buffer, sizeof(buffer), "%d", sizes[i]));
|
||||
EsTextDisplay *display = EsTextDisplayCreate(row, ES_TEXT_DISPLAY_NO_FONT_SUBSTITUTION);
|
||||
const char *string = interfaceString_FontBookPreviewTextLongDefault;
|
||||
EsTextRun runs[2] = {};
|
||||
EsElementGetTextStyle(display, &runs[0].style);
|
||||
runs[0].style.size = sizes[i];
|
||||
runs[0].style.font.family = instance->fontPreviewID;
|
||||
runs[1].offset = EsCStringLength(string);
|
||||
EsTextDisplaySetStyledContents(display, string, runs, 1);
|
||||
}
|
||||
|
||||
EsPanelSwitchTo(instance->switcher, instance->fontPreview, ES_TRANSITION_NONE);
|
||||
EsWindowSwitchToolbar(instance->window, instance->fontPreviewToolbar, ES_TRANSITION_SLIDE_UP);
|
||||
}
|
||||
|
||||
EsInstanceOpenComplete(instance, message->instanceOpen.file, true);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ES_HANDLED;
|
||||
}
|
||||
|
||||
void _start() {
|
||||
_init();
|
||||
|
||||
|
@ -306,6 +362,7 @@ void _start() {
|
|||
|
||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
||||
Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(FontBookTitle));
|
||||
instance->callback = InstanceCallback;
|
||||
EsWindowSetIcon(instance->window, ES_ICON_APPLICATIONS_FONTS);
|
||||
EsPanel *rootPanel = EsPanelCreate(instance->window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER);
|
||||
|
||||
|
@ -374,56 +431,6 @@ void _start() {
|
|||
button->accessKey = 'B';
|
||||
EsButtonSetIcon(button, ES_ICON_GO_PREVIOUS_SYMBOLIC);
|
||||
EsButtonOnCommand(button, BackCommand);
|
||||
} else if (message->type == ES_MSG_INSTANCE_CLOSE) {
|
||||
Instance *instance = message->instanceClose.instance;
|
||||
instance->switcher = nullptr;
|
||||
instance->fontList = nullptr;
|
||||
instance->fontSizeTextbox = nullptr;
|
||||
instance->previewTextTextbox = nullptr;
|
||||
instance->fontPreview = nullptr;
|
||||
instance->fontListToolbar = nullptr;
|
||||
instance->fontPreviewToolbar = nullptr;
|
||||
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
|
||||
if (!message->instanceOpen.update) {
|
||||
Instance *instance = message->instanceOpen.instance;
|
||||
EsFontInformation information = {};
|
||||
information.availableWeightsNormal = 1 << 4 /* regular */;
|
||||
instance->fontPreviewID = EsFontDatabaseInsertFile(&information, message->instanceOpen.file);
|
||||
// TODO Check that the font is valid.
|
||||
|
||||
EsElementDestroyContents(instance->fontPreview);
|
||||
|
||||
EsPanel *titleRow = EsPanelCreate(instance->fontPreview, ES_CELL_H_CENTER | ES_PANEL_HORIZONTAL, &styleFontInformationRow);
|
||||
EsIconDisplayCreate(titleRow, ES_FLAGS_DEFAULT, ES_STYLE_ICON_DISPLAY, ES_ICON_FONT_X_GENERIC);
|
||||
EsTextDisplayCreate(titleRow, ES_FLAGS_DEFAULT, ES_STYLE_TEXT_HEADING0, message->instanceOpen.name, message->instanceOpen.nameBytes);
|
||||
EsSpacerCreate(instance->fontPreview, ES_FLAGS_DEFAULT, 0, 0, 20);
|
||||
|
||||
int sizes[] = { 12, 18, 24, 36, 48, 60, 72, 0 };
|
||||
|
||||
for (uintptr_t i = 0; sizes[i]; i++) {
|
||||
EsPanel *row = EsPanelCreate(instance->fontPreview, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL, &styleFontInformationRow);
|
||||
char buffer[64];
|
||||
EsTextDisplayCreate(row, ES_FLAGS_DEFAULT, 0, buffer, EsStringFormat(buffer, sizeof(buffer), "%d", sizes[i]));
|
||||
EsTextDisplay *display = EsTextDisplayCreate(row, ES_TEXT_DISPLAY_NO_FONT_SUBSTITUTION);
|
||||
const char *string = interfaceString_FontBookPreviewTextLongDefault;
|
||||
EsTextRun runs[2] = {};
|
||||
EsElementGetTextStyle(display, &runs[0].style);
|
||||
runs[0].style.size = sizes[i];
|
||||
runs[0].style.font.family = instance->fontPreviewID;
|
||||
runs[1].offset = EsCStringLength(string);
|
||||
EsTextDisplaySetStyledContents(display, string, runs, 1);
|
||||
}
|
||||
|
||||
EsPanelSwitchTo(instance->switcher, instance->fontPreview, ES_TRANSITION_NONE);
|
||||
EsWindowSwitchToolbar(instance->window, instance->fontPreviewToolbar, ES_TRANSITION_SLIDE_UP);
|
||||
}
|
||||
|
||||
EsInstanceOpenComplete(message, true);
|
||||
} else if (message->type == ES_MSG_INSTANCE_DESTROY) {
|
||||
SaveSettings(message->instanceDestroy.instance);
|
||||
EsHeapFree(message->instanceDestroy.instance->previewText);
|
||||
message->instanceDestroy.instance->fonts.Free();
|
||||
// TODO Remove the font added to the font database.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -692,8 +692,111 @@ void MenuImage(Instance *instance, EsElement *element, EsCommand *) {
|
|||
EsMenuShow(menu);
|
||||
}
|
||||
|
||||
void WriteCallback(void *context, void *data, int size) {
|
||||
EsBufferWrite((EsBuffer *) context, data, size);
|
||||
}
|
||||
|
||||
void SwapRedAndBlueChannels(uint32_t *bits, size_t width, size_t height, size_t stride) {
|
||||
for (uintptr_t i = 0; i < height; i++) {
|
||||
for (uintptr_t j = 0; j < width; j++) {
|
||||
uint32_t *pixel = &bits[i * stride / 4 + j];
|
||||
*pixel = (*pixel & 0xFF00FF00) | (((*pixel >> 16) | (*pixel << 16)) & 0x00FF00FF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int InstanceCallback(Instance *instance, EsMessage *message) {
|
||||
if (message->type == ES_MSG_INSTANCE_DESTROY) {
|
||||
EsPaintTargetDestroy(instance->bitmap);
|
||||
ImageDelete(instance->image);
|
||||
} else if (message->type == ES_MSG_INSTANCE_SAVE) {
|
||||
// TODO Error handling.
|
||||
|
||||
uintptr_t extensionOffset = message->instanceSave.nameBytes;
|
||||
|
||||
while (extensionOffset) {
|
||||
if (message->instanceSave.name[extensionOffset - 1] == '.') {
|
||||
break;
|
||||
} else {
|
||||
extensionOffset--;
|
||||
}
|
||||
}
|
||||
|
||||
const char *extension = extensionOffset ? message->instanceSave.name + extensionOffset : "png";
|
||||
size_t extensionBytes = extensionOffset ? message->instanceSave.nameBytes - extensionOffset : 3;
|
||||
|
||||
uint32_t *bits;
|
||||
size_t width, height, stride;
|
||||
EsPaintTargetStartDirectAccess(instance->bitmap, &bits, &width, &height, &stride);
|
||||
EsAssert(stride == width * 4); // TODO Other strides.
|
||||
SwapRedAndBlueChannels(bits, width, height, stride); // stbi_write uses the other order. We swap back below.
|
||||
|
||||
size_t _bufferBytes = 262144;
|
||||
uint8_t *_buffer = (uint8_t *) EsHeapAllocate(_bufferBytes, false);
|
||||
EsBuffer buffer = { .out = _buffer, .bytes = _bufferBytes };
|
||||
buffer.fileStore = message->instanceSave.file;
|
||||
|
||||
if (0 == EsStringCompare(extension, extensionBytes, EsLiteral("jpg"))
|
||||
|| 0 == EsStringCompare(extension, extensionBytes, EsLiteral("jpeg"))) {
|
||||
stbi_write_jpg_to_func(WriteCallback, &buffer, width, height, 4, bits, 90);
|
||||
} else if (0 == EsStringCompare(extension, extensionBytes, EsLiteral("bmp"))) {
|
||||
stbi_write_bmp_to_func(WriteCallback, &buffer, width, height, 4, bits);
|
||||
} else if (0 == EsStringCompare(extension, extensionBytes, EsLiteral("tga"))) {
|
||||
stbi_write_tga_to_func(WriteCallback, &buffer, width, height, 4, bits);
|
||||
} else {
|
||||
stbi_write_png_to_func(WriteCallback, &buffer, width, height, 4, bits, stride);
|
||||
}
|
||||
|
||||
SwapRedAndBlueChannels(bits, width, height, stride); // Swap back.
|
||||
EsBufferFlushToFileStore(&buffer);
|
||||
EsHeapFree(_buffer);
|
||||
EsPaintTargetEndDirectAccess(instance->bitmap);
|
||||
EsInstanceSaveComplete(instance, message->instanceSave.file, true);
|
||||
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
|
||||
size_t fileSize;
|
||||
uint8_t *file = (uint8_t *) EsFileStoreReadAll(message->instanceOpen.file, &fileSize);
|
||||
|
||||
if (!file) {
|
||||
EsInstanceOpenComplete(instance, message->instanceOpen.file, false);
|
||||
return ES_HANDLED;
|
||||
}
|
||||
|
||||
uint32_t width, height;
|
||||
uint8_t *bits = EsImageLoad(file, fileSize, &width, &height, 4);
|
||||
EsHeapFree(file);
|
||||
|
||||
if (!bits) {
|
||||
EsInstanceOpenComplete(instance, message->instanceOpen.file, false, INTERFACE_STRING(ImageEditorUnsupportedFormat));
|
||||
return ES_HANDLED;
|
||||
}
|
||||
|
||||
EsPaintTargetDestroy(instance->bitmap);
|
||||
ImageDelete(instance->image);
|
||||
|
||||
instance->bitmapWidth = width;
|
||||
instance->bitmapHeight = height;
|
||||
instance->bitmap = EsPaintTargetCreate(instance->bitmapWidth, instance->bitmapHeight, false);
|
||||
EsPainter painter = {};
|
||||
painter.clip = ES_RECT_4(0, instance->bitmapWidth, 0, instance->bitmapHeight);
|
||||
painter.target = instance->bitmap;
|
||||
EsDrawBitmap(&painter, painter.clip, (uint32_t *) bits, width * 4, 0xFF);
|
||||
instance->image = ImageFork(instance, {}, instance->bitmapWidth, instance->bitmapHeight);
|
||||
ImageCopyFromPaintTarget(instance, &instance->image, painter.clip);
|
||||
EsElementRelayout(EsElementGetLayoutParent(instance->canvas));
|
||||
|
||||
EsHeapFree(bits);
|
||||
EsInstanceOpenComplete(instance, message->instanceOpen.file, true);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ES_HANDLED;
|
||||
}
|
||||
|
||||
void InstanceCreate(EsMessage *message) {
|
||||
Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(ImageEditorTitle));
|
||||
instance->callback = InstanceCallback;
|
||||
|
||||
EsElement *toolbar = EsWindowGetToolbar(instance->window);
|
||||
EsInstanceSetClassEditor(instance, &editorSettings);
|
||||
|
||||
|
@ -802,19 +905,6 @@ void InstanceCreate(EsMessage *message) {
|
|||
ImageCopyFromPaintTarget(instance, &instance->image, painter.clip);
|
||||
}
|
||||
|
||||
void WriteCallback(void *context, void *data, int size) {
|
||||
EsBufferWrite((EsBuffer *) context, data, size);
|
||||
}
|
||||
|
||||
void SwapRedAndBlueChannels(uint32_t *bits, size_t width, size_t height, size_t stride) {
|
||||
for (uintptr_t i = 0; i < height; i++) {
|
||||
for (uintptr_t j = 0; j < width; j++) {
|
||||
uint32_t *pixel = &bits[i * stride / 4 + j];
|
||||
*pixel = (*pixel & 0xFF00FF00) | (((*pixel >> 16) | (*pixel << 16)) & 0x00FF00FF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _start() {
|
||||
_init();
|
||||
|
||||
|
@ -823,86 +913,6 @@ void _start() {
|
|||
|
||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
||||
InstanceCreate(message);
|
||||
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
|
||||
Instance *instance = message->instanceOpen.instance;
|
||||
size_t fileSize;
|
||||
uint8_t *file = (uint8_t *) EsFileStoreReadAll(message->instanceOpen.file, &fileSize);
|
||||
|
||||
if (!file) {
|
||||
EsInstanceOpenComplete(message, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t width, height;
|
||||
uint8_t *bits = EsImageLoad(file, fileSize, &width, &height, 4);
|
||||
EsHeapFree(file);
|
||||
|
||||
if (!bits) {
|
||||
EsInstanceOpenComplete(message, false, INTERFACE_STRING(ImageEditorUnsupportedFormat));
|
||||
continue;
|
||||
}
|
||||
|
||||
EsPaintTargetDestroy(instance->bitmap);
|
||||
ImageDelete(instance->image);
|
||||
|
||||
instance->bitmapWidth = width;
|
||||
instance->bitmapHeight = height;
|
||||
instance->bitmap = EsPaintTargetCreate(instance->bitmapWidth, instance->bitmapHeight, false);
|
||||
EsPainter painter = {};
|
||||
painter.clip = ES_RECT_4(0, instance->bitmapWidth, 0, instance->bitmapHeight);
|
||||
painter.target = instance->bitmap;
|
||||
EsDrawBitmap(&painter, painter.clip, (uint32_t *) bits, width * 4, 0xFF);
|
||||
instance->image = ImageFork(instance, {}, instance->bitmapWidth, instance->bitmapHeight);
|
||||
ImageCopyFromPaintTarget(instance, &instance->image, painter.clip);
|
||||
EsElementRelayout(EsElementGetLayoutParent(instance->canvas));
|
||||
|
||||
EsHeapFree(bits);
|
||||
EsInstanceOpenComplete(message, true);
|
||||
} else if (message->type == ES_MSG_INSTANCE_SAVE) {
|
||||
Instance *instance = message->instanceSave.instance;
|
||||
|
||||
uintptr_t extensionOffset = message->instanceSave.nameBytes;
|
||||
|
||||
while (extensionOffset) {
|
||||
if (message->instanceSave.name[extensionOffset - 1] == '.') {
|
||||
break;
|
||||
} else {
|
||||
extensionOffset--;
|
||||
}
|
||||
}
|
||||
|
||||
const char *extension = extensionOffset ? message->instanceSave.name + extensionOffset : "png";
|
||||
size_t extensionBytes = extensionOffset ? message->instanceSave.nameBytes - extensionOffset : 3;
|
||||
|
||||
uint32_t *bits;
|
||||
size_t width, height, stride;
|
||||
EsPaintTargetStartDirectAccess(instance->bitmap, &bits, &width, &height, &stride);
|
||||
EsAssert(stride == width * 4); // TODO Other strides.
|
||||
SwapRedAndBlueChannels(bits, width, height, stride); // stbi_write uses the other order. We swap back below.
|
||||
|
||||
uint8_t _buffer[4096];
|
||||
EsBuffer buffer = { .out = _buffer, .bytes = sizeof(_buffer) };
|
||||
buffer.fileStore = message->instanceSave.file;
|
||||
|
||||
if (0 == EsStringCompare(extension, extensionBytes, EsLiteral("jpg"))
|
||||
|| 0 == EsStringCompare(extension, extensionBytes, EsLiteral("jpeg"))) {
|
||||
stbi_write_jpg_to_func(WriteCallback, &buffer, width, height, 4, bits, 90);
|
||||
} else if (0 == EsStringCompare(extension, extensionBytes, EsLiteral("bmp"))) {
|
||||
stbi_write_bmp_to_func(WriteCallback, &buffer, width, height, 4, bits);
|
||||
} else if (0 == EsStringCompare(extension, extensionBytes, EsLiteral("tga"))) {
|
||||
stbi_write_tga_to_func(WriteCallback, &buffer, width, height, 4, bits);
|
||||
} else {
|
||||
stbi_write_png_to_func(WriteCallback, &buffer, width, height, 4, bits, stride);
|
||||
}
|
||||
|
||||
SwapRedAndBlueChannels(bits, width, height, stride); // Swap back.
|
||||
EsBufferFlushToFileStore(&buffer);
|
||||
EsPaintTargetEndDirectAccess(instance->bitmap);
|
||||
EsInstanceSaveComplete(message, true);
|
||||
} else if (message->type == ES_MSG_INSTANCE_DESTROY) {
|
||||
Instance *instance = message->instanceDestroy.instance;
|
||||
EsPaintTargetDestroy(instance->bitmap);
|
||||
ImageDelete(instance->image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -445,18 +445,8 @@ int ParserText(MD_TEXTTYPE type, const MD_CHAR *text, MD_SIZE size, void *_insta
|
|||
return 0;
|
||||
}
|
||||
|
||||
void ProcessApplicationMessage(EsMessage *message) {
|
||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
||||
Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(MarkdownViewerTitle));
|
||||
EsInstanceSetClassViewer(instance, nullptr);
|
||||
EsWindow *window = instance->window;
|
||||
EsPanel *wrapper = EsPanelCreate(instance->window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER);
|
||||
EsPanel *background = EsPanelCreate(wrapper, ES_CELL_FILL | ES_PANEL_V_SCROLL_AUTO, &styleBackground);
|
||||
instance->root = EsPanelCreate(background, ES_CELL_H_SHRINK, &styleRoot);
|
||||
EsWindowSetIcon(window, ES_ICON_TEXT_MARKDOWN);
|
||||
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
|
||||
Instance *instance = message->instanceOpen.instance;
|
||||
|
||||
int InstanceCallback(Instance *instance, EsMessage *message) {
|
||||
if (message->type == ES_MSG_INSTANCE_OPEN) {
|
||||
if (message->instanceOpen.update) {
|
||||
EsElementStartTransition(instance->root, ES_TRANSITION_ZOOM_IN);
|
||||
}
|
||||
|
@ -467,8 +457,8 @@ void ProcessApplicationMessage(EsMessage *message) {
|
|||
char *file = (char *) EsFileStoreReadAll(message->instanceOpen.file, &fileSize);
|
||||
|
||||
if (!file || !EsUTF8IsValid(file, fileSize)) {
|
||||
EsInstanceOpenComplete(message, false);
|
||||
return;
|
||||
EsInstanceOpenComplete(instance, message->instanceOpen.file, false);
|
||||
return ES_HANDLED;
|
||||
}
|
||||
|
||||
MD_PARSER parser = {};
|
||||
|
@ -481,12 +471,29 @@ void ProcessApplicationMessage(EsMessage *message) {
|
|||
instance->active = instance->root;
|
||||
int result = md_parse(file, fileSize, &parser, instance);
|
||||
if (result) EsElementDestroyContents(instance->root); // An error occurred.
|
||||
EsInstanceOpenComplete(message, result == 0);
|
||||
EsInstanceOpenComplete(instance, message->instanceOpen.file, result == 0);
|
||||
EsHeapFree(file);
|
||||
|
||||
EsElementRelayout(instance->root);
|
||||
instance->spans.Free();
|
||||
instance->text.Free();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ES_HANDLED;
|
||||
}
|
||||
|
||||
void ProcessApplicationMessage(EsMessage *message) {
|
||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
||||
Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(MarkdownViewerTitle));
|
||||
instance->callback = InstanceCallback;
|
||||
EsInstanceSetClassViewer(instance, nullptr);
|
||||
EsWindow *window = instance->window;
|
||||
EsPanel *wrapper = EsPanelCreate(instance->window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER);
|
||||
EsPanel *background = EsPanelCreate(wrapper, ES_CELL_FILL | ES_PANEL_V_SCROLL_AUTO, &styleBackground);
|
||||
instance->root = EsPanelCreate(background, ES_CELL_H_SHRINK, &styleRoot);
|
||||
EsWindowSetIcon(window, ES_ICON_TEXT_MARKDOWN);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -363,9 +363,18 @@ void TerminateProcess(Instance *instance, EsElement *, EsCommand *) {
|
|||
}
|
||||
}
|
||||
|
||||
int InstanceCallback(Instance *, EsMessage *message) {
|
||||
if (message->type == ES_MSG_INSTANCE_DESTROY) {
|
||||
processes.Free();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ProcessApplicationMessage(EsMessage *message) {
|
||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
||||
Instance *instance = EsInstanceCreate(message, "System Monitor");
|
||||
instance->callback = InstanceCallback;
|
||||
|
||||
EsCommandRegister(&instance->commandTerminateProcess, instance, EsLiteral("Terminate process"), TerminateProcess, 1, "Del", false);
|
||||
|
||||
|
@ -401,8 +410,6 @@ void ProcessApplicationMessage(EsMessage *message) {
|
|||
EsSpacerCreate(buttonGroup, ES_CELL_V_FILL, ES_STYLE_TOOLBAR_BUTTON_GROUP_SEPARATOR);
|
||||
AddTab(buttonGroup, DISPLAY_MEMORY, "Memory");
|
||||
EsSpacerCreate(toolbar, ES_CELL_H_FILL);
|
||||
} else if (message->type == ES_MSG_INSTANCE_DESTROY) {
|
||||
processes.Free();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -239,9 +239,52 @@ int TextboxDocumentMessage(EsElement *element, EsMessage *message) {
|
|||
}
|
||||
}
|
||||
|
||||
int InstanceCallback(Instance *instance, EsMessage *message) {
|
||||
if (message->type == ES_MSG_INSTANCE_SAVE) {
|
||||
size_t byteCount;
|
||||
char *contents = EsTextboxGetContents(instance->textboxDocument, &byteCount);
|
||||
EsFileStoreWriteAll(message->instanceSave.file, contents, byteCount);
|
||||
EsHeapFree(contents);
|
||||
EsInstanceSaveComplete(instance, message->instanceSave.file, true);
|
||||
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
|
||||
size_t fileSize;
|
||||
char *file = (char *) EsFileStoreReadAll(message->instanceOpen.file, &fileSize);
|
||||
|
||||
if (!file) {
|
||||
EsInstanceOpenComplete(instance, message->instanceOpen.file, false);
|
||||
} else if (!EsUTF8IsValid(file, fileSize)) {
|
||||
EsInstanceOpenComplete(instance, message->instanceOpen.file, false);
|
||||
} else {
|
||||
EsTextboxSelectAll(instance->textboxDocument);
|
||||
EsTextboxInsert(instance->textboxDocument, file, fileSize);
|
||||
EsTextboxSetSelection(instance->textboxDocument, 0, 0, 0, 0);
|
||||
EsElementRelayout(instance->textboxDocument);
|
||||
|
||||
if (EsStringEndsWith(message->instanceOpen.name, message->instanceOpen.nameBytes, EsLiteral(".c"), true)
|
||||
|| EsStringEndsWith(message->instanceOpen.name, message->instanceOpen.nameBytes, EsLiteral(".cpp"), true)
|
||||
|| EsStringEndsWith(message->instanceOpen.name, message->instanceOpen.nameBytes, EsLiteral(".h"), true)) {
|
||||
SetLanguage(instance, ES_SYNTAX_HIGHLIGHTING_LANGUAGE_C);
|
||||
} else if (EsStringEndsWith(message->instanceOpen.name, message->instanceOpen.nameBytes, EsLiteral(".ini"), true)) {
|
||||
SetLanguage(instance, ES_SYNTAX_HIGHLIGHTING_LANGUAGE_INI);
|
||||
} else {
|
||||
SetLanguage(instance, 0);
|
||||
}
|
||||
|
||||
EsInstanceOpenComplete(instance, message->instanceOpen.file, true);
|
||||
}
|
||||
|
||||
EsHeapFree(file);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ES_HANDLED;
|
||||
}
|
||||
|
||||
void ProcessApplicationMessage(EsMessage *message) {
|
||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
||||
Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(TextEditorTitle));
|
||||
instance->callback = InstanceCallback;
|
||||
EsInstanceSetClassEditor(instance, &editorSettings);
|
||||
|
||||
EsWindow *window = instance->window;
|
||||
|
@ -357,43 +400,6 @@ void ProcessApplicationMessage(EsMessage *message) {
|
|||
button = EsButtonCreate(buttonGroup, ES_FLAGS_DEFAULT, {}, INTERFACE_STRING(CommonSearchPrevious));
|
||||
button->accessKey = 'P';
|
||||
EsCommandAddButton(&instance->commandFindPrevious, button);
|
||||
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
|
||||
Instance *instance = message->instanceOpen.instance;
|
||||
|
||||
size_t fileSize;
|
||||
char *file = (char *) EsFileStoreReadAll(message->instanceOpen.file, &fileSize);
|
||||
|
||||
if (!file) {
|
||||
EsInstanceOpenComplete(message, false);
|
||||
} else if (!EsUTF8IsValid(file, fileSize)) {
|
||||
EsInstanceOpenComplete(message, false);
|
||||
} else {
|
||||
EsTextboxSelectAll(instance->textboxDocument);
|
||||
EsTextboxInsert(instance->textboxDocument, file, fileSize);
|
||||
EsTextboxSetSelection(instance->textboxDocument, 0, 0, 0, 0);
|
||||
EsElementRelayout(instance->textboxDocument);
|
||||
|
||||
if (EsStringEndsWith(message->instanceOpen.name, message->instanceOpen.nameBytes, EsLiteral(".c"), true)
|
||||
|| EsStringEndsWith(message->instanceOpen.name, message->instanceOpen.nameBytes, EsLiteral(".cpp"), true)
|
||||
|| EsStringEndsWith(message->instanceOpen.name, message->instanceOpen.nameBytes, EsLiteral(".h"), true)) {
|
||||
SetLanguage(instance, ES_SYNTAX_HIGHLIGHTING_LANGUAGE_C);
|
||||
} else if (EsStringEndsWith(message->instanceOpen.name, message->instanceOpen.nameBytes, EsLiteral(".ini"), true)) {
|
||||
SetLanguage(instance, ES_SYNTAX_HIGHLIGHTING_LANGUAGE_INI);
|
||||
} else {
|
||||
SetLanguage(instance, 0);
|
||||
}
|
||||
|
||||
EsInstanceOpenComplete(message, true);
|
||||
}
|
||||
|
||||
EsHeapFree(file);
|
||||
} else if (message->type == ES_MSG_INSTANCE_SAVE) {
|
||||
Instance *instance = message->instanceSave.instance;
|
||||
size_t byteCount;
|
||||
char *contents = EsTextboxGetContents(instance->textboxDocument, &byteCount);
|
||||
EsFileStoreWriteAll(message->instanceSave.file, contents, byteCount);
|
||||
EsHeapFree(contents);
|
||||
EsInstanceSaveComplete(message, true);
|
||||
} else if (message->type == ES_MSG_APPLICATION_EXIT) {
|
||||
EsBuffer buffer = {};
|
||||
buffer.canGrow = true;
|
||||
|
|
210
desktop/api.cpp
210
desktop/api.cpp
|
@ -238,10 +238,6 @@ struct APIInstance {
|
|||
|
||||
bool closeAfterSaveCompletes;
|
||||
|
||||
// Do not propagate messages about this instance to the application.
|
||||
// Currently only used for inspectors.
|
||||
bool internalOnly;
|
||||
|
||||
union {
|
||||
EsInstanceClassEditorSettings editorSettings;
|
||||
EsInstanceClassViewerSettings viewerSettings;
|
||||
|
@ -799,17 +795,6 @@ void InstanceCreateFileStore(APIInstance *instance, EsHandle handle) {
|
|||
instance->fileStore = FileStoreCreateFromHandle(handle);
|
||||
}
|
||||
|
||||
void InstancePostOpenMessage(EsInstance *_instance, bool update) {
|
||||
APIInstance *instance = (APIInstance *) _instance->_private;
|
||||
EsMessage m = { ES_MSG_INSTANCE_OPEN };
|
||||
m.instanceOpen.instance = _instance;
|
||||
m.instanceOpen.name = instance->startupInformation->filePath;
|
||||
m.instanceOpen.nameBytes = instance->startupInformation->filePathBytes;
|
||||
m.instanceOpen.file = instance->fileStore;
|
||||
m.instanceOpen.update = update;
|
||||
EsMessagePost(nullptr, &m);
|
||||
}
|
||||
|
||||
APIInstance *InstanceSetup(EsInstance *instance) {
|
||||
APIInstance *apiInstance = (APIInstance *) EsHeapAllocate(sizeof(APIInstance), true);
|
||||
|
||||
|
@ -886,9 +871,15 @@ EsInstance *_EsInstanceCreate(size_t bytes, EsMessage *message, const char *appl
|
|||
|
||||
if (apiInstance->startupInformation && apiInstance->startupInformation->readHandle) {
|
||||
InstanceCreateFileStore(apiInstance, apiInstance->startupInformation->readHandle);
|
||||
InstancePostOpenMessage(instance, false);
|
||||
EsWindowSetTitle(instance->window, apiInstance->startupInformation->filePath, apiInstance->startupInformation->filePathBytes);
|
||||
EsCommandSetDisabled(&apiInstance->commandShowInFileManager, false);
|
||||
|
||||
// HACK Delay sending the instance open message so that application has a chance to initialise the instance.
|
||||
// TODO Change how this works!!
|
||||
// TODO Can the posted message be raced by a ES_MSG_INSTANCE_DOCUMENT_UPDATED?
|
||||
EsMessage m = { ES_MSG_INSTANCE_OPEN_DELAYED };
|
||||
m._argument = instance;
|
||||
EsMessagePost(nullptr, &m);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -922,19 +913,61 @@ void EsInstanceCloseReference(EsInstance *_instance) {
|
|||
instance->referenceCount--;
|
||||
|
||||
if (!instance->referenceCount) {
|
||||
EsMessage m = {};
|
||||
m.type = ES_MSG_INSTANCE_DESTROY;
|
||||
m.instanceDestroy.instance = _instance;
|
||||
EsMessagePost(nullptr, &m);
|
||||
if (_instance->callback) {
|
||||
EsMessage m = {};
|
||||
m.type = ES_MSG_INSTANCE_DESTROY;
|
||||
_instance->callback(_instance, &m);
|
||||
}
|
||||
|
||||
if (instance->startupInformation) {
|
||||
EsHeapFree((void *) instance->startupInformation->filePath);
|
||||
EsHeapFree((void *) instance->startupInformation->containingFolder);
|
||||
}
|
||||
|
||||
EsHeapFree(instance->startupInformation);
|
||||
EsHeapFree(instance->documentPath);
|
||||
EsHeapFree(instance->newName);
|
||||
|
||||
for (uintptr_t i = 0; i < instance->commands.Count(); i++) {
|
||||
EsCommand *command = instance->commands[i];
|
||||
EsAssert(command->registered);
|
||||
EsAssert(!ArrayLength(command->elements));
|
||||
Array<EsElement *> elements = { command->elements };
|
||||
elements.Free();
|
||||
}
|
||||
|
||||
instance->commands.Free();
|
||||
if (instance->fileStore) FileStoreCloseHandle(instance->fileStore);
|
||||
EsHeapFree(instance);
|
||||
EsHeapFree(_instance);
|
||||
}
|
||||
}
|
||||
|
||||
void EsInstanceClose(EsInstance *instance) {
|
||||
EsMessageMutexCheck();
|
||||
EsMessage m = {};
|
||||
m.type = ES_MSG_INSTANCE_CLOSE;
|
||||
m.instanceClose.instance = instance;
|
||||
EsMessagePost(nullptr, &m);
|
||||
|
||||
if (instance->callback) {
|
||||
EsMessage m = {};
|
||||
m.type = ES_MSG_INSTANCE_CLOSE;
|
||||
instance->callback(instance, &m);
|
||||
}
|
||||
|
||||
InspectorWindow **inspector = &((APIInstance *) instance->_private)->attachedInspector;
|
||||
|
||||
if (*inspector) {
|
||||
EsInstance *instance2 = *inspector;
|
||||
UndoManagerDestroy(instance2->undoManager);
|
||||
EsAssert(instance2->window->instance == instance2);
|
||||
EsElementDestroy(instance2->window);
|
||||
EsInstanceCloseReference(instance2);
|
||||
instance2->window->InternalDestroy();
|
||||
*inspector = nullptr;
|
||||
}
|
||||
|
||||
UndoManagerDestroy(instance->undoManager);
|
||||
EsAssert(instance->window->instance == instance);
|
||||
EsElementDestroy(instance->window);
|
||||
EsInstanceCloseReference(instance);
|
||||
}
|
||||
|
||||
EsWindow *WindowFromWindowID(EsObjectID id) {
|
||||
|
@ -952,6 +985,22 @@ EsInstance *InstanceFromWindowID(EsObjectID id) {
|
|||
return window ? window->instance : nullptr;
|
||||
}
|
||||
|
||||
void InstanceSendOpenMessage(EsInstance *instance, bool update) {
|
||||
APIInstance *apiInstance = (APIInstance *) instance->_private;
|
||||
|
||||
EsMessage m = { .type = ES_MSG_INSTANCE_OPEN };
|
||||
m.instanceOpen.name = apiInstance->startupInformation->filePath;
|
||||
m.instanceOpen.nameBytes = apiInstance->startupInformation->filePathBytes;
|
||||
m.instanceOpen.file = apiInstance->fileStore;
|
||||
m.instanceOpen.update = update;
|
||||
|
||||
int response = instance->callback ? instance->callback(instance, &m) : 0;
|
||||
if (!response) EsInstanceOpenComplete(instance, m.instanceOpen.file, true); // Ignored.
|
||||
|
||||
// TODO Support multithreaded file operations.
|
||||
EsAssert(m.instanceOpen.file->operationComplete);
|
||||
}
|
||||
|
||||
EsError GetMessage(_EsMessageWithObject *message) {
|
||||
// Process posted messages first,
|
||||
// so that messages like ES_MSG_WINDOW_DESTROYED are received last.
|
||||
|
@ -980,13 +1029,6 @@ EsMessage *EsMessageReceive() {
|
|||
if (message.message.createInstance.data != ES_INVALID_HANDLE) {
|
||||
EsHandleClose(message.message.createInstance.data);
|
||||
}
|
||||
} else if (message.message.type == ES_MSG_INSTANCE_OPEN) {
|
||||
// TODO Support multithreaded file operations.
|
||||
EsAssert(message.message.instanceOpen.file->operationComplete);
|
||||
} else if (message.message.type == ES_MSG_INSTANCE_SAVE) {
|
||||
// TODO Support multithreaded file operations.
|
||||
EsAssert(message.message.instanceSave.file->operationComplete);
|
||||
FileStoreCloseHandle(message.message.instanceSave.file);
|
||||
} else if (message.message.type == ES_MSG_APPLICATION_EXIT) {
|
||||
if (api.startupInformation->isDesktop) {
|
||||
// Desktop tracks the number of instances it owns, so it needs to know when it exits.
|
||||
|
@ -1024,48 +1066,6 @@ EsMessage *EsMessageReceive() {
|
|||
#endif
|
||||
EsProcessTerminateCurrent();
|
||||
}
|
||||
} else if (message.message.type == ES_MSG_INSTANCE_DESTROY) {
|
||||
APIInstance *instance = (APIInstance *) message.message.instanceDestroy.instance->_private;
|
||||
|
||||
if (instance->startupInformation) {
|
||||
EsHeapFree((void *) instance->startupInformation->filePath);
|
||||
EsHeapFree((void *) instance->startupInformation->containingFolder);
|
||||
}
|
||||
|
||||
EsHeapFree(instance->startupInformation);
|
||||
EsHeapFree(instance->documentPath);
|
||||
EsHeapFree(instance->newName);
|
||||
|
||||
for (uintptr_t i = 0; i < instance->commands.Count(); i++) {
|
||||
EsCommand *command = instance->commands[i];
|
||||
EsAssert(command->registered);
|
||||
EsAssert(!ArrayLength(command->elements));
|
||||
Array<EsElement *> elements = { command->elements };
|
||||
elements.Free();
|
||||
}
|
||||
|
||||
instance->commands.Free();
|
||||
if (instance->fileStore) FileStoreCloseHandle(instance->fileStore);
|
||||
EsHeapFree(instance);
|
||||
EsHeapFree(message.message.instanceDestroy.instance);
|
||||
} else if (message.message.type == ES_MSG_INSTANCE_CLOSE) {
|
||||
EsInstance *instance = message.message.instanceClose.instance;
|
||||
InspectorWindow **inspector = &((APIInstance *) instance->_private)->attachedInspector;
|
||||
|
||||
if (*inspector) {
|
||||
EsInstance *instance2 = *inspector;
|
||||
UndoManagerDestroy(instance2->undoManager);
|
||||
EsAssert(instance2->window->instance == instance2);
|
||||
EsElementDestroy(instance2->window);
|
||||
EsInstanceCloseReference(instance2);
|
||||
instance2->window->InternalDestroy();
|
||||
*inspector = nullptr;
|
||||
}
|
||||
|
||||
UndoManagerDestroy(instance->undoManager);
|
||||
EsAssert(instance->window->instance == instance);
|
||||
EsElementDestroy(instance->window);
|
||||
EsInstanceCloseReference(instance);
|
||||
} else if (message.message.type == ES_MSG_UNREGISTER_FILE_SYSTEM) {
|
||||
for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) {
|
||||
if (api.mountPoints[i].information.id == message.message.unregisterFileSystem.id) {
|
||||
|
@ -1132,34 +1132,37 @@ EsMessage *EsMessageReceive() {
|
|||
InstanceClose(instance);
|
||||
}
|
||||
} else if (type == ES_MSG_INSTANCE_SAVE_RESPONSE) {
|
||||
// TODO Support multithreaded file operations.
|
||||
|
||||
EsMessage m = {};
|
||||
m.type = ES_MSG_INSTANCE_SAVE;
|
||||
m.instanceSave.file = (EsFileStore *) EsHeapAllocate(sizeof(EsFileStore), true);
|
||||
|
||||
if (m.instanceSave.file) {
|
||||
EsInstance *_instance = InstanceFromWindowID(message.message.tabOperation.id);
|
||||
APIInstance *instance = (APIInstance *) _instance->_private;
|
||||
|
||||
m.instanceSave.file->error = message.message.tabOperation.error;
|
||||
m.instanceSave.file->handle = message.message.tabOperation.handle;
|
||||
m.instanceSave.file->type = FILE_STORE_HANDLE;
|
||||
m.instanceSave.file->handles = 1;
|
||||
m.instanceSave.instance = InstanceFromWindowID(message.message.tabOperation.id);
|
||||
|
||||
APIInstance *instance = (APIInstance *) m.instanceSave.instance->_private;
|
||||
m.instanceSave.name = instance->startupInformation->filePath;
|
||||
m.instanceSave.nameBytes = instance->startupInformation->filePathBytes;
|
||||
|
||||
if (m.instanceSave.file->error == ES_SUCCESS) {
|
||||
EsMemoryCopy(&message.message, &m, sizeof(EsMessage));
|
||||
return &message.message;
|
||||
if (m.instanceSave.file->error == ES_SUCCESS && _instance->callback && _instance->callback(_instance, &m)) {
|
||||
// The instance callback will have called EsInstanceSaveComplete.
|
||||
} else {
|
||||
EsInstanceSaveComplete(&m, false);
|
||||
EsInstanceSaveComplete(_instance, m.instanceSave.file, false);
|
||||
}
|
||||
|
||||
EsMemoryCopy(&message.message, &m, sizeof(EsMessage));
|
||||
} else {
|
||||
if (message.message.tabOperation.handle) {
|
||||
EsHandleClose(message.message.tabOperation.handle);
|
||||
}
|
||||
}
|
||||
|
||||
EsAssert(m.instanceSave.file->operationComplete);
|
||||
FileStoreCloseHandle(m.instanceSave.file);
|
||||
} else if (type == ES_MSG_INSTANCE_RENAME_RESPONSE) {
|
||||
EsInstance *instance = InstanceFromWindowID(message.message.tabOperation.id);
|
||||
|
||||
|
@ -1239,11 +1242,13 @@ EsMessage *EsMessageReceive() {
|
|||
InstanceCreateFileStore(instance, message.message.tabOperation.handle);
|
||||
|
||||
if (!message.message.tabOperation.isSource) {
|
||||
InstancePostOpenMessage(_instance, true);
|
||||
InstanceSendOpenMessage(_instance, true);
|
||||
}
|
||||
} else {
|
||||
EsHandleClose(message.message.tabOperation.handle);
|
||||
}
|
||||
} else if (type == ES_MSG_INSTANCE_OPEN_DELAYED) {
|
||||
InstanceSendOpenMessage((EsInstance *) message.message._argument, false);
|
||||
} else if (type == ES_MSG_PRIMARY_CLIPBOARD_UPDATED) {
|
||||
EsInstance *instance = InstanceFromWindowID(message.message.tabOperation.id);
|
||||
if (instance) UIRefreshPrimaryClipboard(instance->window);
|
||||
|
@ -1314,12 +1319,6 @@ EsMessage *EsMessageReceive() {
|
|||
return &message.message;
|
||||
}
|
||||
}
|
||||
} else if (type == ES_MSG_INSTANCE_DESTROY || type == ES_MSG_INSTANCE_CLOSE) {
|
||||
APIInstance *instance = (APIInstance *) message.message.instanceDestroy.instance->_private;
|
||||
|
||||
if (!instance->internalOnly) {
|
||||
return &message.message;
|
||||
}
|
||||
} else {
|
||||
return &message.message;
|
||||
}
|
||||
|
@ -1335,18 +1334,16 @@ void EsInstanceSetModified(EsInstance *instance, bool modified) {
|
|||
MessageDesktop(m, 2, instance->window->handle);
|
||||
}
|
||||
|
||||
void EsInstanceOpenComplete(EsMessage *message, bool success, const char *errorText, ptrdiff_t errorTextBytes) {
|
||||
EsInstance *instance = message->instanceOpen.instance;
|
||||
|
||||
if (!success || message->instanceOpen.file->error != ES_SUCCESS) {
|
||||
if (errorTextBytes) {
|
||||
void EsInstanceOpenComplete(EsInstance *instance, EsFileStore *file, bool success, const char *errorText, ptrdiff_t errorTextBytes) {
|
||||
if (!success || file->error != ES_SUCCESS) {
|
||||
if (errorText && errorTextBytes) {
|
||||
EsDialogShow(instance->window, INTERFACE_STRING(FileCannotOpen),
|
||||
errorText, errorTextBytes,
|
||||
ES_ICON_DIALOG_ERROR, ES_DIALOG_ALERT_OK_BUTTON);
|
||||
} else {
|
||||
const char *errorMessage = interfaceString_FileLoadErrorUnknown;
|
||||
|
||||
switch (message->instanceOpen.file->error) {
|
||||
switch (file->error) {
|
||||
case ES_ERROR_DRIVE_ERROR_FILE_DAMAGED:
|
||||
errorMessage = interfaceString_FileLoadErrorCorrupt;
|
||||
break;
|
||||
|
@ -1362,33 +1359,34 @@ void EsInstanceOpenComplete(EsMessage *message, bool success, const char *errorT
|
|||
errorMessage, -1, ES_ICON_DIALOG_ERROR, ES_DIALOG_ALERT_OK_BUTTON);
|
||||
}
|
||||
|
||||
// TODO Close the instance.
|
||||
// TODO Close the instance after the dialog is closed?
|
||||
} else {
|
||||
#if 0
|
||||
if (!message->instanceOpen.update) {
|
||||
EsUndoClear(instance->undoManager);
|
||||
}
|
||||
#endif
|
||||
|
||||
EsInstanceSetModified(instance, false);
|
||||
}
|
||||
|
||||
EsAssert(!message->instanceOpen.file->operationComplete);
|
||||
message->instanceOpen.file->operationComplete = true;
|
||||
EsAssert(!file->operationComplete);
|
||||
file->operationComplete = true;
|
||||
}
|
||||
|
||||
void EsInstanceSaveComplete(EsMessage *message, bool success) {
|
||||
if (message->instanceSave.file->error != ES_SUCCESS) {
|
||||
void EsInstanceSaveComplete(EsInstance *instance, EsFileStore *file, bool success) {
|
||||
if (file->error != ES_SUCCESS) {
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
message->instanceSave.file->error = EsFileControl(message->instanceSave.file->handle, ES_FILE_CONTROL_FLUSH);
|
||||
file->error = EsFileControl(file->handle, ES_FILE_CONTROL_FLUSH);
|
||||
|
||||
if (message->instanceSave.file->error != ES_SUCCESS) {
|
||||
if (file->error != ES_SUCCESS) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
EsInstance *instance = message->instanceSave.instance;
|
||||
APIInstance *apiInstance = (APIInstance *) instance->_private;
|
||||
|
||||
if (instance) {
|
||||
|
@ -1415,7 +1413,7 @@ void EsInstanceSaveComplete(EsMessage *message, bool success) {
|
|||
const char *errorMessage = interfaceString_FileSaveErrorUnknown;
|
||||
ptrdiff_t errorMessageBytes = -1;
|
||||
|
||||
switch (message->instanceSave.file->error) {
|
||||
switch (file->error) {
|
||||
case ES_ERROR_FILE_DOES_NOT_EXIST:
|
||||
case ES_ERROR_NODE_DELETED:
|
||||
case ES_ERROR_PERMISSION_NOT_GRANTED:
|
||||
|
@ -1459,8 +1457,8 @@ void EsInstanceSaveComplete(EsMessage *message, bool success) {
|
|||
}
|
||||
}
|
||||
|
||||
EsAssert(!message->instanceSave.file->operationComplete);
|
||||
message->instanceSave.file->operationComplete = true;
|
||||
EsAssert(!file->operationComplete);
|
||||
file->operationComplete = true;
|
||||
}
|
||||
|
||||
uintptr_t EsSystemGetOptimalWorkQueueThreadCount() {
|
||||
|
@ -2156,8 +2154,6 @@ void EsPOSIXInitialise(int *, char ***) {
|
|||
EsInstance *instance = EsInstanceCreate(message, INTERFACE_STRING(POSIXTitle));
|
||||
EsPanel *panel = EsPanelCreate((EsElement *) instance->window, ES_PANEL_VERTICAL | ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_BACKGROUND);
|
||||
EsTextDisplayCreate(panel, ES_CELL_H_CENTER | ES_CELL_V_FILL | ES_TEXT_DISPLAY_RICH_TEXT, nullptr, INTERFACE_STRING(POSIXUnavailable));
|
||||
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
|
||||
EsInstanceOpenComplete(message, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -131,14 +131,10 @@ struct InstalledApplication {
|
|||
EsFileOffset totalSize; // 0 if uncalculated.
|
||||
};
|
||||
|
||||
struct CommonDesktopInstance : EsInstance {
|
||||
void (*destroy)(EsInstance *);
|
||||
struct CrashedTabInstance : EsInstance {
|
||||
};
|
||||
|
||||
struct CrashedTabInstance : CommonDesktopInstance {
|
||||
};
|
||||
|
||||
struct BlankTabInstance : CommonDesktopInstance {
|
||||
struct BlankTabInstance : EsInstance {
|
||||
};
|
||||
|
||||
struct ApplicationProcess {
|
||||
|
@ -3134,12 +3130,6 @@ void DesktopSendMessage(EsMessage *message) {
|
|||
} else {
|
||||
// The screen resolution will be correctly queried in DesktopSetup.
|
||||
}
|
||||
} else if (message->type == ES_MSG_INSTANCE_DESTROY) {
|
||||
CommonDesktopInstance *instance = (CommonDesktopInstance *) message->instanceDestroy.instance;
|
||||
|
||||
if (instance->destroy) {
|
||||
instance->destroy(instance);
|
||||
}
|
||||
} else if (message->type == ES_MSG_KEY_DOWN) {
|
||||
ProcessGlobalKeyboardShortcuts(nullptr, message);
|
||||
} else if (message->type == MSG_SETUP_DESKTOP_UI || message->type == ES_MSG_UI_SCALE_CHANGED) {
|
||||
|
|
|
@ -151,7 +151,7 @@ void InspectorNotifyElementContentChanged(EsElement *element);
|
|||
#define UI_STATE_USE_MEASUREMENT_CACHE (1 << 21)
|
||||
|
||||
struct EsElement : EsElementPublic {
|
||||
EsUICallback messageClass;
|
||||
EsElementCallback messageClass;
|
||||
EsElement *parent;
|
||||
Array<EsElement *> children;
|
||||
uint32_t state;
|
||||
|
@ -262,7 +262,7 @@ struct EsElement : EsElementPublic {
|
|||
|
||||
void Repaint(bool all, EsRectangle region = ES_RECT_1(0) /* client coordinates */);
|
||||
|
||||
void Initialise(EsElement *_parent, uint64_t _flags, EsUICallback _classCallback, const EsStyle *style);
|
||||
void Initialise(EsElement *_parent, uint64_t _flags, EsElementCallback _classCallback, const EsStyle *style);
|
||||
};
|
||||
|
||||
struct MeasurementCache {
|
||||
|
@ -6301,7 +6301,7 @@ void EsElementInsertAfter(EsElement *element) {
|
|||
gui.insertAfter = element;
|
||||
}
|
||||
|
||||
void EsElement::Initialise(EsElement *_parent, uint64_t _flags, EsUICallback _classCallback, const EsStyle *_style) {
|
||||
void EsElement::Initialise(EsElement *_parent, uint64_t _flags, EsElementCallback _classCallback, const EsStyle *_style) {
|
||||
EsMessageMutexCheck();
|
||||
|
||||
// EsPrint("New element '%z' %x with parent %x.\n", _debugName, this, _parent);
|
||||
|
@ -6409,7 +6409,7 @@ float EsElementGetScaleFactor(EsElement *element) {
|
|||
return theming.scale;
|
||||
}
|
||||
|
||||
void EsElementSetCallback(EsElement *element, EsUICallback callback) {
|
||||
void EsElementSetCallback(EsElement *element, EsElementCallback callback) {
|
||||
EsMessageMutexCheck();
|
||||
element->messageUser = callback;
|
||||
}
|
||||
|
@ -8090,7 +8090,6 @@ void InspectorSetup(EsWindow *window) {
|
|||
EsInstanceOpenReference(inspector);
|
||||
|
||||
inspector->instance = window->instance;
|
||||
((APIInstance *) inspector->_private)->internalOnly = true;
|
||||
window->instance = inspector;
|
||||
|
||||
inspector->selectedElement = -1;
|
||||
|
|
|
@ -1757,6 +1757,7 @@ struct EsListView : EsElement {
|
|||
secondaryCellStyle->CloseReference();
|
||||
selectedCellStyle->CloseReference();
|
||||
fixedItems.Free();
|
||||
fixedItemIndices.Free();
|
||||
visibleItems.Free();
|
||||
groups.Free();
|
||||
activeColumns.Free();
|
||||
|
|
|
@ -938,7 +938,9 @@ enum EsMessageType {
|
|||
// It will be removed from the `children` later (but before the next ES_MSG_LAYOUT message is received).
|
||||
ES_MSG_PRE_ADD_CHILD = 0x200D // An element has been created with this element as its parent, but is not yet added to the parent.
|
||||
ES_MSG_HIT_TEST = 0x200E // For non-rectangular elements: test whether a pixel should be considered inside the element. Set response to ES_HANDLED.
|
||||
ES_MSG_KEY_TYPED = 0x2011 // Sent to the focused element when a key is pressed. Only if ES_HANDLED is returned the message will not propagate; this allows messageUser to block input processing by returning ES_REJECTED.
|
||||
ES_MSG_KEY_TYPED = 0x2011 // Sent to the focused element when a key is pressed.
|
||||
// Only if ES_HANDLED is returned the message will not propagate;
|
||||
// this allows messageUser to block input processing by returning ES_REJECTED.
|
||||
ES_MSG_SCROLL_X = 0x2012 // The element has been horizontally scrolled.
|
||||
ES_MSG_SCROLL_Y = 0x2013 // The element has been vertically scrolled.
|
||||
ES_MSG_STRONG_FOCUS_END = 0x2014 // Sent once when the user 'clicks off' the element, even if a new element was not necessarily focused.
|
||||
|
@ -963,6 +965,8 @@ enum EsMessageType {
|
|||
ES_MSG_TRANSITION_COMPLETE = 0x202B // The transition started with EsElementStartTransition completed.
|
||||
ES_MSG_PAINT_FOREGROUND = 0x202C // Paint the element's foreground. Sent after the children are painted.
|
||||
// The width/height parameters of EsPainter may be larger than expected - this includes the 'non-client' area.
|
||||
ES_MSG_PRIMARY_CLIPBOARD_UPDATED = 0x202D // Send to the focused element when the contents of the primary clipboard is changes.
|
||||
// This message might be delayed if the window containing the element is inactive.
|
||||
|
||||
// State change messages: (causes a style refresh)
|
||||
ES_MSG_STATE_CHANGE_MESSAGE_START = 0x2080
|
||||
|
@ -984,39 +988,11 @@ enum EsMessageType {
|
|||
ES_MSG_LIST_DISPLAY_GET_MARKER = 0x3004 // Get the string for a marker in an EsListDisplay. See message->getContent.
|
||||
ES_MSG_SLIDER_MOVED = 0x3006 // The slider has been moved.
|
||||
|
||||
// Desktop messages:
|
||||
ES_MSG_EMBEDDED_WINDOW_DESTROYED = 0x4802
|
||||
ES_MSG_SET_SCREEN_RESOLUTION = 0x4803
|
||||
ES_MSG_REGISTER_FILE_SYSTEM = 0x4804
|
||||
ES_MSG_UNREGISTER_FILE_SYSTEM = 0x4805
|
||||
ES_MSG_DESKTOP = 0x4806
|
||||
ES_MSG_DEVICE_CONNECTED = 0x4807
|
||||
ES_MSG_DEVICE_DISCONNECTED = 0x4808
|
||||
|
||||
// Messages sent from Desktop to application instances:
|
||||
ES_MSG_TAB_INSPECT_UI = 0x4A01
|
||||
ES_MSG_TAB_CLOSE_REQUEST = 0x4A02
|
||||
ES_MSG_INSTANCE_SAVE_RESPONSE = 0x4A03 // Sent by Desktop after an application requested to save its document.
|
||||
ES_MSG_INSTANCE_DOCUMENT_RENAMED = 0x4A04
|
||||
ES_MSG_INSTANCE_DOCUMENT_UPDATED = 0x4A05
|
||||
ES_MSG_PRIMARY_CLIPBOARD_UPDATED = 0x4A06
|
||||
ES_MSG_INSTANCE_RENAME_RESPONSE = 0x4A07
|
||||
|
||||
// Debugger messages:
|
||||
ES_MSG_APPLICATION_CRASH = 0x4C00
|
||||
ES_MSG_PROCESS_TERMINATED = 0x4C01
|
||||
|
||||
// Undo item messages:
|
||||
ES_MSG_UNDO_CANCEL = 0x4D00
|
||||
ES_MSG_UNDO_INVOKE = 0x4D01
|
||||
ES_MSG_UNDO_TO_STRING = 0x4D02
|
||||
|
||||
// Misc messages:
|
||||
ES_MSG_EYEDROP_REPORT = 0x5001
|
||||
ES_MSG_TIMER = 0x5003
|
||||
ES_MSG_PING = 0x5004 // Sent by Desktop to check processes are processing messages.
|
||||
ES_MSG_WAKEUP = 0x5005 // Sent to wakeup the message thread, so that it can process locally posted messages.
|
||||
|
||||
// File Manager messages:
|
||||
ES_MSG_FILE_MANAGER_FILE_MODIFIED = 0x5100
|
||||
ES_MSG_FILE_MANAGER_PATH_MOVED = 0x5101
|
||||
|
@ -1057,12 +1033,22 @@ enum EsMessageType {
|
|||
ES_MSG_REORDER_ITEM_MOVED = 0x5401
|
||||
|
||||
// Application messages:
|
||||
ES_MSG_APPLICATION_EXIT = 0x7001
|
||||
ES_MSG_INSTANCE_CREATE = 0x7002
|
||||
ES_MSG_INSTANCE_OPEN = 0x7003
|
||||
ES_MSG_INSTANCE_SAVE = 0x7004
|
||||
ES_MSG_INSTANCE_DESTROY = 0x7005
|
||||
ES_MSG_INSTANCE_CLOSE = 0x7006
|
||||
ES_MSG_APPLICATION_EXIT = 0x6001
|
||||
ES_MSG_INSTANCE_CREATE = 0x6002
|
||||
ES_MSG_DEVICE_CONNECTED = 0x6003
|
||||
ES_MSG_DEVICE_DISCONNECTED = 0x6004
|
||||
ES_MSG_REGISTER_FILE_SYSTEM = 0x6005
|
||||
ES_MSG_UNREGISTER_FILE_SYSTEM = 0x6006
|
||||
|
||||
// Instance messages:
|
||||
ES_MSG_INSTANCE_OPEN = 0x6800
|
||||
ES_MSG_INSTANCE_SAVE = 0x6801
|
||||
ES_MSG_INSTANCE_DESTROY = 0x6802
|
||||
ES_MSG_INSTANCE_CLOSE = 0x6803
|
||||
|
||||
// Messages for internal use by the system:
|
||||
ES_MSG_SYSTEM_START = 0x7000
|
||||
ES_MSG_SYSTEM_END = 0x7FFF
|
||||
|
||||
// User messages:
|
||||
ES_MSG_USER_START = 0x8000
|
||||
|
@ -1182,7 +1168,8 @@ enum EsDeviceControlType {
|
|||
ES_DEVICE_CONTROL_CLOCK_READ = 0x2001
|
||||
}
|
||||
|
||||
function_pointer int EsUICallback(struct EsElement *element, struct EsMessage *message);
|
||||
function_pointer int EsElementCallback(struct EsElement *element, struct EsMessage *message);
|
||||
function_pointer int EsInstanceCallback(ES_INSTANCE_TYPE *instance, struct EsMessage *message);
|
||||
|
||||
struct EsBuffer {
|
||||
union { const uint8_t *in; uint8_t *out; };
|
||||
|
@ -1193,7 +1180,7 @@ struct EsBuffer {
|
|||
};
|
||||
|
||||
struct EsElementPublic {
|
||||
EsUICallback messageUser;
|
||||
EsElementCallback messageUser;
|
||||
EsCString cName;
|
||||
EsGeneric userData;
|
||||
char accessKey; // Upper-case.
|
||||
|
@ -1339,6 +1326,9 @@ struct EsInstance {
|
|||
void *_private;
|
||||
EsWindow *window;
|
||||
EsUndoManager *undoManager;
|
||||
|
||||
// Read-write.
|
||||
EsInstanceCallback callback;
|
||||
};
|
||||
|
||||
struct EsPanelBand {
|
||||
|
@ -1769,26 +1759,16 @@ struct EsMessageEndEdit {
|
|||
// Instance messages.
|
||||
|
||||
struct EsMessageInstanceOpen {
|
||||
ES_INSTANCE_TYPE *instance;
|
||||
EsFileStore *file;
|
||||
STRING name;
|
||||
bool update;
|
||||
};
|
||||
|
||||
struct EsMessageInstanceSave {
|
||||
ES_INSTANCE_TYPE *instance;
|
||||
EsFileStore *file;
|
||||
STRING name;
|
||||
};
|
||||
|
||||
struct EsMessageInstanceDestroy {
|
||||
ES_INSTANCE_TYPE *instance;
|
||||
};
|
||||
|
||||
struct EsMessageInstanceClose {
|
||||
ES_INSTANCE_TYPE *instance;
|
||||
};
|
||||
|
||||
// Internal system messages.
|
||||
|
||||
struct EsMessageProcessCrash {
|
||||
|
@ -1902,8 +1882,6 @@ struct EsMessage {
|
|||
// Instance messages:
|
||||
EsMessageInstanceOpen instanceOpen;
|
||||
EsMessageInstanceSave instanceSave;
|
||||
EsMessageInstanceDestroy instanceDestroy;
|
||||
EsMessageInstanceClose instanceClose;
|
||||
|
||||
// Internal messages:
|
||||
void *_argument;
|
||||
|
@ -2423,8 +2401,8 @@ function void EsInstanceSetActiveUndoManager(ES_INSTANCE_TYPE *instance, EsUndoM
|
|||
function void EsInstanceSetClassEditor(ES_INSTANCE_TYPE *instance, const EsInstanceClassEditorSettings *settings);
|
||||
function void EsInstanceSetClassViewer(ES_INSTANCE_TYPE *instance, const EsInstanceClassViewerSettings *settings);
|
||||
function EsApplicationStartupRequest EsInstanceGetStartupRequest(ES_INSTANCE_TYPE *instance);
|
||||
function void EsInstanceOpenComplete(EsMessage *message, bool success, STRING errorText = BLANK_STRING);
|
||||
function void EsInstanceSaveComplete(EsMessage *message, bool success);
|
||||
function void EsInstanceOpenComplete(ES_INSTANCE_TYPE *instance, EsFileStore *file, bool success, STRING errorText = BLANK_STRING);
|
||||
function void EsInstanceSaveComplete(ES_INSTANCE_TYPE *instance, EsFileStore *file, bool success);
|
||||
function void EsInstanceSetModified(ES_INSTANCE_TYPE *instance, bool modified);
|
||||
|
||||
function EsError EsUserTaskStart(EsUserTaskCallback callback, EsGeneric data, STRING title, uint32_t iconID);
|
||||
|
@ -2450,7 +2428,7 @@ function bool EsElementIsFocused(EsElement *element);
|
|||
function void EsElementSetDisabled(EsElement *element, bool disabled = true);
|
||||
function void EsElementSetHidden(EsElement *element, bool hidden = true);
|
||||
function bool EsElementIsHidden(EsElement *element);
|
||||
function void EsElementSetCallback(EsElement *element, EsUICallback callback);
|
||||
function void EsElementSetCallback(EsElement *element, EsElementCallback callback);
|
||||
function void EsElementGetSize(EsElement *element, int *width, int *height);
|
||||
function void EsElementRepaint(EsElement *element, const EsRectangle *region = ES_NULL); // Mark an element to be repainted. If region is null, then the whole element is repainted.
|
||||
function void EsElementRepaintForScroll(EsElement *element, EsMessage *message, EsRectangle border); // Minimal repaint for ES_MSG_SCROLL_X/Y.
|
||||
|
|
|
@ -387,6 +387,30 @@ extern "C" void *EsBufferWrite(EsBuffer *buffer, const void *source, size_t writ
|
|||
#define ES_THEME_CURSORS_WIDTH (264)
|
||||
#define ES_THEME_CURSORS_HEIGHT (128)
|
||||
|
||||
// Desktop messages:
|
||||
#define ES_MSG_EMBEDDED_WINDOW_DESTROYED ((EsMessageType) (ES_MSG_SYSTEM_START + 0x001))
|
||||
#define ES_MSG_SET_SCREEN_RESOLUTION ((EsMessageType) (ES_MSG_SYSTEM_START + 0x002))
|
||||
#define ES_MSG_DESKTOP ((EsMessageType) (ES_MSG_SYSTEM_START + 0x005))
|
||||
|
||||
// Messages sent from Desktop to application instances:
|
||||
#define ES_MSG_TAB_INSPECT_UI ((EsMessageType) (ES_MSG_SYSTEM_START + 0x101))
|
||||
#define ES_MSG_TAB_CLOSE_REQUEST ((EsMessageType) (ES_MSG_SYSTEM_START + 0x102))
|
||||
#define ES_MSG_INSTANCE_SAVE_RESPONSE ((EsMessageType) (ES_MSG_SYSTEM_START + 0x103)) // Sent by Desktop after an application requested to save its document.
|
||||
#define ES_MSG_INSTANCE_DOCUMENT_RENAMED ((EsMessageType) (ES_MSG_SYSTEM_START + 0x104))
|
||||
#define ES_MSG_INSTANCE_DOCUMENT_UPDATED ((EsMessageType) (ES_MSG_SYSTEM_START + 0x105))
|
||||
#define ES_MSG_INSTANCE_RENAME_RESPONSE ((EsMessageType) (ES_MSG_SYSTEM_START + 0x107))
|
||||
|
||||
// Debugger messages:
|
||||
#define ES_MSG_APPLICATION_CRASH ((EsMessageType) (ES_MSG_SYSTEM_START + 0x201))
|
||||
#define ES_MSG_PROCESS_TERMINATED ((EsMessageType) (ES_MSG_SYSTEM_START + 0x202))
|
||||
|
||||
// Misc messages:
|
||||
#define ES_MSG_EYEDROP_REPORT ((EsMessageType) (ES_MSG_SYSTEM_START + 0x301))
|
||||
#define ES_MSG_TIMER ((EsMessageType) (ES_MSG_SYSTEM_START + 0x302))
|
||||
#define ES_MSG_PING ((EsMessageType) (ES_MSG_SYSTEM_START + 0x303)) // Sent by Desktop to check processes are processing messages.
|
||||
#define ES_MSG_WAKEUP ((EsMessageType) (ES_MSG_SYSTEM_START + 0x304)) // Sent to wakeup the message thread, so that it can process locally posted messages.
|
||||
#define ES_MSG_INSTANCE_OPEN_DELAYED ((EsMessageType) (ES_MSG_SYSTEM_START + 0x305))
|
||||
|
||||
#endif
|
||||
|
||||
// --------- CRT function macros:
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// It is released under the terms of the MIT license -- see LICENSE.md.
|
||||
// Written by: nakst.
|
||||
|
||||
struct SettingsInstance : CommonDesktopInstance {
|
||||
struct SettingsInstance : EsInstance {
|
||||
EsPanel *switcher;
|
||||
EsPanel *mainPage;
|
||||
EsButton *undoButton, *backButton;
|
||||
|
@ -885,7 +885,11 @@ void InstanceSettingsCreate(EsMessage *message) {
|
|||
}
|
||||
}
|
||||
|
||||
instance->destroy = [] (EsInstance *) {
|
||||
ConfigurationWriteToFile();
|
||||
instance->callback = [] (EsInstance *, EsMessage *message) {
|
||||
if (message->type == ES_MSG_INSTANCE_DESTROY) {
|
||||
ConfigurationWriteToFile();
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2921,7 +2921,7 @@ struct EsTextbox : EsElement {
|
|||
|
||||
bool ensureCaretVisibleQueued;
|
||||
|
||||
EsUICallback overlayCallback;
|
||||
EsElementCallback overlayCallback;
|
||||
EsGeneric overlayData;
|
||||
|
||||
char *activeLine;
|
||||
|
@ -3348,8 +3348,6 @@ void TextboxEnsureCaretVisibleActionCallback(EsElement *element, EsGeneric conte
|
|||
bool verticallyCenter = context.u;
|
||||
TextboxCaret caret = textbox->carets[1];
|
||||
|
||||
EsPrint("TextboxEnsureCaretVisibleActionCallback ------------\n");
|
||||
|
||||
for (uintptr_t i = 0; i < 3; i++) {
|
||||
// ScrollPane::SetY causes ES_MSG_SCROLL_Y to get sent to the textbox.
|
||||
// This causes a TextboxRefreshVisibleLines, which may cause new lines to added.
|
||||
|
|
|
@ -197,6 +197,8 @@ static bool ReadWrite(FSNode *file, uint64_t offset, uint64_t count, uint8_t *bu
|
|||
ESFS_CHECK(data, "Read - Expected data attribute.");
|
||||
|
||||
if (data->indirection == ESFS_INDIRECTION_DIRECT) {
|
||||
EsAssert(data->dataOffset + offset <= data->size && data->dataOffset + offset + count <= data->size);
|
||||
|
||||
if (write) {
|
||||
EsMemoryCopy((uint8_t *) data + data->dataOffset + offset, buffer, count);
|
||||
} else {
|
||||
|
@ -1423,15 +1425,18 @@ static EsError RemoveDirectoryEntry(FSNode *file, uint8_t *blockBuffers /* super
|
|||
|
||||
// EsPrint("\tpositionOfLastEntry = %d\n\tThis node Reference = %d/%d\n", positionOfLastEntry, file->reference.block, file->reference.offsetIntoBlock);
|
||||
|
||||
ESFS_CHECK_TO_ERROR(AccessBlock(volume, file->reference.block, 1, blockBuffers, FS_BLOCK_ACCESS_CACHED, K_ACCESS_READ), "Remove - Could not load the container block.", ES_ERROR_DRIVE_CONTROLLER_REPORTED);
|
||||
ESFS_CHECK_TO_ERROR(AccessBlock(volume, file->reference.block, 1, blockBuffers, FS_BLOCK_ACCESS_CACHED, K_ACCESS_READ),
|
||||
"Remove - Could not load the container block.", ES_ERROR_DRIVE_CONTROLLER_REPORTED);
|
||||
ESFS_CHECK_TO_ERROR(ReadWrite(directory, positionOfLastEntry & ~(superblock->blockSize - 1), superblock->blockSize,
|
||||
blockBuffers + superblock->blockSize, false, false), "Remove - Could not load the last block.", ES_ERROR_DRIVE_CONTROLLER_REPORTED);
|
||||
ESFS_CHECK_TO_ERROR(0 == EsMemoryCompare(blockBuffers + file->reference.offsetIntoBlock, &file->entry, sizeof(DirectoryEntry)), "Remove - Inconsistent file entry.", ES_ERROR_DRIVE_CONTROLLER_REPORTED);
|
||||
ESFS_CHECK_TO_ERROR(0 == EsMemoryCompare(blockBuffers + file->reference.offsetIntoBlock, &file->entry, sizeof(DirectoryEntry)),
|
||||
"Remove - Inconsistent file entry.", ES_ERROR_DRIVE_CONTROLLER_REPORTED);
|
||||
|
||||
DirectoryEntry *movedEntry = (DirectoryEntry *) (blockBuffers + superblock->blockSize + (positionOfLastEntry & (superblock->blockSize - 1)));
|
||||
DirectoryEntry *deletedEntry = (DirectoryEntry *) (blockBuffers + file->reference.offsetIntoBlock);
|
||||
EsMemoryCopy(deletedEntry, movedEntry, sizeof(DirectoryEntry));
|
||||
ESFS_CHECK_TO_ERROR(AccessBlock(volume, file->reference.block, 1, blockBuffers, FS_BLOCK_ACCESS_CACHED, K_ACCESS_WRITE), "Remove - Could not save the container block.", ES_ERROR_DRIVE_CONTROLLER_REPORTED);
|
||||
ESFS_CHECK_TO_ERROR(AccessBlock(volume, file->reference.block, 1, blockBuffers, FS_BLOCK_ACCESS_CACHED, K_ACCESS_WRITE),
|
||||
"Remove - Could not save the container block.", ES_ERROR_DRIVE_CONTROLLER_REPORTED);
|
||||
|
||||
// Step 2: Update the node for the moved entry.
|
||||
|
||||
|
@ -1450,7 +1455,8 @@ static EsError RemoveDirectoryEntry(FSNode *file, uint8_t *blockBuffers /* super
|
|||
|
||||
uint64_t key = CalculateCRC64(filename->filename, filename->length);
|
||||
// EsPrint("\tModify index key for %s\n", filename->length, filename->filename);
|
||||
ESFS_CHECK_TO_ERROR(IndexModifyKey(volume, key, file->reference, directoryAttribute->indexRootBlock, blockBuffers + superblock->blockSize), "Remove - Could not update index (2).", ES_ERROR_DRIVE_CONTROLLER_REPORTED);
|
||||
ESFS_CHECK_TO_ERROR(IndexModifyKey(volume, key, file->reference, directoryAttribute->indexRootBlock, blockBuffers + superblock->blockSize),
|
||||
"Remove - Could not update index (2).", ES_ERROR_DRIVE_CONTROLLER_REPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1094,6 +1094,7 @@ EsError CCSpaceAccess(CCSpace *cache, K_USER_BUFFER void *_buffer, EsFileOffset
|
|||
KMutexRelease(&cache->cachedSectionsMutex);
|
||||
|
||||
if (error != ES_SUCCESS) {
|
||||
CCActiveSectionReturnToLists(section, false);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
|
@ -913,8 +913,14 @@ EsError FSDirectoryEntryFound(KNode *_parent, KNodeMetadata *metadata,
|
|||
nameBytes, name, parent);
|
||||
}
|
||||
|
||||
if (update) {
|
||||
EsMemoryCopy(existingEntry->thisItem + 1, driverData, driverDataBytes);
|
||||
}
|
||||
|
||||
if (node) {
|
||||
if (!update) {
|
||||
// Only try to create a node for this directory entry if update is false.
|
||||
|
||||
if (existingEntry->thisItem->node) {
|
||||
KernelPanic("FSDirectoryEntryFound - Entry exists and is created on file system.\n");
|
||||
}
|
||||
|
@ -927,9 +933,9 @@ EsError FSDirectoryEntryFound(KNode *_parent, KNodeMetadata *metadata,
|
|||
}
|
||||
|
||||
*node = existingEntry->thisItem->node;
|
||||
} else if (update) {
|
||||
EsMemoryCopy(existingEntry->thisItem + 1, driverData, driverDataBytes);
|
||||
} else if (EsMemoryCompare(existingEntry->thisItem + 1, driverData, driverDataBytes)) {
|
||||
}
|
||||
|
||||
if (!node && !update && EsMemoryCompare(existingEntry->thisItem + 1, driverData, driverDataBytes)) {
|
||||
// NOTE This can be caused by a directory containing an entry with the same name multiple times.
|
||||
KernelLog(LOG_ERROR, "FS", "directory entry driverData changed", "FSDirectoryEntryFound - 'update' is false but driverData has changed.\n");
|
||||
}
|
||||
|
|
|
@ -230,6 +230,26 @@ void SetDimensions(int width, int height) {
|
|||
EsElementRepaint(instance->display);
|
||||
}
|
||||
|
||||
int InstanceCallback(Instance *instance, EsMessage *message) {
|
||||
if (message->type == ES_MSG_INSTANCE_DESTROY) {
|
||||
// TODO Tell the emulator to stop.
|
||||
// unlink(configurationFile); (Do this on the POSIX thread.)
|
||||
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
|
||||
configurationFileData = (char *) EsFileStoreReadAll(message->instanceOpen.file, &configurationFileBytes);
|
||||
|
||||
if (!configurationFileData) {
|
||||
EsInstanceOpenComplete(instance, message->instanceOpen.file, false);
|
||||
} else {
|
||||
EsEventSet(openEvent);
|
||||
EsInstanceOpenComplete(instance, message->instanceOpen.file, true);
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ES_HANDLED;
|
||||
}
|
||||
|
||||
void MessageLoopThread(EsGeneric) {
|
||||
EsPrint("Reached message loop thread...\n");
|
||||
EsMessageMutexAcquire();
|
||||
|
@ -239,24 +259,13 @@ void MessageLoopThread(EsGeneric) {
|
|||
|
||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
||||
instance = EsInstanceCreate(message, "Bochs");
|
||||
instance->callback = InstanceCallback;
|
||||
EsWindowSetTitle(instance->window, "Bochs", -1);
|
||||
EsWindowSetIcon(instance->window, ES_ICON_APPLICATIONS_DEVELOPMENT);
|
||||
instance->display = EsCustomElementCreate(instance->window, ES_CELL_FILL | ES_ELEMENT_FOCUSABLE);
|
||||
instance->display->messageUser = CanvasCallback;
|
||||
EsElementFocus(instance->display);
|
||||
SetDimensions(640, 480);
|
||||
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
|
||||
configurationFileData = (char *) EsFileStoreReadAll(message->instanceOpen.file, &configurationFileBytes);
|
||||
|
||||
if (!configurationFileData) {
|
||||
EsInstanceOpenComplete(message, false);
|
||||
} else {
|
||||
EsEventSet(openEvent);
|
||||
EsInstanceOpenComplete(message, true);
|
||||
}
|
||||
} else if (message->type == ES_MSG_INSTANCE_DESTROY) {
|
||||
// TODO Tell the emulator to stop.
|
||||
// unlink(configurationFile); (Do this on the POSIX thread.)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -298,6 +298,19 @@ bool LoadModel(char *model, size_t modelBytes) {
|
|||
return true;
|
||||
}
|
||||
|
||||
int InstanceCallback(EsInstance *, EsMessage *message) {
|
||||
if (message->type == ES_MSG_INSTANCE_OPEN) {
|
||||
size_t modelBytes;
|
||||
void *model = EsFileStoreReadAll(message->instanceOpen.file, &modelBytes);
|
||||
EsInstanceOpenComplete(message, LoadModel(model, modelBytes), NULL, 0);
|
||||
EsHeapFree(model, 0, NULL);
|
||||
loadedModel = true;
|
||||
return ES_HANDLED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
@ -436,16 +449,11 @@ int main(int argc, char **argv) {
|
|||
|
||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
||||
EsInstance *instance = EsInstanceCreate(message, "Object Viewer", -1);
|
||||
instance->callback = InstanceCallback;
|
||||
EsWindowSetIcon(instance->window, ES_ICON_MODEL);
|
||||
EsElement *canvas = EsCustomElementCreate(instance->window, ES_CELL_FILL, 0);
|
||||
canvas->messageUser = (EsUICallback) CanvasCallback;
|
||||
EsElementStartAnimating(canvas);
|
||||
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
|
||||
size_t modelBytes;
|
||||
void *model = EsFileStoreReadAll(message->instanceOpen.file, &modelBytes);
|
||||
EsInstanceOpenComplete(message, LoadModel(model, modelBytes), NULL, 0);
|
||||
EsHeapFree(model, 0, NULL);
|
||||
loadedModel = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -337,20 +337,28 @@ int CanvasMessage(EsElement *element, EsMessage *message) {
|
|||
return ES_HANDLED;
|
||||
}
|
||||
|
||||
int InstanceCallback(EsInstance *instance, EsMessage *message) {
|
||||
if (message->type == ES_MSG_INSTANCE_OPEN) {
|
||||
size_t romBytes;
|
||||
void *rom = EsFileStoreReadAll(message->instanceOpen.file, &romBytes);
|
||||
EsInstanceOpenComplete(instance, message->instanceOpen.file, rom && Launch(rom, romBytes), NULL, 0);
|
||||
EsHeapFree(rom, 0, NULL);
|
||||
return ES_HANDLED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _start() {
|
||||
while (true) {
|
||||
EsMessage *message = EsMessageReceive();
|
||||
|
||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
||||
EsInstance *instance = EsInstanceCreate(message, "Uxn Emulator", -1);
|
||||
instance->callback = InstanceCallback;
|
||||
canvas = EsCustomElementCreate(instance->window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER);
|
||||
canvas->messageUser = (EsUICallback) CanvasMessage;
|
||||
canvas->messageUser = (EsElementCallback) CanvasMessage;
|
||||
EsElementStartAnimating(canvas);
|
||||
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
|
||||
size_t romBytes;
|
||||
void *rom = EsFileStoreReadAll(message->instanceOpen.file, &romBytes);
|
||||
EsInstanceOpenComplete(message, rom && Launch(rom, romBytes), NULL, 0);
|
||||
EsHeapFree(rom, 0, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1626,6 +1626,10 @@ uint8_t *EsImageLoad(const void *file, size_t fileSize, uint32_t *imageX, uint32
|
|||
int unused;
|
||||
uint32_t *image = (uint32_t *) stbi_load_from_memory((uint8_t *) file, fileSize, (int *) imageX, (int *) imageY, &unused, imageChannels);
|
||||
|
||||
if (!image) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (uintptr_t j = 0; j < *imageY; j++) {
|
||||
for (uintptr_t i = 0; i < *imageX; i++) {
|
||||
uint32_t in = image[i + j * *imageX];
|
||||
|
@ -2605,15 +2609,23 @@ void *EsBufferWrite(EsBuffer *buffer, const void *source, size_t writeBytes) {
|
|||
return NULL;
|
||||
#ifdef ES_API
|
||||
} else if (buffer->fileStore) {
|
||||
while (writeBytes && !buffer->error) {
|
||||
if (buffer->position == buffer->bytes) {
|
||||
EsBufferFlushToFileStore(buffer);
|
||||
} else {
|
||||
size_t bytesToWrite = writeBytes > buffer->bytes - buffer->position ? buffer->bytes - buffer->position : writeBytes;
|
||||
EsMemoryCopy(buffer->out + buffer->position, source, bytesToWrite);
|
||||
buffer->position += bytesToWrite;
|
||||
writeBytes -= bytesToWrite;
|
||||
source = (const uint8_t *) source + bytesToWrite;
|
||||
if (writeBytes > buffer->bytes) {
|
||||
EsBufferFlushToFileStore(buffer);
|
||||
|
||||
if (!buffer->error) {
|
||||
buffer->error = !EsFileStoreAppend(buffer->fileStore, source, writeBytes);
|
||||
}
|
||||
} else {
|
||||
while (writeBytes && !buffer->error) {
|
||||
if (buffer->position == buffer->bytes) {
|
||||
EsBufferFlushToFileStore(buffer);
|
||||
} else {
|
||||
size_t bytesToWrite = writeBytes > buffer->bytes - buffer->position ? buffer->bytes - buffer->position : writeBytes;
|
||||
EsMemoryCopy(buffer->out + buffer->position, source, bytesToWrite);
|
||||
buffer->position += bytesToWrite;
|
||||
writeBytes -= bytesToWrite;
|
||||
source = (const uint8_t *) source + bytesToWrite;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,8 +38,6 @@
|
|||
// Path boolean operations.
|
||||
// Timeline editor for applying a given state change, with rows for possibly many different layers.
|
||||
// Metrics: layoutVertical, textFigures.
|
||||
|
||||
// TODO Reorganize old theming data!
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -3760,19 +3758,25 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
#ifdef OS_ESSENCE
|
||||
void _UIMessageProcess(EsMessage *message) {
|
||||
if (message->type == ES_MSG_INSTANCE_OPEN) {
|
||||
void _UIMessageProcess(EsMessage *message) {}
|
||||
|
||||
int _UIInstanceCallback(EsInstance *instance, EsMessage *message) {
|
||||
if (message->type == ES_MSG_INSTANCE_SAVE) {
|
||||
fileStore = message->instanceSave.file;
|
||||
DocumentSave(nullptr);
|
||||
EsInstanceSaveComplete(instance, fileStore, true);
|
||||
fileStore = nullptr;
|
||||
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
|
||||
DocumentFree();
|
||||
fileStore = message->instanceOpen.file;
|
||||
DocumentLoad();
|
||||
EsInstanceOpenComplete(instance, fileStore, true);
|
||||
fileStore = nullptr;
|
||||
EsInstanceOpenComplete(message, true);
|
||||
} else if (message->type == ES_MSG_INSTANCE_SAVE) {
|
||||
fileStore = message->instanceSave.file;
|
||||
DocumentSave(nullptr);
|
||||
fileStore = nullptr;
|
||||
EsInstanceSaveComplete(message, true);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ES_HANDLED;
|
||||
}
|
||||
|
||||
void _start() {
|
||||
|
|
|
@ -69,6 +69,9 @@
|
|||
|
||||
// Callback to allow the application to process messages.
|
||||
void _UIMessageProcess(EsMessage *message);
|
||||
|
||||
// Callback for instances.
|
||||
int _UIInstanceCallback(ES_INSTANCE_TYPE *instance, EsMessage *message);
|
||||
#endif
|
||||
|
||||
#ifdef UI_DEBUG
|
||||
|
@ -729,7 +732,7 @@ struct {
|
|||
#endif
|
||||
|
||||
#ifdef UI_ESSENCE
|
||||
EsInstance *instance;
|
||||
ES_INSTANCE_TYPE *instance;
|
||||
|
||||
void *menuData[256]; // HACK This limits the number of menu items to 128.
|
||||
uintptr_t menuIndex;
|
||||
|
@ -5339,6 +5342,7 @@ void UIInitialise() {
|
|||
|
||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
||||
ui.instance = EsInstanceCreate(message, NULL, 0);
|
||||
ui.instance->callback = _UIInstanceCallback;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue