mirror of https://gitlab.com/nakst/essence
opening files in new tab; ReorderItem exiting
This commit is contained in:
parent
c2dc5adbe7
commit
02cc8d14fb
|
@ -821,7 +821,8 @@ int ListCallback(EsElement *element, EsMessage *message) {
|
|||
request.id = fileType->openHandler;
|
||||
request.filePath = path.text;
|
||||
request.filePathBytes = path.bytes;
|
||||
EsApplicationStart(&request);
|
||||
request.flags = EsKeyboardIsCtrlHeld() ? ES_APPLICATION_STARTUP_IN_SAME_CONTAINER : ES_FLAGS_DEFAULT;
|
||||
EsApplicationStart(instance, &request);
|
||||
StringDestroy(&path);
|
||||
} else {
|
||||
EsDialogShow(instance->window, INTERFACE_STRING(FileManagerOpenFileError),
|
||||
|
|
|
@ -252,6 +252,29 @@ struct APIInstance {
|
|||
EsTextbox *fileMenuNameTextbox; // Also used by the file save dialog.
|
||||
};
|
||||
|
||||
#define CHARACTER_MONO (1) // 1 bit per pixel.
|
||||
#define CHARACTER_SUBPIXEL (2) // 24 bits per pixel; each byte specifies the alpha of each RGB channel.
|
||||
#define CHARACTER_IMAGE (3) // 32 bits per pixel, ARGB.
|
||||
#define CHARACTER_RECOLOR (4) // 32 bits per pixel, AXXX.
|
||||
|
||||
#include "renderer.cpp"
|
||||
#include "theme.cpp"
|
||||
|
||||
#define TEXT_RENDERER
|
||||
#include "text.cpp"
|
||||
#undef TEXT_RENDERER
|
||||
|
||||
#include "gui.cpp"
|
||||
|
||||
#ifndef NO_API_TABLE
|
||||
const void *const apiTable[] = {
|
||||
#include <bin/api_array.h>
|
||||
};
|
||||
#endif
|
||||
|
||||
extern "C" void _init();
|
||||
typedef void (*StartFunction)();
|
||||
|
||||
MountPoint *NodeAddMountPoint(const char *prefix, size_t prefixBytes, EsHandle base, bool queryInformation) {
|
||||
MountPoint mountPoint = {};
|
||||
EsAssert(prefixBytes < sizeof(mountPoint.prefix));
|
||||
|
@ -485,7 +508,7 @@ _EsApplicationStartupInformation *ApplicationStartupInformationParse(const void
|
|||
return startupInformation;
|
||||
}
|
||||
|
||||
void EsApplicationStart(const EsApplicationStartupRequest *request) {
|
||||
void EsApplicationStart(EsInstance *instance, const EsApplicationStartupRequest *request) {
|
||||
EsApplicationStartupRequest copy = *request;
|
||||
|
||||
if (copy.filePathBytes == -1) {
|
||||
|
@ -498,7 +521,7 @@ void EsApplicationStart(const EsApplicationStartupRequest *request) {
|
|||
EsBufferWrite(&buffer, copy.filePath, copy.filePathBytes);
|
||||
|
||||
if (!buffer.error) {
|
||||
MessageDesktop(buffer.out, buffer.position);
|
||||
MessageDesktop(buffer.out, buffer.position, instance ? instance->window->handle : ES_INVALID_HANDLE);
|
||||
}
|
||||
|
||||
EsHeapFree(buffer.out);
|
||||
|
@ -523,29 +546,6 @@ void EsInstanceSetClassViewer(EsInstance *_instance, const EsInstanceClassViewer
|
|||
instance->instanceClass = ES_INSTANCE_CLASS_VIEWER;
|
||||
}
|
||||
|
||||
#define CHARACTER_MONO (1) // 1 bit per pixel.
|
||||
#define CHARACTER_SUBPIXEL (2) // 24 bits per pixel; each byte specifies the alpha of each RGB channel.
|
||||
#define CHARACTER_IMAGE (3) // 32 bits per pixel, ARGB.
|
||||
#define CHARACTER_RECOLOR (4) // 32 bits per pixel, AXXX.
|
||||
|
||||
#include "renderer.cpp"
|
||||
#include "theme.cpp"
|
||||
|
||||
#define TEXT_RENDERER
|
||||
#include "text.cpp"
|
||||
#undef TEXT_RENDERER
|
||||
|
||||
#include "gui.cpp"
|
||||
|
||||
#ifndef NO_API_TABLE
|
||||
const void *const apiTable[] = {
|
||||
#include <bin/api_array.h>
|
||||
};
|
||||
#endif
|
||||
|
||||
extern "C" void _init();
|
||||
typedef void (*StartFunction)();
|
||||
|
||||
const char *EnumLookupNameFromValue(const EnumString *array, int value) {
|
||||
if (array[0].value == -1) {
|
||||
return array[value].cName;
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
struct ReorderItem : EsElement {
|
||||
double sizeProgress, sizeTarget;
|
||||
double offsetProgress, offsetTarget;
|
||||
bool dragging;
|
||||
bool dragging, exiting;
|
||||
int dragOffset, dragPosition;
|
||||
};
|
||||
|
||||
|
@ -70,6 +70,12 @@ struct WindowTab : ReorderItem {
|
|||
struct ApplicationInstance *applicationInstance;
|
||||
struct ApplicationInstance *notRespondingInstance;
|
||||
EsButton *closeButton;
|
||||
|
||||
// Copied from ApplicationInstance.
|
||||
// This needs to store a copy so it can be used during the exit animation.
|
||||
char title[128];
|
||||
size_t titleBytes;
|
||||
uint32_t iconID;
|
||||
};
|
||||
|
||||
struct WindowTabBand : ReorderList {
|
||||
|
@ -91,6 +97,7 @@ struct TaskBar : EsElement {
|
|||
};
|
||||
|
||||
struct ContainerWindow {
|
||||
Array<WindowTab *> openTabs;
|
||||
WindowTabBand *tabBand;
|
||||
TaskBarButton *taskBarButton; // Might be null. For example, in the installer there is no task bar.
|
||||
EsWindow *window;
|
||||
|
@ -247,10 +254,13 @@ void ShutdownModalCreate();
|
|||
//////////////////////////////////////////////////////
|
||||
|
||||
bool ReorderItemAnimate(ReorderItem *item, uint64_t deltaMs, const char *entranceDuration) {
|
||||
const float speed = -3.0f;
|
||||
// const float speed = -0.3f;
|
||||
|
||||
item->sizeProgress += (item->sizeTarget - item->sizeProgress)
|
||||
* (1 - EsCRTexp(deltaMs * -3.0f / GetConstantNumber(entranceDuration)));
|
||||
* (1 - EsCRTexp(deltaMs * speed / GetConstantNumber(entranceDuration)));
|
||||
item->offsetProgress += (item->offsetTarget - item->offsetProgress)
|
||||
* (1 - EsCRTexp(deltaMs * -3.0f / GetConstantNumber("taskBarButtonMoveDuration")));
|
||||
* (1 - EsCRTexp(deltaMs * speed / GetConstantNumber("taskBarButtonMoveDuration")));
|
||||
|
||||
bool complete = true;
|
||||
|
||||
|
@ -266,11 +276,19 @@ bool ReorderItemAnimate(ReorderItem *item, uint64_t deltaMs, const char *entranc
|
|||
complete = false;
|
||||
}
|
||||
|
||||
if (item->sizeProgress <= 1 && item->exiting) {
|
||||
EsElementDestroy(item);
|
||||
}
|
||||
|
||||
EsElementRelayout(item->parent);
|
||||
return complete;
|
||||
}
|
||||
|
||||
bool ReorderItemDragged(ReorderItem *item, int mouseX) {
|
||||
void ReorderItemDragged(ReorderItem *item, int mouseX) {
|
||||
if (item->exiting) {
|
||||
return;
|
||||
}
|
||||
|
||||
ReorderList *list = (ReorderList *) item->parent;
|
||||
size_t childCount = list->items.Length();
|
||||
|
||||
|
@ -295,12 +313,13 @@ bool ReorderItemDragged(ReorderItem *item, int mouseX) {
|
|||
|
||||
EsAssert(currentIndex != -1);
|
||||
|
||||
bool changed = false;
|
||||
|
||||
if (draggedIndex != currentIndex) {
|
||||
list->items.Delete(currentIndex);
|
||||
list->items.Insert(item, draggedIndex);
|
||||
|
||||
EsMessage m = { .type = ES_MSG_REORDER_ITEM_MOVED, .child = item };
|
||||
EsMessageSend(list, &m);
|
||||
|
||||
for (uintptr_t i = 0, x = list->style->insets.l; i < childCount; i++) {
|
||||
ReorderItem *child = (ReorderItem *) list->items[i];
|
||||
|
||||
|
@ -315,18 +334,14 @@ bool ReorderItemDragged(ReorderItem *item, int mouseX) {
|
|||
|
||||
x += child->sizeProgress;
|
||||
}
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
item->dragging = true;
|
||||
EsElementRelayout(item->parent);
|
||||
|
||||
return changed;
|
||||
EsElementRelayout(list);
|
||||
}
|
||||
|
||||
void ReorderItemDragComplete(ReorderItem *item) {
|
||||
if (!item->dragging) {
|
||||
if (!item->dragging || item->exiting) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -361,10 +376,15 @@ int ReorderListLayout(ReorderList *list, int additionalRightMargin, bool clampDr
|
|||
}
|
||||
|
||||
int totalWidth = 0;
|
||||
uintptr_t nonExitingChildCount = 0;
|
||||
|
||||
for (uintptr_t i = 0; i < childCount; i++) {
|
||||
ReorderItem *child = list->items[i];
|
||||
totalWidth += child->style->metrics->maximumWidth + list->style->metrics->gapMinor;
|
||||
|
||||
if (!child->exiting) {
|
||||
totalWidth += child->style->metrics->maximumWidth + list->style->metrics->gapMinor;
|
||||
nonExitingChildCount++;
|
||||
}
|
||||
}
|
||||
|
||||
bool widthClamped = false;
|
||||
|
@ -374,17 +394,20 @@ int ReorderListLayout(ReorderList *list, int additionalRightMargin, bool clampDr
|
|||
widthClamped = true;
|
||||
}
|
||||
|
||||
int targetWidth = totalWidth / childCount;
|
||||
int extraWidth = totalWidth % childCount;
|
||||
int targetWidth = totalWidth / nonExitingChildCount;
|
||||
int extraWidth = totalWidth % nonExitingChildCount;
|
||||
|
||||
list->targetWidth = targetWidth;
|
||||
list->extraWidth = extraWidth;
|
||||
|
||||
for (uintptr_t i = 0; i < childCount; i++) {
|
||||
ReorderItem *child = list->items[i];
|
||||
int sizeTarget = 0;
|
||||
|
||||
int sizeTarget = targetWidth;
|
||||
if (extraWidth) sizeTarget++, extraWidth--;
|
||||
if (!child->exiting) {
|
||||
sizeTarget = targetWidth;
|
||||
if (extraWidth) sizeTarget++, extraWidth--;
|
||||
}
|
||||
|
||||
if (preventTabSizeAnimation) {
|
||||
child->sizeTarget = child->sizeProgress = sizeTarget;
|
||||
|
@ -400,9 +423,13 @@ int ReorderListLayout(ReorderList *list, int additionalRightMargin, bool clampDr
|
|||
|
||||
for (uintptr_t i = 0; i < childCount; i++) {
|
||||
ReorderItem *child = list->items[i];
|
||||
int width = (i == childCount - 1 && widthClamped) ? (totalWidth - x) : child->sizeProgress;
|
||||
int width = child->sizeProgress;
|
||||
int gap = list->style->metrics->gapMinor;
|
||||
|
||||
if (i == childCount - 1 && widthClamped && width > totalWidth - x) {
|
||||
width = totalWidth - x;
|
||||
}
|
||||
|
||||
if (child->dragging) {
|
||||
int p = child->dragPosition;
|
||||
|
||||
|
@ -513,6 +540,10 @@ void DesktopInspectorThread(EsGeneric) {
|
|||
//////////////////////////////////////////////////////
|
||||
|
||||
void WindowTabClose(WindowTab *tab) {
|
||||
if (!tab->applicationInstance) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tab->notRespondingInstance) {
|
||||
// The application is not responding, so force quit the process.
|
||||
EsProcessTerminate(tab->applicationInstance->process->handle, 1);
|
||||
|
@ -522,6 +553,10 @@ void WindowTabClose(WindowTab *tab) {
|
|||
}
|
||||
|
||||
void WindowTabActivate(WindowTab *tab, bool force = false) {
|
||||
if (!tab->applicationInstance) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tab->container->active != tab || force) {
|
||||
tab->container->active = tab;
|
||||
EsElementRelayout(tab->container->tabBand);
|
||||
|
@ -534,26 +569,42 @@ void WindowTabActivate(WindowTab *tab, bool force = false) {
|
|||
void WindowTabDestroy(WindowTab *tab) {
|
||||
ContainerWindow *container = tab->container;
|
||||
|
||||
if (container->tabBand->items.Length() == 1) {
|
||||
if (container->openTabs.Length() == 1) {
|
||||
EsElementDestroy(container->window);
|
||||
if (container->taskBarButton) EsElementDestroy(container->taskBarButton);
|
||||
|
||||
if (container->taskBarButton) {
|
||||
container->taskBarButton->exiting = true;
|
||||
container->taskBarButton->containerWindow = nullptr;
|
||||
EsElementRelayout(&desktop.taskBar);
|
||||
// The button is destroyed by ReorderItemAnimate, once the exit animation completes.
|
||||
}
|
||||
|
||||
desktop.allContainerWindows.FindAndDeleteSwap(container, true);
|
||||
} else {
|
||||
if (container->active == tab) {
|
||||
container->active = nullptr;
|
||||
|
||||
for (uintptr_t i = 0; i < container->tabBand->items.Length(); i++) {
|
||||
if (container->tabBand->items[i] != tab) continue;
|
||||
WindowTabActivate((WindowTab *) container->tabBand->items[i ? (i - 1) : 1]);
|
||||
for (uintptr_t i = 0; i < container->openTabs.Length(); i++) {
|
||||
if (container->openTabs[i] != tab) continue;
|
||||
WindowTabActivate(container->openTabs[i ? (i - 1) : 1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EsElementDestroy(tab);
|
||||
tab->applicationInstance = nullptr;
|
||||
tab->exiting = true;
|
||||
tab->SetStyle(ES_STYLE_WINDOW_TAB_INACTIVE);
|
||||
container->openTabs.FindAndDelete(tab, true);
|
||||
EsElementRelayout(container->tabBand);
|
||||
// The tab is destroyed by ReorderItemAnimate, once the exit animation completes.
|
||||
}
|
||||
}
|
||||
|
||||
WindowTab *WindowTabMoveToNewContainer(WindowTab *tab, ContainerWindow *container, int32_t width, int32_t height) {
|
||||
if (!tab->applicationInstance) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!container) {
|
||||
// Create a new container.
|
||||
container = ContainerWindowCreate();
|
||||
|
@ -674,17 +725,17 @@ int ContainerWindowMessage(EsElement *element, EsMessage *message) {
|
|||
if (((message->keyboard.modifiers & ~ES_MODIFIER_SHIFT) == ES_MODIFIER_CTRL) && message->keyboard.scancode == ES_SCANCODE_TAB) {
|
||||
int tab = -1;
|
||||
|
||||
for (uintptr_t i = 0; i < container->tabBand->items.Length(); i++) {
|
||||
if (container->tabBand->items[i] == container->active) {
|
||||
for (uintptr_t i = 0; i < container->openTabs.Length(); i++) {
|
||||
if (container->openTabs[i] == container->active) {
|
||||
tab = i;
|
||||
}
|
||||
}
|
||||
|
||||
EsAssert(tab != -1);
|
||||
tab += ((message->keyboard.modifiers & ES_MODIFIER_SHIFT) ? -1 : 1);
|
||||
if (tab == -1) tab = container->tabBand->items.Length() - 1;
|
||||
if (tab == (int) container->tabBand->items.Length()) tab = 0;
|
||||
WindowTabActivate((WindowTab *) container->tabBand->items[tab]);
|
||||
if (tab == -1) tab = container->openTabs.Length() - 1;
|
||||
if (tab == (int) container->openTabs.Length()) tab = 0;
|
||||
WindowTabActivate(container->openTabs[tab]);
|
||||
} else if (ctrlOnly && scancode == ES_SCANCODE_T && !message->keyboard.repeat) {
|
||||
ApplicationInstanceCreate(APPLICATION_ID_DESKTOP_BLANK_TAB, nullptr, container);
|
||||
} else if (ctrlOnly && scancode == ES_SCANCODE_W && !message->keyboard.repeat) {
|
||||
|
@ -713,8 +764,8 @@ int ContainerWindowMessage(EsElement *element, EsMessage *message) {
|
|||
bool unhandled = true;
|
||||
|
||||
for (uintptr_t i = 0; i < 9; i++) {
|
||||
if (ctrlOnly && scancode == (int) (ES_SCANCODE_1 + i) && container->tabBand->items.Length() > i) {
|
||||
WindowTabActivate((WindowTab *) container->tabBand->items[i]);
|
||||
if (ctrlOnly && scancode == (int) (ES_SCANCODE_1 + i) && container->openTabs.Length() > i) {
|
||||
WindowTabActivate(container->openTabs[i]);
|
||||
unhandled = false;
|
||||
break;
|
||||
}
|
||||
|
@ -736,9 +787,10 @@ int ContainerWindowMessage(EsElement *element, EsMessage *message) {
|
|||
int WindowTabMessage(EsElement *element, EsMessage *message) {
|
||||
WindowTab *tab = (WindowTab *) element;
|
||||
WindowTabBand *band = (WindowTabBand *) tab->parent;
|
||||
ApplicationInstance *instance = tab->applicationInstance;
|
||||
|
||||
if (message->type == ES_MSG_DESTROY) {
|
||||
band->container->openTabs.FindAndDelete(tab, false);
|
||||
|
||||
if (tab->notRespondingInstance) {
|
||||
ApplicationInstanceClose(tab->notRespondingInstance);
|
||||
tab->notRespondingInstance = nullptr;
|
||||
|
@ -762,13 +814,13 @@ int WindowTabMessage(EsElement *element, EsMessage *message) {
|
|||
insets.t, closeButtonWidth, tab->height - insets.t - insets.b);
|
||||
} else if (message->type == ES_MSG_PAINT) {
|
||||
EsDrawContent(message->painter, element, ES_RECT_2S(message->painter->width, message->painter->height),
|
||||
instance->title, instance->titleBytes, instance->iconID);
|
||||
tab->title, tab->titleBytes, tab->iconID);
|
||||
} else if (message->type == ES_MSG_ANIMATE) {
|
||||
message->animate.complete = ReorderItemAnimate(tab, message->animate.deltaMs, "windowTabEntranceDuration");
|
||||
} else if (message->type == ES_MSG_MOUSE_LEFT_DRAG) {
|
||||
EsElementSetDisabled(band->GetChild(0), true);
|
||||
|
||||
if (band->items.Length() == 1) {
|
||||
if (band->container->openTabs.Length() == 1) {
|
||||
// Get the window we're hovering the tab over.
|
||||
EsObjectID hoverWindowID;
|
||||
EsPoint mousePositionOnScreen = EsMouseGetPosition();
|
||||
|
@ -845,9 +897,9 @@ int WindowTabMessage(EsElement *element, EsMessage *message) {
|
|||
} else if (message->type == ES_MSG_MOUSE_LEFT_UP) {
|
||||
ReorderItemDragComplete(tab);
|
||||
EsElementSetDisabled(band->GetChild(0), false);
|
||||
} else if (message->type == ES_MSG_MOUSE_RIGHT_CLICK) {
|
||||
} else if (message->type == ES_MSG_MOUSE_RIGHT_CLICK && tab->applicationInstance) {
|
||||
EsMenu *menu = EsMenuCreate(tab, ES_FLAGS_DEFAULT);
|
||||
uint64_t disableIfOnlyTab = tab->container->tabBand->items.Length() == 1 ? ES_ELEMENT_DISABLED : ES_FLAGS_DEFAULT;
|
||||
uint64_t disableIfOnlyTab = tab->container->openTabs.Length() == 1 ? ES_ELEMENT_DISABLED : ES_FLAGS_DEFAULT;
|
||||
|
||||
EsMenuAddItem(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(DesktopCloseTab), [] (EsMenu *, EsGeneric context) {
|
||||
WindowTabClose((WindowTab *) context.p);
|
||||
|
@ -883,6 +935,7 @@ int WindowTabMessage(EsElement *element, EsMessage *message) {
|
|||
EsMenuAddItem(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(DesktopInspectUI), [] (EsMenu *, EsGeneric context) {
|
||||
WindowTab *tab = (WindowTab *) context.p;
|
||||
ApplicationInstance *instance = tab->applicationInstance;
|
||||
if (!instance) return;
|
||||
EsMessage m = { ES_MSG_TAB_INSPECT_UI };
|
||||
m.tabOperation.id = instance->embeddedWindowID;
|
||||
EsMessagePostRemote(instance->process->handle, &m);
|
||||
|
@ -912,6 +965,7 @@ WindowTab *WindowTabCreate(ContainerWindow *container) {
|
|||
tab->container = container;
|
||||
tab->Initialise(container->tabBand, ES_CELL_H_SHRINK | ES_CELL_V_BOTTOM, WindowTabMessage, nullptr);
|
||||
tab->cName = "window tab";
|
||||
container->openTabs.Add(tab);
|
||||
|
||||
tab->closeButton = EsButtonCreate(tab, ES_FLAGS_DEFAULT, ES_STYLE_WINDOW_TAB_CLOSE_BUTTON);
|
||||
tab->closeButton->userData = tab;
|
||||
|
@ -927,8 +981,8 @@ int WindowTabBandMessage(EsElement *element, EsMessage *message) {
|
|||
WindowTabBand *band = (WindowTabBand *) element;
|
||||
|
||||
if (message->type == ES_MSG_LAYOUT) {
|
||||
for (uint16_t i = 0; i < band->items.Length(); i++) {
|
||||
WindowTab *tab = (WindowTab *) band->items[i];
|
||||
for (uint16_t i = 0; i < band->container->openTabs.Length(); i++) {
|
||||
WindowTab *tab = band->container->openTabs[i];
|
||||
tab->SetStyle(tab == tab->container->active ? ES_STYLE_WINDOW_TAB_ACTIVE : ES_STYLE_WINDOW_TAB_INACTIVE);
|
||||
|
||||
if (tab == tab->container->active) {
|
||||
|
@ -951,16 +1005,15 @@ int WindowTabBandMessage(EsElement *element, EsMessage *message) {
|
|||
}
|
||||
} else if (message->type == ES_MSG_MOUSE_RIGHT_CLICK) {
|
||||
EsMenu *menu = EsMenuCreate(band, ES_MENU_AT_CURSOR);
|
||||
const char *string = band->container->openTabs.Length() > 1 ? interfaceString_DesktopCloseAllTabs : interfaceString_DesktopCloseWindow;
|
||||
|
||||
EsMenuAddItem(menu, ES_FLAGS_DEFAULT,
|
||||
band->items.Length() > 1 ? interfaceString_DesktopCloseAllTabs : interfaceString_DesktopCloseWindow, -1,
|
||||
[] (EsMenu *, EsGeneric context) {
|
||||
WindowTabBand *band = (WindowTabBand *) context.p;
|
||||
EsMenuAddItem(menu, ES_FLAGS_DEFAULT, string, -1, [] (EsMenu *, EsGeneric context) {
|
||||
ContainerWindow *container = (ContainerWindow *) context.p;
|
||||
|
||||
for (uintptr_t i = 0; i < band->items.Length(); i++) {
|
||||
WindowTabClose((WindowTab *) band->items[i]);
|
||||
for (uintptr_t i = 0; i < container->openTabs.Length(); i++) {
|
||||
WindowTabClose(container->openTabs[i]);
|
||||
}
|
||||
}, band);
|
||||
}, band->container);
|
||||
|
||||
EsMenuAddSeparator(menu);
|
||||
|
||||
|
@ -1006,6 +1059,22 @@ int WindowTabBandMessage(EsElement *element, EsMessage *message) {
|
|||
}, band->window);
|
||||
|
||||
EsMenuShow(menu);
|
||||
} else if (message->type == ES_MSG_REORDER_ITEM_MOVED) {
|
||||
WindowTab *tab = (WindowTab *) message->child;
|
||||
|
||||
if (band->container->openTabs.FindAndDelete(tab, false)) {
|
||||
uintptr_t openTabsBeforeTab = 0;
|
||||
|
||||
for (uintptr_t i = 0; i < band->items.Length(); i++) {
|
||||
if (band->items[i] == tab) {
|
||||
break;
|
||||
} else if (!band->items[i]->exiting) {
|
||||
openTabsBeforeTab++;
|
||||
}
|
||||
}
|
||||
|
||||
band->container->openTabs.Insert(tab, openTabsBeforeTab);
|
||||
}
|
||||
} else {
|
||||
return ReorderListMessage(band, message);
|
||||
}
|
||||
|
@ -1081,12 +1150,15 @@ ContainerWindow *ContainerWindowCreate() {
|
|||
int TaskBarButtonMessage(EsElement *element, EsMessage *message) {
|
||||
TaskBarButton *button = (TaskBarButton *) element;
|
||||
|
||||
if (message->type == ES_MSG_PAINT) {
|
||||
if (message->type == ES_MSG_PAINT && button->containerWindow) {
|
||||
ContainerWindow *containerWindow = button->containerWindow;
|
||||
ApplicationInstance *instance = containerWindow->active->applicationInstance;
|
||||
EsDrawContent(message->painter, element, ES_RECT_2S(message->painter->width, message->painter->height),
|
||||
instance->title, instance->titleBytes, instance->iconID);
|
||||
} else if (message->type == ES_MSG_MOUSE_LEFT_CLICK) {
|
||||
|
||||
if (instance) {
|
||||
EsDrawContent(message->painter, element, ES_RECT_2S(message->painter->width, message->painter->height),
|
||||
instance->title, instance->titleBytes, instance->iconID);
|
||||
}
|
||||
} else if (message->type == ES_MSG_MOUSE_LEFT_CLICK && button->containerWindow) {
|
||||
if (button->customStyleState & THEME_STATE_SELECTED) {
|
||||
EsSyscall(ES_SYSCALL_WINDOW_MOVE, button->containerWindow->window->handle, 0, 0, ES_WINDOW_MOVE_HIDDEN);
|
||||
} else {
|
||||
|
@ -1458,6 +1530,10 @@ void InstanceBlankTabCreate(EsMessage *message) {
|
|||
//////////////////////////////////////////////////////
|
||||
|
||||
ApplicationInstance *ApplicationInstanceFindByWindowID(EsObjectID windowID, bool remove) {
|
||||
if (!windowID) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) {
|
||||
ApplicationInstance *instance = desktop.allApplicationInstances[i];
|
||||
|
||||
|
@ -1983,7 +2059,7 @@ void OpenDocumentOpenReference(EsObjectID id) {
|
|||
document->referenceCount++;
|
||||
}
|
||||
|
||||
void OpenDocumentWithApplication(EsApplicationStartupRequest *startupRequest) {
|
||||
void OpenDocumentWithApplication(EsApplicationStartupRequest *startupRequest, ContainerWindow *container) {
|
||||
bool foundDocument = false;
|
||||
|
||||
_EsApplicationStartupInformation startupInformation = {};
|
||||
|
@ -2029,7 +2105,7 @@ void OpenDocumentWithApplication(EsApplicationStartupRequest *startupRequest) {
|
|||
OpenDocumentListUpdated();
|
||||
}
|
||||
|
||||
ApplicationInstanceCreate(startupInformation.id, &startupInformation, nullptr);
|
||||
ApplicationInstanceCreate(startupInformation.id, &startupInformation, container);
|
||||
OpenDocumentCloseReference(startupInformation.documentID);
|
||||
}
|
||||
|
||||
|
@ -2635,7 +2711,16 @@ void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
|
|||
EsApplicationStartupRequest request = {};
|
||||
EsBufferReadInto(&b, &request, sizeof(EsApplicationStartupRequest));
|
||||
request.filePath = (const char *) EsBufferRead(&b, request.filePathBytes);
|
||||
if (!b.error) OpenDocumentWithApplication(&request);
|
||||
|
||||
if (!b.error) {
|
||||
ContainerWindow *container = nullptr /* new container */;
|
||||
|
||||
if ((request.flags & ES_APPLICATION_STARTUP_IN_SAME_CONTAINER) && instance && instance->tab) {
|
||||
container = instance->tab->container;
|
||||
}
|
||||
|
||||
OpenDocumentWithApplication(&request, container);
|
||||
}
|
||||
}
|
||||
} else if (buffer[0] == DESKTOP_MSG_CREATE_CLIPBOARD_FILE && pipe) {
|
||||
EsHandle processHandle = EsProcessOpen(message->desktop.processID);
|
||||
|
@ -2851,6 +2936,10 @@ void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
|
|||
}
|
||||
|
||||
if (instance->tab) {
|
||||
EsMemoryCopy(instance->tab->title, instance->title, instance->titleBytes);
|
||||
instance->tab->titleBytes = instance->titleBytes;
|
||||
instance->tab->iconID = instance->iconID;
|
||||
|
||||
instance->tab->Repaint(true);
|
||||
|
||||
if (instance->tab == instance->tab->container->active && instance->tab->container->taskBarButton) {
|
||||
|
|
|
@ -7470,15 +7470,16 @@ void UIProcessWindowManagerMessage(EsWindow *window, EsMessage *message, Process
|
|||
UIMaybeRefreshStyleAll(window);
|
||||
}
|
||||
} else if (message->type == ES_MSG_WINDOW_ACTIVATED) {
|
||||
gui.leftModifiers = message->windowActivated.leftModifiers;
|
||||
gui.rightModifiers = message->windowActivated.rightModifiers;
|
||||
|
||||
if (!window->activated) {
|
||||
AccessKeyModeExit();
|
||||
|
||||
gui.leftModifiers = gui.rightModifiers = 0;
|
||||
gui.clickChainStartMs = 0;
|
||||
|
||||
window->activated = true;
|
||||
EsMessage m = { ES_MSG_WINDOW_ACTIVATED };
|
||||
EsMessageSend(window, &m);
|
||||
|
||||
EsMessageSend(window, message);
|
||||
|
||||
if (!window->focused && window->inactiveFocus) {
|
||||
EsElementFocus(window->inactiveFocus, false);
|
||||
|
|
|
@ -1257,9 +1257,9 @@ struct EsListView : EsElement {
|
|||
focusedItemIndex = item->index;
|
||||
element->customStyleState |= THEME_STATE_FOCUSED_ITEM;
|
||||
|
||||
Select(item->group, item->index, EsKeyboardIsShiftHeld(), EsKeyboardIsCtrlHeld(), false);
|
||||
|
||||
if (message->mouseDown.clickChainCount == 2 && !EsKeyboardIsShiftHeld() && !EsKeyboardIsCtrlHeld()) {
|
||||
if (message->mouseDown.clickChainCount == 1 || (~element->customStyleState & THEME_STATE_SELECTED)) {
|
||||
Select(item->group, item->index, EsKeyboardIsShiftHeld(), EsKeyboardIsCtrlHeld(), false);
|
||||
} else if (message->mouseDown.clickChainCount == 2) {
|
||||
EsMessage m = { ES_MSG_LIST_VIEW_CHOOSE_ITEM };
|
||||
m.chooseItem.group = item->group;
|
||||
m.chooseItem.index = item->index;
|
||||
|
@ -1512,7 +1512,7 @@ struct EsListView : EsElement {
|
|||
} else if (isSpace && ctrl && !shift && hasFocusedItem) {
|
||||
Select(focusedItemGroup, focusedItemIndex, false, true, false);
|
||||
return true;
|
||||
} else if (isEnter && hasFocusedItem && !shift && !ctrl && !alt) {
|
||||
} else if (isEnter && hasFocusedItem) {
|
||||
if (searchBufferBytes) {
|
||||
searchBufferLastKeyTime = 0;
|
||||
searchBufferBytes = 0;
|
||||
|
|
|
@ -700,6 +700,7 @@ define ES_ELEMENT_FOCUS_FROM_KEYBOARD (1 << 1)
|
|||
|
||||
define ES_APPLICATION_STARTUP_MANUAL_PATH (1 << 0)
|
||||
define ES_APPLICATION_STARTUP_BACKGROUND_SERVICE (1 << 1)
|
||||
define ES_APPLICATION_STARTUP_IN_SAME_CONTAINER (1 << 2)
|
||||
|
||||
define ES_LIST_VIEW_INLINE_TEXTBOX_COPY_EXISTING_TEXT (1 << 0)
|
||||
define ES_LIST_VIEW_INLINE_TEXTBOX_REJECT_EDIT_IF_FOCUS_LOST (1 << 1)
|
||||
|
@ -962,7 +963,6 @@ enum EsMessageType {
|
|||
ES_MSG_RADIO_GROUP_UPDATED = 0x3002 // Sent to all siblings of a radiobox when it is checked, so they can uncheck themselves.
|
||||
ES_MSG_COLOR_CHANGED = 0x3003 // Color well's color has changed. See message->colorChanged.
|
||||
ES_MSG_LIST_DISPLAY_GET_MARKER = 0x3004 // Get the string for a marker in an EsListDisplay. See message->getContent.
|
||||
ES_MSG_REORDER_ITEM_TEST = 0x3005
|
||||
ES_MSG_SLIDER_MOVED = 0x3006 // The slider has been moved.
|
||||
|
||||
// Desktop messages:
|
||||
|
@ -1032,6 +1032,10 @@ enum EsMessageType {
|
|||
ES_MSG_LIST_VIEW_GET_SUMMARY = 0x5314
|
||||
ES_MSG_LIST_VIEW_GET_COLUMN_SORT = 0x5315
|
||||
|
||||
// Reorder list messages:
|
||||
ES_MSG_REORDER_ITEM_TEST = 0x5400
|
||||
ES_MSG_REORDER_ITEM_MOVED = 0x5401
|
||||
|
||||
// Application messages:
|
||||
ES_MSG_APPLICATION_EXIT = 0x7001
|
||||
ES_MSG_INSTANCE_CREATE = 0x7002
|
||||
|
@ -1558,6 +1562,10 @@ struct EsMessageKeyboard {
|
|||
bool repeat, numpad, numlock, single;
|
||||
};
|
||||
|
||||
struct EsMessageWindowActivated {
|
||||
uint8_t leftModifiers, rightModifiers;
|
||||
};
|
||||
|
||||
struct EsMessageScrollWheel {
|
||||
int32_t dx, dy;
|
||||
};
|
||||
|
@ -1813,6 +1821,7 @@ struct EsMessage {
|
|||
EsMessageItemToString itemToString;
|
||||
EsMessageFocus focus;
|
||||
EsMessageScrollWheel scrollWheel;
|
||||
EsMessageWindowActivated windowActivated;
|
||||
const EsStyle *childStyleVariant;
|
||||
EsRectangle *accessKeyHintBounds;
|
||||
EsPainter *painter;
|
||||
|
@ -1954,7 +1963,7 @@ function_pointer void EsWorkCallback(EsGeneric context);
|
|||
|
||||
// System.
|
||||
|
||||
function void EsApplicationStart(const EsApplicationStartupRequest *request);
|
||||
function void EsApplicationStart(ES_INSTANCE_TYPE *instance, const EsApplicationStartupRequest *request);
|
||||
function void EsApplicationRunTemporary(ES_INSTANCE_TYPE *instance, STRING path);
|
||||
function EsHandle EsTakeSystemSnapshot(int type, size_t *bufferSize);
|
||||
function EsInstance *_EsInstanceCreate(size_t bytes, EsMessage *message, STRING name = BLANK_STRING);
|
||||
|
|
|
@ -191,7 +191,7 @@ bool SettingsPutValue(const char *cConfigurationSection, const char *cConfigurat
|
|||
}
|
||||
|
||||
void SettingsLoadDefaults() {
|
||||
SettingsPutValue("general", "click_chain_timeout_ms", EsLiteral("500"), nullptr, nullptr, true, false);
|
||||
SettingsPutValue("general", "click_chain_timeout_ms", EsLiteral("300"), nullptr, nullptr, true, false);
|
||||
SettingsPutValue("general", "show_cursor_shadow", EsLiteral("1"), nullptr, nullptr, true, false);
|
||||
SettingsPutValue("general", "scroll_lines_per_notch", EsLiteral("3"), nullptr, nullptr, true, false);
|
||||
SettingsPutValue("general", "ui_scale", EsLiteral("100"), nullptr, nullptr, true, false);
|
||||
|
|
|
@ -112,10 +112,8 @@ struct WindowManager {
|
|||
|
||||
// Keyboard:
|
||||
|
||||
bool shift, alt, ctrl, flag;
|
||||
bool shift2, alt2, ctrl2, flag2;
|
||||
bool numlock;
|
||||
uint8_t modifiers;
|
||||
uint8_t leftModifiers, rightModifiers;
|
||||
uint16_t keysHeld, maximumKeysHeld /* cleared when all released */;
|
||||
uint8_t keysHeldBitSet[512 / 8];
|
||||
|
||||
|
@ -341,39 +339,33 @@ void WindowManager::PressKey(uint32_t scancode) {
|
|||
|
||||
// TODO Caps lock.
|
||||
|
||||
if (scancode == ES_SCANCODE_LEFT_CTRL) ctrl = true;
|
||||
if (scancode == (ES_SCANCODE_LEFT_CTRL | K_SCANCODE_KEY_RELEASED)) ctrl = false;
|
||||
if (scancode == ES_SCANCODE_LEFT_SHIFT) shift = true;
|
||||
if (scancode == (ES_SCANCODE_LEFT_SHIFT | K_SCANCODE_KEY_RELEASED)) shift = false;
|
||||
if (scancode == ES_SCANCODE_LEFT_ALT) alt = true;
|
||||
if (scancode == (ES_SCANCODE_LEFT_ALT | K_SCANCODE_KEY_RELEASED)) alt = false;
|
||||
if (scancode == ES_SCANCODE_LEFT_FLAG) flag = true;
|
||||
if (scancode == (ES_SCANCODE_LEFT_FLAG | K_SCANCODE_KEY_RELEASED)) flag = false;
|
||||
if (scancode == ES_SCANCODE_LEFT_CTRL) leftModifiers |= ES_MODIFIER_CTRL;
|
||||
if (scancode == (ES_SCANCODE_LEFT_CTRL | K_SCANCODE_KEY_RELEASED)) leftModifiers &= ~ES_MODIFIER_CTRL;
|
||||
if (scancode == ES_SCANCODE_LEFT_SHIFT) leftModifiers |= ES_MODIFIER_SHIFT;
|
||||
if (scancode == (ES_SCANCODE_LEFT_SHIFT | K_SCANCODE_KEY_RELEASED)) leftModifiers &= ~ES_MODIFIER_SHIFT;
|
||||
if (scancode == ES_SCANCODE_LEFT_ALT) leftModifiers |= ES_MODIFIER_ALT;
|
||||
if (scancode == (ES_SCANCODE_LEFT_ALT | K_SCANCODE_KEY_RELEASED)) leftModifiers &= ~ES_MODIFIER_ALT;
|
||||
if (scancode == ES_SCANCODE_LEFT_FLAG) leftModifiers |= ES_MODIFIER_FLAG;
|
||||
if (scancode == (ES_SCANCODE_LEFT_FLAG | K_SCANCODE_KEY_RELEASED)) leftModifiers &= ~ES_MODIFIER_FLAG;
|
||||
|
||||
if (scancode == ES_SCANCODE_RIGHT_CTRL) ctrl2 = true;
|
||||
if (scancode == (ES_SCANCODE_RIGHT_CTRL | K_SCANCODE_KEY_RELEASED)) ctrl2 = false;
|
||||
if (scancode == ES_SCANCODE_RIGHT_SHIFT) shift2 = true;
|
||||
if (scancode == (ES_SCANCODE_RIGHT_SHIFT | K_SCANCODE_KEY_RELEASED)) shift2 = false;
|
||||
if (scancode == ES_SCANCODE_RIGHT_ALT) alt2 = true;
|
||||
if (scancode == (ES_SCANCODE_RIGHT_ALT | K_SCANCODE_KEY_RELEASED)) alt2 = false;
|
||||
if (scancode == ES_SCANCODE_RIGHT_FLAG) flag2 = true;
|
||||
if (scancode == (ES_SCANCODE_RIGHT_FLAG | K_SCANCODE_KEY_RELEASED)) flag2 = false;
|
||||
if (scancode == ES_SCANCODE_RIGHT_CTRL) leftModifiers |= ES_MODIFIER_CTRL;
|
||||
if (scancode == (ES_SCANCODE_RIGHT_CTRL | K_SCANCODE_KEY_RELEASED)) leftModifiers &= ~ES_MODIFIER_CTRL;
|
||||
if (scancode == ES_SCANCODE_RIGHT_SHIFT) leftModifiers |= ES_MODIFIER_SHIFT;
|
||||
if (scancode == (ES_SCANCODE_RIGHT_SHIFT | K_SCANCODE_KEY_RELEASED)) leftModifiers &= ~ES_MODIFIER_SHIFT;
|
||||
if (scancode == ES_SCANCODE_RIGHT_ALT) leftModifiers |= ES_MODIFIER_ALT_GR;
|
||||
if (scancode == (ES_SCANCODE_RIGHT_ALT | K_SCANCODE_KEY_RELEASED)) leftModifiers &= ~ES_MODIFIER_ALT_GR;
|
||||
if (scancode == ES_SCANCODE_RIGHT_FLAG) leftModifiers |= ES_MODIFIER_FLAG;
|
||||
if (scancode == (ES_SCANCODE_RIGHT_FLAG | K_SCANCODE_KEY_RELEASED)) leftModifiers &= ~ES_MODIFIER_FLAG;
|
||||
|
||||
if (scancode == ES_SCANCODE_NUM_LOCK) {
|
||||
numlock = !numlock;
|
||||
HIDeviceUpdateIndicators();
|
||||
}
|
||||
|
||||
modifiers = (alt ? ES_MODIFIER_ALT : 0)
|
||||
| (alt2 ? ES_MODIFIER_ALT_GR : 0)
|
||||
| ((ctrl | ctrl2) ? ES_MODIFIER_CTRL : 0)
|
||||
| ((shift | shift2) ? ES_MODIFIER_SHIFT : 0)
|
||||
| ((flag | flag2) ? ES_MODIFIER_FLAG : 0);
|
||||
|
||||
EsMessage message;
|
||||
EsMemoryZero(&message, sizeof(EsMessage));
|
||||
message.type = (scancode & K_SCANCODE_KEY_RELEASED) ? ES_MSG_KEY_UP : ES_MSG_KEY_DOWN;
|
||||
message.keyboard.modifiers = modifiers;
|
||||
message.keyboard.modifiers = leftModifiers | rightModifiers;
|
||||
message.keyboard.scancode = scancode & ~K_SCANCODE_KEY_RELEASED;
|
||||
message.keyboard.numlock = numlock;
|
||||
|
||||
|
@ -397,9 +389,9 @@ void WindowManager::PressKey(uint32_t scancode) {
|
|||
maximumKeysHeld = (!keysHeld || keysHeld > maximumKeysHeld) ? keysHeld : maximumKeysHeld;
|
||||
|
||||
KernelLog(LOG_VERBOSE, "WM", "press key", "WindowManager::PressKey - Received key press %x. Modifiers are %X. Keys held: %d/%d%z.\n",
|
||||
scancode, modifiers, keysHeld, maximumKeysHeld, message.keyboard.single ? " (single)" : "");
|
||||
scancode, leftModifiers | rightModifiers, keysHeld, maximumKeysHeld, message.keyboard.single ? " (single)" : "");
|
||||
|
||||
if (((modifiers & ES_MODIFIER_CTRL) && (modifiers & ES_MODIFIER_FLAG)) || !activeWindow) {
|
||||
if ((((leftModifiers | rightModifiers) & ES_MODIFIER_CTRL) && ((leftModifiers | rightModifiers) & ES_MODIFIER_FLAG)) || !activeWindow) {
|
||||
_EsMessageWithObject messageWithObject = { nullptr, message };
|
||||
DesktopSendMessage(&messageWithObject);
|
||||
} else {
|
||||
|
@ -524,6 +516,8 @@ bool WindowManager::ActivateWindow(Window *window) {
|
|||
|
||||
// Activate the new window.
|
||||
message.type = ES_MSG_WINDOW_ACTIVATED;
|
||||
message.windowActivated.leftModifiers = leftModifiers;
|
||||
message.windowActivated.rightModifiers = rightModifiers;
|
||||
SendMessageToWindow(window, &message);
|
||||
} else {
|
||||
// No window is active.
|
||||
|
@ -642,7 +636,7 @@ void WindowManager::MoveCursor(int64_t xMovement, int64_t yMovement) {
|
|||
xMovement *= CURSOR_SPEED(cursorProperties);
|
||||
yMovement *= CURSOR_SPEED(cursorProperties);
|
||||
|
||||
if (alt && (cursorProperties & CURSOR_USE_ALT_SLOW)) {
|
||||
if ((leftModifiers & ES_MODIFIER_ALT) && (cursorProperties & CURSOR_USE_ALT_SLOW)) {
|
||||
// Apply cursor slowdown.
|
||||
xMovement /= 5, yMovement /= 5;
|
||||
}
|
||||
|
@ -1239,6 +1233,12 @@ void Window::SetEmbed(EmbeddedWindow *newEmbed) {
|
|||
EsMessage message;
|
||||
EsMemoryZero(&message, sizeof(message));
|
||||
message.type = windowManager.activeWindow == this ? ES_MSG_WINDOW_ACTIVATED : ES_MSG_WINDOW_DEACTIVATED;
|
||||
|
||||
if (message.type == ES_MSG_WINDOW_ACTIVATED) {
|
||||
message.windowActivated.leftModifiers = windowManager.leftModifiers;
|
||||
message.windowActivated.rightModifiers = windowManager.rightModifiers;
|
||||
}
|
||||
|
||||
embed->owner->messageQueue.SendMessage(embed->apiWindow, &message);
|
||||
}
|
||||
|
||||
|
|
|
@ -55,16 +55,18 @@ struct Array {
|
|||
return -1;
|
||||
}
|
||||
|
||||
inline void FindAndDelete(T item, bool failIfNotFound) {
|
||||
inline bool FindAndDelete(T item, bool failIfNotFound) {
|
||||
intptr_t index = Find(item, failIfNotFound);
|
||||
if (index == -1) return;
|
||||
if (index == -1) return false;
|
||||
Delete(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void FindAndDeleteSwap(T item, bool failIfNotFound) {
|
||||
inline bool FindAndDeleteSwap(T item, bool failIfNotFound) {
|
||||
intptr_t index = Find(item, failIfNotFound);
|
||||
if (index == -1) return;
|
||||
if (index == -1) return false;
|
||||
DeleteSwap(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void AddFast(T item) {
|
||||
|
|
Loading…
Reference in New Issue