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() {
|
void _start() {
|
||||||
_init();
|
_init();
|
||||||
|
|
||||||
|
@ -514,6 +538,7 @@ void _start() {
|
||||||
|
|
||||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
||||||
Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(FileManagerTitle));
|
Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(FileManagerTitle));
|
||||||
|
instance->callback = InstanceCallback;
|
||||||
|
|
||||||
EsApplicationStartupRequest request = EsInstanceGetStartupRequest(instance);
|
EsApplicationStartupRequest request = EsInstanceGetStartupRequest(instance);
|
||||||
|
|
||||||
|
@ -523,26 +548,6 @@ void _start() {
|
||||||
instances.Add(instance);
|
instances.Add(instance);
|
||||||
InstanceCreateUI(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) {
|
} else if (message->type == ES_MSG_APPLICATION_EXIT) {
|
||||||
#ifdef DEBUG_BUILD
|
#ifdef DEBUG_BUILD
|
||||||
for (uintptr_t i = 0; i < drives.Length(); i++) {
|
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);
|
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() {
|
void _start() {
|
||||||
_init();
|
_init();
|
||||||
|
|
||||||
|
@ -306,6 +362,7 @@ void _start() {
|
||||||
|
|
||||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
||||||
Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(FontBookTitle));
|
Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(FontBookTitle));
|
||||||
|
instance->callback = InstanceCallback;
|
||||||
EsWindowSetIcon(instance->window, ES_ICON_APPLICATIONS_FONTS);
|
EsWindowSetIcon(instance->window, ES_ICON_APPLICATIONS_FONTS);
|
||||||
EsPanel *rootPanel = EsPanelCreate(instance->window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER);
|
EsPanel *rootPanel = EsPanelCreate(instance->window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER);
|
||||||
|
|
||||||
|
@ -374,56 +431,6 @@ void _start() {
|
||||||
button->accessKey = 'B';
|
button->accessKey = 'B';
|
||||||
EsButtonSetIcon(button, ES_ICON_GO_PREVIOUS_SYMBOLIC);
|
EsButtonSetIcon(button, ES_ICON_GO_PREVIOUS_SYMBOLIC);
|
||||||
EsButtonOnCommand(button, BackCommand);
|
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);
|
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) {
|
void InstanceCreate(EsMessage *message) {
|
||||||
Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(ImageEditorTitle));
|
Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(ImageEditorTitle));
|
||||||
|
instance->callback = InstanceCallback;
|
||||||
|
|
||||||
EsElement *toolbar = EsWindowGetToolbar(instance->window);
|
EsElement *toolbar = EsWindowGetToolbar(instance->window);
|
||||||
EsInstanceSetClassEditor(instance, &editorSettings);
|
EsInstanceSetClassEditor(instance, &editorSettings);
|
||||||
|
|
||||||
|
@ -802,19 +905,6 @@ void InstanceCreate(EsMessage *message) {
|
||||||
ImageCopyFromPaintTarget(instance, &instance->image, painter.clip);
|
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() {
|
void _start() {
|
||||||
_init();
|
_init();
|
||||||
|
|
||||||
|
@ -823,86 +913,6 @@ void _start() {
|
||||||
|
|
||||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
||||||
InstanceCreate(message);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessApplicationMessage(EsMessage *message) {
|
int InstanceCallback(Instance *instance, EsMessage *message) {
|
||||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
if (message->type == ES_MSG_INSTANCE_OPEN) {
|
||||||
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;
|
|
||||||
|
|
||||||
if (message->instanceOpen.update) {
|
if (message->instanceOpen.update) {
|
||||||
EsElementStartTransition(instance->root, ES_TRANSITION_ZOOM_IN);
|
EsElementStartTransition(instance->root, ES_TRANSITION_ZOOM_IN);
|
||||||
}
|
}
|
||||||
|
@ -467,8 +457,8 @@ void ProcessApplicationMessage(EsMessage *message) {
|
||||||
char *file = (char *) EsFileStoreReadAll(message->instanceOpen.file, &fileSize);
|
char *file = (char *) EsFileStoreReadAll(message->instanceOpen.file, &fileSize);
|
||||||
|
|
||||||
if (!file || !EsUTF8IsValid(file, fileSize)) {
|
if (!file || !EsUTF8IsValid(file, fileSize)) {
|
||||||
EsInstanceOpenComplete(message, false);
|
EsInstanceOpenComplete(instance, message->instanceOpen.file, false);
|
||||||
return;
|
return ES_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
MD_PARSER parser = {};
|
MD_PARSER parser = {};
|
||||||
|
@ -481,12 +471,29 @@ void ProcessApplicationMessage(EsMessage *message) {
|
||||||
instance->active = instance->root;
|
instance->active = instance->root;
|
||||||
int result = md_parse(file, fileSize, &parser, instance);
|
int result = md_parse(file, fileSize, &parser, instance);
|
||||||
if (result) EsElementDestroyContents(instance->root); // An error occurred.
|
if (result) EsElementDestroyContents(instance->root); // An error occurred.
|
||||||
EsInstanceOpenComplete(message, result == 0);
|
EsInstanceOpenComplete(instance, message->instanceOpen.file, result == 0);
|
||||||
EsHeapFree(file);
|
EsHeapFree(file);
|
||||||
|
|
||||||
EsElementRelayout(instance->root);
|
EsElementRelayout(instance->root);
|
||||||
instance->spans.Free();
|
instance->spans.Free();
|
||||||
instance->text.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) {
|
void ProcessApplicationMessage(EsMessage *message) {
|
||||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
||||||
Instance *instance = EsInstanceCreate(message, "System Monitor");
|
Instance *instance = EsInstanceCreate(message, "System Monitor");
|
||||||
|
instance->callback = InstanceCallback;
|
||||||
|
|
||||||
EsCommandRegister(&instance->commandTerminateProcess, instance, EsLiteral("Terminate process"), TerminateProcess, 1, "Del", false);
|
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);
|
EsSpacerCreate(buttonGroup, ES_CELL_V_FILL, ES_STYLE_TOOLBAR_BUTTON_GROUP_SEPARATOR);
|
||||||
AddTab(buttonGroup, DISPLAY_MEMORY, "Memory");
|
AddTab(buttonGroup, DISPLAY_MEMORY, "Memory");
|
||||||
EsSpacerCreate(toolbar, ES_CELL_H_FILL);
|
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) {
|
void ProcessApplicationMessage(EsMessage *message) {
|
||||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
||||||
Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(TextEditorTitle));
|
Instance *instance = EsInstanceCreate(message, INTERFACE_STRING(TextEditorTitle));
|
||||||
|
instance->callback = InstanceCallback;
|
||||||
EsInstanceSetClassEditor(instance, &editorSettings);
|
EsInstanceSetClassEditor(instance, &editorSettings);
|
||||||
|
|
||||||
EsWindow *window = instance->window;
|
EsWindow *window = instance->window;
|
||||||
|
@ -357,43 +400,6 @@ void ProcessApplicationMessage(EsMessage *message) {
|
||||||
button = EsButtonCreate(buttonGroup, ES_FLAGS_DEFAULT, {}, INTERFACE_STRING(CommonSearchPrevious));
|
button = EsButtonCreate(buttonGroup, ES_FLAGS_DEFAULT, {}, INTERFACE_STRING(CommonSearchPrevious));
|
||||||
button->accessKey = 'P';
|
button->accessKey = 'P';
|
||||||
EsCommandAddButton(&instance->commandFindPrevious, button);
|
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) {
|
} else if (message->type == ES_MSG_APPLICATION_EXIT) {
|
||||||
EsBuffer buffer = {};
|
EsBuffer buffer = {};
|
||||||
buffer.canGrow = true;
|
buffer.canGrow = true;
|
||||||
|
|
210
desktop/api.cpp
210
desktop/api.cpp
|
@ -238,10 +238,6 @@ struct APIInstance {
|
||||||
|
|
||||||
bool closeAfterSaveCompletes;
|
bool closeAfterSaveCompletes;
|
||||||
|
|
||||||
// Do not propagate messages about this instance to the application.
|
|
||||||
// Currently only used for inspectors.
|
|
||||||
bool internalOnly;
|
|
||||||
|
|
||||||
union {
|
union {
|
||||||
EsInstanceClassEditorSettings editorSettings;
|
EsInstanceClassEditorSettings editorSettings;
|
||||||
EsInstanceClassViewerSettings viewerSettings;
|
EsInstanceClassViewerSettings viewerSettings;
|
||||||
|
@ -799,17 +795,6 @@ void InstanceCreateFileStore(APIInstance *instance, EsHandle handle) {
|
||||||
instance->fileStore = FileStoreCreateFromHandle(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 *InstanceSetup(EsInstance *instance) {
|
||||||
APIInstance *apiInstance = (APIInstance *) EsHeapAllocate(sizeof(APIInstance), true);
|
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) {
|
if (apiInstance->startupInformation && apiInstance->startupInformation->readHandle) {
|
||||||
InstanceCreateFileStore(apiInstance, apiInstance->startupInformation->readHandle);
|
InstanceCreateFileStore(apiInstance, apiInstance->startupInformation->readHandle);
|
||||||
InstancePostOpenMessage(instance, false);
|
|
||||||
EsWindowSetTitle(instance->window, apiInstance->startupInformation->filePath, apiInstance->startupInformation->filePathBytes);
|
EsWindowSetTitle(instance->window, apiInstance->startupInformation->filePath, apiInstance->startupInformation->filePathBytes);
|
||||||
EsCommandSetDisabled(&apiInstance->commandShowInFileManager, false);
|
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--;
|
instance->referenceCount--;
|
||||||
|
|
||||||
if (!instance->referenceCount) {
|
if (!instance->referenceCount) {
|
||||||
EsMessage m = {};
|
if (_instance->callback) {
|
||||||
m.type = ES_MSG_INSTANCE_DESTROY;
|
EsMessage m = {};
|
||||||
m.instanceDestroy.instance = _instance;
|
m.type = ES_MSG_INSTANCE_DESTROY;
|
||||||
EsMessagePost(nullptr, &m);
|
_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) {
|
void EsInstanceClose(EsInstance *instance) {
|
||||||
EsMessageMutexCheck();
|
EsMessageMutexCheck();
|
||||||
EsMessage m = {};
|
|
||||||
m.type = ES_MSG_INSTANCE_CLOSE;
|
if (instance->callback) {
|
||||||
m.instanceClose.instance = instance;
|
EsMessage m = {};
|
||||||
EsMessagePost(nullptr, &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) {
|
EsWindow *WindowFromWindowID(EsObjectID id) {
|
||||||
|
@ -952,6 +985,22 @@ EsInstance *InstanceFromWindowID(EsObjectID id) {
|
||||||
return window ? window->instance : nullptr;
|
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) {
|
EsError GetMessage(_EsMessageWithObject *message) {
|
||||||
// Process posted messages first,
|
// Process posted messages first,
|
||||||
// so that messages like ES_MSG_WINDOW_DESTROYED are received last.
|
// 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) {
|
if (message.message.createInstance.data != ES_INVALID_HANDLE) {
|
||||||
EsHandleClose(message.message.createInstance.data);
|
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) {
|
} else if (message.message.type == ES_MSG_APPLICATION_EXIT) {
|
||||||
if (api.startupInformation->isDesktop) {
|
if (api.startupInformation->isDesktop) {
|
||||||
// Desktop tracks the number of instances it owns, so it needs to know when it exits.
|
// Desktop tracks the number of instances it owns, so it needs to know when it exits.
|
||||||
|
@ -1024,48 +1066,6 @@ EsMessage *EsMessageReceive() {
|
||||||
#endif
|
#endif
|
||||||
EsProcessTerminateCurrent();
|
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) {
|
} else if (message.message.type == ES_MSG_UNREGISTER_FILE_SYSTEM) {
|
||||||
for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) {
|
for (uintptr_t i = 0; i < api.mountPoints.Length(); i++) {
|
||||||
if (api.mountPoints[i].information.id == message.message.unregisterFileSystem.id) {
|
if (api.mountPoints[i].information.id == message.message.unregisterFileSystem.id) {
|
||||||
|
@ -1132,34 +1132,37 @@ EsMessage *EsMessageReceive() {
|
||||||
InstanceClose(instance);
|
InstanceClose(instance);
|
||||||
}
|
}
|
||||||
} else if (type == ES_MSG_INSTANCE_SAVE_RESPONSE) {
|
} else if (type == ES_MSG_INSTANCE_SAVE_RESPONSE) {
|
||||||
|
// TODO Support multithreaded file operations.
|
||||||
|
|
||||||
EsMessage m = {};
|
EsMessage m = {};
|
||||||
m.type = ES_MSG_INSTANCE_SAVE;
|
m.type = ES_MSG_INSTANCE_SAVE;
|
||||||
m.instanceSave.file = (EsFileStore *) EsHeapAllocate(sizeof(EsFileStore), true);
|
m.instanceSave.file = (EsFileStore *) EsHeapAllocate(sizeof(EsFileStore), true);
|
||||||
|
|
||||||
if (m.instanceSave.file) {
|
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->error = message.message.tabOperation.error;
|
||||||
m.instanceSave.file->handle = message.message.tabOperation.handle;
|
m.instanceSave.file->handle = message.message.tabOperation.handle;
|
||||||
m.instanceSave.file->type = FILE_STORE_HANDLE;
|
m.instanceSave.file->type = FILE_STORE_HANDLE;
|
||||||
m.instanceSave.file->handles = 1;
|
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.name = instance->startupInformation->filePath;
|
||||||
m.instanceSave.nameBytes = instance->startupInformation->filePathBytes;
|
m.instanceSave.nameBytes = instance->startupInformation->filePathBytes;
|
||||||
|
|
||||||
if (m.instanceSave.file->error == ES_SUCCESS) {
|
if (m.instanceSave.file->error == ES_SUCCESS && _instance->callback && _instance->callback(_instance, &m)) {
|
||||||
EsMemoryCopy(&message.message, &m, sizeof(EsMessage));
|
// The instance callback will have called EsInstanceSaveComplete.
|
||||||
return &message.message;
|
|
||||||
} else {
|
} else {
|
||||||
EsInstanceSaveComplete(&m, false);
|
EsInstanceSaveComplete(_instance, m.instanceSave.file, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
EsMemoryCopy(&message.message, &m, sizeof(EsMessage));
|
|
||||||
} else {
|
} else {
|
||||||
if (message.message.tabOperation.handle) {
|
if (message.message.tabOperation.handle) {
|
||||||
EsHandleClose(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) {
|
} else if (type == ES_MSG_INSTANCE_RENAME_RESPONSE) {
|
||||||
EsInstance *instance = InstanceFromWindowID(message.message.tabOperation.id);
|
EsInstance *instance = InstanceFromWindowID(message.message.tabOperation.id);
|
||||||
|
|
||||||
|
@ -1239,11 +1242,13 @@ EsMessage *EsMessageReceive() {
|
||||||
InstanceCreateFileStore(instance, message.message.tabOperation.handle);
|
InstanceCreateFileStore(instance, message.message.tabOperation.handle);
|
||||||
|
|
||||||
if (!message.message.tabOperation.isSource) {
|
if (!message.message.tabOperation.isSource) {
|
||||||
InstancePostOpenMessage(_instance, true);
|
InstanceSendOpenMessage(_instance, true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
EsHandleClose(message.message.tabOperation.handle);
|
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) {
|
} else if (type == ES_MSG_PRIMARY_CLIPBOARD_UPDATED) {
|
||||||
EsInstance *instance = InstanceFromWindowID(message.message.tabOperation.id);
|
EsInstance *instance = InstanceFromWindowID(message.message.tabOperation.id);
|
||||||
if (instance) UIRefreshPrimaryClipboard(instance->window);
|
if (instance) UIRefreshPrimaryClipboard(instance->window);
|
||||||
|
@ -1314,12 +1319,6 @@ EsMessage *EsMessageReceive() {
|
||||||
return &message.message;
|
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 {
|
} else {
|
||||||
return &message.message;
|
return &message.message;
|
||||||
}
|
}
|
||||||
|
@ -1335,18 +1334,16 @@ void EsInstanceSetModified(EsInstance *instance, bool modified) {
|
||||||
MessageDesktop(m, 2, instance->window->handle);
|
MessageDesktop(m, 2, instance->window->handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EsInstanceOpenComplete(EsMessage *message, bool success, const char *errorText, ptrdiff_t errorTextBytes) {
|
void EsInstanceOpenComplete(EsInstance *instance, EsFileStore *file, bool success, const char *errorText, ptrdiff_t errorTextBytes) {
|
||||||
EsInstance *instance = message->instanceOpen.instance;
|
if (!success || file->error != ES_SUCCESS) {
|
||||||
|
if (errorText && errorTextBytes) {
|
||||||
if (!success || message->instanceOpen.file->error != ES_SUCCESS) {
|
|
||||||
if (errorTextBytes) {
|
|
||||||
EsDialogShow(instance->window, INTERFACE_STRING(FileCannotOpen),
|
EsDialogShow(instance->window, INTERFACE_STRING(FileCannotOpen),
|
||||||
errorText, errorTextBytes,
|
errorText, errorTextBytes,
|
||||||
ES_ICON_DIALOG_ERROR, ES_DIALOG_ALERT_OK_BUTTON);
|
ES_ICON_DIALOG_ERROR, ES_DIALOG_ALERT_OK_BUTTON);
|
||||||
} else {
|
} else {
|
||||||
const char *errorMessage = interfaceString_FileLoadErrorUnknown;
|
const char *errorMessage = interfaceString_FileLoadErrorUnknown;
|
||||||
|
|
||||||
switch (message->instanceOpen.file->error) {
|
switch (file->error) {
|
||||||
case ES_ERROR_DRIVE_ERROR_FILE_DAMAGED:
|
case ES_ERROR_DRIVE_ERROR_FILE_DAMAGED:
|
||||||
errorMessage = interfaceString_FileLoadErrorCorrupt;
|
errorMessage = interfaceString_FileLoadErrorCorrupt;
|
||||||
break;
|
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);
|
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 {
|
} else {
|
||||||
|
#if 0
|
||||||
if (!message->instanceOpen.update) {
|
if (!message->instanceOpen.update) {
|
||||||
EsUndoClear(instance->undoManager);
|
EsUndoClear(instance->undoManager);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
EsInstanceSetModified(instance, false);
|
EsInstanceSetModified(instance, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
EsAssert(!message->instanceOpen.file->operationComplete);
|
EsAssert(!file->operationComplete);
|
||||||
message->instanceOpen.file->operationComplete = true;
|
file->operationComplete = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EsInstanceSaveComplete(EsMessage *message, bool success) {
|
void EsInstanceSaveComplete(EsInstance *instance, EsFileStore *file, bool success) {
|
||||||
if (message->instanceSave.file->error != ES_SUCCESS) {
|
if (file->error != ES_SUCCESS) {
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (success) {
|
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;
|
success = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EsInstance *instance = message->instanceSave.instance;
|
|
||||||
APIInstance *apiInstance = (APIInstance *) instance->_private;
|
APIInstance *apiInstance = (APIInstance *) instance->_private;
|
||||||
|
|
||||||
if (instance) {
|
if (instance) {
|
||||||
|
@ -1415,7 +1413,7 @@ void EsInstanceSaveComplete(EsMessage *message, bool success) {
|
||||||
const char *errorMessage = interfaceString_FileSaveErrorUnknown;
|
const char *errorMessage = interfaceString_FileSaveErrorUnknown;
|
||||||
ptrdiff_t errorMessageBytes = -1;
|
ptrdiff_t errorMessageBytes = -1;
|
||||||
|
|
||||||
switch (message->instanceSave.file->error) {
|
switch (file->error) {
|
||||||
case ES_ERROR_FILE_DOES_NOT_EXIST:
|
case ES_ERROR_FILE_DOES_NOT_EXIST:
|
||||||
case ES_ERROR_NODE_DELETED:
|
case ES_ERROR_NODE_DELETED:
|
||||||
case ES_ERROR_PERMISSION_NOT_GRANTED:
|
case ES_ERROR_PERMISSION_NOT_GRANTED:
|
||||||
|
@ -1459,8 +1457,8 @@ void EsInstanceSaveComplete(EsMessage *message, bool success) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EsAssert(!message->instanceSave.file->operationComplete);
|
EsAssert(!file->operationComplete);
|
||||||
message->instanceSave.file->operationComplete = true;
|
file->operationComplete = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t EsSystemGetOptimalWorkQueueThreadCount() {
|
uintptr_t EsSystemGetOptimalWorkQueueThreadCount() {
|
||||||
|
@ -2156,8 +2154,6 @@ void EsPOSIXInitialise(int *, char ***) {
|
||||||
EsInstance *instance = EsInstanceCreate(message, INTERFACE_STRING(POSIXTitle));
|
EsInstance *instance = EsInstanceCreate(message, INTERFACE_STRING(POSIXTitle));
|
||||||
EsPanel *panel = EsPanelCreate((EsElement *) instance->window, ES_PANEL_VERTICAL | ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_BACKGROUND);
|
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));
|
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.
|
EsFileOffset totalSize; // 0 if uncalculated.
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CommonDesktopInstance : EsInstance {
|
struct CrashedTabInstance : EsInstance {
|
||||||
void (*destroy)(EsInstance *);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CrashedTabInstance : CommonDesktopInstance {
|
struct BlankTabInstance : EsInstance {
|
||||||
};
|
|
||||||
|
|
||||||
struct BlankTabInstance : CommonDesktopInstance {
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ApplicationProcess {
|
struct ApplicationProcess {
|
||||||
|
@ -3134,12 +3130,6 @@ void DesktopSendMessage(EsMessage *message) {
|
||||||
} else {
|
} else {
|
||||||
// The screen resolution will be correctly queried in DesktopSetup.
|
// 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) {
|
} else if (message->type == ES_MSG_KEY_DOWN) {
|
||||||
ProcessGlobalKeyboardShortcuts(nullptr, message);
|
ProcessGlobalKeyboardShortcuts(nullptr, message);
|
||||||
} else if (message->type == MSG_SETUP_DESKTOP_UI || message->type == ES_MSG_UI_SCALE_CHANGED) {
|
} 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)
|
#define UI_STATE_USE_MEASUREMENT_CACHE (1 << 21)
|
||||||
|
|
||||||
struct EsElement : EsElementPublic {
|
struct EsElement : EsElementPublic {
|
||||||
EsUICallback messageClass;
|
EsElementCallback messageClass;
|
||||||
EsElement *parent;
|
EsElement *parent;
|
||||||
Array<EsElement *> children;
|
Array<EsElement *> children;
|
||||||
uint32_t state;
|
uint32_t state;
|
||||||
|
@ -262,7 +262,7 @@ struct EsElement : EsElementPublic {
|
||||||
|
|
||||||
void Repaint(bool all, EsRectangle region = ES_RECT_1(0) /* client coordinates */);
|
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 {
|
struct MeasurementCache {
|
||||||
|
@ -6301,7 +6301,7 @@ void EsElementInsertAfter(EsElement *element) {
|
||||||
gui.insertAfter = 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();
|
EsMessageMutexCheck();
|
||||||
|
|
||||||
// EsPrint("New element '%z' %x with parent %x.\n", _debugName, this, _parent);
|
// EsPrint("New element '%z' %x with parent %x.\n", _debugName, this, _parent);
|
||||||
|
@ -6409,7 +6409,7 @@ float EsElementGetScaleFactor(EsElement *element) {
|
||||||
return theming.scale;
|
return theming.scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EsElementSetCallback(EsElement *element, EsUICallback callback) {
|
void EsElementSetCallback(EsElement *element, EsElementCallback callback) {
|
||||||
EsMessageMutexCheck();
|
EsMessageMutexCheck();
|
||||||
element->messageUser = callback;
|
element->messageUser = callback;
|
||||||
}
|
}
|
||||||
|
@ -8090,7 +8090,6 @@ void InspectorSetup(EsWindow *window) {
|
||||||
EsInstanceOpenReference(inspector);
|
EsInstanceOpenReference(inspector);
|
||||||
|
|
||||||
inspector->instance = window->instance;
|
inspector->instance = window->instance;
|
||||||
((APIInstance *) inspector->_private)->internalOnly = true;
|
|
||||||
window->instance = inspector;
|
window->instance = inspector;
|
||||||
|
|
||||||
inspector->selectedElement = -1;
|
inspector->selectedElement = -1;
|
||||||
|
|
|
@ -1757,6 +1757,7 @@ struct EsListView : EsElement {
|
||||||
secondaryCellStyle->CloseReference();
|
secondaryCellStyle->CloseReference();
|
||||||
selectedCellStyle->CloseReference();
|
selectedCellStyle->CloseReference();
|
||||||
fixedItems.Free();
|
fixedItems.Free();
|
||||||
|
fixedItemIndices.Free();
|
||||||
visibleItems.Free();
|
visibleItems.Free();
|
||||||
groups.Free();
|
groups.Free();
|
||||||
activeColumns.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).
|
// 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_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_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_X = 0x2012 // The element has been horizontally scrolled.
|
||||||
ES_MSG_SCROLL_Y = 0x2013 // The element has been vertically 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.
|
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_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.
|
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.
|
// 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)
|
// State change messages: (causes a style refresh)
|
||||||
ES_MSG_STATE_CHANGE_MESSAGE_START = 0x2080
|
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_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.
|
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:
|
// Undo item messages:
|
||||||
ES_MSG_UNDO_CANCEL = 0x4D00
|
ES_MSG_UNDO_CANCEL = 0x4D00
|
||||||
ES_MSG_UNDO_INVOKE = 0x4D01
|
ES_MSG_UNDO_INVOKE = 0x4D01
|
||||||
ES_MSG_UNDO_TO_STRING = 0x4D02
|
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:
|
// File Manager messages:
|
||||||
ES_MSG_FILE_MANAGER_FILE_MODIFIED = 0x5100
|
ES_MSG_FILE_MANAGER_FILE_MODIFIED = 0x5100
|
||||||
ES_MSG_FILE_MANAGER_PATH_MOVED = 0x5101
|
ES_MSG_FILE_MANAGER_PATH_MOVED = 0x5101
|
||||||
|
@ -1057,12 +1033,22 @@ enum EsMessageType {
|
||||||
ES_MSG_REORDER_ITEM_MOVED = 0x5401
|
ES_MSG_REORDER_ITEM_MOVED = 0x5401
|
||||||
|
|
||||||
// Application messages:
|
// Application messages:
|
||||||
ES_MSG_APPLICATION_EXIT = 0x7001
|
ES_MSG_APPLICATION_EXIT = 0x6001
|
||||||
ES_MSG_INSTANCE_CREATE = 0x7002
|
ES_MSG_INSTANCE_CREATE = 0x6002
|
||||||
ES_MSG_INSTANCE_OPEN = 0x7003
|
ES_MSG_DEVICE_CONNECTED = 0x6003
|
||||||
ES_MSG_INSTANCE_SAVE = 0x7004
|
ES_MSG_DEVICE_DISCONNECTED = 0x6004
|
||||||
ES_MSG_INSTANCE_DESTROY = 0x7005
|
ES_MSG_REGISTER_FILE_SYSTEM = 0x6005
|
||||||
ES_MSG_INSTANCE_CLOSE = 0x7006
|
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:
|
// User messages:
|
||||||
ES_MSG_USER_START = 0x8000
|
ES_MSG_USER_START = 0x8000
|
||||||
|
@ -1182,7 +1168,8 @@ enum EsDeviceControlType {
|
||||||
ES_DEVICE_CONTROL_CLOCK_READ = 0x2001
|
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 {
|
struct EsBuffer {
|
||||||
union { const uint8_t *in; uint8_t *out; };
|
union { const uint8_t *in; uint8_t *out; };
|
||||||
|
@ -1193,7 +1180,7 @@ struct EsBuffer {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EsElementPublic {
|
struct EsElementPublic {
|
||||||
EsUICallback messageUser;
|
EsElementCallback messageUser;
|
||||||
EsCString cName;
|
EsCString cName;
|
||||||
EsGeneric userData;
|
EsGeneric userData;
|
||||||
char accessKey; // Upper-case.
|
char accessKey; // Upper-case.
|
||||||
|
@ -1339,6 +1326,9 @@ struct EsInstance {
|
||||||
void *_private;
|
void *_private;
|
||||||
EsWindow *window;
|
EsWindow *window;
|
||||||
EsUndoManager *undoManager;
|
EsUndoManager *undoManager;
|
||||||
|
|
||||||
|
// Read-write.
|
||||||
|
EsInstanceCallback callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EsPanelBand {
|
struct EsPanelBand {
|
||||||
|
@ -1769,26 +1759,16 @@ struct EsMessageEndEdit {
|
||||||
// Instance messages.
|
// Instance messages.
|
||||||
|
|
||||||
struct EsMessageInstanceOpen {
|
struct EsMessageInstanceOpen {
|
||||||
ES_INSTANCE_TYPE *instance;
|
|
||||||
EsFileStore *file;
|
EsFileStore *file;
|
||||||
STRING name;
|
STRING name;
|
||||||
bool update;
|
bool update;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EsMessageInstanceSave {
|
struct EsMessageInstanceSave {
|
||||||
ES_INSTANCE_TYPE *instance;
|
|
||||||
EsFileStore *file;
|
EsFileStore *file;
|
||||||
STRING name;
|
STRING name;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EsMessageInstanceDestroy {
|
|
||||||
ES_INSTANCE_TYPE *instance;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct EsMessageInstanceClose {
|
|
||||||
ES_INSTANCE_TYPE *instance;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Internal system messages.
|
// Internal system messages.
|
||||||
|
|
||||||
struct EsMessageProcessCrash {
|
struct EsMessageProcessCrash {
|
||||||
|
@ -1902,8 +1882,6 @@ struct EsMessage {
|
||||||
// Instance messages:
|
// Instance messages:
|
||||||
EsMessageInstanceOpen instanceOpen;
|
EsMessageInstanceOpen instanceOpen;
|
||||||
EsMessageInstanceSave instanceSave;
|
EsMessageInstanceSave instanceSave;
|
||||||
EsMessageInstanceDestroy instanceDestroy;
|
|
||||||
EsMessageInstanceClose instanceClose;
|
|
||||||
|
|
||||||
// Internal messages:
|
// Internal messages:
|
||||||
void *_argument;
|
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 EsInstanceSetClassEditor(ES_INSTANCE_TYPE *instance, const EsInstanceClassEditorSettings *settings);
|
||||||
function void EsInstanceSetClassViewer(ES_INSTANCE_TYPE *instance, const EsInstanceClassViewerSettings *settings);
|
function void EsInstanceSetClassViewer(ES_INSTANCE_TYPE *instance, const EsInstanceClassViewerSettings *settings);
|
||||||
function EsApplicationStartupRequest EsInstanceGetStartupRequest(ES_INSTANCE_TYPE *instance);
|
function EsApplicationStartupRequest EsInstanceGetStartupRequest(ES_INSTANCE_TYPE *instance);
|
||||||
function void EsInstanceOpenComplete(EsMessage *message, bool success, STRING errorText = BLANK_STRING);
|
function void EsInstanceOpenComplete(ES_INSTANCE_TYPE *instance, EsFileStore *file, bool success, STRING errorText = BLANK_STRING);
|
||||||
function void EsInstanceSaveComplete(EsMessage *message, bool success);
|
function void EsInstanceSaveComplete(ES_INSTANCE_TYPE *instance, EsFileStore *file, bool success);
|
||||||
function void EsInstanceSetModified(ES_INSTANCE_TYPE *instance, bool modified);
|
function void EsInstanceSetModified(ES_INSTANCE_TYPE *instance, bool modified);
|
||||||
|
|
||||||
function EsError EsUserTaskStart(EsUserTaskCallback callback, EsGeneric data, STRING title, uint32_t iconID);
|
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 EsElementSetDisabled(EsElement *element, bool disabled = true);
|
||||||
function void EsElementSetHidden(EsElement *element, bool hidden = true);
|
function void EsElementSetHidden(EsElement *element, bool hidden = true);
|
||||||
function bool EsElementIsHidden(EsElement *element);
|
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 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 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.
|
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_WIDTH (264)
|
||||||
#define ES_THEME_CURSORS_HEIGHT (128)
|
#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
|
#endif
|
||||||
|
|
||||||
// --------- CRT function macros:
|
// --------- CRT function macros:
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// It is released under the terms of the MIT license -- see LICENSE.md.
|
// It is released under the terms of the MIT license -- see LICENSE.md.
|
||||||
// Written by: nakst.
|
// Written by: nakst.
|
||||||
|
|
||||||
struct SettingsInstance : CommonDesktopInstance {
|
struct SettingsInstance : EsInstance {
|
||||||
EsPanel *switcher;
|
EsPanel *switcher;
|
||||||
EsPanel *mainPage;
|
EsPanel *mainPage;
|
||||||
EsButton *undoButton, *backButton;
|
EsButton *undoButton, *backButton;
|
||||||
|
@ -885,7 +885,11 @@ void InstanceSettingsCreate(EsMessage *message) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
instance->destroy = [] (EsInstance *) {
|
instance->callback = [] (EsInstance *, EsMessage *message) {
|
||||||
ConfigurationWriteToFile();
|
if (message->type == ES_MSG_INSTANCE_DESTROY) {
|
||||||
|
ConfigurationWriteToFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -2921,7 +2921,7 @@ struct EsTextbox : EsElement {
|
||||||
|
|
||||||
bool ensureCaretVisibleQueued;
|
bool ensureCaretVisibleQueued;
|
||||||
|
|
||||||
EsUICallback overlayCallback;
|
EsElementCallback overlayCallback;
|
||||||
EsGeneric overlayData;
|
EsGeneric overlayData;
|
||||||
|
|
||||||
char *activeLine;
|
char *activeLine;
|
||||||
|
@ -3348,8 +3348,6 @@ void TextboxEnsureCaretVisibleActionCallback(EsElement *element, EsGeneric conte
|
||||||
bool verticallyCenter = context.u;
|
bool verticallyCenter = context.u;
|
||||||
TextboxCaret caret = textbox->carets[1];
|
TextboxCaret caret = textbox->carets[1];
|
||||||
|
|
||||||
EsPrint("TextboxEnsureCaretVisibleActionCallback ------------\n");
|
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < 3; i++) {
|
for (uintptr_t i = 0; i < 3; i++) {
|
||||||
// ScrollPane::SetY causes ES_MSG_SCROLL_Y to get sent to the textbox.
|
// ScrollPane::SetY causes ES_MSG_SCROLL_Y to get sent to the textbox.
|
||||||
// This causes a TextboxRefreshVisibleLines, which may cause new lines to added.
|
// 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.");
|
ESFS_CHECK(data, "Read - Expected data attribute.");
|
||||||
|
|
||||||
if (data->indirection == ESFS_INDIRECTION_DIRECT) {
|
if (data->indirection == ESFS_INDIRECTION_DIRECT) {
|
||||||
|
EsAssert(data->dataOffset + offset <= data->size && data->dataOffset + offset + count <= data->size);
|
||||||
|
|
||||||
if (write) {
|
if (write) {
|
||||||
EsMemoryCopy((uint8_t *) data + data->dataOffset + offset, buffer, count);
|
EsMemoryCopy((uint8_t *) data + data->dataOffset + offset, buffer, count);
|
||||||
} else {
|
} 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);
|
// 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,
|
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);
|
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 *movedEntry = (DirectoryEntry *) (blockBuffers + superblock->blockSize + (positionOfLastEntry & (superblock->blockSize - 1)));
|
||||||
DirectoryEntry *deletedEntry = (DirectoryEntry *) (blockBuffers + file->reference.offsetIntoBlock);
|
DirectoryEntry *deletedEntry = (DirectoryEntry *) (blockBuffers + file->reference.offsetIntoBlock);
|
||||||
EsMemoryCopy(deletedEntry, movedEntry, sizeof(DirectoryEntry));
|
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.
|
// 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);
|
uint64_t key = CalculateCRC64(filename->filename, filename->length);
|
||||||
// EsPrint("\tModify index key for %s\n", filename->length, filename->filename);
|
// 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);
|
KMutexRelease(&cache->cachedSectionsMutex);
|
||||||
|
|
||||||
if (error != ES_SUCCESS) {
|
if (error != ES_SUCCESS) {
|
||||||
|
CCActiveSectionReturnToLists(section, false);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -913,8 +913,14 @@ EsError FSDirectoryEntryFound(KNode *_parent, KNodeMetadata *metadata,
|
||||||
nameBytes, name, parent);
|
nameBytes, name, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (update) {
|
||||||
|
EsMemoryCopy(existingEntry->thisItem + 1, driverData, driverDataBytes);
|
||||||
|
}
|
||||||
|
|
||||||
if (node) {
|
if (node) {
|
||||||
if (!update) {
|
if (!update) {
|
||||||
|
// Only try to create a node for this directory entry if update is false.
|
||||||
|
|
||||||
if (existingEntry->thisItem->node) {
|
if (existingEntry->thisItem->node) {
|
||||||
KernelPanic("FSDirectoryEntryFound - Entry exists and is created on file system.\n");
|
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;
|
*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.
|
// 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");
|
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);
|
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) {
|
void MessageLoopThread(EsGeneric) {
|
||||||
EsPrint("Reached message loop thread...\n");
|
EsPrint("Reached message loop thread...\n");
|
||||||
EsMessageMutexAcquire();
|
EsMessageMutexAcquire();
|
||||||
|
@ -239,24 +259,13 @@ void MessageLoopThread(EsGeneric) {
|
||||||
|
|
||||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
||||||
instance = EsInstanceCreate(message, "Bochs");
|
instance = EsInstanceCreate(message, "Bochs");
|
||||||
|
instance->callback = InstanceCallback;
|
||||||
EsWindowSetTitle(instance->window, "Bochs", -1);
|
EsWindowSetTitle(instance->window, "Bochs", -1);
|
||||||
EsWindowSetIcon(instance->window, ES_ICON_APPLICATIONS_DEVELOPMENT);
|
EsWindowSetIcon(instance->window, ES_ICON_APPLICATIONS_DEVELOPMENT);
|
||||||
instance->display = EsCustomElementCreate(instance->window, ES_CELL_FILL | ES_ELEMENT_FOCUSABLE);
|
instance->display = EsCustomElementCreate(instance->window, ES_CELL_FILL | ES_ELEMENT_FOCUSABLE);
|
||||||
instance->display->messageUser = CanvasCallback;
|
instance->display->messageUser = CanvasCallback;
|
||||||
EsElementFocus(instance->display);
|
EsElementFocus(instance->display);
|
||||||
SetDimensions(640, 480);
|
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;
|
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) {
|
int main(int argc, char **argv) {
|
||||||
(void) argc;
|
(void) argc;
|
||||||
(void) argv;
|
(void) argv;
|
||||||
|
@ -436,16 +449,11 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
||||||
EsInstance *instance = EsInstanceCreate(message, "Object Viewer", -1);
|
EsInstance *instance = EsInstanceCreate(message, "Object Viewer", -1);
|
||||||
|
instance->callback = InstanceCallback;
|
||||||
EsWindowSetIcon(instance->window, ES_ICON_MODEL);
|
EsWindowSetIcon(instance->window, ES_ICON_MODEL);
|
||||||
EsElement *canvas = EsCustomElementCreate(instance->window, ES_CELL_FILL, 0);
|
EsElement *canvas = EsCustomElementCreate(instance->window, ES_CELL_FILL, 0);
|
||||||
canvas->messageUser = (EsUICallback) CanvasCallback;
|
canvas->messageUser = (EsUICallback) CanvasCallback;
|
||||||
EsElementStartAnimating(canvas);
|
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;
|
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() {
|
void _start() {
|
||||||
while (true) {
|
while (true) {
|
||||||
EsMessage *message = EsMessageReceive();
|
EsMessage *message = EsMessageReceive();
|
||||||
|
|
||||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
||||||
EsInstance *instance = EsInstanceCreate(message, "Uxn Emulator", -1);
|
EsInstance *instance = EsInstanceCreate(message, "Uxn Emulator", -1);
|
||||||
|
instance->callback = InstanceCallback;
|
||||||
canvas = EsCustomElementCreate(instance->window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER);
|
canvas = EsCustomElementCreate(instance->window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER);
|
||||||
canvas->messageUser = (EsUICallback) CanvasMessage;
|
canvas->messageUser = (EsElementCallback) CanvasMessage;
|
||||||
EsElementStartAnimating(canvas);
|
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;
|
int unused;
|
||||||
uint32_t *image = (uint32_t *) stbi_load_from_memory((uint8_t *) file, fileSize, (int *) imageX, (int *) imageY, &unused, imageChannels);
|
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 j = 0; j < *imageY; j++) {
|
||||||
for (uintptr_t i = 0; i < *imageX; i++) {
|
for (uintptr_t i = 0; i < *imageX; i++) {
|
||||||
uint32_t in = image[i + j * *imageX];
|
uint32_t in = image[i + j * *imageX];
|
||||||
|
@ -2605,15 +2609,23 @@ void *EsBufferWrite(EsBuffer *buffer, const void *source, size_t writeBytes) {
|
||||||
return NULL;
|
return NULL;
|
||||||
#ifdef ES_API
|
#ifdef ES_API
|
||||||
} else if (buffer->fileStore) {
|
} else if (buffer->fileStore) {
|
||||||
while (writeBytes && !buffer->error) {
|
if (writeBytes > buffer->bytes) {
|
||||||
if (buffer->position == buffer->bytes) {
|
EsBufferFlushToFileStore(buffer);
|
||||||
EsBufferFlushToFileStore(buffer);
|
|
||||||
} else {
|
if (!buffer->error) {
|
||||||
size_t bytesToWrite = writeBytes > buffer->bytes - buffer->position ? buffer->bytes - buffer->position : writeBytes;
|
buffer->error = !EsFileStoreAppend(buffer->fileStore, source, writeBytes);
|
||||||
EsMemoryCopy(buffer->out + buffer->position, source, bytesToWrite);
|
}
|
||||||
buffer->position += bytesToWrite;
|
} else {
|
||||||
writeBytes -= bytesToWrite;
|
while (writeBytes && !buffer->error) {
|
||||||
source = (const uint8_t *) source + bytesToWrite;
|
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.
|
// Path boolean operations.
|
||||||
// Timeline editor for applying a given state change, with rows for possibly many different layers.
|
// Timeline editor for applying a given state change, with rows for possibly many different layers.
|
||||||
// Metrics: layoutVertical, textFigures.
|
// Metrics: layoutVertical, textFigures.
|
||||||
|
|
||||||
// TODO Reorganize old theming data!
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -3760,19 +3758,25 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef OS_ESSENCE
|
#ifdef OS_ESSENCE
|
||||||
void _UIMessageProcess(EsMessage *message) {
|
void _UIMessageProcess(EsMessage *message) {}
|
||||||
if (message->type == ES_MSG_INSTANCE_OPEN) {
|
|
||||||
|
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();
|
DocumentFree();
|
||||||
fileStore = message->instanceOpen.file;
|
fileStore = message->instanceOpen.file;
|
||||||
DocumentLoad();
|
DocumentLoad();
|
||||||
|
EsInstanceOpenComplete(instance, fileStore, true);
|
||||||
fileStore = nullptr;
|
fileStore = nullptr;
|
||||||
EsInstanceOpenComplete(message, true);
|
} else {
|
||||||
} else if (message->type == ES_MSG_INSTANCE_SAVE) {
|
return 0;
|
||||||
fileStore = message->instanceSave.file;
|
|
||||||
DocumentSave(nullptr);
|
|
||||||
fileStore = nullptr;
|
|
||||||
EsInstanceSaveComplete(message, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ES_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _start() {
|
void _start() {
|
||||||
|
|
|
@ -69,6 +69,9 @@
|
||||||
|
|
||||||
// Callback to allow the application to process messages.
|
// Callback to allow the application to process messages.
|
||||||
void _UIMessageProcess(EsMessage *message);
|
void _UIMessageProcess(EsMessage *message);
|
||||||
|
|
||||||
|
// Callback for instances.
|
||||||
|
int _UIInstanceCallback(ES_INSTANCE_TYPE *instance, EsMessage *message);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef UI_DEBUG
|
#ifdef UI_DEBUG
|
||||||
|
@ -729,7 +732,7 @@ struct {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef UI_ESSENCE
|
#ifdef UI_ESSENCE
|
||||||
EsInstance *instance;
|
ES_INSTANCE_TYPE *instance;
|
||||||
|
|
||||||
void *menuData[256]; // HACK This limits the number of menu items to 128.
|
void *menuData[256]; // HACK This limits the number of menu items to 128.
|
||||||
uintptr_t menuIndex;
|
uintptr_t menuIndex;
|
||||||
|
@ -5339,6 +5342,7 @@ void UIInitialise() {
|
||||||
|
|
||||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
||||||
ui.instance = EsInstanceCreate(message, NULL, 0);
|
ui.instance = EsInstanceCreate(message, NULL, 0);
|
||||||
|
ui.instance->callback = _UIInstanceCallback;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue