mirror of https://gitlab.com/nakst/essence
rename button in file menu
This commit is contained in:
parent
b66cdda741
commit
c166eee594
|
@ -590,6 +590,29 @@ void _start() {
|
|||
|
||||
EsHandleClose(message->user.context1.u);
|
||||
EsHeapFree(_path);
|
||||
} else if (message->type == ES_MSG_FILE_MANAGER_PATH_MOVED) {
|
||||
char *data = (char *) EsHeapAllocate(message->user.context2.u, false);
|
||||
uintptr_t *bytes = (uintptr_t *) data;
|
||||
char *paths = data + sizeof(size_t) * 2;
|
||||
EsConstantBufferRead(message->user.context1.u, data);
|
||||
String oldPath = StringFromLiteralWithSize(paths, bytes[0]);
|
||||
String newPath = StringFromLiteralWithSize(paths + bytes[0], bytes[1]);
|
||||
FolderPathMoved(oldPath, newPath, false);
|
||||
size_t pathSectionCount;
|
||||
|
||||
pathSectionCount = PathCountSections(oldPath);
|
||||
|
||||
for (uintptr_t i = 0; i < pathSectionCount; i++) {
|
||||
FolderFileUpdatedAtPath(PathGetParent(oldPath, i + 1), nullptr);
|
||||
}
|
||||
|
||||
pathSectionCount = PathCountSections(newPath);
|
||||
|
||||
for (uintptr_t i = 0; i < pathSectionCount; i++) {
|
||||
FolderFileUpdatedAtPath(PathGetParent(newPath, i + 1), nullptr);
|
||||
}
|
||||
|
||||
EsHeapFree(data);
|
||||
} else if (message->type == MESSAGE_BLOCKING_TASK_COMPLETE) {
|
||||
Instance *instance = (Instance *) message->user.context1.p;
|
||||
if (message->user.context2.u == instance->blockingTaskID) BlockingTaskComplete(instance);
|
||||
|
|
|
@ -63,6 +63,7 @@ struct EnumString { const char *cName; int value; };
|
|||
#define DESKTOP_MSG_UNHANDLED_KEY_EVENT (15)
|
||||
#define DESKTOP_MSG_START_USER_TASK (16)
|
||||
#define DESKTOP_MSG_SET_PROGRESS (17)
|
||||
#define DESKTOP_MSG_RENAME (18)
|
||||
|
||||
struct EsFileStore {
|
||||
#define FILE_STORE_HANDLE (1)
|
||||
|
@ -218,6 +219,11 @@ struct APIInstance {
|
|||
EsInstanceClassEditorSettings editorSettings;
|
||||
EsInstanceClassViewerSettings viewerSettings;
|
||||
};
|
||||
|
||||
// For the file menu.
|
||||
EsPanel *fileMenuNameSwitcher;
|
||||
EsPanel *fileMenuNamePanel;
|
||||
EsTextbox *fileMenuNameTextbox;
|
||||
};
|
||||
|
||||
MountPoint *NodeAddMountPoint(const char *prefix, size_t prefixBytes, EsHandle base, bool queryInformation) {
|
||||
|
@ -982,6 +988,41 @@ EsMessage *EsMessageReceive() {
|
|||
EsHandleClose(message.message.tabOperation.handle);
|
||||
}
|
||||
}
|
||||
} else if (type == ES_MSG_INSTANCE_RENAME_RESPONSE) {
|
||||
EsInstance *instance = InstanceFromWindowID(message.message.tabOperation.id);
|
||||
|
||||
if (instance) {
|
||||
if (message.message.tabOperation.error == ES_SUCCESS) {
|
||||
EsRectangle bounds = EsElementGetWindowBounds(instance->window->toolbarSwitcher);
|
||||
EsAnnouncementShow(instance->window, ES_FLAGS_DEFAULT, (bounds.l + bounds.r) / 2, bounds.b, INTERFACE_STRING(FileRenameSuccess));
|
||||
} else {
|
||||
const char *errorMessage = interfaceString_FileSaveErrorUnknown;
|
||||
|
||||
switch (message.message.tabOperation.error) {
|
||||
case ES_ERROR_FILE_DOES_NOT_EXIST:
|
||||
case ES_ERROR_NODE_DELETED:
|
||||
case ES_ERROR_PERMISSION_NOT_GRANTED:
|
||||
case ES_ERROR_INCORRECT_NODE_TYPE:
|
||||
errorMessage = interfaceString_FileSaveErrorFileDeleted;
|
||||
break;
|
||||
case ES_ERROR_DRIVE_ERROR_FILE_DAMAGED:
|
||||
errorMessage = interfaceString_FileSaveErrorCorrupt;
|
||||
break;
|
||||
case ES_ERROR_DRIVE_CONTROLLER_REPORTED:
|
||||
errorMessage = interfaceString_FileSaveErrorDrive;
|
||||
break;
|
||||
case ES_ERROR_INSUFFICIENT_RESOURCES:
|
||||
errorMessage = interfaceString_FileSaveErrorResourcesLow;
|
||||
break;
|
||||
case ES_ERROR_FILE_ALREADY_EXISTS:
|
||||
errorMessage = interfaceString_FileSaveErrorAlreadyExists;
|
||||
break;
|
||||
}
|
||||
|
||||
EsDialogShowAlert(instance->window, INTERFACE_STRING(FileCannotRename),
|
||||
errorMessage, -1, ES_ICON_DIALOG_ERROR, ES_DIALOG_ALERT_OK_BUTTON);
|
||||
}
|
||||
}
|
||||
} else if (type == ES_MSG_INSTANCE_DOCUMENT_RENAMED) {
|
||||
char *buffer = (char *) EsHeapAllocate(message.message.tabOperation.bytes, false);
|
||||
|
||||
|
@ -1202,6 +1243,9 @@ void EsInstanceSaveComplete(EsMessage *message, bool success) {
|
|||
case ES_ERROR_FILE_ALREADY_EXISTS:
|
||||
errorMessage = interfaceString_FileSaveErrorAlreadyExists;
|
||||
break;
|
||||
case ES_ERROR_TOO_MANY_FILES_WITH_NAME:
|
||||
errorMessage = interfaceString_FileSaveErrorTooManyFiles;
|
||||
break;
|
||||
}
|
||||
|
||||
EsDialogShowAlert(instance->window, INTERFACE_STRING(FileCannotSave),
|
||||
|
|
|
@ -1624,7 +1624,7 @@ EsError TemporaryFileCreate(EsHandle *handle, char **path, size_t *pathBytes, ui
|
|||
return file.error;
|
||||
}
|
||||
|
||||
void ApplicationInstanceRequestSave(ApplicationInstance *instance, const char *newName, size_t newNameBytes) {
|
||||
void ApplicationInstanceRequestSave(ApplicationInstance *instance, const char *newName, size_t newNameBytes, bool failIfAlreadyExists) {
|
||||
if (!instance->processHandle) return;
|
||||
|
||||
EsMessage m = {};
|
||||
|
@ -1640,9 +1640,9 @@ void ApplicationInstanceRequestSave(ApplicationInstance *instance, const char *n
|
|||
EsHeapFree(folder);
|
||||
size_t nameBytes = EsPathFindUniqueName(name, folderBytes + newNameBytes, folderBytes + newNameBytes + 32);
|
||||
|
||||
if (!nameBytes) {
|
||||
if (!nameBytes || (failIfAlreadyExists && nameBytes != folderBytes + newNameBytes)) {
|
||||
EsHeapFree(name);
|
||||
m.tabOperation.error = ES_ERROR_FILE_ALREADY_EXISTS;
|
||||
m.tabOperation.error = nameBytes ? ES_ERROR_FILE_ALREADY_EXISTS : ES_ERROR_TOO_MANY_FILES_WITH_NAME;
|
||||
EsMessagePostRemote(instance->processHandle, &m);
|
||||
return;
|
||||
}
|
||||
|
@ -1710,22 +1710,10 @@ void ApplicationInstanceRequestSave(ApplicationInstance *instance, const char *n
|
|||
EsMessagePostRemote(instance->processHandle, &m);
|
||||
}
|
||||
|
||||
void InstanceAnnouncePathMoved(InstalledApplication *fromApplication, const uint8_t *buffer, size_t embedWindowMessageBytes) {
|
||||
void InstanceAnnouncePathMoved(InstalledApplication *fromApplication, const char *oldPath, size_t oldPathBytes, const char *newPath, size_t newPathBytes) {
|
||||
// TODO Update the location of installed applications and other things in the configuration.
|
||||
// TODO Replace fromApplication with something better.
|
||||
|
||||
uintptr_t oldPathBytes, newPathBytes;
|
||||
EsMemoryCopy(&oldPathBytes, buffer + 1, sizeof(uintptr_t));
|
||||
EsMemoryCopy(&newPathBytes, buffer + 1 + sizeof(uintptr_t), sizeof(uintptr_t));
|
||||
|
||||
if (oldPathBytes >= 0x4000 || newPathBytes >= 0x4000
|
||||
|| oldPathBytes + newPathBytes + sizeof(uintptr_t) * 2 + 1 != embedWindowMessageBytes) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char *oldPath = (const char *) buffer + 1 + sizeof(uintptr_t) * 2;
|
||||
const char *newPath = (const char *) buffer + 1 + sizeof(uintptr_t) * 2 + oldPathBytes;
|
||||
|
||||
EsObjectID documentID = 0;
|
||||
|
||||
for (uintptr_t i = 0; i < desktop.openDocuments.Count(); i++) {
|
||||
|
@ -1769,6 +1757,20 @@ void InstanceAnnouncePathMoved(InstalledApplication *fromApplication, const uint
|
|||
m.tabOperation.bytes = newPathBytes - newNameOffset;
|
||||
EsMessagePostRemote(instance->processHandle, &m);
|
||||
}
|
||||
|
||||
if (fromApplication != desktop.fileManager && desktop.fileManager && desktop.fileManager->singleProcessHandle) {
|
||||
char *data = (char *) EsHeapAllocate(sizeof(size_t) * 2 + oldPathBytes + newPathBytes, false);
|
||||
EsMemoryCopy(data + 0, &oldPathBytes, sizeof(size_t));
|
||||
EsMemoryCopy(data + sizeof(size_t), &newPathBytes, sizeof(size_t));
|
||||
EsMemoryCopy(data + sizeof(size_t) * 2, oldPath, oldPathBytes);
|
||||
EsMemoryCopy(data + sizeof(size_t) * 2 + oldPathBytes, newPath, newPathBytes);
|
||||
EsMessage m = {};
|
||||
m.type = ES_MSG_FILE_MANAGER_PATH_MOVED;
|
||||
m.user.context2 = sizeof(size_t) * 2 + oldPathBytes + newPathBytes;
|
||||
m.user.context1 = EsConstantBufferCreate(data, m.user.context2.u, desktop.fileManager->singleProcessHandle);
|
||||
EsMessagePostRemote(desktop.fileManager->singleProcessHandle, &m);
|
||||
EsHeapFree(data);
|
||||
}
|
||||
}
|
||||
|
||||
void ApplicationInstanceCompleteSave(ApplicationInstance *fromInstance) {
|
||||
|
@ -2253,7 +2255,19 @@ void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
|
|||
InstalledApplication *application = ApplicationFindByPID(message->desktop.processID);
|
||||
|
||||
if (application && (application->permissions & APPLICATION_PERMISSION_ALL_FILES)) {
|
||||
InstanceAnnouncePathMoved(application, buffer, message->desktop.bytes);
|
||||
uintptr_t oldPathBytes, newPathBytes;
|
||||
EsMemoryCopy(&oldPathBytes, buffer + 1, sizeof(uintptr_t));
|
||||
EsMemoryCopy(&newPathBytes, buffer + 1 + sizeof(uintptr_t), sizeof(uintptr_t));
|
||||
|
||||
if (oldPathBytes >= 0x4000 || newPathBytes >= 0x4000
|
||||
|| oldPathBytes + newPathBytes + sizeof(uintptr_t) * 2 + 1 != message->desktop.bytes) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char *oldPath = (const char *) buffer + 1 + sizeof(uintptr_t) * 2;
|
||||
const char *newPath = (const char *) buffer + 1 + sizeof(uintptr_t) * 2 + oldPathBytes;
|
||||
|
||||
InstanceAnnouncePathMoved(application, oldPath, oldPathBytes, newPath, newPathBytes);
|
||||
}
|
||||
} else if (buffer[0] == DESKTOP_MSG_START_USER_TASK && pipe) {
|
||||
InstalledApplication *application = ApplicationFindByPID(message->desktop.processID);
|
||||
|
@ -2335,7 +2349,39 @@ void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
|
|||
EsElementRepaint(desktop.tasksButton);
|
||||
}
|
||||
} else if (buffer[0] == DESKTOP_MSG_REQUEST_SAVE) {
|
||||
ApplicationInstanceRequestSave(instance, (const char *) buffer + 1, message->desktop.bytes - 1);
|
||||
ApplicationInstanceRequestSave(instance, (const char *) buffer + 1, message->desktop.bytes - 1, false);
|
||||
} else if (buffer[0] == DESKTOP_MSG_RENAME) {
|
||||
const char *newName = (const char *) buffer + 1;
|
||||
size_t newNameBytes = message->desktop.bytes - 1;
|
||||
OpenDocument *document = desktop.openDocuments.Get(&instance->documentID);
|
||||
|
||||
if (!instance->documentID) {
|
||||
ApplicationInstanceRequestSave(instance, newName, newNameBytes, true);
|
||||
} else if (document) {
|
||||
size_t folderBytes = 0, oldPathBytes, newPathBytes;
|
||||
|
||||
for (uintptr_t i = 0; i < document->pathBytes; i++) {
|
||||
if (document->path[i] == '/') {
|
||||
folderBytes = i;
|
||||
}
|
||||
}
|
||||
|
||||
char *oldPath = EsStringAllocateAndFormat(&oldPathBytes, "%s", document->pathBytes, document->path);
|
||||
char *newPath = EsStringAllocateAndFormat(&newPathBytes, "%s/%s", folderBytes, document->path, newNameBytes, newName);
|
||||
|
||||
EsMessage m = {};
|
||||
m.type = ES_MSG_INSTANCE_RENAME_RESPONSE;
|
||||
m.tabOperation.id = instance->embeddedWindowID;
|
||||
m.tabOperation.error = EsPathMove(oldPath, oldPathBytes, newPath, newPathBytes);
|
||||
EsMessagePostRemote(instance->processHandle, &m);
|
||||
|
||||
if (m.tabOperation.error == ES_SUCCESS) {
|
||||
InstanceAnnouncePathMoved(nullptr, oldPath, oldPathBytes, newPath, newPathBytes);
|
||||
}
|
||||
|
||||
EsHeapFree(oldPath);
|
||||
EsHeapFree(newPath);
|
||||
}
|
||||
} else if (buffer[0] == DESKTOP_MSG_COMPLETE_SAVE) {
|
||||
ApplicationInstanceCompleteSave(instance);
|
||||
} else if (buffer[0] == DESKTOP_MSG_SHOW_IN_FILE_MANAGER) {
|
||||
|
|
282
desktop/gui.cpp
282
desktop/gui.cpp
|
@ -1072,105 +1072,6 @@ void EsMenuCloseAll() {
|
|||
}
|
||||
}
|
||||
|
||||
// --------------------------------- File menu.
|
||||
|
||||
const EsStyle styleFileMenuDocumentInformationPanel1 = {
|
||||
.metrics = {
|
||||
.mask = ES_THEME_METRICS_INSETS | ES_THEME_METRICS_GAP_MAJOR,
|
||||
.insets = ES_RECT_4(10, 10, 5, 5),
|
||||
.gapMajor = 5,
|
||||
},
|
||||
};
|
||||
|
||||
const EsStyle styleFileMenuDocumentInformationPanel2 = {
|
||||
.metrics = {
|
||||
.mask = ES_THEME_METRICS_GAP_MAJOR,
|
||||
.gapMajor = 5,
|
||||
},
|
||||
};
|
||||
|
||||
void FileMenuCreate(EsInstance *_instance, EsElement *element, EsCommand *) {
|
||||
// TODO Make this user-customizable?
|
||||
|
||||
// const EsFileMenuSettings *settings = (const EsFileMenuSettings *) element->userData.p;
|
||||
APIInstance *instance = (APIInstance *) _instance->_private;
|
||||
EsAssert(instance->instanceClass == ES_INSTANCE_CLASS_EDITOR);
|
||||
EsInstanceClassEditorSettings *editorSettings = &instance->editorSettings;
|
||||
bool newDocument = !instance->startupInformation || !instance->startupInformation->filePath;
|
||||
|
||||
EsMenu *menu = EsMenuCreate(element, ES_FLAGS_DEFAULT);
|
||||
if (!menu) return;
|
||||
EsPanel *panel1 = EsPanelCreate(menu, ES_PANEL_HORIZONTAL | ES_CELL_H_LEFT, &styleFileMenuDocumentInformationPanel1);
|
||||
if (!panel1) goto show;
|
||||
|
||||
{
|
||||
// TODO Get this icon from the file type database?
|
||||
// We'll probably need Desktop to send this via EsApplicationStartupInformation and when the file is renamed.
|
||||
|
||||
EsIconDisplayCreate(panel1, ES_FLAGS_DEFAULT, 0, editorSettings->documentIconID);
|
||||
EsSpacerCreate(panel1, ES_FLAGS_DEFAULT, 0, 5, 0);
|
||||
|
||||
EsPanel *panel2 = EsPanelCreate(panel1, ES_FLAGS_DEFAULT, &styleFileMenuDocumentInformationPanel2);
|
||||
if (!panel2) goto show;
|
||||
EsPanel *panel3 = EsPanelCreate(panel2, ES_PANEL_HORIZONTAL | ES_PANEL_H_LEFT, &styleFileMenuDocumentInformationPanel2);
|
||||
if (!panel3) goto show;
|
||||
|
||||
if (newDocument) {
|
||||
EsTextDisplayCreate(panel3, ES_FLAGS_DEFAULT, ES_STYLE_TEXT_LABEL,
|
||||
editorSettings->newDocumentTitle, editorSettings->newDocumentTitleBytes);
|
||||
} else {
|
||||
EsTextDisplayCreate(panel3, ES_FLAGS_DEFAULT, ES_STYLE_TEXT_LABEL,
|
||||
instance->startupInformation->filePath, instance->startupInformation->filePathBytes);
|
||||
}
|
||||
|
||||
EsButton *renameButton = EsButtonCreate(panel3, ES_BUTTON_TOOLBAR); // TODO.
|
||||
if (!renameButton) goto show;
|
||||
EsButtonSetIcon(renameButton, ES_ICON_DOCUMENT_EDIT_SYMBOLIC);
|
||||
|
||||
if (!newDocument) {
|
||||
EsPanel *panel4 = EsPanelCreate(panel2, ES_PANEL_TABLE | ES_PANEL_HORIZONTAL | ES_CELL_H_LEFT, &styleFileMenuDocumentInformationPanel2);
|
||||
if (!panel4) goto show;
|
||||
EsPanelSetBands(panel4, 2 /* columns */);
|
||||
|
||||
char buffer[64];
|
||||
size_t bytes;
|
||||
|
||||
bytes = EsStringFormat(buffer, sizeof(buffer), "%D", EsFileStoreGetSize(instance->fileStore));
|
||||
EsTextDisplayCreate(panel4, ES_CELL_H_RIGHT, ES_STYLE_TEXT_LABEL_SECONDARY, INTERFACE_STRING(CommonFileMenuFileSize));
|
||||
EsTextDisplayCreate(panel4, ES_CELL_H_LEFT, ES_STYLE_TEXT_LABEL, buffer, bytes);
|
||||
|
||||
// TODO Modification date, author, etc.
|
||||
}
|
||||
}
|
||||
|
||||
EsMenuAddSeparator(menu);
|
||||
|
||||
if (instance->instanceClass == ES_INSTANCE_CLASS_EDITOR) {
|
||||
if (instance->commandSave.disabled) {
|
||||
EsMenuAddItem(menu, ES_ELEMENT_DISABLED, INTERFACE_STRING(CommonFileUnchanged));
|
||||
} else {
|
||||
EsMenuAddCommand(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(CommonFileSave), &instance->commandSave);
|
||||
}
|
||||
|
||||
EsMenuAddItem(menu, newDocument ? ES_ELEMENT_DISABLED : ES_FLAGS_DEFAULT, INTERFACE_STRING(CommonFileMakeCopy)); // TODO.
|
||||
EsMenuAddSeparator(menu);
|
||||
}
|
||||
|
||||
EsMenuAddItem(menu, newDocument ? ES_ELEMENT_DISABLED : ES_FLAGS_DEFAULT, INTERFACE_STRING(CommonFileShare)); // TODO.
|
||||
EsMenuAddItem(menu, newDocument ? ES_ELEMENT_DISABLED : ES_FLAGS_DEFAULT, INTERFACE_STRING(CommonFileVersionHistory)); // TODO.
|
||||
EsMenuAddCommand(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(CommonFileShowInFileManager), &instance->commandShowInFileManager);
|
||||
|
||||
show: EsMenuShow(menu);
|
||||
}
|
||||
|
||||
void EsToolbarAddFileMenu(EsElement *element, const EsFileMenuSettings *settings) {
|
||||
EsButton *button = EsButtonCreate(element, ES_BUTTON_DROPDOWN, 0, INTERFACE_STRING(CommonFileMenu));
|
||||
if (!button) return;
|
||||
button->accessKey = 'F';
|
||||
button->userData = (void *) settings;
|
||||
EsButtonOnCommand(button, FileMenuCreate);
|
||||
}
|
||||
|
||||
// --------------------------------- Paint targets.
|
||||
|
||||
bool EsPaintTargetTake(EsPaintTarget *target, size_t width, size_t height, bool hasAlphaChannel = true) {
|
||||
|
@ -3132,7 +3033,8 @@ int ProcessPanelMessage(EsElement *element, EsMessage *message) {
|
|||
|
||||
for (uintptr_t i = 0; i < element->GetChildCount(); i++) {
|
||||
EsElement *child = element->GetChild(i);
|
||||
if (child->flags & (ES_ELEMENT_HIDDEN | ES_ELEMENT_NON_CLIENT)) continue;
|
||||
if (child->flags & ES_ELEMENT_NON_CLIENT) continue;
|
||||
if ((child->flags & ES_ELEMENT_HIDDEN) && (~panel->flags & ES_PANEL_SWITCHER_MEASURE_LARGEST)) continue;
|
||||
int size = child->GetWidth(message->measure.height);
|
||||
if (size > maximum) maximum = size;
|
||||
}
|
||||
|
@ -3153,7 +3055,8 @@ int ProcessPanelMessage(EsElement *element, EsMessage *message) {
|
|||
|
||||
for (uintptr_t i = 0; i < element->GetChildCount(); i++) {
|
||||
EsElement *child = element->GetChild(i);
|
||||
if (child->flags & (ES_ELEMENT_HIDDEN | ES_ELEMENT_NON_CLIENT)) continue;
|
||||
if (child->flags & ES_ELEMENT_NON_CLIENT) continue;
|
||||
if ((child->flags & ES_ELEMENT_HIDDEN) && (~panel->flags & ES_PANEL_SWITCHER_MEASURE_LARGEST)) continue;
|
||||
int size = child->GetHeight(message->measure.width);
|
||||
if (size > maximum) maximum = size;
|
||||
}
|
||||
|
@ -5237,6 +5140,183 @@ EsSlider *EsSliderCreate(EsElement *parent, uint64_t flags, const EsStyle *style
|
|||
return slider;
|
||||
}
|
||||
|
||||
// --------------------------------- File menu.
|
||||
|
||||
const EsStyle styleFileMenuDocumentInformationPanel1 = {
|
||||
.metrics = {
|
||||
.mask = ES_THEME_METRICS_INSETS | ES_THEME_METRICS_GAP_MAJOR,
|
||||
.insets = ES_RECT_4(10, 10, 5, 5),
|
||||
.gapMajor = 5,
|
||||
},
|
||||
};
|
||||
|
||||
const EsStyle styleFileMenuDocumentInformationPanel2 = {
|
||||
.metrics = {
|
||||
.mask = ES_THEME_METRICS_GAP_MAJOR,
|
||||
.gapMajor = 5,
|
||||
},
|
||||
};
|
||||
|
||||
const EsStyle styleFileMenuNameTextbox = {
|
||||
.inherit = ES_STYLE_TEXTBOX_TRANSPARENT,
|
||||
|
||||
.metrics = {
|
||||
.mask = ES_THEME_METRICS_PREFERRED_WIDTH,
|
||||
.preferredWidth = 0,
|
||||
},
|
||||
};
|
||||
|
||||
int FileMenuNameTextboxMessage(EsElement *element, EsMessage *message) {
|
||||
if (message->type == ES_MSG_TEXTBOX_EDIT_END) {
|
||||
APIInstance *instance = (APIInstance *) element->instance->_private;
|
||||
|
||||
if (!message->endEdit.rejected) {
|
||||
size_t newNameBytes;
|
||||
char *newName = EsTextboxGetContents(instance->fileMenuNameTextbox, &newNameBytes);
|
||||
uint8_t *buffer = (uint8_t *) EsHeapAllocate(1 + newNameBytes, false);
|
||||
buffer[0] = DESKTOP_MSG_RENAME;
|
||||
EsMemoryCopy(buffer + 1, newName, newNameBytes);
|
||||
MessageDesktop(buffer, 1 + newNameBytes, element->instance->window->handle);
|
||||
EsHeapFree(buffer);
|
||||
EsHeapFree(newName);
|
||||
EsElementDestroy(element->window);
|
||||
} else {
|
||||
EsPanelSwitchTo(instance->fileMenuNameSwitcher, instance->fileMenuNamePanel, ES_TRANSITION_SLIDE_DOWN);
|
||||
}
|
||||
|
||||
return ES_HANDLED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FileMenuRename(EsInstance *_instance, EsElement *, EsCommand *) {
|
||||
APIInstance *instance = (APIInstance *) _instance->_private;
|
||||
EsTextboxClear(instance->fileMenuNameTextbox, false);
|
||||
|
||||
uintptr_t extensionOffset = 0;
|
||||
const char *initialName = nullptr;
|
||||
ptrdiff_t initialNameBytes = 0;
|
||||
|
||||
if (instance->startupInformation && instance->startupInformation->filePathBytes) {
|
||||
initialName = instance->startupInformation->filePath;
|
||||
initialNameBytes = instance->startupInformation->filePathBytes;
|
||||
} else {
|
||||
EsInstanceClassEditorSettings *editorSettings = &instance->editorSettings;
|
||||
initialName = editorSettings->newDocumentFileName;
|
||||
initialNameBytes = editorSettings->newDocumentFileNameBytes;
|
||||
}
|
||||
|
||||
if (initialNameBytes == -1) {
|
||||
initialNameBytes = EsCStringLength(initialName);
|
||||
}
|
||||
|
||||
EsTextboxInsert(instance->fileMenuNameTextbox, initialName, initialNameBytes, false);
|
||||
|
||||
for (intptr_t i = 1; i < initialNameBytes; i++) {
|
||||
if (initialName[i] == '.') {
|
||||
extensionOffset = i;
|
||||
}
|
||||
}
|
||||
|
||||
EsPanelSwitchTo(instance->fileMenuNameSwitcher, instance->fileMenuNameTextbox, ES_TRANSITION_SLIDE_UP);
|
||||
EsElementFocus(instance->fileMenuNameTextbox);
|
||||
EsTextboxStartEdit(instance->fileMenuNameTextbox);
|
||||
if (extensionOffset) EsTextboxSetSelection(instance->fileMenuNameTextbox, 0, 0, 0, extensionOffset);
|
||||
instance->fileMenuNameTextbox->messageUser = FileMenuNameTextboxMessage;
|
||||
}
|
||||
|
||||
void FileMenuCreate(EsInstance *_instance, EsElement *element, EsCommand *) {
|
||||
// TODO Make this user-customizable?
|
||||
|
||||
// const EsFileMenuSettings *settings = (const EsFileMenuSettings *) element->userData.p;
|
||||
APIInstance *instance = (APIInstance *) _instance->_private;
|
||||
EsAssert(instance->instanceClass == ES_INSTANCE_CLASS_EDITOR);
|
||||
EsInstanceClassEditorSettings *editorSettings = &instance->editorSettings;
|
||||
bool newDocument = !instance->startupInformation || !instance->startupInformation->filePath;
|
||||
|
||||
EsMenu *menu = EsMenuCreate(element, ES_FLAGS_DEFAULT);
|
||||
if (!menu) return;
|
||||
EsPanel *panel1 = EsPanelCreate(menu, ES_PANEL_HORIZONTAL | ES_CELL_H_LEFT, &styleFileMenuDocumentInformationPanel1);
|
||||
if (!panel1) goto show;
|
||||
|
||||
{
|
||||
// TODO Get this icon from the file type database?
|
||||
// We'll probably need Desktop to send this via EsApplicationStartupInformation and when the file is renamed.
|
||||
|
||||
EsIconDisplayCreate(panel1, ES_FLAGS_DEFAULT, 0, editorSettings->documentIconID);
|
||||
EsSpacerCreate(panel1, ES_FLAGS_DEFAULT, 0, 5, 0);
|
||||
|
||||
EsPanel *panel2 = EsPanelCreate(panel1, ES_FLAGS_DEFAULT, &styleFileMenuDocumentInformationPanel2);
|
||||
if (!panel2) goto show;
|
||||
EsPanel *switcher = EsPanelCreate(panel2, ES_PANEL_H_LEFT | ES_PANEL_SWITCHER | ES_PANEL_SWITCHER_MEASURE_LARGEST);
|
||||
if (!switcher) goto show;
|
||||
EsPanel *panel3 = EsPanelCreate(switcher, ES_PANEL_HORIZONTAL | ES_PANEL_H_LEFT, &styleFileMenuDocumentInformationPanel2);
|
||||
if (!panel3) goto show;
|
||||
|
||||
instance->fileMenuNameTextbox = EsTextboxCreate(switcher, ES_CELL_H_FILL | ES_TEXTBOX_EDIT_BASED, &styleFileMenuNameTextbox);
|
||||
|
||||
instance->fileMenuNameSwitcher = switcher;
|
||||
instance->fileMenuNamePanel = panel3;
|
||||
EsPanelSwitchTo(instance->fileMenuNameSwitcher, instance->fileMenuNamePanel, ES_TRANSITION_NONE);
|
||||
|
||||
if (newDocument) {
|
||||
EsTextDisplayCreate(panel3, ES_FLAGS_DEFAULT, ES_STYLE_TEXT_LABEL,
|
||||
editorSettings->newDocumentTitle, editorSettings->newDocumentTitleBytes);
|
||||
} else {
|
||||
EsTextDisplayCreate(panel3, ES_FLAGS_DEFAULT, ES_STYLE_TEXT_LABEL,
|
||||
instance->startupInformation->filePath, instance->startupInformation->filePathBytes);
|
||||
}
|
||||
|
||||
EsButton *renameButton = EsButtonCreate(panel3, ES_BUTTON_TOOLBAR); // TODO.
|
||||
if (!renameButton) goto show;
|
||||
EsButtonSetIcon(renameButton, ES_ICON_DOCUMENT_EDIT_SYMBOLIC);
|
||||
EsButtonOnCommand(renameButton, FileMenuRename);
|
||||
|
||||
if (!newDocument) {
|
||||
EsPanel *panel4 = EsPanelCreate(panel2, ES_PANEL_TABLE | ES_PANEL_HORIZONTAL | ES_CELL_H_LEFT, &styleFileMenuDocumentInformationPanel2);
|
||||
if (!panel4) goto show;
|
||||
EsPanelSetBands(panel4, 2 /* columns */);
|
||||
|
||||
char buffer[64];
|
||||
size_t bytes;
|
||||
|
||||
bytes = EsStringFormat(buffer, sizeof(buffer), "%D", EsFileStoreGetSize(instance->fileStore));
|
||||
EsTextDisplayCreate(panel4, ES_CELL_H_RIGHT, ES_STYLE_TEXT_LABEL_SECONDARY, INTERFACE_STRING(CommonFileMenuFileSize));
|
||||
EsTextDisplayCreate(panel4, ES_CELL_H_LEFT, ES_STYLE_TEXT_LABEL, buffer, bytes);
|
||||
|
||||
// TODO Modification date, author, etc.
|
||||
}
|
||||
}
|
||||
|
||||
EsMenuAddSeparator(menu);
|
||||
|
||||
if (instance->instanceClass == ES_INSTANCE_CLASS_EDITOR) {
|
||||
if (instance->commandSave.disabled) {
|
||||
EsMenuAddItem(menu, ES_ELEMENT_DISABLED, INTERFACE_STRING(CommonFileUnchanged));
|
||||
} else {
|
||||
EsMenuAddCommand(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(CommonFileSave), &instance->commandSave);
|
||||
}
|
||||
|
||||
EsMenuAddItem(menu, newDocument ? ES_ELEMENT_DISABLED : ES_FLAGS_DEFAULT, INTERFACE_STRING(CommonFileMakeCopy)); // TODO.
|
||||
EsMenuAddSeparator(menu);
|
||||
}
|
||||
|
||||
EsMenuAddItem(menu, newDocument ? ES_ELEMENT_DISABLED : ES_FLAGS_DEFAULT, INTERFACE_STRING(CommonFileShare)); // TODO.
|
||||
EsMenuAddItem(menu, newDocument ? ES_ELEMENT_DISABLED : ES_FLAGS_DEFAULT, INTERFACE_STRING(CommonFileVersionHistory)); // TODO.
|
||||
EsMenuAddCommand(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(CommonFileShowInFileManager), &instance->commandShowInFileManager);
|
||||
|
||||
show: EsMenuShow(menu);
|
||||
}
|
||||
|
||||
void EsToolbarAddFileMenu(EsElement *element, const EsFileMenuSettings *settings) {
|
||||
EsButton *button = EsButtonCreate(element, ES_BUTTON_DROPDOWN, 0, INTERFACE_STRING(CommonFileMenu));
|
||||
if (!button) return;
|
||||
button->accessKey = 'F';
|
||||
button->userData = (void *) settings;
|
||||
EsButtonOnCommand(button, FileMenuCreate);
|
||||
}
|
||||
|
||||
// --------------------------------- Message loop and core UI infrastructure.
|
||||
|
||||
void EsElement::PrintTree(int depth) {
|
||||
|
|
|
@ -331,6 +331,7 @@ define ES_ERROR_DIRECTORY_ENTRY_BEING_REMOVED (-72)
|
|||
define ES_ERROR_CANCELLED (-73)
|
||||
define ES_ERROR_BLOCK_ACCESS_INVALID (-74)
|
||||
define ES_ERROR_DEVICE_REMOVED (-75)
|
||||
define ES_ERROR_TOO_MANY_FILES_WITH_NAME (-76)
|
||||
|
||||
define ES_INVALID_HANDLE ((EsHandle) (0))
|
||||
define ES_CURRENT_THREAD ((EsHandle) (0x10))
|
||||
|
@ -468,6 +469,10 @@ define ES_PANEL_VERTICAL (0) // Default.
|
|||
define ES_PANEL_HORIZONTAL (1 << 8)
|
||||
define ES_PANEL_REVERSE (1 << 9) // Reverse layout is not supported with ES_PANEL_TABLE yet.
|
||||
|
||||
// For ES_PANEL_SWITCHER.
|
||||
define ES_PANEL_SWITCHER_MEASURE_SHOWN (0 << 15) // Use the shown child to determine size.
|
||||
define ES_PANEL_SWITCHER_MEASURE_LARGEST (1 << 15) // Use the largest child to determine size.
|
||||
|
||||
// For ES_PANEL_TABLE.
|
||||
// TODO Implement these!
|
||||
define ES_PANEL_H_LEFT (1 << 16)
|
||||
|
@ -968,6 +973,7 @@ enum EsMessageType {
|
|||
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
|
||||
|
@ -986,6 +992,7 @@ enum EsMessageType {
|
|||
|
||||
// File Manager messages:
|
||||
ES_MSG_FILE_MANAGER_FILE_MODIFIED = 0x5100
|
||||
ES_MSG_FILE_MANAGER_PATH_MOVED = 0x5101
|
||||
|
||||
// Textbox messages:
|
||||
ES_MSG_TEXTBOX_UPDATED = 0x5200
|
||||
|
|
|
@ -141,6 +141,9 @@ DEFINE_INTERFACE_STRING(DesktopSettingsThemeWallpaper, "Wallpaper");
|
|||
|
||||
DEFINE_INTERFACE_STRING(FileCannotSave, "The document was not saved.");
|
||||
DEFINE_INTERFACE_STRING(FileCannotOpen, "The file could not be opened.");
|
||||
DEFINE_INTERFACE_STRING(FileCannotRename, "The file could not be renamed.");
|
||||
|
||||
DEFINE_INTERFACE_STRING(FileRenameSuccess, "Renamed");
|
||||
|
||||
DEFINE_INTERFACE_STRING(FileSaveErrorFileDeleted, "Another application deleted the file.");
|
||||
DEFINE_INTERFACE_STRING(FileSaveErrorCorrupt, "The file has been corrupted, and it cannot be modified.");
|
||||
|
@ -149,7 +152,8 @@ DEFINE_INTERFACE_STRING(FileSaveErrorTooLarge, "The drive does not support files
|
|||
DEFINE_INTERFACE_STRING(FileSaveErrorConcurrentAccess, "Another application is modifying the file.");
|
||||
DEFINE_INTERFACE_STRING(FileSaveErrorDriveFull, "The drive is full. Try deleting some files to free up space.");
|
||||
DEFINE_INTERFACE_STRING(FileSaveErrorResourcesLow, "The system is low on resources. Close some applcations and try again.");
|
||||
DEFINE_INTERFACE_STRING(FileSaveErrorAlreadyExists, "Too many files already have the same name.");
|
||||
DEFINE_INTERFACE_STRING(FileSaveErrorAlreadyExists, "There is already a file with this name.");
|
||||
DEFINE_INTERFACE_STRING(FileSaveErrorTooManyFiles, "Too many files already have the same name.");
|
||||
DEFINE_INTERFACE_STRING(FileSaveErrorUnknown, "An unknown error occurred. Please try again later.");
|
||||
|
||||
DEFINE_INTERFACE_STRING(FileLoadErrorCorrupt, "The file has been corrupted, and it cannot be opened.");
|
||||
|
|
Loading…
Reference in New Issue