mirror of https://gitlab.com/nakst/essence
changing UI scale
This commit is contained in:
parent
e2130fb3ba
commit
0c50335c62
|
@ -141,7 +141,7 @@ int FontPreviewMessage(EsElement *element, EsMessage *message) {
|
||||||
runs[0].style.font.italic = element->instance->fontVariant / 10;
|
runs[0].style.font.italic = element->instance->fontVariant / 10;
|
||||||
runs[0].style.size = element->instance->fontSize;
|
runs[0].style.size = element->instance->fontSize;
|
||||||
runs[1].offset = element->instance->previewTextBytes;
|
runs[1].offset = element->instance->previewTextBytes;
|
||||||
EsTextPlan *plan = EsTextPlanCreate(&properties, bounds, element->instance->previewText, runs, 1);
|
EsTextPlan *plan = EsTextPlanCreate(element, &properties, bounds, element->instance->previewText, runs, 1);
|
||||||
EsDrawText(message->painter, plan, bounds);
|
EsDrawText(message->painter, plan, bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,12 +21,7 @@
|
||||||
// - Trim trailing space
|
// - Trim trailing space
|
||||||
// - Indent/comment/join/split shortcuts
|
// - Indent/comment/join/split shortcuts
|
||||||
|
|
||||||
const EsStyle styleFormatPopupColumn = {
|
#define SETTINGS_FILE "|Settings:/Default.ini"
|
||||||
.metrics = {
|
|
||||||
.mask = ES_THEME_METRICS_GAP_MAJOR,
|
|
||||||
.gapMajor = 5,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const EsInstanceClassEditorSettings editorSettings = {
|
const EsInstanceClassEditorSettings editorSettings = {
|
||||||
INTERFACE_STRING(TextEditorNewFileName),
|
INTERFACE_STRING(TextEditorNewFileName),
|
||||||
|
@ -34,6 +29,13 @@ const EsInstanceClassEditorSettings editorSettings = {
|
||||||
ES_ICON_TEXT,
|
ES_ICON_TEXT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const EsStyle styleFormatPopupColumn = {
|
||||||
|
.metrics = {
|
||||||
|
.mask = ES_THEME_METRICS_GAP_MAJOR,
|
||||||
|
.gapMajor = 5,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
struct Instance : EsInstance {
|
struct Instance : EsInstance {
|
||||||
EsTextbox *textboxDocument,
|
EsTextbox *textboxDocument,
|
||||||
*textboxSearch;
|
*textboxSearch;
|
||||||
|
@ -50,8 +52,11 @@ struct Instance : EsInstance {
|
||||||
commandFormat;
|
commandFormat;
|
||||||
|
|
||||||
uint32_t syntaxHighlightingLanguage;
|
uint32_t syntaxHighlightingLanguage;
|
||||||
|
int32_t textSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int32_t globalTextSize = 10;
|
||||||
|
|
||||||
void Find(Instance *instance, bool backwards) {
|
void Find(Instance *instance, bool backwards) {
|
||||||
EsWindowSwitchToolbar(instance->window, instance->toolbarSearch, ES_TRANSITION_SLIDE_UP);
|
EsWindowSwitchToolbar(instance->window, instance->toolbarSearch, ES_TRANSITION_SLIDE_UP);
|
||||||
|
|
||||||
|
@ -96,10 +101,10 @@ void Find(Instance *instance, bool backwards) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetLanguage(Instance *instance, uint32_t newLanguage) {
|
void SetLanguage(Instance *instance, uint32_t newLanguage) {
|
||||||
EsTextStyle textStyle = {};
|
EsFont font = {};
|
||||||
EsTextboxGetTextStyle(instance->textboxDocument, &textStyle);
|
font.family = newLanguage ? ES_FONT_MONOSPACED : ES_FONT_SANS;
|
||||||
textStyle.font.family = newLanguage ? ES_FONT_MONOSPACED : ES_FONT_SANS;
|
font.weight = ES_FONT_REGULAR;
|
||||||
EsTextboxSetTextStyle(instance->textboxDocument, &textStyle);
|
EsTextboxSetFont(instance->textboxDocument, font);
|
||||||
|
|
||||||
instance->syntaxHighlightingLanguage = newLanguage;
|
instance->syntaxHighlightingLanguage = newLanguage;
|
||||||
EsTextboxSetupSyntaxHighlighting(instance->textboxDocument, newLanguage);
|
EsTextboxSetupSyntaxHighlighting(instance->textboxDocument, newLanguage);
|
||||||
|
@ -122,14 +127,25 @@ void FormatPopupCreate(Instance *instance) {
|
||||||
72, 96, 120, 144,
|
72, 96, 120, 144,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < sizeof(presetSizes) / sizeof(presetSizes[0]); i++) {
|
size_t presetSizeCount = sizeof(presetSizes) / sizeof(presetSizes[0]);
|
||||||
char buffer[64];
|
int currentSize = instance->textSize;
|
||||||
EsListViewFixedItemInsert(list, buffer, EsStringFormat(buffer, sizeof(buffer), "%d pt", presetSizes[i]), presetSizes[i]);
|
char buffer[64];
|
||||||
|
|
||||||
|
if (currentSize < presetSizes[0]) {
|
||||||
|
// The current size is not in the list; add it.
|
||||||
|
EsListViewFixedItemInsert(list, buffer, EsStringFormat(buffer, sizeof(buffer), "%d pt", currentSize), currentSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
EsTextStyle textStyle = {};
|
for (uintptr_t i = 0; i < presetSizeCount; i++) {
|
||||||
EsTextboxGetTextStyle(instance->textboxDocument, &textStyle);
|
EsListViewFixedItemInsert(list, buffer, EsStringFormat(buffer, sizeof(buffer), "%d pt", presetSizes[i]), presetSizes[i]);
|
||||||
EsListViewFixedItemSelect(list, textStyle.size);
|
|
||||||
|
if (currentSize > presetSizes[i] && (i == presetSizeCount - 1 || (i != presetSizeCount - 1 && currentSize < presetSizes[i + 1]))) {
|
||||||
|
// The current size is not in the list; add it.
|
||||||
|
EsListViewFixedItemInsert(list, buffer, EsStringFormat(buffer, sizeof(buffer), "%d pt", currentSize), currentSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EsListViewFixedItemSelect(list, currentSize);
|
||||||
|
|
||||||
list->messageUser = [] (EsElement *element, EsMessage *message) {
|
list->messageUser = [] (EsElement *element, EsMessage *message) {
|
||||||
if (message->type == ES_MSG_LIST_VIEW_SELECT) {
|
if (message->type == ES_MSG_LIST_VIEW_SELECT) {
|
||||||
|
@ -137,10 +153,8 @@ void FormatPopupCreate(Instance *instance) {
|
||||||
EsGeneric newSize;
|
EsGeneric newSize;
|
||||||
|
|
||||||
if (EsListViewFixedItemGetSelected(((EsListView *) element), &newSize)) {
|
if (EsListViewFixedItemGetSelected(((EsListView *) element), &newSize)) {
|
||||||
EsTextStyle textStyle = {};
|
globalTextSize = instance->textSize = newSize.u;
|
||||||
EsTextboxGetTextStyle(instance->textboxDocument, &textStyle);
|
EsTextboxSetTextSize(instance->textboxDocument, newSize.u);
|
||||||
textStyle.size = newSize.u;
|
|
||||||
EsTextboxSetTextStyle(instance->textboxDocument, &textStyle);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,10 +226,11 @@ void ProcessApplicationMessage(EsMessage *message) {
|
||||||
// Content:
|
// Content:
|
||||||
|
|
||||||
EsPanel *panel = EsPanelCreate(window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER);
|
EsPanel *panel = EsPanelCreate(window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER);
|
||||||
instance->textboxDocument = EsTextboxCreate(panel,
|
uint64_t documentFlags = ES_CELL_FILL | ES_TEXTBOX_MULTILINE | ES_TEXTBOX_ALLOW_TABS | ES_TEXTBOX_MARGIN;
|
||||||
ES_CELL_FILL | ES_TEXTBOX_MULTILINE | ES_TEXTBOX_ALLOW_TABS | ES_TEXTBOX_MARGIN,
|
instance->textboxDocument = EsTextboxCreate(panel, documentFlags, ES_STYLE_TEXTBOX_NO_BORDER);
|
||||||
ES_STYLE_TEXTBOX_NO_BORDER);
|
|
||||||
instance->textboxDocument->cName = "document";
|
instance->textboxDocument->cName = "document";
|
||||||
|
instance->textSize = globalTextSize;
|
||||||
|
EsTextboxSetTextSize(instance->textboxDocument, globalTextSize);
|
||||||
EsTextboxSetUndoManager(instance->textboxDocument, instance->undoManager);
|
EsTextboxSetUndoManager(instance->textboxDocument, instance->undoManager);
|
||||||
EsElementFocus(instance->textboxDocument);
|
EsElementFocus(instance->textboxDocument);
|
||||||
|
|
||||||
|
@ -324,12 +339,28 @@ void ProcessApplicationMessage(EsMessage *message) {
|
||||||
EsFileStoreWriteAll(message->instanceSave.file, contents, byteCount);
|
EsFileStoreWriteAll(message->instanceSave.file, contents, byteCount);
|
||||||
EsHeapFree(contents);
|
EsHeapFree(contents);
|
||||||
EsInstanceSaveComplete(message, true);
|
EsInstanceSaveComplete(message, true);
|
||||||
|
} else if (message->type == ES_MSG_APPLICATION_EXIT) {
|
||||||
|
EsBuffer buffer = {};
|
||||||
|
buffer.canGrow = true;
|
||||||
|
EsBufferFormat(&buffer, "[general]\ntext_size=%d\n", globalTextSize);
|
||||||
|
EsFileWriteAll(EsLiteral(SETTINGS_FILE), buffer.out, buffer.position);
|
||||||
|
EsHeapFree(buffer.out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _start() {
|
void _start() {
|
||||||
_init();
|
_init();
|
||||||
|
|
||||||
|
EsINIState state = { (char *) EsFileReadAll(EsLiteral(SETTINGS_FILE), &state.bytes) };
|
||||||
|
|
||||||
|
while (EsINIParse(&state)) {
|
||||||
|
if (0 == EsStringCompareRaw(state.section, state.sectionBytes, EsLiteral("general"))) {
|
||||||
|
if (0 == EsStringCompareRaw(state.key, state.keyBytes, EsLiteral("text_size"))) {
|
||||||
|
globalTextSize = EsIntegerParse(state.value, state.valueBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
ProcessApplicationMessage(EsMessageReceive());
|
ProcessApplicationMessage(EsMessageReceive());
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,9 +85,10 @@ struct EsFileStore {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GlobalData {
|
struct GlobalData {
|
||||||
int32_t clickChainTimeoutMs;
|
volatile int32_t clickChainTimeoutMs;
|
||||||
bool swapLeftAndRightButtons;
|
volatile float uiScale;
|
||||||
bool showCursorShadow;
|
volatile bool swapLeftAndRightButtons;
|
||||||
|
volatile bool showCursorShadow;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ThreadLocalStorage {
|
struct ThreadLocalStorage {
|
||||||
|
@ -147,7 +148,7 @@ extern "C" uintptr_t ProcessorTLSRead(uintptr_t offset);
|
||||||
void MaybeDestroyElement(EsElement *element);
|
void MaybeDestroyElement(EsElement *element);
|
||||||
const char *GetConstantString(const char *key);
|
const char *GetConstantString(const char *key);
|
||||||
void UndoManagerDestroy(EsUndoManager *manager);
|
void UndoManagerDestroy(EsUndoManager *manager);
|
||||||
int TextGetStringWidth(const EsTextStyle *style, const char *string, size_t stringBytes);
|
int TextGetStringWidth(EsElement *element, const EsTextStyle *style, const char *string, size_t stringBytes);
|
||||||
struct APIInstance *InstanceSetup(EsInstance *instance);
|
struct APIInstance *InstanceSetup(EsInstance *instance);
|
||||||
EsTextStyle TextPlanGetPrimaryStyle(EsTextPlan *plan);
|
EsTextStyle TextPlanGetPrimaryStyle(EsTextPlan *plan);
|
||||||
EsFileStore *FileStoreCreateFromEmbeddedFile(const char *path, size_t pathBytes);
|
EsFileStore *FileStoreCreateFromEmbeddedFile(const char *path, size_t pathBytes);
|
||||||
|
@ -967,6 +968,20 @@ EsMessage *EsMessageReceive() {
|
||||||
} 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);
|
||||||
|
} else if (type == ES_MSG_UI_SCALE_CHANGED) {
|
||||||
|
if (theming.scale != api.global->uiScale) {
|
||||||
|
theming.scale = api.global->uiScale;
|
||||||
|
gui.accessKeys.hintStyle = nullptr;
|
||||||
|
// TODO Clear old keepAround styles.
|
||||||
|
|
||||||
|
for (uintptr_t i = 0; i < gui.allWindows.Length(); i++) {
|
||||||
|
UIScaleChanged(gui.allWindows[i], &message.message);
|
||||||
|
gui.allWindows[i]->state |= UI_STATE_RELAYOUT;
|
||||||
|
UIWindowNeedsUpdate(gui.allWindows[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return &message.message;
|
||||||
|
}
|
||||||
} else if (type == ES_MSG_REGISTER_FILE_SYSTEM) {
|
} else if (type == ES_MSG_REGISTER_FILE_SYSTEM) {
|
||||||
EsMessageRegisterFileSystem *m = &message.message.registerFileSystem;
|
EsMessageRegisterFileSystem *m = &message.message.registerFileSystem;
|
||||||
|
|
||||||
|
@ -1219,23 +1234,7 @@ extern "C" void _start(EsProcessStartupInformation *_startupInformation) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uiProcess) {
|
if (uiProcess) {
|
||||||
// Initialise the GUI.
|
EsAssert(ThemeInitialise());
|
||||||
|
|
||||||
theming.scale = api.systemConstants[ES_SYSTEM_CONSTANT_UI_SCALE] / 100.0f;
|
|
||||||
|
|
||||||
size_t fileBytes;
|
|
||||||
const void *file = EsEmbeddedFileGet(EsLiteral("$Desktop/Theme.dat"), &fileBytes);
|
|
||||||
EsAssert(ThemeLoadData(file, fileBytes));
|
|
||||||
|
|
||||||
iconManagement.standardPack = (const uint8_t *) EsEmbeddedFileGet(EsLiteral("$Desktop/Icons.dat"), &iconManagement.standardPackSize);
|
|
||||||
|
|
||||||
theming.cursors.width = ES_THEME_CURSORS_WIDTH;
|
|
||||||
theming.cursors.height = ES_THEME_CURSORS_HEIGHT;
|
|
||||||
theming.cursors.stride = ES_THEME_CURSORS_WIDTH * 4;
|
|
||||||
theming.cursors.bits = EsObjectMap(EsMemoryOpen(theming.cursors.height * theming.cursors.stride, EsLiteral(ES_THEME_CURSORS_NAME), 0),
|
|
||||||
0, ES_MAP_OBJECT_ALL, ES_MAP_OBJECT_READ_ONLY);
|
|
||||||
theming.cursors.fullAlpha = true;
|
|
||||||
theming.cursors.readOnly = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (desktop) {
|
if (desktop) {
|
||||||
|
|
|
@ -24,10 +24,10 @@
|
||||||
// - Switch to window.
|
// - Switch to window.
|
||||||
// - Print screen.
|
// - Print screen.
|
||||||
|
|
||||||
// TODO Only let File Manager read the file_type sections of the system configuration.
|
|
||||||
// TODO Restarting Desktop if it crashes.
|
// TODO Restarting Desktop if it crashes.
|
||||||
// TODO Make sure applications can't delete |Fonts:.
|
// TODO Make sure applications can't delete |Fonts:.
|
||||||
// TODO Handle open document deletion.
|
// TODO Handle open document deletion.
|
||||||
|
// TODO Store an array of processes for each InstalledApplication.
|
||||||
|
|
||||||
#define MSG_SETUP_DESKTOP_UI ((EsMessageType) (ES_MSG_USER_START + 1))
|
#define MSG_SETUP_DESKTOP_UI ((EsMessageType) (ES_MSG_USER_START + 1))
|
||||||
|
|
||||||
|
@ -2395,7 +2395,7 @@ void DesktopMessage(EsMessage *message) {
|
||||||
if (instance->destroy) {
|
if (instance->destroy) {
|
||||||
instance->destroy(instance);
|
instance->destroy(instance);
|
||||||
}
|
}
|
||||||
} else if (message->type == MSG_SETUP_DESKTOP_UI) {
|
} else if (message->type == MSG_SETUP_DESKTOP_UI || message->type == ES_MSG_UI_SCALE_CHANGED) {
|
||||||
DesktopSetup();
|
DesktopSetup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -402,7 +402,7 @@ struct EsTextPlanProperties {
|
||||||
#define ES_TEXT_PLAN_RTL (1 << 10)
|
#define ES_TEXT_PLAN_RTL (1 << 10)
|
||||||
#define ES_TEXT_PLAN_CLIP_UNBREAKABLE_LINES (1 << 11)
|
#define ES_TEXT_PLAN_CLIP_UNBREAKABLE_LINES (1 << 11)
|
||||||
|
|
||||||
EsTextPlan *EsTextPlanCreate(EsTextPlanProperties *properties, EsRectangle bounds, const char *string, const EsTextRun *textRuns, size_t textRunCount);
|
EsTextPlan *EsTextPlanCreate(EsElement *element, EsTextPlanProperties *properties, EsRectangle bounds, const char *string, const EsTextRun *textRuns, size_t textRunCount);
|
||||||
|
|
||||||
int EsTextPlanGetWidth(EsTextPlan *plan);
|
int EsTextPlanGetWidth(EsTextPlan *plan);
|
||||||
int EsTextPlanGetHeight(EsTextPlan *plan);
|
int EsTextPlanGetHeight(EsTextPlan *plan);
|
||||||
|
@ -418,6 +418,7 @@ void EsTextPlanReplaceStyleRenderProperties(EsTextPlan *plan, EsTextStyle *style
|
||||||
Before you can draw text, you first need to create a *text plan*, which contains all the necessary information to draw the text. The advantage of using text plans is that it enables you to draw the same block of text multiple times without needing the text shaping and layout to be recalculated.
|
Before you can draw text, you first need to create a *text plan*, which contains all the necessary information to draw the text. The advantage of using text plans is that it enables you to draw the same block of text multiple times without needing the text shaping and layout to be recalculated.
|
||||||
|
|
||||||
To create a text plan, use `EsTextPlanCreate`.
|
To create a text plan, use `EsTextPlanCreate`.
|
||||||
|
- `element`: The user interface element which will use the text plan. The text plan will inherit appropriate display settings from the element, such as the UI scaling factor.
|
||||||
- `properties`: Contains properties to apply while laying out the text. `cLanguage` is the BCP 47 language tag as a string; if `NULL`, the default language is used. `maxLines` contains the maximum number of lines allowed in the layout, after which lines will be clipped; if `0`, the number of lines will be unlimited. `flags` contains any combination of the following constants:
|
- `properties`: Contains properties to apply while laying out the text. `cLanguage` is the BCP 47 language tag as a string; if `NULL`, the default language is used. `maxLines` contains the maximum number of lines allowed in the layout, after which lines will be clipped; if `0`, the number of lines will be unlimited. `flags` contains any combination of the following constants:
|
||||||
- `ES_TEXT_H/V_...`: Sets the alignment of the text in the bounds.
|
- `ES_TEXT_H/V_...`: Sets the alignment of the text in the bounds.
|
||||||
- `ES_TEXT_WRAP`: The text is allowed to wrap when it reaches the end of a line.
|
- `ES_TEXT_WRAP`: The text is allowed to wrap when it reaches the end of a line.
|
||||||
|
@ -445,7 +446,7 @@ void DrawElementText(EsElement *element, EsRectangle bounds, const char *string,
|
||||||
textRun[0].offset = 0;
|
textRun[0].offset = 0;
|
||||||
textRun[1].offset = stringBytes;
|
textRun[1].offset = stringBytes;
|
||||||
EsTextPlanProperties properties = {};
|
EsTextPlanProperties properties = {};
|
||||||
EsTextPlan *plan = EsTextPlanCreate(&properties, bounds, string, textRun, 1);
|
EsTextPlan *plan = EsTextPlanCreate(element, &properties, bounds, string, textRun, 1);
|
||||||
EsDrawText(painter, plan, bounds, nullptr, nullptr);
|
EsDrawText(painter, plan, bounds, nullptr, nullptr);
|
||||||
EsTextPlanDestroy(plan);
|
EsTextPlanDestroy(plan);
|
||||||
}
|
}
|
||||||
|
|
105
desktop/gui.cpp
105
desktop/gui.cpp
|
@ -17,9 +17,9 @@
|
||||||
// Behaviour of activation clicks. --> Only ignore activation clicks from menus.
|
// Behaviour of activation clicks. --> Only ignore activation clicks from menus.
|
||||||
// Behaviour of the scroll wheel with regards to focused/hovered elements --> Scroll the hovered element only.
|
// Behaviour of the scroll wheel with regards to focused/hovered elements --> Scroll the hovered element only.
|
||||||
|
|
||||||
#define WINDOW_INSET ((int) api.systemConstants[ES_SYSTEM_CONSTANT_WINDOW_INSET])
|
#define WINDOW_INSET ((int) api.systemConstants[ES_SYSTEM_CONSTANT_WINDOW_INSET])
|
||||||
#define CONTAINER_TAB_BAND_HEIGHT ((int) api.systemConstants[ES_SYSTEM_CONSTANT_CONTAINER_TAB_BAND_HEIGHT])
|
#define CONTAINER_TAB_BAND_HEIGHT ((int) api.systemConstants[ES_SYSTEM_CONSTANT_CONTAINER_TAB_BAND_HEIGHT])
|
||||||
#define BORDER_THICKNESS ((int) api.systemConstants[ES_SYSTEM_CONSTANT_BORDER_THICKNESS])
|
#define BORDER_THICKNESS ((int) (9 * theming.scale))
|
||||||
|
|
||||||
// #define TRACE_LAYOUT
|
// #define TRACE_LAYOUT
|
||||||
|
|
||||||
|
@ -403,7 +403,7 @@ void HeapDuplicate(void **pointer, const void *data, size_t bytes) {
|
||||||
*pointer = nullptr;
|
*pointer = nullptr;
|
||||||
} else {
|
} else {
|
||||||
void *buffer = EsHeapAllocate(bytes, false);
|
void *buffer = EsHeapAllocate(bytes, false);
|
||||||
EsMemoryCopy(buffer, data, bytes);
|
if (buffer) EsMemoryCopy(buffer, data, bytes);
|
||||||
*pointer = buffer;
|
*pointer = buffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -497,18 +497,18 @@ void WindowSnap(EsWindow *window, bool restored, bool dragging, uint8_t edge) {
|
||||||
|
|
||||||
if (edge == SNAP_EDGE_MAXIMIZE) {
|
if (edge == SNAP_EDGE_MAXIMIZE) {
|
||||||
bounds.t = screen.t - 16 * theming.scale;
|
bounds.t = screen.t - 16 * theming.scale;
|
||||||
bounds.b = screen.b + 19 * theming.scale;
|
bounds.b = screen.b + WINDOW_INSET;
|
||||||
bounds.l = screen.l - 19 * theming.scale;
|
bounds.l = screen.l - WINDOW_INSET;
|
||||||
bounds.r = screen.r + 19 * theming.scale;
|
bounds.r = screen.r + WINDOW_INSET;
|
||||||
} else if (edge == SNAP_EDGE_LEFT) {
|
} else if (edge == SNAP_EDGE_LEFT) {
|
||||||
bounds.t = screen.t;
|
bounds.t = screen.t;
|
||||||
bounds.b = screen.b;
|
bounds.b = screen.b;
|
||||||
bounds.l = screen.l;
|
bounds.l = screen.l;
|
||||||
bounds.r = (screen.r + screen.l) / 2;
|
bounds.r = (screen.r + screen.l) / 2 + BORDER_THICKNESS / 2;
|
||||||
} else if (edge == SNAP_EDGE_RIGHT) {
|
} else if (edge == SNAP_EDGE_RIGHT) {
|
||||||
bounds.t = screen.t;
|
bounds.t = screen.t;
|
||||||
bounds.b = screen.b;
|
bounds.b = screen.b;
|
||||||
bounds.l = (screen.r + screen.l) / 2;
|
bounds.l = (screen.r + screen.l) / 2 - BORDER_THICKNESS / 2;
|
||||||
bounds.r = screen.r;
|
bounds.r = screen.r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1368,6 +1368,17 @@ EsRectangle EsPainterBoundsInset(EsPainter *painter) {
|
||||||
painter->offsetY + style->insets.t, painter->offsetY + painter->height - style->insets.b);
|
painter->offsetY + style->insets.t, painter->offsetY + painter->height - style->insets.b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
EsDeviceColor EsPainterRealizeColorRGB(EsPainter *painter, float alpha, float red, float green, float blue) {
|
||||||
|
// TODO Convert the color to the device's color space.
|
||||||
|
EsAssert(painter);
|
||||||
|
return ((uint32_t) (alpha * 255.0f) << 24)
|
||||||
|
+ ((uint32_t) (red * 255.0f) << 16)
|
||||||
|
+ ((uint32_t) (green * 255.0f) << 8)
|
||||||
|
+ ((uint32_t) (blue * 255.0f) << 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void EsElement::Repaint(bool all, EsRectangle region) {
|
void EsElement::Repaint(bool all, EsRectangle region) {
|
||||||
// TODO Optimisation: don't paint if overlapped by an opaque child or sibling.
|
// TODO Optimisation: don't paint if overlapped by an opaque child or sibling.
|
||||||
|
|
||||||
|
@ -1772,6 +1783,7 @@ void EsElement::RefreshStyle(UIStyleKey *_oldStyleKey, bool alreadyRefreshStyleS
|
||||||
|
|
||||||
UIStyleKey oldStyleKey = _oldStyleKey ? *_oldStyleKey : currentStyleKey;
|
UIStyleKey oldStyleKey = _oldStyleKey ? *_oldStyleKey : currentStyleKey;
|
||||||
currentStyleKey.stateFlags = styleStateFlags;
|
currentStyleKey.stateFlags = styleStateFlags;
|
||||||
|
currentStyleKey.scale = theming.scale;
|
||||||
|
|
||||||
if (!force && 0 == EsMemoryCompare(¤tStyleKey, &oldStyleKey, sizeof(UIStyleKey)) && currentStyle) {
|
if (!force && 0 == EsMemoryCompare(¤tStyleKey, &oldStyleKey, sizeof(UIStyleKey)) && currentStyle) {
|
||||||
return;
|
return;
|
||||||
|
@ -1787,6 +1799,8 @@ void EsElement::RefreshStyle(UIStyleKey *_oldStyleKey, bool alreadyRefreshStyleS
|
||||||
UIStyle *oldStyle = currentStyle;
|
UIStyle *oldStyle = currentStyle;
|
||||||
currentStyle = GetStyle(currentStyleKey, false); // TODO Forcing new styles if force flag set.
|
currentStyle = GetStyle(currentStyleKey, false); // TODO Forcing new styles if force flag set.
|
||||||
|
|
||||||
|
state &= ~UI_STATE_USE_MEASUREMENT_CACHE;
|
||||||
|
|
||||||
// Respond to modifications.
|
// Respond to modifications.
|
||||||
|
|
||||||
bool repaint = false, animate = false;
|
bool repaint = false, animate = false;
|
||||||
|
@ -1960,6 +1974,10 @@ void LayoutTable(EsPanel *panel, EsMessage *message) {
|
||||||
|
|
||||||
uint8_t *memoryBase = (uint8_t *) EsHeapAllocate(sizeof(int) * childCount * 2 + sizeof(EsPanelBand) * (panel->bandCount[0] + panel->bandCount[1]), true), *memory = memoryBase;
|
uint8_t *memoryBase = (uint8_t *) EsHeapAllocate(sizeof(int) * childCount * 2 + sizeof(EsPanelBand) * (panel->bandCount[0] + panel->bandCount[1]), true), *memory = memoryBase;
|
||||||
|
|
||||||
|
if (!memoryBase) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int *calculatedSize[2];
|
int *calculatedSize[2];
|
||||||
calculatedSize[0] = (int *) memory; memory += sizeof(int) * childCount;
|
calculatedSize[0] = (int *) memory; memory += sizeof(int) * childCount;
|
||||||
calculatedSize[1] = (int *) memory; memory += sizeof(int) * childCount;
|
calculatedSize[1] = (int *) memory; memory += sizeof(int) * childCount;
|
||||||
|
@ -3391,8 +3409,8 @@ void EsPanelSetBands(EsPanel *panel, size_t columnCount, size_t rowCount, EsPane
|
||||||
panel->bandCount[1] = rowCount;
|
panel->bandCount[1] = rowCount;
|
||||||
panel->bands[0] = columns ? (EsPanelBand *) EsHeapAllocate(columnCount * sizeof(EsPanelBand), false) : nullptr;
|
panel->bands[0] = columns ? (EsPanelBand *) EsHeapAllocate(columnCount * sizeof(EsPanelBand), false) : nullptr;
|
||||||
panel->bands[1] = rows ? (EsPanelBand *) EsHeapAllocate(rowCount * sizeof(EsPanelBand), false) : nullptr;
|
panel->bands[1] = rows ? (EsPanelBand *) EsHeapAllocate(rowCount * sizeof(EsPanelBand), false) : nullptr;
|
||||||
if (columns) EsMemoryCopy(panel->bands[0], columns, columnCount * sizeof(EsPanelBand));
|
if (columns && panel->bands[0]) EsMemoryCopy(panel->bands[0], columns, columnCount * sizeof(EsPanelBand));
|
||||||
if (rows) EsMemoryCopy(panel->bands[1], rows, rowCount * sizeof(EsPanelBand));
|
if (rows && panel->bands[1]) EsMemoryCopy(panel->bands[1], rows, rowCount * sizeof(EsPanelBand));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EsPanelSetBandsAll(EsPanel *panel, EsPanelBand *column, EsPanelBand *row) {
|
void EsPanelSetBandsAll(EsPanel *panel, EsPanelBand *column, EsPanelBand *row) {
|
||||||
|
@ -3408,8 +3426,10 @@ void EsPanelSetBandsAll(EsPanel *panel, EsPanelBand *column, EsPanelBand *row) {
|
||||||
panel->bands[axis] = (EsPanelBand *) EsHeapAllocate(panel->bandCount[axis] * sizeof(EsPanelBand), false);
|
panel->bands[axis] = (EsPanelBand *) EsHeapAllocate(panel->bandCount[axis] * sizeof(EsPanelBand), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < panel->bandCount[axis]; i++) {
|
if (panel->bands[axis]) {
|
||||||
panel->bands[axis][i] = *templates[axis];
|
for (uintptr_t i = 0; i < panel->bandCount[axis]; i++) {
|
||||||
|
panel->bands[axis][i] = *templates[axis];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3667,7 +3687,9 @@ int ProcessButtonMessage(EsElement *element, EsMessage *message) {
|
||||||
(button->flags & ES_BUTTON_DROPDOWN) ? ES_DRAW_CONTENT_MARKER_DOWN_ARROW : ES_FLAGS_DEFAULT);
|
(button->flags & ES_BUTTON_DROPDOWN) ? ES_DRAW_CONTENT_MARKER_DOWN_ARROW : ES_FLAGS_DEFAULT);
|
||||||
} else if (message->type == ES_MSG_GET_WIDTH) {
|
} else if (message->type == ES_MSG_GET_WIDTH) {
|
||||||
if (!button->measurementCache.Get(message, &button->state)) {
|
if (!button->measurementCache.Get(message, &button->state)) {
|
||||||
int stringWidth = button->currentStyle->MeasureTextWidth(button->label, button->labelBytes);
|
EsTextStyle textStyle;
|
||||||
|
button->currentStyle->GetTextStyle(&textStyle);
|
||||||
|
int stringWidth = TextGetStringWidth(button, &textStyle, button->label, button->labelBytes);
|
||||||
int iconWidth = button->iconID ? button->currentStyle->metrics->iconSize : 0;
|
int iconWidth = button->iconID ? button->currentStyle->metrics->iconSize : 0;
|
||||||
int contentWidth = stringWidth + iconWidth + ((stringWidth && iconWidth) ? button->currentStyle->gapMinor : 0)
|
int contentWidth = stringWidth + iconWidth + ((stringWidth && iconWidth) ? button->currentStyle->gapMinor : 0)
|
||||||
+ button->currentStyle->insets.l + button->currentStyle->insets.r;
|
+ button->currentStyle->insets.l + button->currentStyle->insets.r;
|
||||||
|
@ -4508,6 +4530,7 @@ struct EsSplitter : EsElement {
|
||||||
bool horizontal;
|
bool horizontal;
|
||||||
bool addingSplitBar;
|
bool addingSplitBar;
|
||||||
int previousSize;
|
int previousSize;
|
||||||
|
float previousScale;
|
||||||
Array<int64_t> resizeStartSizes;
|
Array<int64_t> resizeStartSizes;
|
||||||
bool calculatedInitialSize;
|
bool calculatedInitialSize;
|
||||||
};
|
};
|
||||||
|
@ -4748,6 +4771,7 @@ int ProcessSplitterMessage(EsElement *element, EsMessage *message) {
|
||||||
|
|
||||||
splitter->calculatedInitialSize = true;
|
splitter->calculatedInitialSize = true;
|
||||||
splitter->previousSize = newSize;
|
splitter->previousSize = newSize;
|
||||||
|
splitter->previousScale = theming.scale;
|
||||||
|
|
||||||
int position = splitter->horizontal ? bounds.l : bounds.t;
|
int position = splitter->horizontal ? bounds.l : bounds.t;
|
||||||
|
|
||||||
|
@ -4822,6 +4846,18 @@ int ProcessSplitterMessage(EsElement *element, EsMessage *message) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (message->type == ES_MSG_UI_SCALE_CHANGED) {
|
||||||
|
float changeFactor = theming.scale / splitter->previousScale;
|
||||||
|
splitter->previousScale = theming.scale;
|
||||||
|
|
||||||
|
for (uintptr_t i = 1; i < splitter->GetChildCount(); i += 2) {
|
||||||
|
SplitBar *bar = (SplitBar *) splitter->GetChild(i);
|
||||||
|
bar->position *= changeFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uintptr_t i = 0; i < splitter->resizeStartSizes.Length(); i++) {
|
||||||
|
splitter->resizeStartSizes[i] *= changeFactor;
|
||||||
|
}
|
||||||
} else if (message->type == ES_MSG_DESTROY) {
|
} else if (message->type == ES_MSG_DESTROY) {
|
||||||
splitter->resizeStartSizes.Free();
|
splitter->resizeStartSizes.Free();
|
||||||
}
|
}
|
||||||
|
@ -4916,10 +4952,15 @@ EsImageDisplay *EsImageDisplayCreate(EsElement *parent, uint64_t flags, const Es
|
||||||
void EsImageDisplayLoadBits(EsImageDisplay *display, const uint32_t *bits, size_t width, size_t height, size_t stride) {
|
void EsImageDisplayLoadBits(EsImageDisplay *display, const uint32_t *bits, size_t width, size_t height, size_t stride) {
|
||||||
EsHeapFree(display->bits);
|
EsHeapFree(display->bits);
|
||||||
display->bits = (uint32_t *) EsHeapAllocate(stride * height, false);
|
display->bits = (uint32_t *) EsHeapAllocate(stride * height, false);
|
||||||
display->width = width;
|
|
||||||
display->height = height;
|
if (!display->bits) {
|
||||||
display->stride = stride;
|
display->width = display->height = display->stride = 0;
|
||||||
EsMemoryCopy(display->bits, bits, stride * height);
|
} else {
|
||||||
|
display->width = width;
|
||||||
|
display->height = height;
|
||||||
|
display->stride = stride;
|
||||||
|
EsMemoryCopy(display->bits, bits, stride * height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EsImageDisplayLoadFromMemory(EsImageDisplay *display, const void *buffer, size_t bufferBytes) {
|
void EsImageDisplayLoadFromMemory(EsImageDisplay *display, const void *buffer, size_t bufferBytes) {
|
||||||
|
@ -5645,6 +5686,11 @@ EsThemeMetrics EsElementGetMetrics(EsElement *element) {
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float EsElementGetScaleFactor(EsElement *element) {
|
||||||
|
EsAssert(element);
|
||||||
|
return theming.scale;
|
||||||
|
}
|
||||||
|
|
||||||
void EsElementSetCallback(EsElement *element, EsUICallback callback) {
|
void EsElementSetCallback(EsElement *element, EsUICallback callback) {
|
||||||
EsMessageMutexCheck();
|
EsMessageMutexCheck();
|
||||||
element->messageUser = callback;
|
element->messageUser = callback;
|
||||||
|
@ -5768,29 +5814,14 @@ bool EsMouseIsLeftHeld() { return gui.mouseButtonDown && gui.lastClickButton
|
||||||
bool EsMouseIsRightHeld() { return gui.mouseButtonDown && gui.lastClickButton == ES_MSG_MOUSE_RIGHT_DOWN; }
|
bool EsMouseIsRightHeld() { return gui.mouseButtonDown && gui.lastClickButton == ES_MSG_MOUSE_RIGHT_DOWN; }
|
||||||
bool EsMouseIsMiddleHeld() { return gui.mouseButtonDown && gui.lastClickButton == ES_MSG_MOUSE_MIDDLE_DOWN; }
|
bool EsMouseIsMiddleHeld() { return gui.mouseButtonDown && gui.lastClickButton == ES_MSG_MOUSE_MIDDLE_DOWN; }
|
||||||
|
|
||||||
void EsStyleRefreshAll(EsElement *element) {
|
void UIScaleChanged(EsElement *element, EsMessage *message) {
|
||||||
EsMessageMutexCheck();
|
EsMessageMutexCheck();
|
||||||
|
|
||||||
element->RefreshStyle(nullptr, false, true);
|
element->RefreshStyle(nullptr, false, true);
|
||||||
|
EsMessageSend(element, message);
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < element->children.Length(); i++) {
|
for (uintptr_t i = 0; i < element->children.Length(); i++) {
|
||||||
if (element->children[i]) {
|
UIScaleChanged(element->children[i], message);
|
||||||
EsStyleRefreshAll(element->children[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EsUISetDPI(int dpiScale) {
|
|
||||||
EsMessageMutexCheck();
|
|
||||||
|
|
||||||
if (dpiScale < 50) {
|
|
||||||
dpiScale = 50;
|
|
||||||
}
|
|
||||||
|
|
||||||
theming.scale = dpiScale / 100.0f;
|
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < gui.allWindows.Length(); i++) {
|
|
||||||
EsStyleRefreshAll(gui.allWindows[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6083,7 +6114,7 @@ void AccessKeyHintsShow(EsPainter *painter) {
|
||||||
|
|
||||||
style->PaintLayers(painter, entry->bounds, 0, THEME_LAYER_MODE_BACKGROUND);
|
style->PaintLayers(painter, entry->bounds, 0, THEME_LAYER_MODE_BACKGROUND);
|
||||||
char c = gui.accessKeys.typedCharacter ? entry->number + '0' : entry->character;
|
char c = gui.accessKeys.typedCharacter ? entry->number + '0' : entry->character;
|
||||||
style->PaintText(painter, nullptr, entry->bounds, &c, 1, 0, ES_FLAGS_DEFAULT);
|
style->PaintText(painter, gui.accessKeys.window, entry->bounds, &c, 1, 0, ES_FLAGS_DEFAULT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,6 @@ struct EsListView : EsElement {
|
||||||
int64_t fixedWidth, fixedHeight;
|
int64_t fixedWidth, fixedHeight;
|
||||||
int64_t fixedHeaderSize, fixedFooterSize;
|
int64_t fixedHeaderSize, fixedFooterSize;
|
||||||
|
|
||||||
// TODO Updating these when the style changes.
|
|
||||||
UIStyle *primaryCellStyle;
|
UIStyle *primaryCellStyle;
|
||||||
UIStyle *secondaryCellStyle;
|
UIStyle *secondaryCellStyle;
|
||||||
UIStyle *selectedCellStyle;
|
UIStyle *selectedCellStyle;
|
||||||
|
@ -87,7 +86,6 @@ struct EsListView : EsElement {
|
||||||
EsListViewColumn *columns;
|
EsListViewColumn *columns;
|
||||||
size_t columnCount;
|
size_t columnCount;
|
||||||
int columnResizingOriginalWidth;
|
int columnResizingOriginalWidth;
|
||||||
// TODO Updating this when the style changes.
|
|
||||||
int64_t totalColumnWidth;
|
int64_t totalColumnWidth;
|
||||||
|
|
||||||
EsTextbox *inlineTextbox;
|
EsTextbox *inlineTextbox;
|
||||||
|
@ -1782,7 +1780,7 @@ struct EsListView : EsElement {
|
||||||
style->GetTextStyle(&textRun[0].style);
|
style->GetTextStyle(&textRun[0].style);
|
||||||
textRun[1].offset = emptyMessageBytes;
|
textRun[1].offset = emptyMessageBytes;
|
||||||
EsRectangle bounds = EsPainterBoundsInset(message->painter);
|
EsRectangle bounds = EsPainterBoundsInset(message->painter);
|
||||||
EsTextPlan *plan = EsTextPlanCreate(&properties, bounds, emptyMessage, textRun, 1);
|
EsTextPlan *plan = EsTextPlanCreate(this, &properties, bounds, emptyMessage, textRun, 1);
|
||||||
EsDrawText(message->painter, plan, bounds);
|
EsDrawText(message->painter, plan, bounds);
|
||||||
} else if (message->type == ES_MSG_ANIMATE) {
|
} else if (message->type == ES_MSG_ANIMATE) {
|
||||||
if (scroll.dragScrolling && (flags & ES_LIST_VIEW_CHOICE_SELECT)) {
|
if (scroll.dragScrolling && (flags & ES_LIST_VIEW_CHOICE_SELECT)) {
|
||||||
|
@ -1823,6 +1821,16 @@ struct EsListView : EsElement {
|
||||||
zOrderItems.Free();
|
zOrderItems.Free();
|
||||||
} else if (message->type == ES_MSG_GET_ACCESS_KEY_HINT_BOUNDS) {
|
} else if (message->type == ES_MSG_GET_ACCESS_KEY_HINT_BOUNDS) {
|
||||||
AccessKeysCenterHint(this, message);
|
AccessKeysCenterHint(this, message);
|
||||||
|
} else if (message->type == ES_MSG_UI_SCALE_CHANGED) {
|
||||||
|
primaryCellStyle->CloseReference();
|
||||||
|
secondaryCellStyle->CloseReference();
|
||||||
|
selectedCellStyle->CloseReference();
|
||||||
|
|
||||||
|
primaryCellStyle = GetStyle(MakeStyleKey(ES_STYLE_LIST_PRIMARY_CELL, 0), false);
|
||||||
|
secondaryCellStyle = GetStyle(MakeStyleKey(ES_STYLE_LIST_SECONDARY_CELL, 0), false);
|
||||||
|
selectedCellStyle = GetStyle(MakeStyleKey(ES_STYLE_LIST_SELECTED_CHOICE_CELL, 0), false);
|
||||||
|
|
||||||
|
EsListViewChangeStyles(this, nullptr, nullptr, nullptr, nullptr, ES_FLAGS_DEFAULT, ES_FLAGS_DEFAULT);
|
||||||
} else if (message->type == ES_MSG_LIST_VIEW_GET_CONTENT && (flags & ES_LIST_VIEW_FIXED_ITEMS)) {
|
} else if (message->type == ES_MSG_LIST_VIEW_GET_CONTENT && (flags & ES_LIST_VIEW_FIXED_ITEMS)) {
|
||||||
uintptr_t index = message->getContent.index;
|
uintptr_t index = message->getContent.index;
|
||||||
EsAssert(index < fixedItems.Length());
|
EsAssert(index < fixedItems.Length());
|
||||||
|
@ -1851,6 +1859,14 @@ int ListViewProcessItemMessage(EsElement *_element, EsMessage *message) {
|
||||||
return ((EsListView *) element->parent)->ProcessItemMessage(element->index, message, element);
|
return ((EsListView *) element->parent)->ProcessItemMessage(element->index, message, element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ListViewCalculateTotalColumnWidth(EsListView *view) {
|
||||||
|
view->totalColumnWidth = -view->secondaryCellStyle->gapMajor;
|
||||||
|
|
||||||
|
for (uintptr_t i = 0; i < view->columnCount; i++) {
|
||||||
|
view->totalColumnWidth += view->columns[i].width * theming.scale + view->secondaryCellStyle->gapMajor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EsListViewChangeStyles(EsListView *view, const EsStyle *style, const EsStyle *itemStyle,
|
void EsListViewChangeStyles(EsListView *view, const EsStyle *style, const EsStyle *itemStyle,
|
||||||
const EsStyle *headerItemStyle, const EsStyle *footerItemStyle, uint32_t addFlags, uint32_t removeFlags) {
|
const EsStyle *headerItemStyle, const EsStyle *footerItemStyle, uint32_t addFlags, uint32_t removeFlags) {
|
||||||
// TODO Animating changes.
|
// TODO Animating changes.
|
||||||
|
@ -1926,6 +1942,7 @@ void EsListViewChangeStyles(EsListView *view, const EsStyle *style, const EsStyl
|
||||||
}
|
}
|
||||||
|
|
||||||
view->scroll.Setup(view, scrollXMode, scrollYMode, SCROLL_X_DRAG | SCROLL_Y_DRAG);
|
view->scroll.Setup(view, scrollXMode, scrollYMode, SCROLL_X_DRAG | SCROLL_Y_DRAG);
|
||||||
|
ListViewCalculateTotalColumnWidth(view);
|
||||||
|
|
||||||
// Remove existing visible items; the list will need to be repopulated.
|
// Remove existing visible items; the list will need to be repopulated.
|
||||||
|
|
||||||
|
@ -2207,14 +2224,6 @@ int ListViewColumnHeaderItemMessage(EsElement *element, EsMessage *message) {
|
||||||
return ES_HANDLED;
|
return ES_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListViewCalculateTotalColumnWidth(EsListView *view) {
|
|
||||||
view->totalColumnWidth = -view->secondaryCellStyle->gapMajor;
|
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < view->columnCount; i++) {
|
|
||||||
view->totalColumnWidth += view->columns[i].width * theming.scale + view->secondaryCellStyle->gapMajor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EsListViewSetColumns(EsListView *view, EsListViewColumn *columns, size_t columnCount) {
|
void EsListViewSetColumns(EsListView *view, EsListViewColumn *columns, size_t columnCount) {
|
||||||
EsMessageMutexCheck();
|
EsMessageMutexCheck();
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ type_name uint16_t EsFontFamily;
|
||||||
type_name uint64_t EsTimer;
|
type_name uint64_t EsTimer;
|
||||||
type_name int64_t EsListViewIndex;
|
type_name int64_t EsListViewIndex;
|
||||||
type_name uint64_t EsObjectID;
|
type_name uint64_t EsObjectID;
|
||||||
|
type_name uint32_t EsDeviceColor; // TODO Make this 64-bit?
|
||||||
|
|
||||||
define ES_SCANCODE_A (0x04)
|
define ES_SCANCODE_A (0x04)
|
||||||
define ES_SCANCODE_B (0x05)
|
define ES_SCANCODE_B (0x05)
|
||||||
|
@ -334,8 +335,7 @@ define ES_SYSTEM_CONSTANT_OPTIMAL_WORK_QUEUE_THREAD_COUNT (1)
|
||||||
define ES_SYSTEM_CONSTANT_WINDOW_INSET (2)
|
define ES_SYSTEM_CONSTANT_WINDOW_INSET (2)
|
||||||
define ES_SYSTEM_CONSTANT_CONTAINER_TAB_BAND_HEIGHT (3)
|
define ES_SYSTEM_CONSTANT_CONTAINER_TAB_BAND_HEIGHT (3)
|
||||||
define ES_SYSTEM_CONSTANT_UI_SCALE (4)
|
define ES_SYSTEM_CONSTANT_UI_SCALE (4)
|
||||||
define ES_SYSTEM_CONSTANT_BORDER_THICKNESS (5)
|
define ES_SYSTEM_CONSTANT_COUNT (5)
|
||||||
define ES_SYSTEM_CONSTANT_COUNT (6)
|
|
||||||
|
|
||||||
define ES_INVALID_HANDLE ((EsHandle) (0))
|
define ES_INVALID_HANDLE ((EsHandle) (0))
|
||||||
define ES_CURRENT_THREAD ((EsHandle) (0x10))
|
define ES_CURRENT_THREAD ((EsHandle) (0x10))
|
||||||
|
@ -934,6 +934,7 @@ enum EsMessageType {
|
||||||
ES_MSG_MOUSE_RIGHT_DRAG = 0x2027 // Similar to LEFT_DRAG above, but for the right button.
|
ES_MSG_MOUSE_RIGHT_DRAG = 0x2027 // Similar to LEFT_DRAG above, but for the right button.
|
||||||
ES_MSG_MOUSE_MIDDLE_DRAG = 0x2028 // Similar to LEFT_DRAG above, but for the middle button.
|
ES_MSG_MOUSE_MIDDLE_DRAG = 0x2028 // Similar to LEFT_DRAG above, but for the middle button.
|
||||||
ES_MSG_GET_ACCESS_KEY_HINT_BOUNDS = 0x2029 // Get the bounds to display an access key hint.
|
ES_MSG_GET_ACCESS_KEY_HINT_BOUNDS = 0x2029 // Get the bounds to display an access key hint.
|
||||||
|
ES_MSG_UI_SCALE_CHANGED = 0x202A // The UI scale has changed.
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -2061,13 +2062,13 @@ function uint32_t EsColorParse(STRING string);
|
||||||
|
|
||||||
function void EsDrawBitmap(EsPainter *painter, EsRectangle region, uint32_t *bits, uintptr_t stride, uint16_t mode); // OR mode with alpha.
|
function void EsDrawBitmap(EsPainter *painter, EsRectangle region, uint32_t *bits, uintptr_t stride, uint16_t mode); // OR mode with alpha.
|
||||||
function void EsDrawBitmapScaled(EsPainter *painter, EsRectangle destinationRegion, EsRectangle sourceRegion, uint32_t *bits, uintptr_t stride, uint16_t alpha); // Set alpha to 0xFFFF if source is opaque.
|
function void EsDrawBitmapScaled(EsPainter *painter, EsRectangle destinationRegion, EsRectangle sourceRegion, uint32_t *bits, uintptr_t stride, uint16_t alpha); // Set alpha to 0xFFFF if source is opaque.
|
||||||
function void EsDrawBlock(EsPainter *painter, EsRectangle bounds, uint32_t mainColor);
|
function void EsDrawBlock(EsPainter *painter, EsRectangle bounds, EsDeviceColor mainColor);
|
||||||
function void EsDrawClear(EsPainter *painter, EsRectangle bounds);
|
function void EsDrawClear(EsPainter *painter, EsRectangle bounds);
|
||||||
function void EsDrawContent(EsPainter *painter, EsElement *element, EsRectangle rectangle, STRING text, uint32_t iconID = 0, uint32_t flags = ES_FLAGS_DEFAULT, EsTextSelection *selectionProperties = ES_NULL);
|
function void EsDrawContent(EsPainter *painter, EsElement *element, EsRectangle rectangle, STRING text, uint32_t iconID = 0, uint32_t flags = ES_FLAGS_DEFAULT, EsTextSelection *selectionProperties = ES_NULL);
|
||||||
function void EsDrawInvert(EsPainter *painter, EsRectangle bounds);
|
function void EsDrawInvert(EsPainter *painter, EsRectangle bounds);
|
||||||
function void EsDrawLine(EsPainter *painter, float *vertices, size_t vertexCount, uint32_t color, float width, uint32_t flags); // Vertices are pairs of x,y coordinates.
|
function void EsDrawLine(EsPainter *painter, float *vertices, size_t vertexCount, EsDeviceColor color, float width, uint32_t flags); // Vertices are pairs of x,y coordinates.
|
||||||
function void EsDrawRectangle(EsPainter *painter, EsRectangle bounds, uint32_t mainColor, uint32_t borderColor, EsRectangle borderSize);
|
function void EsDrawRectangle(EsPainter *painter, EsRectangle bounds, EsDeviceColor mainColor, EsDeviceColor borderColor, EsRectangle borderSize);
|
||||||
function bool EsDrawStandardIcon(EsPainter *painter, uint32_t id, int size, EsRectangle region, uint32_t color);
|
function bool EsDrawStandardIcon(EsPainter *painter, uint32_t id, int size, EsRectangle region, EsDeviceColor color);
|
||||||
function void EsDrawPaintTarget(EsPainter *painter, EsPaintTarget *source, EsRectangle destinationRegion, EsRectangle sourceRegion, uint8_t alpha);
|
function void EsDrawPaintTarget(EsPainter *painter, EsPaintTarget *source, EsRectangle destinationRegion, EsRectangle sourceRegion, uint8_t alpha);
|
||||||
function void EsDrawText(EsPainter *painter, EsTextPlan *plan, EsRectangle bounds, EsRectangle *clip = ES_NULL, EsTextSelection *selectionProperties = ES_NULL);
|
function void EsDrawText(EsPainter *painter, EsTextPlan *plan, EsRectangle bounds, EsRectangle *clip = ES_NULL, EsTextSelection *selectionProperties = ES_NULL);
|
||||||
function void EsDrawTextLayers(EsPainter *painter, EsTextPlan *plan, EsRectangle bounds, EsTextSelection *selectionProperties = ES_NULL);
|
function void EsDrawTextLayers(EsPainter *painter, EsTextPlan *plan, EsRectangle bounds, EsTextSelection *selectionProperties = ES_NULL);
|
||||||
|
@ -2088,8 +2089,7 @@ function EsPaintTarget *EsPaintTargetCreateFromBitmap(uint32_t *bits, size_t wid
|
||||||
function void EsPaintTargetGetSize(EsPaintTarget *target, size_t *width, size_t *height);
|
function void EsPaintTargetGetSize(EsPaintTarget *target, size_t *width, size_t *height);
|
||||||
function void EsPaintTargetDestroy(EsPaintTarget *target);
|
function void EsPaintTargetDestroy(EsPaintTarget *target);
|
||||||
|
|
||||||
function int EsTextGetLineHeight(const EsTextStyle *style);
|
function EsTextPlan *EsTextPlanCreate(EsElement *element, EsTextPlanProperties *properties, EsRectangle bounds, const char *string, const EsTextRun *textRuns, size_t textRunCount); // textRuns should point to an array of (textRunCount + 1) EsTextRuns; the last one should have its offset set to the total number of bytes in the string. The passed string must remain valid until the plan is destroyed. The element is used for UI scaling calculations.
|
||||||
function EsTextPlan *EsTextPlanCreate(EsTextPlanProperties *properties, EsRectangle bounds, const char *string, const EsTextRun *textRuns, size_t textRunCount); // textRuns should point to an array of (textRunCount + 1) EsTextRuns; the last one should have its offset set to the total number of bytes in the string. The passed string must remain valid until the plan is destroyed.
|
|
||||||
function int EsTextPlanGetWidth(EsTextPlan *plan); // TODO Public property?
|
function int EsTextPlanGetWidth(EsTextPlan *plan); // TODO Public property?
|
||||||
function int EsTextPlanGetHeight(EsTextPlan *plan); // TODO Public property?
|
function int EsTextPlanGetHeight(EsTextPlan *plan); // TODO Public property?
|
||||||
function size_t EsTextPlanGetLineCount(EsTextPlan *plan); // TODO Public property?
|
function size_t EsTextPlanGetLineCount(EsTextPlan *plan); // TODO Public property?
|
||||||
|
@ -2300,7 +2300,8 @@ function void EsElementRelayout(EsElement *element);
|
||||||
function void EsElementSetCellRange(EsElement *element, int xFrom, int yFrom, int xTo = -1, int yTo = -1); // Use only if the parent is a ES_PANEL_TABLE.
|
function void EsElementSetCellRange(EsElement *element, int xFrom, int yFrom, int xTo = -1, int yTo = -1); // Use only if the parent is a ES_PANEL_TABLE.
|
||||||
function EsRectangle EsElementGetInsets(EsElement *element);
|
function EsRectangle EsElementGetInsets(EsElement *element);
|
||||||
function EsRectangle EsElementGetInsetSize(EsElement *element); // Get the size of the element, minus the insets.
|
function EsRectangle EsElementGetInsetSize(EsElement *element); // Get the size of the element, minus the insets.
|
||||||
function EsThemeMetrics EsElementGetMetrics(EsElement *element);
|
function EsThemeMetrics EsElementGetMetrics(EsElement *element); // Returns the *scaled* metrics; the metrics given in the EsStyle passed to element creation functions should *not* be scaled.
|
||||||
|
function float EsElementGetScaleFactor(EsElement *element);
|
||||||
function EsRectangle EsElementGetPreferredSize(EsElement *element);
|
function EsRectangle EsElementGetPreferredSize(EsElement *element);
|
||||||
function void EsElementMove(EsElement *element, int x, int y, int width, int height, bool applyCellLayout = true); // x, y are given relative to the top-left of the parent.
|
function void EsElementMove(EsElement *element, int x, int y, int width, int height, bool applyCellLayout = true); // x, y are given relative to the top-left of the parent.
|
||||||
function EsElement *EsElementGetLayoutParent(EsElement *element);
|
function EsElement *EsElementGetLayoutParent(EsElement *element);
|
||||||
|
@ -2371,8 +2372,8 @@ function void EsTextboxUseBreadcrumbOverlay(EsTextbox *textbox);
|
||||||
function void EsTextboxMoveCaretRelative(EsTextbox *textbox, uint32_t flags);
|
function void EsTextboxMoveCaretRelative(EsTextbox *textbox, uint32_t flags);
|
||||||
function void EsTextboxEnsureCaretVisible(EsTextbox *textbox, bool verticallyCenter = false);
|
function void EsTextboxEnsureCaretVisible(EsTextbox *textbox, bool verticallyCenter = false);
|
||||||
function void EsTextboxSetUndoManager(EsTextbox *textbox, EsUndoManager *manager);
|
function void EsTextboxSetUndoManager(EsTextbox *textbox, EsUndoManager *manager);
|
||||||
function void EsTextboxGetTextStyle(EsTextbox *textbox, EsTextStyle *textStyle);
|
function void EsTextboxSetTextSize(EsTextbox *textbox, uint16_t size);
|
||||||
function void EsTextboxSetTextStyle(EsTextbox *textbox, const EsTextStyle *textStyle);
|
function void EsTextboxSetFont(EsTextbox *textbox, EsFont font);
|
||||||
function void EsTextboxSetupSyntaxHighlighting(EsTextbox *textbox, uint32_t language, uint32_t *customColors = ES_NULL, size_t customColorCount = 0);
|
function void EsTextboxSetupSyntaxHighlighting(EsTextbox *textbox, uint32_t language, uint32_t *customColors = ES_NULL, size_t customColorCount = 0);
|
||||||
function void EsTextboxStartEdit(EsTextbox *textbox);
|
function void EsTextboxStartEdit(EsTextbox *textbox);
|
||||||
|
|
||||||
|
|
|
@ -200,7 +200,7 @@ void RastSurfaceFill(RastSurface surface, RastShape shape, RastPaint paint, bool
|
||||||
if (paint.type == RAST_PAINT_LINEAR_GRADIENT
|
if (paint.type == RAST_PAINT_LINEAR_GRADIENT
|
||||||
|| paint.type == RAST_PAINT_RADIAL_GRADIENT
|
|| paint.type == RAST_PAINT_RADIAL_GRADIENT
|
||||||
|| paint.type == RAST_PAINT_ANGULAR_GRADIENT) {
|
|| paint.type == RAST_PAINT_ANGULAR_GRADIENT) {
|
||||||
if (!paint.gradient.color) {
|
if (!paint.gradient.color || !paint.gradient.alpha) {
|
||||||
_RastShapeDestroy(shape);
|
_RastShapeDestroy(shape);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -867,6 +867,10 @@ void RastGradientInitialise(RastPaint *paint, RastGradientStop *stops, size_t st
|
||||||
|
|
||||||
paint->gradient.color = (uint32_t *) EsHeapAllocate(4 * RAST_GRADIENT_COLORS, false);
|
paint->gradient.color = (uint32_t *) EsHeapAllocate(4 * RAST_GRADIENT_COLORS, false);
|
||||||
paint->gradient.alpha = (float *) EsHeapAllocate(sizeof(float) * RAST_GRADIENT_COLORS, false);
|
paint->gradient.alpha = (float *) EsHeapAllocate(sizeof(float) * RAST_GRADIENT_COLORS, false);
|
||||||
|
|
||||||
|
if (!paint->gradient.color || !paint->gradient.alpha) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (uintptr_t stop = 0; stop < stopCount - 1; stop++) {
|
for (uintptr_t stop = 0; stop < stopCount - 1; stop++) {
|
||||||
float fa = ((stops[stop + 0].color >> 24) & 0xFF) / 255.0f;
|
float fa = ((stops[stop + 0].color >> 24) & 0xFF) / 255.0f;
|
||||||
|
|
|
@ -22,7 +22,7 @@ struct SettingsControl {
|
||||||
int32_t originalValueInt;
|
int32_t originalValueInt;
|
||||||
int32_t minimumValue, maximumValue;
|
int32_t minimumValue, maximumValue;
|
||||||
uint32_t steps;
|
uint32_t steps;
|
||||||
double dragSpeed, dragValue;
|
double dragSpeed, dragValue, discreteStep;
|
||||||
const char *suffix;
|
const char *suffix;
|
||||||
size_t suffixBytes;
|
size_t suffixBytes;
|
||||||
const char *cConfigurationSection;
|
const char *cConfigurationSection;
|
||||||
|
@ -125,6 +125,31 @@ void SettingsUpdateGlobalAndWindowManager() {
|
||||||
api.global->swapLeftAndRightButtons = EsSystemConfigurationReadInteger(EsLiteral("general"), EsLiteral("swap_left_and_right_buttons"));
|
api.global->swapLeftAndRightButtons = EsSystemConfigurationReadInteger(EsLiteral("general"), EsLiteral("swap_left_and_right_buttons"));
|
||||||
api.global->showCursorShadow = EsSystemConfigurationReadInteger(EsLiteral("general"), EsLiteral("show_cursor_shadow"));
|
api.global->showCursorShadow = EsSystemConfigurationReadInteger(EsLiteral("general"), EsLiteral("show_cursor_shadow"));
|
||||||
|
|
||||||
|
{
|
||||||
|
float newUIScale = EsSystemConfigurationReadInteger(EsLiteral("general"), EsLiteral("ui_scale")) * 0.01f;
|
||||||
|
bool changed = api.global->uiScale != newUIScale && api.global->uiScale;
|
||||||
|
api.global->uiScale = newUIScale;
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
EsMessage m;
|
||||||
|
EsMemoryZero(&m, sizeof(EsMessage));
|
||||||
|
m.type = ES_MSG_UI_SCALE_CHANGED;
|
||||||
|
|
||||||
|
for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) {
|
||||||
|
ApplicationInstance *instance = desktop.allApplicationInstances[i];
|
||||||
|
|
||||||
|
if (instance->processHandle && !instance->application->notified) {
|
||||||
|
EsMessagePostRemote(instance->processHandle, &m);
|
||||||
|
if (instance->application->useSingleProcess) instance->application->notified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) {
|
||||||
|
desktop.installedApplications[i]->notified = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t cursorProperties = 0;
|
uint32_t cursorProperties = 0;
|
||||||
if (EsSystemConfigurationReadInteger(EsLiteral("general"), EsLiteral("use_cursor_acceleration"))) cursorProperties |= CURSOR_USE_ACCELERATION;
|
if (EsSystemConfigurationReadInteger(EsLiteral("general"), EsLiteral("use_cursor_acceleration"))) cursorProperties |= CURSOR_USE_ACCELERATION;
|
||||||
if (EsSystemConfigurationReadInteger(EsLiteral("general"), EsLiteral("use_cursor_alt_slow"))) cursorProperties |= CURSOR_USE_ALT_SLOW;
|
if (EsSystemConfigurationReadInteger(EsLiteral("general"), EsLiteral("use_cursor_alt_slow"))) cursorProperties |= CURSOR_USE_ALT_SLOW;
|
||||||
|
@ -148,11 +173,13 @@ void SettingsBackButton(EsInstance *_instance, EsElement *, EsCommand *) {
|
||||||
ConfigurationWriteToFile();
|
ConfigurationWriteToFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsNumberBoxSetValue(EsElement *element, int32_t newValue) {
|
void SettingsNumberBoxSetValue(EsElement *element, double newValueDouble) {
|
||||||
EsTextbox *textbox = (EsTextbox *) element;
|
EsTextbox *textbox = (EsTextbox *) element;
|
||||||
SettingsInstance *instance = (SettingsInstance *) textbox->instance;
|
SettingsInstance *instance = (SettingsInstance *) textbox->instance;
|
||||||
SettingsControl *control = (SettingsControl *) textbox->userData.p;
|
SettingsControl *control = (SettingsControl *) textbox->userData.p;
|
||||||
|
|
||||||
|
int32_t newValue = (int32_t) (newValueDouble / control->discreteStep + 0.5) * control->discreteStep;
|
||||||
|
|
||||||
newValue = ClampInteger(control->minimumValue, control->maximumValue, newValue);
|
newValue = ClampInteger(control->minimumValue, control->maximumValue, newValue);
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
size_t bytes = EsStringFormat(buffer, sizeof(buffer), "%i%s", newValue, control->suffixBytes, control->suffix);
|
size_t bytes = EsStringFormat(buffer, sizeof(buffer), "%i%s", newValue, control->suffixBytes, control->suffix);
|
||||||
|
@ -258,12 +285,20 @@ int SettingsNumberBoxMessage(EsElement *element, EsMessage *message) {
|
||||||
SettingsControl *control = (SettingsControl *) textbox->userData.p;
|
SettingsControl *control = (SettingsControl *) textbox->userData.p;
|
||||||
|
|
||||||
if (message->type == ES_MSG_TEXTBOX_EDIT_END || message->type == ES_MSG_TEXTBOX_NUMBER_DRAG_END) {
|
if (message->type == ES_MSG_TEXTBOX_EDIT_END || message->type == ES_MSG_TEXTBOX_NUMBER_DRAG_END) {
|
||||||
char *expression = EsTextboxGetContents(textbox);
|
size_t bytes;
|
||||||
|
char *expression = EsTextboxGetContents(textbox, &bytes);
|
||||||
|
|
||||||
|
if (control->suffixBytes && bytes > control->suffixBytes && 0 == EsMemoryCompare(control->suffix,
|
||||||
|
expression + bytes - control->suffixBytes, control->suffixBytes)) {
|
||||||
|
// Trim the suffix.
|
||||||
|
expression[bytes - control->suffixBytes] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
EsCalculationValue value = EsCalculateFromUserExpression(expression);
|
EsCalculationValue value = EsCalculateFromUserExpression(expression);
|
||||||
EsHeapFree(expression);
|
EsHeapFree(expression);
|
||||||
|
|
||||||
if (!value.error) {
|
if (!value.error) {
|
||||||
SettingsNumberBoxSetValue(element, value.number + 0.5);
|
SettingsNumberBoxSetValue(element, value.number);
|
||||||
return ES_HANDLED;
|
return ES_HANDLED;
|
||||||
} else {
|
} else {
|
||||||
return ES_REJECTED;
|
return ES_REJECTED;
|
||||||
|
@ -286,7 +321,7 @@ int SettingsNumberBoxMessage(EsElement *element, EsMessage *message) {
|
||||||
|
|
||||||
void SettingsAddNumberBox(EsElement *table, const char *string, ptrdiff_t stringBytes, char accessKey,
|
void SettingsAddNumberBox(EsElement *table, const char *string, ptrdiff_t stringBytes, char accessKey,
|
||||||
const char *cConfigurationSection, const char *cConfigurationKey,
|
const char *cConfigurationSection, const char *cConfigurationKey,
|
||||||
int32_t minimumValue, int32_t maximumValue, const char *suffix, ptrdiff_t suffixBytes, double dragSpeed) {
|
int32_t minimumValue, int32_t maximumValue, const char *suffix, ptrdiff_t suffixBytes, double dragSpeed, double discreteStep) {
|
||||||
if (suffixBytes == -1) {
|
if (suffixBytes == -1) {
|
||||||
suffixBytes = EsCStringLength(suffix);
|
suffixBytes = EsCStringLength(suffix);
|
||||||
}
|
}
|
||||||
|
@ -303,6 +338,7 @@ void SettingsAddNumberBox(EsElement *table, const char *string, ptrdiff_t string
|
||||||
control->minimumValue = minimumValue;
|
control->minimumValue = minimumValue;
|
||||||
control->maximumValue = maximumValue;
|
control->maximumValue = maximumValue;
|
||||||
control->dragSpeed = dragSpeed;
|
control->dragSpeed = dragSpeed;
|
||||||
|
control->discreteStep = discreteStep;
|
||||||
|
|
||||||
EsTextDisplayCreate(table, ES_CELL_H_RIGHT | ES_CELL_H_PUSH, 0, string, stringBytes);
|
EsTextDisplayCreate(table, ES_CELL_H_RIGHT | ES_CELL_H_PUSH, 0, string, stringBytes);
|
||||||
EsTextbox *textbox = EsTextboxCreate(table, ES_CELL_H_LEFT | ES_CELL_H_PUSH | ES_TEXTBOX_EDIT_BASED | ES_ELEMENT_FREE_USER_DATA, &styleSettingsNumberTextbox);
|
EsTextbox *textbox = EsTextboxCreate(table, ES_CELL_H_LEFT | ES_CELL_H_PUSH | ES_TEXTBOX_EDIT_BASED | ES_ELEMENT_FREE_USER_DATA, &styleSettingsNumberTextbox);
|
||||||
|
@ -413,7 +449,7 @@ void SettingsPageMouse(EsElement *element, SettingsPage *page) {
|
||||||
EsPanelSetBands(table, 2);
|
EsPanelSetBands(table, 2);
|
||||||
|
|
||||||
SettingsAddNumberBox(table, INTERFACE_STRING(DesktopSettingsMouseLinesPerScrollNotch), 'S', "general", "scroll_lines_per_notch",
|
SettingsAddNumberBox(table, INTERFACE_STRING(DesktopSettingsMouseLinesPerScrollNotch), 'S', "general", "scroll_lines_per_notch",
|
||||||
1, 100, nullptr, 0, 0.04);
|
1, 100, nullptr, 0, 0.04, 1);
|
||||||
|
|
||||||
table = EsPanelCreate(container, ES_CELL_H_FILL, &styleSettingsCheckboxGroup);
|
table = EsPanelCreate(container, ES_CELL_H_FILL, &styleSettingsCheckboxGroup);
|
||||||
SettingsAddCheckbox(table, INTERFACE_STRING(DesktopSettingsMouseSwapLeftAndRightButtons), 'B', "general", "swap_left_and_right_buttons");
|
SettingsAddCheckbox(table, INTERFACE_STRING(DesktopSettingsMouseSwapLeftAndRightButtons), 'B', "general", "swap_left_and_right_buttons");
|
||||||
|
@ -426,7 +462,7 @@ void SettingsPageMouse(EsElement *element, SettingsPage *page) {
|
||||||
EsPanelSetBands(table, 2);
|
EsPanelSetBands(table, 2);
|
||||||
|
|
||||||
SettingsAddNumberBox(table, INTERFACE_STRING(DesktopSettingsMouseDoubleClickSpeed), 'D', "general", "click_chain_timeout_ms",
|
SettingsAddNumberBox(table, INTERFACE_STRING(DesktopSettingsMouseDoubleClickSpeed), 'D', "general", "click_chain_timeout_ms",
|
||||||
100, 1500, INTERFACE_STRING(CommonUnitMilliseconds), 1.0);
|
100, 1500, INTERFACE_STRING(CommonUnitMilliseconds), 1.0, 1);
|
||||||
|
|
||||||
EsPanel *testBox = EsPanelCreate(container, ES_CELL_H_FILL);
|
EsPanel *testBox = EsPanelCreate(container, ES_CELL_H_FILL);
|
||||||
EsTextDisplayCreate(testBox, ES_CELL_H_FILL, ES_STYLE_TEXT_PARAGRAPH, INTERFACE_STRING(DesktopSettingsMouseTestDoubleClickIntroduction));
|
EsTextDisplayCreate(testBox, ES_CELL_H_FILL, ES_STYLE_TEXT_PARAGRAPH, INTERFACE_STRING(DesktopSettingsMouseTestDoubleClickIntroduction));
|
||||||
|
@ -474,10 +510,27 @@ void SettingsPageKeyboard(EsElement *element, SettingsPage *page) {
|
||||||
EsTextboxCreate(testBox, ES_CELL_H_LEFT)->accessKey = 'T';
|
EsTextboxCreate(testBox, ES_CELL_H_LEFT)->accessKey = 'T';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsPageDisplay(EsElement *element, SettingsPage *page) {
|
||||||
|
EsElementSetHidden(((SettingsInstance *) element->instance)->undoButton, false);
|
||||||
|
|
||||||
|
EsPanel *content = EsPanelCreate(element, ES_CELL_FILL | ES_PANEL_V_SCROLL_AUTO, &styleNewTabContent);
|
||||||
|
EsPanel *container = EsPanelCreate(content, ES_PANEL_VERTICAL | ES_CELL_H_SHRINK, &styleSettingsGroupContainer2);
|
||||||
|
SettingsAddTitle(container, page);
|
||||||
|
|
||||||
|
EsPanel *warningRow = EsPanelCreate(container, ES_CELL_H_CENTER | ES_PANEL_HORIZONTAL, &styleSettingsTable);
|
||||||
|
EsIconDisplayCreate(warningRow, ES_FLAGS_DEFAULT, 0, ES_ICON_DIALOG_WARNING);
|
||||||
|
EsTextDisplayCreate(warningRow, ES_FLAGS_DEFAULT, 0, "Work in progress" ELLIPSIS);
|
||||||
|
|
||||||
|
EsPanel *table = EsPanelCreate(container, ES_CELL_H_FILL | ES_PANEL_TABLE | ES_PANEL_HORIZONTAL, &styleSettingsTable);
|
||||||
|
EsPanelSetBands(table, 2);
|
||||||
|
SettingsAddNumberBox(table, INTERFACE_STRING(DesktopSettingsDisplayUIScale), 'S', "general", "ui_scale",
|
||||||
|
100, 400, INTERFACE_STRING(CommonUnitPercent), 0.05, 5);
|
||||||
|
}
|
||||||
|
|
||||||
SettingsPage settingsPages[] = {
|
SettingsPage settingsPages[] = {
|
||||||
{ INTERFACE_STRING(DesktopSettingsAccessibility), ES_ICON_PREFERENCES_DESKTOP_ACCESSIBILITY, SettingsPageUnimplemented, 'A' }, // TODO.
|
{ INTERFACE_STRING(DesktopSettingsAccessibility), ES_ICON_PREFERENCES_DESKTOP_ACCESSIBILITY, SettingsPageUnimplemented, 'A' }, // TODO.
|
||||||
{ INTERFACE_STRING(DesktopSettingsDateAndTime), ES_ICON_PREFERENCES_SYSTEM_TIME, SettingsPageUnimplemented, 'C' }, // TODO.
|
{ INTERFACE_STRING(DesktopSettingsDateAndTime), ES_ICON_PREFERENCES_SYSTEM_TIME, SettingsPageUnimplemented, 'C' }, // TODO.
|
||||||
{ INTERFACE_STRING(DesktopSettingsDisplay), ES_ICON_PREFERENCES_DESKTOP_DISPLAY, SettingsPageUnimplemented, 'D' }, // TODO.
|
{ INTERFACE_STRING(DesktopSettingsDisplay), ES_ICON_PREFERENCES_DESKTOP_DISPLAY, SettingsPageDisplay, 'D' },
|
||||||
{ INTERFACE_STRING(DesktopSettingsKeyboard), ES_ICON_INPUT_KEYBOARD, SettingsPageKeyboard, 'E' },
|
{ INTERFACE_STRING(DesktopSettingsKeyboard), ES_ICON_INPUT_KEYBOARD, SettingsPageKeyboard, 'E' },
|
||||||
{ INTERFACE_STRING(DesktopSettingsLocalisation), ES_ICON_PREFERENCES_DESKTOP_LOCALE, SettingsPageUnimplemented, 'F' }, // TODO.
|
{ INTERFACE_STRING(DesktopSettingsLocalisation), ES_ICON_PREFERENCES_DESKTOP_LOCALE, SettingsPageUnimplemented, 'F' }, // TODO.
|
||||||
{ INTERFACE_STRING(DesktopSettingsMouse), ES_ICON_INPUT_MOUSE, SettingsPageMouse, 'G' },
|
{ INTERFACE_STRING(DesktopSettingsMouse), ES_ICON_INPUT_MOUSE, SettingsPageMouse, 'G' },
|
||||||
|
|
|
@ -467,9 +467,18 @@ ptrdiff_t EsDirectoryEnumerateChildren(const char *path, ptrdiff_t pathBytes, Es
|
||||||
}
|
}
|
||||||
|
|
||||||
*buffer = (EsDirectoryChild *) EsHeapAllocate(sizeof(EsDirectoryChild) * node.directoryChildren, true);
|
*buffer = (EsDirectoryChild *) EsHeapAllocate(sizeof(EsDirectoryChild) * node.directoryChildren, true);
|
||||||
|
ptrdiff_t result;
|
||||||
|
|
||||||
ptrdiff_t result = EsDirectoryEnumerateChildrenFromHandle(node.handle, *buffer, node.directoryChildren);
|
if (*buffer) {
|
||||||
if (ES_CHECK_ERROR(result)) { EsHeapFree(*buffer); *buffer = nullptr; }
|
result = EsDirectoryEnumerateChildrenFromHandle(node.handle, *buffer, node.directoryChildren);
|
||||||
|
|
||||||
|
if (ES_CHECK_ERROR(result)) {
|
||||||
|
EsHeapFree(*buffer);
|
||||||
|
*buffer = nullptr;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = ES_ERROR_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
EsHandleClose(node.handle);
|
EsHandleClose(node.handle);
|
||||||
return result;
|
return result;
|
||||||
|
|
212
desktop/text.cpp
212
desktop/text.cpp
|
@ -283,10 +283,11 @@ int32_t FontGetEmWidth(Font *font) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int EsTextGetLineHeight(const EsTextStyle *textStyle) {
|
int TextGetLineHeight(EsElement *element, const EsTextStyle *textStyle) {
|
||||||
|
EsAssert(element);
|
||||||
EsMessageMutexCheck();
|
EsMessageMutexCheck();
|
||||||
Font font = FontGet(textStyle->font);
|
Font font = FontGet(textStyle->font);
|
||||||
FontSetSize(&font, textStyle->size);
|
FontSetSize(&font, textStyle->size * theming.scale);
|
||||||
return (FontGetAscent(&font) - FontGetDescent(&font) + FREETYPE_UNIT_SCALE / 2) / FREETYPE_UNIT_SCALE;
|
return (FontGetAscent(&font) - FontGetDescent(&font) + FREETYPE_UNIT_SCALE / 2) / FREETYPE_UNIT_SCALE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1123,6 +1124,8 @@ IconPackImage *IconPackReadImage(uint32_t id, uint32_t size, int *type) {
|
||||||
bool found = false;
|
bool found = false;
|
||||||
uint32_t variant = 0;
|
uint32_t variant = 0;
|
||||||
|
|
||||||
|
// TODO Clean this up!
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// Look for a perfect match of size and direction.
|
// Look for a perfect match of size and direction.
|
||||||
variant = EsBufferReadInt(&iconManagement.pack);
|
variant = EsBufferReadInt(&iconManagement.pack);
|
||||||
|
@ -1171,13 +1174,18 @@ IconPackImage *IconPackReadImage(uint32_t id, uint32_t size, int *type) {
|
||||||
uintptr_t previous = 0;
|
uintptr_t previous = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!EsBufferReadInt(&iconManagement.pack) && previous) {
|
variant = EsBufferReadInt(&iconManagement.pack);
|
||||||
|
|
||||||
|
if (!variant) {
|
||||||
iconManagement.pack.position = previous;
|
iconManagement.pack.position = previous;
|
||||||
found = true;
|
found = previous != 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
previous = iconManagement.pack.position;
|
if ((~variant & 0x8000) || rtl) {
|
||||||
|
previous = iconManagement.pack.position;
|
||||||
|
}
|
||||||
|
|
||||||
iconManagement.pack.position = EsBufferReadInt(&iconManagement.pack);
|
iconManagement.pack.position = EsBufferReadInt(&iconManagement.pack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1342,16 +1350,33 @@ bool EsDrawStandardIcon(EsPainter *painter, uint32_t id, int size, EsRectangle r
|
||||||
|
|
||||||
GlyphCacheEntry *cacheEntry = LookupGlyphCacheEntry(key);
|
GlyphCacheEntry *cacheEntry = LookupGlyphCacheEntry(key);
|
||||||
|
|
||||||
|
if (!cacheEntry) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!cacheEntry->data) {
|
if (!cacheEntry->data) {
|
||||||
|
if (!iconManagement.standardPack) {
|
||||||
|
iconManagement.standardPack = (const uint8_t *) EsEmbeddedFileGet(EsLiteral("$Desktop/Icons.dat"), &iconManagement.standardPackSize);
|
||||||
|
}
|
||||||
|
|
||||||
iconManagement.buffer = (char *) EsHeapAllocate((iconManagement.bufferAllocated = 131072), false);
|
iconManagement.buffer = (char *) EsHeapAllocate((iconManagement.bufferAllocated = 131072), false);
|
||||||
if (!iconManagement.buffer) return false;
|
if (!iconManagement.buffer) return false;
|
||||||
iconManagement.pack = { .in = iconManagement.standardPack, .bytes = iconManagement.standardPackSize };
|
iconManagement.pack = { .in = iconManagement.standardPack, .bytes = iconManagement.standardPackSize };
|
||||||
cacheEntry->width = size, cacheEntry->height = size;
|
cacheEntry->width = size, cacheEntry->height = size;
|
||||||
cacheEntry->dataBytes = size * size * 4;
|
cacheEntry->dataBytes = size * size * 4;
|
||||||
cacheEntry->data = (uint8_t *) EsHeapAllocate(cacheEntry->dataBytes, true);
|
cacheEntry->data = (uint8_t *) EsHeapAllocate(cacheEntry->dataBytes, true);
|
||||||
RegisterGlyphCacheEntry(key, cacheEntry);
|
|
||||||
IconPackImage *image = IconPackReadImage(id, size, &cacheEntry->type);
|
if (cacheEntry->data) {
|
||||||
if (image) DrawIcon(size, size, cacheEntry->data, image, size * 4, 0, 0, (float) size / image->width, (float) size / image->height);
|
RegisterGlyphCacheEntry(key, cacheEntry);
|
||||||
|
IconPackImage *image = IconPackReadImage(id, size, &cacheEntry->type);
|
||||||
|
|
||||||
|
if (image) {
|
||||||
|
DrawIcon(size, size, cacheEntry->data, image, size * 4, 0, 0, (float) size / image->width, (float) size / image->height);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
EsHeapFree(cacheEntry);
|
||||||
|
}
|
||||||
|
|
||||||
EsHeapFree(iconManagement.buffer);
|
EsHeapFree(iconManagement.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1368,6 +1393,10 @@ void EsDrawVectorFile(EsPainter *painter, EsRectangle bounds, const void *data,
|
||||||
iconManagement.buffer = (char *) EsHeapAllocate((iconManagement.bufferAllocated = 131072), false);
|
iconManagement.buffer = (char *) EsHeapAllocate((iconManagement.bufferAllocated = 131072), false);
|
||||||
iconManagement.pack = { .in = (const uint8_t *) data, .bytes = dataBytes };
|
iconManagement.pack = { .in = (const uint8_t *) data, .bytes = dataBytes };
|
||||||
|
|
||||||
|
if (!iconManagement.buffer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
IconPackImage *image = (IconPackImage *) IconBufferAllocate(sizeof(IconPackImage));
|
IconPackImage *image = (IconPackImage *) IconBufferAllocate(sizeof(IconPackImage));
|
||||||
image->width = EsBufferReadFloat(&iconManagement.pack);
|
image->width = EsBufferReadFloat(&iconManagement.pack);
|
||||||
image->height = EsBufferReadFloat(&iconManagement.pack);
|
image->height = EsBufferReadFloat(&iconManagement.pack);
|
||||||
|
@ -1562,14 +1591,14 @@ TextStyleDifference CompareTextStyles(const EsTextStyle *style1, const EsTextSty
|
||||||
return TEXT_STYLE_IDENTICAL;
|
return TEXT_STYLE_IDENTICAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptrdiff_t TextGetCharacterAtPoint(const EsTextStyle *textStyle, const char *string, size_t stringBytes, int *_pointX, uint32_t flags) {
|
ptrdiff_t TextGetCharacterAtPoint(EsElement *element, const EsTextStyle *textStyle, const char *string, size_t stringBytes, int *_pointX, uint32_t flags) {
|
||||||
// TODO Better integration with the EsTextPlan API.
|
// TODO Better integration with the EsTextPlan API.
|
||||||
|
|
||||||
EsTextPlanProperties properties = {};
|
EsTextPlanProperties properties = {};
|
||||||
EsTextRun textRuns[2] = {};
|
EsTextRun textRuns[2] = {};
|
||||||
textRuns[0].style = *textStyle;
|
textRuns[0].style = *textStyle;
|
||||||
textRuns[1].offset = stringBytes;
|
textRuns[1].offset = stringBytes;
|
||||||
EsTextPlan *plan = EsTextPlanCreate(&properties, {}, string, textRuns, 1);
|
EsTextPlan *plan = EsTextPlanCreate(element, &properties, {}, string, textRuns, 1);
|
||||||
if (!plan) return 0;
|
if (!plan) return 0;
|
||||||
|
|
||||||
EsAssert(plan->lines.Length() == 1);
|
EsAssert(plan->lines.Length() == 1);
|
||||||
|
@ -1605,7 +1634,7 @@ ptrdiff_t TextGetCharacterAtPoint(const EsTextStyle *textStyle, const char *stri
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TextGetPartialStringWidth(const EsTextStyle *textStyle, const char *fullString, size_t fullStringBytes, size_t measureBytes) {
|
int TextGetPartialStringWidth(EsElement *element, const EsTextStyle *textStyle, const char *fullString, size_t fullStringBytes, size_t measureBytes) {
|
||||||
// TODO Better integration with the EsTextPlan API.
|
// TODO Better integration with the EsTextPlan API.
|
||||||
|
|
||||||
EsTextPlanProperties properties = {};
|
EsTextPlanProperties properties = {};
|
||||||
|
@ -1614,7 +1643,7 @@ int TextGetPartialStringWidth(const EsTextStyle *textStyle, const char *fullStri
|
||||||
textRuns[1].style = *textStyle;
|
textRuns[1].style = *textStyle;
|
||||||
textRuns[1].offset = measureBytes;
|
textRuns[1].offset = measureBytes;
|
||||||
textRuns[2].offset = fullStringBytes;
|
textRuns[2].offset = fullStringBytes;
|
||||||
EsTextPlan *plan = EsTextPlanCreate(&properties, {}, fullString, textRuns, 2);
|
EsTextPlan *plan = EsTextPlanCreate(element, &properties, {}, fullString, textRuns, 2);
|
||||||
if (!plan) return 0;
|
if (!plan) return 0;
|
||||||
|
|
||||||
int width = 0;
|
int width = 0;
|
||||||
|
@ -1632,8 +1661,8 @@ int TextGetPartialStringWidth(const EsTextStyle *textStyle, const char *fullStri
|
||||||
return width / FREETYPE_UNIT_SCALE;
|
return width / FREETYPE_UNIT_SCALE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TextGetStringWidth(const EsTextStyle *textStyle, const char *string, size_t stringBytes) {
|
int TextGetStringWidth(EsElement *element, const EsTextStyle *textStyle, const char *string, size_t stringBytes) {
|
||||||
return TextGetPartialStringWidth(textStyle, string, stringBytes, stringBytes);
|
return TextGetPartialStringWidth(element, textStyle, string, stringBytes, stringBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextTrimSpaces(EsTextPlan *plan) {
|
void TextTrimSpaces(EsTextPlan *plan) {
|
||||||
|
@ -1834,7 +1863,7 @@ void TextAddEllipsis(EsTextPlan *plan, int32_t maximumLineWidth, bool needFinalE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextItemizeByScript(EsTextPlan *plan, const EsTextRun *runs, size_t runCount) {
|
void TextItemizeByScript(EsTextPlan *plan, const EsTextRun *runs, size_t runCount, float sizeScaleFactor) {
|
||||||
hb_unicode_funcs_t *unicodeFunctions = hb_unicode_funcs_get_default();
|
hb_unicode_funcs_t *unicodeFunctions = hb_unicode_funcs_get_default();
|
||||||
uint32_t lastAssignedScript = FALLBACK_SCRIPT;
|
uint32_t lastAssignedScript = FALLBACK_SCRIPT;
|
||||||
|
|
||||||
|
@ -1863,6 +1892,7 @@ void TextItemizeByScript(EsTextPlan *plan, const EsTextRun *runs, size_t runCoun
|
||||||
run.offset = offset;
|
run.offset = offset;
|
||||||
run.script = lastAssignedScript;
|
run.script = lastAssignedScript;
|
||||||
run.style.font.family = FontApplySubstitution(&plan->properties, run.style.font.family, run.script);
|
run.style.font.family = FontApplySubstitution(&plan->properties, run.style.font.family, run.script);
|
||||||
|
run.style.size *= sizeScaleFactor;
|
||||||
plan->textRuns.Add(run);
|
plan->textRuns.Add(run);
|
||||||
offset = j;
|
offset = j;
|
||||||
}
|
}
|
||||||
|
@ -1876,6 +1906,7 @@ void TextItemizeByScript(EsTextPlan *plan, const EsTextRun *runs, size_t runCoun
|
||||||
run.offset = offset;
|
run.offset = offset;
|
||||||
run.script = lastAssignedScript;
|
run.script = lastAssignedScript;
|
||||||
run.style.font.family = FontApplySubstitution(&plan->properties, run.style.font.family, run.script);
|
run.style.font.family = FontApplySubstitution(&plan->properties, run.style.font.family, run.script);
|
||||||
|
run.style.size *= sizeScaleFactor;
|
||||||
plan->textRuns.Add(run);
|
plan->textRuns.Add(run);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2045,7 +2076,15 @@ int32_t TextBuildTextPieces(EsTextPlan *plan, uintptr_t sectionStart, uintptr_t
|
||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
EsTextPlan *EsTextPlanCreate(EsTextPlanProperties *properties, EsRectangle bounds, const char *string, const EsTextRun *formatRuns, size_t formatRunCount) {
|
void TextPlanDestroy(EsTextPlan *plan) {
|
||||||
|
plan->glyphInfos.Free();
|
||||||
|
plan->glyphPositions.Free();
|
||||||
|
plan->pieces.Free();
|
||||||
|
plan->lines.Free();
|
||||||
|
plan->textRuns.Free();
|
||||||
|
}
|
||||||
|
|
||||||
|
EsTextPlan *EsTextPlanCreate(EsElement *element, EsTextPlanProperties *properties, EsRectangle bounds, const char *string, const EsTextRun *formatRuns, size_t formatRunCount) {
|
||||||
// TODO Bidirectional text (UAX9).
|
// TODO Bidirectional text (UAX9).
|
||||||
// TODO Vertical text layout (UAX50).
|
// TODO Vertical text layout (UAX50).
|
||||||
// TODO Supporting arbitrary OpenType features.
|
// TODO Supporting arbitrary OpenType features.
|
||||||
|
@ -2054,6 +2093,8 @@ EsTextPlan *EsTextPlanCreate(EsTextPlanProperties *properties, EsRectangle bound
|
||||||
// EsPrint("EsTextPlanCreate... width %d\n", Width(bounds) * FREETYPE_UNIT_SCALE);
|
// EsPrint("EsTextPlanCreate... width %d\n", Width(bounds) * FREETYPE_UNIT_SCALE);
|
||||||
|
|
||||||
EsMessageMutexCheck();
|
EsMessageMutexCheck();
|
||||||
|
EsAssert(element);
|
||||||
|
float scale = theming.scale; // TODO Get the scale factor from the element's window.
|
||||||
|
|
||||||
EsTextPlan plan = {};
|
EsTextPlan plan = {};
|
||||||
|
|
||||||
|
@ -2088,8 +2129,9 @@ EsTextPlan *EsTextPlanCreate(EsTextPlanProperties *properties, EsRectangle bound
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Subdivide the runs by character script.
|
// Subdivide the runs by character script.
|
||||||
|
// This is also responsible for scaling the text sizes.
|
||||||
|
|
||||||
TextItemizeByScript(&plan, formatRuns, formatRunCount);
|
TextItemizeByScript(&plan, formatRuns, formatRunCount, scale);
|
||||||
|
|
||||||
// Layout the paragraph.
|
// Layout the paragraph.
|
||||||
|
|
||||||
|
@ -2197,18 +2239,20 @@ EsTextPlan *EsTextPlanCreate(EsTextPlanProperties *properties, EsRectangle bound
|
||||||
// Return the plan.
|
// Return the plan.
|
||||||
|
|
||||||
EsTextPlan *copy = (EsTextPlan *) EsHeapAllocate(sizeof(EsTextPlan), true);
|
EsTextPlan *copy = (EsTextPlan *) EsHeapAllocate(sizeof(EsTextPlan), true);
|
||||||
*copy = plan;
|
|
||||||
return copy;
|
if (copy) {
|
||||||
|
*copy = plan;
|
||||||
|
return copy;
|
||||||
|
} else {
|
||||||
|
TextPlanDestroy(&plan);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EsTextPlanDestroy(EsTextPlan *plan) {
|
void EsTextPlanDestroy(EsTextPlan *plan) {
|
||||||
EsMessageMutexCheck();
|
EsMessageMutexCheck();
|
||||||
EsAssert(!plan->singleUse);
|
EsAssert(!plan->singleUse);
|
||||||
plan->glyphInfos.Free();
|
TextPlanDestroy(plan);
|
||||||
plan->glyphPositions.Free();
|
|
||||||
plan->pieces.Free();
|
|
||||||
plan->lines.Free();
|
|
||||||
plan->textRuns.Free();
|
|
||||||
EsHeapFree(plan);
|
EsHeapFree(plan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2337,6 +2381,10 @@ void DrawTextPiece(EsPainter *painter, EsTextPlan *plan, TextPiece *piece, TextL
|
||||||
|
|
||||||
entry = LookupGlyphCacheEntry(key);
|
entry = LookupGlyphCacheEntry(key);
|
||||||
|
|
||||||
|
if (!entry) {
|
||||||
|
goto nextCharacter;
|
||||||
|
}
|
||||||
|
|
||||||
if (!entry->data) {
|
if (!entry->data) {
|
||||||
if (!FontRenderGlyph(mono, key, entry)) {
|
if (!FontRenderGlyph(mono, key, entry)) {
|
||||||
EsHeapFree(entry);
|
EsHeapFree(entry);
|
||||||
|
@ -2828,6 +2876,8 @@ struct EsTextbox : EsElement {
|
||||||
|
|
||||||
EsRectangle borders, insets;
|
EsRectangle borders, insets;
|
||||||
EsTextStyle textStyle;
|
EsTextStyle textStyle;
|
||||||
|
EsFont overrideFont;
|
||||||
|
uint16_t overrideTextSize;
|
||||||
|
|
||||||
uint32_t syntaxHighlightingLanguage;
|
uint32_t syntaxHighlightingLanguage;
|
||||||
uint32_t syntaxHighlightingColors[8];
|
uint32_t syntaxHighlightingColors[8];
|
||||||
|
@ -3260,7 +3310,7 @@ void EsTextboxEnsureCaretVisible(EsTextbox *textbox, bool verticallyCenter) {
|
||||||
DocumentLine *line = &textbox->lines[caret.line];
|
DocumentLine *line = &textbox->lines[caret.line];
|
||||||
int scrollX = textbox->scroll.position[0];
|
int scrollX = textbox->scroll.position[0];
|
||||||
int viewportWidth = bounds.r;
|
int viewportWidth = bounds.r;
|
||||||
int caretX = TextGetPartialStringWidth(&textbox->textStyle,
|
int caretX = TextGetPartialStringWidth(textbox, &textbox->textStyle,
|
||||||
line->GetBuffer(textbox), line->lengthBytes, caret.byte) - scrollX + textbox->insets.l;
|
line->GetBuffer(textbox), line->lengthBytes, caret.byte) - scrollX + textbox->insets.l;
|
||||||
|
|
||||||
if (caretX < textbox->insets.l) {
|
if (caretX < textbox->insets.l) {
|
||||||
|
@ -3288,7 +3338,7 @@ bool TextboxMoveCaret(EsTextbox *textbox, TextboxCaret *caret, bool right, int m
|
||||||
}
|
}
|
||||||
|
|
||||||
if (textbox->verticalMotionHorizontalDepth == -1) {
|
if (textbox->verticalMotionHorizontalDepth == -1) {
|
||||||
textbox->verticalMotionHorizontalDepth = TextGetPartialStringWidth(&textbox->textStyle,
|
textbox->verticalMotionHorizontalDepth = TextGetPartialStringWidth(textbox, &textbox->textStyle,
|
||||||
textbox->lines[caret->line].GetBuffer(textbox), textbox->lines[caret->line].lengthBytes, caret->byte);
|
textbox->lines[caret->line].GetBuffer(textbox), textbox->lines[caret->line].lengthBytes, caret->byte);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3297,7 +3347,7 @@ bool TextboxMoveCaret(EsTextbox *textbox, TextboxCaret *caret, bool right, int m
|
||||||
|
|
||||||
DocumentLine *line = &textbox->lines[caret->line];
|
DocumentLine *line = &textbox->lines[caret->line];
|
||||||
int pointX = textbox->verticalMotionHorizontalDepth ? textbox->verticalMotionHorizontalDepth - 1 : 0;
|
int pointX = textbox->verticalMotionHorizontalDepth ? textbox->verticalMotionHorizontalDepth - 1 : 0;
|
||||||
ptrdiff_t result = TextGetCharacterAtPoint(&textbox->textStyle,
|
ptrdiff_t result = TextGetCharacterAtPoint(textbox, &textbox->textStyle,
|
||||||
line->GetBuffer(textbox), line->lengthBytes, &pointX, ES_TEXT_GET_CHARACTER_AT_POINT_MIDDLE);
|
line->GetBuffer(textbox), line->lengthBytes, &pointX, ES_TEXT_GET_CHARACTER_AT_POINT_MIDDLE);
|
||||||
caret->byte = result == -1 ? line->lengthBytes : result;
|
caret->byte = result == -1 ? line->lengthBytes : result;
|
||||||
} else {
|
} else {
|
||||||
|
@ -3445,7 +3495,7 @@ void TextboxRefreshVisibleLines(EsTextbox *textbox, bool repaint = true) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
line->lengthWidth = TextGetStringWidth(&textbox->textStyle,
|
line->lengthWidth = TextGetStringWidth(textbox, &textbox->textStyle,
|
||||||
line->GetBuffer(textbox), line->lengthBytes);
|
line->GetBuffer(textbox), line->lengthBytes);
|
||||||
|
|
||||||
if (textbox->longestLine != -1 && line->lengthWidth > textbox->longestLineWidth) {
|
if (textbox->longestLine != -1 && line->lengthWidth > textbox->longestLineWidth) {
|
||||||
|
@ -3617,7 +3667,7 @@ void EsTextboxInsert(EsTextbox *textbox, const char *string, ptrdiff_t stringByt
|
||||||
|
|
||||||
// Step 4: Update the width of the line and repaint it.
|
// Step 4: Update the width of the line and repaint it.
|
||||||
|
|
||||||
line->lengthWidth = TextGetStringWidth(&textbox->textStyle, textbox->activeLine, textbox->activeLineBytes);
|
line->lengthWidth = TextGetStringWidth(textbox, &textbox->textStyle, textbox->activeLine, textbox->activeLineBytes);
|
||||||
TextboxRepaintLine(textbox, deleteFrom.line);
|
TextboxRepaintLine(textbox, deleteFrom.line);
|
||||||
|
|
||||||
// Step 5: Update the active line buffer.
|
// Step 5: Update the active line buffer.
|
||||||
|
@ -3658,7 +3708,7 @@ void EsTextboxInsert(EsTextbox *textbox, const char *string, ptrdiff_t stringByt
|
||||||
|
|
||||||
DocumentLine *firstLine = &textbox->lines[deleteFrom.line];
|
DocumentLine *firstLine = &textbox->lines[deleteFrom.line];
|
||||||
firstLine->lengthBytes = textbox->lines[deleteTo.line].lengthBytes - deleteTo.byte + deleteFrom.byte;
|
firstLine->lengthBytes = textbox->lines[deleteTo.line].lengthBytes - deleteTo.byte + deleteFrom.byte;
|
||||||
firstLine->lengthWidth = TextGetStringWidth(&textbox->textStyle, textbox->data + firstLine->offset, firstLine->lengthBytes);
|
firstLine->lengthWidth = TextGetStringWidth(textbox, &textbox->textStyle, textbox->data + firstLine->offset, firstLine->lengthBytes);
|
||||||
|
|
||||||
// Step 7: Remove the deleted lines and update the textbox.
|
// Step 7: Remove the deleted lines and update the textbox.
|
||||||
|
|
||||||
|
@ -3741,7 +3791,7 @@ void EsTextboxInsert(EsTextbox *textbox, const char *string, ptrdiff_t stringByt
|
||||||
|
|
||||||
textbox->carets[0].byte += bytesToInsert;
|
textbox->carets[0].byte += bytesToInsert;
|
||||||
textbox->carets[1].byte += bytesToInsert;
|
textbox->carets[1].byte += bytesToInsert;
|
||||||
line->lengthWidth = TextGetStringWidth(&textbox->textStyle, textbox->activeLine, line->lengthBytes);
|
line->lengthWidth = TextGetStringWidth(textbox, &textbox->textStyle, textbox->activeLine, line->lengthBytes);
|
||||||
TextboxRepaintLine(textbox, insertionPoint.line);
|
TextboxRepaintLine(textbox, insertionPoint.line);
|
||||||
|
|
||||||
// Step 4: Update the longest line.
|
// Step 4: Update the longest line.
|
||||||
|
@ -3776,7 +3826,7 @@ void EsTextboxInsert(EsTextbox *textbox, const char *string, ptrdiff_t stringByt
|
||||||
|
|
||||||
if (i) {
|
if (i) {
|
||||||
EsMemoryZero(line, sizeof(*line));
|
EsMemoryZero(line, sizeof(*line));
|
||||||
line->height = EsTextGetLineHeight(&textbox->textStyle);
|
line->height = TextGetLineHeight(textbox, &textbox->textStyle);
|
||||||
line->yPosition = previous->yPosition + previous->height;
|
line->yPosition = previous->yPosition + previous->height;
|
||||||
line->offset = lineByteOffset + insertedBytes;
|
line->offset = lineByteOffset + insertedBytes;
|
||||||
}
|
}
|
||||||
|
@ -4068,7 +4118,7 @@ bool TextboxFindCaret(EsTextbox *textbox, int positionX, int positionY, bool sec
|
||||||
DocumentLine *line = &textbox->lines[i + textbox->firstVisibleLine];
|
DocumentLine *line = &textbox->lines[i + textbox->firstVisibleLine];
|
||||||
int pointX = positionX + textbox->scroll.position[0] - textbox->insets.l;
|
int pointX = positionX + textbox->scroll.position[0] - textbox->insets.l;
|
||||||
if (pointX < 0) pointX = 0;
|
if (pointX < 0) pointX = 0;
|
||||||
ptrdiff_t result = TextGetCharacterAtPoint(&textbox->textStyle,
|
ptrdiff_t result = TextGetCharacterAtPoint(textbox, &textbox->textStyle,
|
||||||
line->GetBuffer(textbox), line->lengthBytes,
|
line->GetBuffer(textbox), line->lengthBytes,
|
||||||
&pointX, ES_TEXT_GET_CHARACTER_AT_POINT_MIDDLE);
|
&pointX, ES_TEXT_GET_CHARACTER_AT_POINT_MIDDLE);
|
||||||
textbox->carets[1].byte = result == -1 ? line->lengthBytes : result;
|
textbox->carets[1].byte = result == -1 ? line->lengthBytes : result;
|
||||||
|
@ -4160,13 +4210,40 @@ int ProcessTextboxMarginMessage(EsElement *element, EsMessage *message) {
|
||||||
textRun[1].offset = EsStringFormat(label, sizeof(label), "%d", i + textbox->firstVisibleLine + 1);
|
textRun[1].offset = EsStringFormat(label, sizeof(label), "%d", i + textbox->firstVisibleLine + 1);
|
||||||
EsTextPlanProperties properties = {};
|
EsTextPlanProperties properties = {};
|
||||||
properties.flags = ES_TEXT_V_CENTER | ES_TEXT_H_RIGHT | ES_TEXT_ELLIPSIS | ES_TEXT_PLAN_SINGLE_USE;
|
properties.flags = ES_TEXT_V_CENTER | ES_TEXT_H_RIGHT | ES_TEXT_ELLIPSIS | ES_TEXT_PLAN_SINGLE_USE;
|
||||||
EsDrawText(painter, EsTextPlanCreate(&properties, bounds, label, textRun, 1), bounds, nullptr, nullptr);
|
EsDrawText(painter, EsTextPlanCreate(element, &properties, bounds, label, textRun, 1), bounds, nullptr, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextboxStyleChanged(EsTextbox *textbox) {
|
||||||
|
textbox->borders = textbox->currentStyle->borders;
|
||||||
|
textbox->insets = textbox->currentStyle->insets;
|
||||||
|
|
||||||
|
if (textbox->flags & ES_TEXTBOX_MARGIN) {
|
||||||
|
int marginWidth = textbox->margin->currentStyle->preferredWidth;
|
||||||
|
textbox->borders.l += marginWidth;
|
||||||
|
textbox->insets.l += marginWidth + textbox->margin->currentStyle->gapMajor;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lineHeight = TextGetLineHeight(textbox, &textbox->textStyle);
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < (int32_t) textbox->lines.Length(); i++) {
|
||||||
|
DocumentLine *line = &textbox->lines[i];
|
||||||
|
DocumentLine *previous = i ? (&textbox->lines[i - 1]) : nullptr;
|
||||||
|
line->height = lineHeight;
|
||||||
|
line->yPosition = previous ? (previous->yPosition + previous->height) : 0;
|
||||||
|
line->lengthWidth = -1;
|
||||||
|
textbox->longestLine = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextboxRefreshVisibleLines(textbox);
|
||||||
|
TextboxFindLongestLine(textbox);
|
||||||
|
textbox->scroll.Refresh();
|
||||||
|
EsElementRepaint(textbox);
|
||||||
|
}
|
||||||
|
|
||||||
int ProcessTextboxMessage(EsElement *element, EsMessage *message) {
|
int ProcessTextboxMessage(EsElement *element, EsMessage *message) {
|
||||||
EsTextbox *textbox = (EsTextbox *) element;
|
EsTextbox *textbox = (EsTextbox *) element;
|
||||||
|
|
||||||
|
@ -4241,10 +4318,10 @@ int ProcessTextboxMessage(EsElement *element, EsMessage *message) {
|
||||||
EsTextPlan *plan;
|
EsTextPlan *plan;
|
||||||
|
|
||||||
if (textRuns[1].offset) {
|
if (textRuns[1].offset) {
|
||||||
plan = EsTextPlanCreate(&properties, lineBounds, line->GetBuffer(textbox), textRuns.array, textRuns.Length() - 1);
|
plan = EsTextPlanCreate(element, &properties, lineBounds, line->GetBuffer(textbox), textRuns.array, textRuns.Length() - 1);
|
||||||
} else {
|
} else {
|
||||||
textRuns[1].offset = 1; // Make sure that the caret and selection is draw correctly, even on empty lines.
|
textRuns[1].offset = 1; // Make sure that the caret and selection is draw correctly, even on empty lines.
|
||||||
plan = EsTextPlanCreate(&properties, lineBounds, " ", textRuns.array, textRuns.Length() - 1);
|
plan = EsTextPlanCreate(element, &properties, lineBounds, " ", textRuns.array, textRuns.Length() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plan) {
|
if (plan) {
|
||||||
|
@ -4510,6 +4587,23 @@ int ProcessTextboxMessage(EsElement *element, EsMessage *message) {
|
||||||
} else if (message->type == ES_MSG_GET_INSPECTOR_INFORMATION) {
|
} else if (message->type == ES_MSG_GET_INSPECTOR_INFORMATION) {
|
||||||
DocumentLine *firstLine = &textbox->lines.First();
|
DocumentLine *firstLine = &textbox->lines.First();
|
||||||
EsBufferFormat(message->getContent.buffer, "'%s'", firstLine->lengthBytes, firstLine->GetBuffer(textbox));
|
EsBufferFormat(message->getContent.buffer, "'%s'", firstLine->lengthBytes, firstLine->GetBuffer(textbox));
|
||||||
|
} else if (message->type == ES_MSG_UI_SCALE_CHANGED) {
|
||||||
|
if (textbox->margin) {
|
||||||
|
// Force the margin to update its style now, so that its width can be read correctly by TextboxStyleChanged.
|
||||||
|
textbox->margin->RefreshStyle(nullptr, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
textbox->currentStyle->GetTextStyle(&textbox->textStyle);
|
||||||
|
|
||||||
|
if (textbox->overrideTextSize) {
|
||||||
|
textbox->textStyle.size = textbox->overrideTextSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textbox->overrideFont.family) {
|
||||||
|
textbox->textStyle.font = textbox->overrideFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextboxStyleChanged(textbox);
|
||||||
} else {
|
} else {
|
||||||
response = 0;
|
response = 0;
|
||||||
}
|
}
|
||||||
|
@ -4539,13 +4633,13 @@ EsTextbox *EsTextboxCreate(EsElement *parent, uint64_t flags, const EsStyle *sty
|
||||||
textbox->undo = &textbox->localUndo;
|
textbox->undo = &textbox->localUndo;
|
||||||
textbox->undo->instance = textbox->instance;
|
textbox->undo->instance = textbox->instance;
|
||||||
|
|
||||||
// TODO Automatically update these when the theme changes.
|
|
||||||
textbox->borders = textbox->currentStyle->borders;
|
textbox->borders = textbox->currentStyle->borders;
|
||||||
textbox->insets = textbox->currentStyle->insets;
|
textbox->insets = textbox->currentStyle->insets;
|
||||||
|
|
||||||
textbox->currentStyle->GetTextStyle(&textbox->textStyle);
|
textbox->currentStyle->GetTextStyle(&textbox->textStyle);
|
||||||
|
|
||||||
DocumentLine firstLine = {};
|
DocumentLine firstLine = {};
|
||||||
firstLine.height = EsTextGetLineHeight(&textbox->textStyle);
|
firstLine.height = TextGetLineHeight(textbox, &textbox->textStyle);
|
||||||
textbox->lines.Add(firstLine);
|
textbox->lines.Add(firstLine);
|
||||||
|
|
||||||
TextboxVisibleLine firstVisibleLine = {};
|
TextboxVisibleLine firstVisibleLine = {};
|
||||||
|
@ -4742,31 +4836,16 @@ void EsTextboxSetUndoManager(EsTextbox *textbox, EsUndoManager *undoManager) {
|
||||||
textbox->undo = undoManager;
|
textbox->undo = undoManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EsTextboxSetTextStyle(EsTextbox *textbox, const EsTextStyle *textStyle) {
|
void EsTextboxSetTextSize(EsTextbox *textbox, uint16_t size) {
|
||||||
if (0 == EsMemoryCompare(textStyle, &textbox->textStyle, sizeof(EsTextStyle))) {
|
textbox->overrideTextSize = size;
|
||||||
return;
|
textbox->textStyle.size = size;
|
||||||
}
|
TextboxStyleChanged(textbox);
|
||||||
|
|
||||||
EsMemoryCopy(&textbox->textStyle, textStyle, sizeof(EsTextStyle));
|
|
||||||
int lineHeight = EsTextGetLineHeight(&textbox->textStyle);
|
|
||||||
|
|
||||||
for (int32_t i = 0; i < (int32_t) textbox->lines.Length(); i++) {
|
|
||||||
DocumentLine *line = &textbox->lines[i];
|
|
||||||
DocumentLine *previous = i ? (&textbox->lines[i - 1]) : nullptr;
|
|
||||||
line->height = lineHeight;
|
|
||||||
line->yPosition = previous ? (previous->yPosition + previous->height) : 0;
|
|
||||||
line->lengthWidth = -1;
|
|
||||||
textbox->longestLine = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextboxRefreshVisibleLines(textbox);
|
|
||||||
TextboxFindLongestLine(textbox);
|
|
||||||
textbox->scroll.Refresh();
|
|
||||||
EsElementRepaint(textbox);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EsTextboxGetTextStyle(EsTextbox *textbox, EsTextStyle *textStyle) {
|
void EsTextboxSetFont(EsTextbox *textbox, EsFont font) {
|
||||||
EsMemoryCopy(textStyle, &textbox->textStyle, sizeof(EsTextStyle));
|
textbox->overrideFont = font;
|
||||||
|
textbox->textStyle.font = font;
|
||||||
|
TextboxStyleChanged(textbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EsTextboxSetupSyntaxHighlighting(EsTextbox *textbox, uint32_t language, uint32_t *customColors, size_t customColorCount) {
|
void EsTextboxSetupSyntaxHighlighting(EsTextbox *textbox, uint32_t language, uint32_t *customColors, size_t customColorCount) {
|
||||||
|
@ -4817,7 +4896,7 @@ int ProcessTextDisplayMessage(EsElement *element, EsMessage *message) {
|
||||||
display->properties.flags = display->currentStyle->textAlign;
|
display->properties.flags = display->currentStyle->textAlign;
|
||||||
if (~display->flags & ES_TEXT_DISPLAY_PREFORMATTED) display->properties.flags |= ES_TEXT_PLAN_TRIM_SPACES;
|
if (~display->flags & ES_TEXT_DISPLAY_PREFORMATTED) display->properties.flags |= ES_TEXT_PLAN_TRIM_SPACES;
|
||||||
if (display->flags & ES_TEXT_DISPLAY_NO_FONT_SUBSTITUTION) display->properties.flags |= ES_TEXT_PLAN_NO_FONT_SUBSTITUTION;
|
if (display->flags & ES_TEXT_DISPLAY_NO_FONT_SUBSTITUTION) display->properties.flags |= ES_TEXT_PLAN_NO_FONT_SUBSTITUTION;
|
||||||
display->plan = EsTextPlanCreate(&display->properties, textBounds, display->contents, display->textRuns, display->textRunCount);
|
display->plan = EsTextPlanCreate(element, &display->properties, textBounds, display->contents, display->textRuns, display->textRunCount);
|
||||||
display->planWidth = textBounds.r - textBounds.l;
|
display->planWidth = textBounds.r - textBounds.l;
|
||||||
display->planHeight = textBounds.b - textBounds.t;
|
display->planHeight = textBounds.b - textBounds.t;
|
||||||
}
|
}
|
||||||
|
@ -4833,7 +4912,7 @@ int ProcessTextDisplayMessage(EsElement *element, EsMessage *message) {
|
||||||
display->planWidth = message->type == ES_MSG_GET_HEIGHT && message->measure.width
|
display->planWidth = message->type == ES_MSG_GET_HEIGHT && message->measure.width
|
||||||
? (message->measure.width - insets.l - insets.r) : 0;
|
? (message->measure.width - insets.l - insets.r) : 0;
|
||||||
display->planHeight = 0;
|
display->planHeight = 0;
|
||||||
display->plan = EsTextPlanCreate(&display->properties,
|
display->plan = EsTextPlanCreate(element, &display->properties,
|
||||||
ES_RECT_4(0, display->planWidth, 0, 0),
|
ES_RECT_4(0, display->planWidth, 0, 0),
|
||||||
display->contents, display->textRuns, display->textRunCount);
|
display->contents, display->textRuns, display->textRunCount);
|
||||||
|
|
||||||
|
@ -4858,6 +4937,11 @@ int ProcessTextDisplayMessage(EsElement *element, EsMessage *message) {
|
||||||
EsHeapFree(display->contents);
|
EsHeapFree(display->contents);
|
||||||
} else if (message->type == ES_MSG_GET_INSPECTOR_INFORMATION) {
|
} else if (message->type == ES_MSG_GET_INSPECTOR_INFORMATION) {
|
||||||
EsBufferFormat(message->getContent.buffer, "'%s'", display->textRuns[display->textRunCount].offset, display->contents);
|
EsBufferFormat(message->getContent.buffer, "'%s'", display->textRuns[display->textRunCount].offset, display->contents);
|
||||||
|
} else if (message->type == ES_MSG_UI_SCALE_CHANGED) {
|
||||||
|
if (display->plan) {
|
||||||
|
EsTextPlanDestroy(display->plan);
|
||||||
|
display->plan = nullptr;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -5015,7 +5099,7 @@ int ProcessListDisplayMessage(EsElement *element, EsMessage *message) {
|
||||||
textRun[0].style.figures = ES_TEXT_FIGURE_TABULAR;
|
textRun[0].style.figures = ES_TEXT_FIGURE_TABULAR;
|
||||||
bounds.t += child->offsetY;
|
bounds.t += child->offsetY;
|
||||||
bounds.b = bounds.t + child->height;
|
bounds.b = bounds.t + child->height;
|
||||||
EsTextPlan *plan = EsTextPlanCreate(&properties, bounds, buffer, textRun, 1);
|
EsTextPlan *plan = EsTextPlanCreate(element, &properties, bounds, buffer, textRun, 1);
|
||||||
EsDrawText(message->painter, plan, bounds);
|
EsDrawText(message->painter, plan, bounds);
|
||||||
bounds.t -= child->offsetY;
|
bounds.t -= child->offsetY;
|
||||||
counter++;
|
counter++;
|
||||||
|
|
|
@ -1295,18 +1295,6 @@ struct UIStyle {
|
||||||
bool IsRegionCompletelyOpaque(EsRectangle region, int width, int height);
|
bool IsRegionCompletelyOpaque(EsRectangle region, int width, int height);
|
||||||
|
|
||||||
inline void GetTextStyle(EsTextStyle *style);
|
inline void GetTextStyle(EsTextStyle *style);
|
||||||
|
|
||||||
inline int GetLineHeight() {
|
|
||||||
EsTextStyle style;
|
|
||||||
GetTextStyle(&style);
|
|
||||||
return EsTextGetLineHeight(&style);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int MeasureTextWidth(const char *text, size_t textBytes) {
|
|
||||||
EsTextStyle style;
|
|
||||||
GetTextStyle(&style);
|
|
||||||
return TextGetStringWidth(&style, text, textBytes);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const void *GetConstant(const char *cKey, size_t *byteCount, bool *scale) {
|
const void *GetConstant(const char *cKey, size_t *byteCount, bool *scale) {
|
||||||
|
@ -1383,22 +1371,32 @@ const char *GetConstantString(const char *cKey) {
|
||||||
return !value || !byteCount || value[byteCount - 1] ? nullptr : value;
|
return !value || !byteCount || value[byteCount - 1] ? nullptr : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ThemeLoadData(const void *buffer, size_t byteCount) {
|
bool ThemeInitialise() {
|
||||||
EsBuffer data = {};
|
EsBuffer data = {};
|
||||||
data.in = (const uint8_t *) buffer;
|
data.in = (const uint8_t *) EsEmbeddedFileGet(EsLiteral("$Desktop/Theme.dat"), &data.bytes);
|
||||||
data.bytes = byteCount;
|
|
||||||
|
|
||||||
const ThemeHeader *header = (const ThemeHeader *) EsBufferRead(&data, sizeof(ThemeHeader));
|
const ThemeHeader *header = (const ThemeHeader *) EsBufferRead(&data, sizeof(ThemeHeader));
|
||||||
|
|
||||||
if (!header || header->signature != THEME_HEADER_SIGNATURE
|
if (!header || header->signature != THEME_HEADER_SIGNATURE
|
||||||
|| !header->styleCount || !EsBufferRead(&data, sizeof(ThemeStyle))
|
|| !header->styleCount || !EsBufferRead(&data, sizeof(ThemeStyle))
|
||||||
|| byteCount < header->bitmapBytes) {
|
|| data.bytes < header->bitmapBytes) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
theming.system.in = (const uint8_t *) buffer;
|
theming.system.in = (const uint8_t *) data.in;
|
||||||
theming.system.bytes = byteCount;
|
theming.system.bytes = data.bytes;
|
||||||
theming.header = header;
|
theming.header = header;
|
||||||
|
|
||||||
|
theming.scale = api.global->uiScale;
|
||||||
|
|
||||||
|
theming.cursors.width = ES_THEME_CURSORS_WIDTH;
|
||||||
|
theming.cursors.height = ES_THEME_CURSORS_HEIGHT;
|
||||||
|
theming.cursors.stride = ES_THEME_CURSORS_WIDTH * 4;
|
||||||
|
theming.cursors.bits = EsObjectMap(EsMemoryOpen(theming.cursors.height * theming.cursors.stride, EsLiteral(ES_THEME_CURSORS_NAME), 0),
|
||||||
|
0, ES_MAP_OBJECT_ALL, ES_MAP_OBJECT_READ_ONLY);
|
||||||
|
theming.cursors.fullAlpha = true;
|
||||||
|
theming.cursors.readOnly = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1618,11 +1616,104 @@ void ThemeAnimationBuild(ThemeAnimation *animation, UIStyle *oldStyle, uint16_t
|
||||||
_ThemeAnimationBuildAddProperties(animation, oldStyle, newStateFlags);
|
_ThemeAnimationBuildAddProperties(animation, oldStyle, newStateFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ThemeStylePrepare(UIStyle *style, UIStyleKey key) {
|
||||||
|
EsStyle *esStyle = (key.part & 1) || (!key.part) ? nullptr : (EsStyle *) (key.part);
|
||||||
|
EsThemeMetrics *customMetrics = esStyle ? &esStyle->metrics : nullptr;
|
||||||
|
const ThemeStyle *themeStyle = style->style;
|
||||||
|
|
||||||
|
// Apply custom metrics and appearance.
|
||||||
|
|
||||||
|
if (customMetrics) {
|
||||||
|
#define ES_RECTANGLE_TO_RECTANGLE_8(x) { (int8_t) (x).l, (int8_t) (x).r, (int8_t) (x).t, (int8_t) (x).b }
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_INSETS) style->metrics->insets = ES_RECTANGLE_TO_RECTANGLE_8(customMetrics->insets);
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_CLIP_INSETS) style->metrics->clipInsets = ES_RECTANGLE_TO_RECTANGLE_8(customMetrics->clipInsets);
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_GLOBAL_OFFSET) style->metrics->globalOffset = ES_RECTANGLE_TO_RECTANGLE_8(customMetrics->globalOffset);
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_CLIP_ENABLED) style->metrics->clipEnabled = customMetrics->clipEnabled;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_CURSOR) style->metrics->cursor = customMetrics->cursor;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_ENTRANCE_TRANSITION) style->metrics->entranceTransition = customMetrics->entranceTransition;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_EXIT_TRANSITION) style->metrics->exitTransition = customMetrics->exitTransition;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_ENTRANCE_DURATION) style->metrics->entranceDuration = customMetrics->entranceDuration;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_EXIT_DURATION) style->metrics->exitDuration = customMetrics->exitDuration;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_PREFERRED_WIDTH) style->metrics->preferredWidth = customMetrics->preferredWidth;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_PREFERRED_HEIGHT) style->metrics->preferredHeight = customMetrics->preferredHeight;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_MINIMUM_WIDTH) style->metrics->minimumWidth = customMetrics->minimumWidth;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_MINIMUM_HEIGHT) style->metrics->minimumHeight = customMetrics->minimumHeight;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_MAXIMUM_WIDTH) style->metrics->maximumWidth = customMetrics->maximumWidth;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_MAXIMUM_HEIGHT) style->metrics->maximumHeight = customMetrics->maximumHeight;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_GAP_MAJOR) style->metrics->gapMajor = customMetrics->gapMajor;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_GAP_MINOR) style->metrics->gapMinor = customMetrics->gapMinor;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_GAP_WRAP) style->metrics->gapWrap = customMetrics->gapWrap;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_TEXT_COLOR) style->metrics->textColor = customMetrics->textColor;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_SELECTED_BACKGROUND) style->metrics->selectedBackground = customMetrics->selectedBackground;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_SELECTED_TEXT) style->metrics->selectedText = customMetrics->selectedText;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_ICON_COLOR) style->metrics->iconColor = customMetrics->iconColor;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_TEXT_ALIGN) style->metrics->textAlign = customMetrics->textAlign;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_TEXT_SIZE) style->metrics->textSize = customMetrics->textSize;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_FONT_FAMILY) style->metrics->fontFamily = customMetrics->fontFamily;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_FONT_WEIGHT) style->metrics->fontWeight = customMetrics->fontWeight;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_ICON_SIZE) style->metrics->iconSize = customMetrics->iconSize;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_IS_ITALIC) style->metrics->isItalic = customMetrics->isItalic;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_ELLIPSIS) style->metrics->ellipsis = customMetrics->ellipsis;
|
||||||
|
if (customMetrics->mask & ES_THEME_METRICS_LAYOUT_VERTICAL) style->metrics->layoutVertical = customMetrics->layoutVertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esStyle && esStyle->appearance.enabled) {
|
||||||
|
style->appearance = &esStyle->appearance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply scaling to the metrics.
|
||||||
|
|
||||||
|
int16_t *scale16[] = {
|
||||||
|
&style->metrics->insets.l, &style->metrics->insets.r, &style->metrics->insets.t, &style->metrics->insets.b,
|
||||||
|
&style->metrics->clipInsets.l, &style->metrics->clipInsets.r, &style->metrics->clipInsets.t, &style->metrics->clipInsets.b,
|
||||||
|
&style->metrics->globalOffset.l, &style->metrics->globalOffset.r, &style->metrics->globalOffset.t, &style->metrics->globalOffset.b,
|
||||||
|
&style->metrics->gapMajor, &style->metrics->gapMinor, &style->metrics->gapWrap,
|
||||||
|
&style->metrics->preferredWidth, &style->metrics->preferredHeight,
|
||||||
|
&style->metrics->minimumWidth, &style->metrics->minimumHeight,
|
||||||
|
&style->metrics->maximumWidth, &style->metrics->maximumHeight,
|
||||||
|
&style->metrics->iconSize,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (uintptr_t i = 0; i < sizeof(scale16) / sizeof(scale16[0]); i++) {
|
||||||
|
*(scale16[i]) = *(scale16[i]) * key.scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
style->scale = key.scale;
|
||||||
|
|
||||||
|
// Copy inline metrics.
|
||||||
|
|
||||||
|
style->borders.l = themeStyle->approximateBorders.l * key.scale;
|
||||||
|
style->borders.r = themeStyle->approximateBorders.r * key.scale;
|
||||||
|
style->borders.t = themeStyle->approximateBorders.t * key.scale;
|
||||||
|
style->borders.b = themeStyle->approximateBorders.b * key.scale;
|
||||||
|
|
||||||
|
style->paintOutsets.l = themeStyle->paintOutsets.l * key.scale;
|
||||||
|
style->paintOutsets.r = themeStyle->paintOutsets.r * key.scale;
|
||||||
|
style->paintOutsets.t = themeStyle->paintOutsets.t * key.scale;
|
||||||
|
style->paintOutsets.b = themeStyle->paintOutsets.b * key.scale;
|
||||||
|
|
||||||
|
if (style->opaqueInsets.l != 0x7F) {
|
||||||
|
style->opaqueInsets.l = themeStyle->opaqueInsets.l * key.scale;
|
||||||
|
style->opaqueInsets.r = themeStyle->opaqueInsets.r * key.scale;
|
||||||
|
style->opaqueInsets.t = themeStyle->opaqueInsets.t * key.scale;
|
||||||
|
style->opaqueInsets.b = themeStyle->opaqueInsets.b * key.scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (style->appearance) {
|
||||||
|
if ((style->appearance->backgroundColor & 0xFF000000) == 0xFF000000) {
|
||||||
|
style->opaqueInsets = ES_RECT_1(0);
|
||||||
|
} else {
|
||||||
|
style->opaqueInsets = ES_RECT_1(0x7F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ThemeStyleCopyInlineMetrics(style);
|
||||||
|
}
|
||||||
|
|
||||||
UIStyle *ThemeStyleInitialise(UIStyleKey key) {
|
UIStyle *ThemeStyleInitialise(UIStyleKey key) {
|
||||||
// Find the ThemeStyle entry.
|
// Find the ThemeStyle entry.
|
||||||
|
|
||||||
EsStyle *esStyle = (key.part & 1) || (!key.part) ? nullptr : (EsStyle *) (key.part);
|
EsStyle *esStyle = (key.part & 1) || (!key.part) ? nullptr : (EsStyle *) (key.part);
|
||||||
EsThemeMetrics *customMetrics = esStyle ? &esStyle->metrics : nullptr;
|
|
||||||
uint16_t id = esStyle ? (uint16_t) (uintptr_t) esStyle->inherit : key.part;
|
uint16_t id = esStyle ? (uint16_t) (uintptr_t) esStyle->inherit : key.part;
|
||||||
if (!id) id = 1;
|
if (!id) id = 1;
|
||||||
|
|
||||||
|
@ -1834,99 +1925,12 @@ UIStyle *ThemeStyleInitialise(UIStyleKey key) {
|
||||||
layerDataByteCount += layer->dataByteCount;
|
layerDataByteCount += layer->dataByteCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply custom metrics and appearance.
|
ThemeStylePrepare(style, key);
|
||||||
|
|
||||||
if (customMetrics) {
|
|
||||||
#define ES_RECTANGLE_TO_RECTANGLE_8(x) { (int8_t) (x).l, (int8_t) (x).r, (int8_t) (x).t, (int8_t) (x).b }
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_INSETS) style->metrics->insets = ES_RECTANGLE_TO_RECTANGLE_8(customMetrics->insets);
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_CLIP_INSETS) style->metrics->clipInsets = ES_RECTANGLE_TO_RECTANGLE_8(customMetrics->clipInsets);
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_GLOBAL_OFFSET) style->metrics->globalOffset = ES_RECTANGLE_TO_RECTANGLE_8(customMetrics->globalOffset);
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_CLIP_ENABLED) style->metrics->clipEnabled = customMetrics->clipEnabled;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_CURSOR) style->metrics->cursor = customMetrics->cursor;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_ENTRANCE_TRANSITION) style->metrics->entranceTransition = customMetrics->entranceTransition;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_EXIT_TRANSITION) style->metrics->exitTransition = customMetrics->exitTransition;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_ENTRANCE_DURATION) style->metrics->entranceDuration = customMetrics->entranceDuration;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_EXIT_DURATION) style->metrics->exitDuration = customMetrics->exitDuration;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_PREFERRED_WIDTH) style->metrics->preferredWidth = customMetrics->preferredWidth;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_PREFERRED_HEIGHT) style->metrics->preferredHeight = customMetrics->preferredHeight;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_MINIMUM_WIDTH) style->metrics->minimumWidth = customMetrics->minimumWidth;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_MINIMUM_HEIGHT) style->metrics->minimumHeight = customMetrics->minimumHeight;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_MAXIMUM_WIDTH) style->metrics->maximumWidth = customMetrics->maximumWidth;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_MAXIMUM_HEIGHT) style->metrics->maximumHeight = customMetrics->maximumHeight;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_GAP_MAJOR) style->metrics->gapMajor = customMetrics->gapMajor;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_GAP_MINOR) style->metrics->gapMinor = customMetrics->gapMinor;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_GAP_WRAP) style->metrics->gapWrap = customMetrics->gapWrap;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_TEXT_COLOR) style->metrics->textColor = customMetrics->textColor;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_SELECTED_BACKGROUND) style->metrics->selectedBackground = customMetrics->selectedBackground;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_SELECTED_TEXT) style->metrics->selectedText = customMetrics->selectedText;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_ICON_COLOR) style->metrics->iconColor = customMetrics->iconColor;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_TEXT_ALIGN) style->metrics->textAlign = customMetrics->textAlign;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_TEXT_SIZE) style->metrics->textSize = customMetrics->textSize;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_FONT_FAMILY) style->metrics->fontFamily = customMetrics->fontFamily;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_FONT_WEIGHT) style->metrics->fontWeight = customMetrics->fontWeight;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_ICON_SIZE) style->metrics->iconSize = customMetrics->iconSize;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_IS_ITALIC) style->metrics->isItalic = customMetrics->isItalic;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_ELLIPSIS) style->metrics->ellipsis = customMetrics->ellipsis;
|
|
||||||
if (customMetrics->mask & ES_THEME_METRICS_LAYOUT_VERTICAL) style->metrics->layoutVertical = customMetrics->layoutVertical;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (esStyle && esStyle->appearance.enabled) {
|
|
||||||
style->appearance = &esStyle->appearance;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply scaling to the metrics.
|
|
||||||
|
|
||||||
int16_t *scale16[] = {
|
|
||||||
&style->metrics->insets.l, &style->metrics->insets.r, &style->metrics->insets.t, &style->metrics->insets.b,
|
|
||||||
&style->metrics->clipInsets.l, &style->metrics->clipInsets.r, &style->metrics->clipInsets.t, &style->metrics->clipInsets.b,
|
|
||||||
&style->metrics->globalOffset.l, &style->metrics->globalOffset.r, &style->metrics->globalOffset.t, &style->metrics->globalOffset.b,
|
|
||||||
&style->metrics->gapMajor, &style->metrics->gapMinor, &style->metrics->gapWrap,
|
|
||||||
&style->metrics->preferredWidth, &style->metrics->preferredHeight,
|
|
||||||
&style->metrics->minimumWidth, &style->metrics->minimumHeight,
|
|
||||||
&style->metrics->maximumWidth, &style->metrics->maximumHeight,
|
|
||||||
&style->metrics->textSize, &style->metrics->iconSize,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < sizeof(scale16) / sizeof(scale16[0]); i++) {
|
|
||||||
*(scale16[i]) = *(scale16[i]) * key.scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
style->scale = key.scale;
|
|
||||||
|
|
||||||
// Copy inline metrics.
|
|
||||||
|
|
||||||
style->borders.l = themeStyle->approximateBorders.l * key.scale;
|
|
||||||
style->borders.r = themeStyle->approximateBorders.r * key.scale;
|
|
||||||
style->borders.t = themeStyle->approximateBorders.t * key.scale;
|
|
||||||
style->borders.b = themeStyle->approximateBorders.b * key.scale;
|
|
||||||
|
|
||||||
style->paintOutsets.l = themeStyle->paintOutsets.l * key.scale;
|
|
||||||
style->paintOutsets.r = themeStyle->paintOutsets.r * key.scale;
|
|
||||||
style->paintOutsets.t = themeStyle->paintOutsets.t * key.scale;
|
|
||||||
style->paintOutsets.b = themeStyle->paintOutsets.b * key.scale;
|
|
||||||
|
|
||||||
if (style->opaqueInsets.l != 0x7F) {
|
|
||||||
style->opaqueInsets.l = themeStyle->opaqueInsets.l * key.scale;
|
|
||||||
style->opaqueInsets.r = themeStyle->opaqueInsets.r * key.scale;
|
|
||||||
style->opaqueInsets.t = themeStyle->opaqueInsets.t * key.scale;
|
|
||||||
style->opaqueInsets.b = themeStyle->opaqueInsets.b * key.scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style->appearance) {
|
|
||||||
if ((style->appearance->backgroundColor & 0xFF000000) == 0xFF000000) {
|
|
||||||
style->opaqueInsets = ES_RECT_1(0);
|
|
||||||
} else {
|
|
||||||
style->opaqueInsets = ES_RECT_1(0x7F);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ThemeStyleCopyInlineMetrics(style);
|
|
||||||
|
|
||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
|
|
||||||
UIStyleKey MakeStyleKey(const EsStyle *style, uint16_t stateFlags) {
|
UIStyleKey MakeStyleKey(const EsStyle *style, uint16_t stateFlags) {
|
||||||
return { .part = (uintptr_t) style, .stateFlags = stateFlags };
|
return { .part = (uintptr_t) style, .scale = theming.scale, .stateFlags = stateFlags };
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeUnusedStyles(bool includePermanentStyles) {
|
void FreeUnusedStyles(bool includePermanentStyles) {
|
||||||
|
@ -1946,10 +1950,8 @@ UIStyle *GetStyle(UIStyleKey key, bool keepAround) {
|
||||||
UIStyle **style = theming.loadedStyles.Get(&key);
|
UIStyle **style = theming.loadedStyles.Get(&key);
|
||||||
|
|
||||||
if (!style) {
|
if (!style) {
|
||||||
UIStyleKey key2 = key;
|
|
||||||
key2.scale = theming.scale; // TODO Per-window scaling.
|
|
||||||
style = theming.loadedStyles.Put(&key);
|
style = theming.loadedStyles.Put(&key);
|
||||||
*style = ThemeStyleInitialise(key2);
|
*style = ThemeStyleInitialise(key);
|
||||||
EsAssert(style);
|
EsAssert(style);
|
||||||
} else if ((*style)->referenceCount != -1) {
|
} else if ((*style)->referenceCount != -1) {
|
||||||
(*style)->referenceCount++;
|
(*style)->referenceCount++;
|
||||||
|
@ -2024,7 +2026,7 @@ void UIStyle::PaintText(EsPainter *painter, EsElement *element, EsRectangle rect
|
||||||
EsMessage m = { ES_MSG_PAINT_ICON };
|
EsMessage m = { ES_MSG_PAINT_ICON };
|
||||||
m.painter = &iconPainter;
|
m.painter = &iconPainter;
|
||||||
|
|
||||||
if (element && ES_HANDLED == EsMessageSend(element, &m)) {
|
if (ES_HANDLED == EsMessageSend(element, &m)) {
|
||||||
// Icon painted by the application.
|
// Icon painted by the application.
|
||||||
} else if (iconID) {
|
} else if (iconID) {
|
||||||
EsDrawStandardIcon(painter, iconID, metrics->iconSize, iconBounds, metrics->iconColor);
|
EsDrawStandardIcon(painter, iconID, metrics->iconSize, iconBounds, metrics->iconColor);
|
||||||
|
@ -2071,13 +2073,13 @@ void UIStyle::PaintText(EsPainter *painter, EsElement *element, EsRectangle rect
|
||||||
EsTextRun *textRuns;
|
EsTextRun *textRuns;
|
||||||
size_t textRunCount;
|
size_t textRunCount;
|
||||||
EsRichTextParse(text, textBytes, &string, &textRuns, &textRunCount, &textRun[0].style);
|
EsRichTextParse(text, textBytes, &string, &textRuns, &textRunCount, &textRun[0].style);
|
||||||
EsTextPlan *plan = EsTextPlanCreate(&properties, textBounds, string, textRuns, textRunCount);
|
EsTextPlan *plan = EsTextPlanCreate(element, &properties, textBounds, string, textRuns, textRunCount);
|
||||||
EsDrawText(painter, plan, textBounds, nullptr, selectionProperties);
|
EsDrawText(painter, plan, textBounds, nullptr, selectionProperties);
|
||||||
EsTextPlanDestroy(plan);
|
EsTextPlanDestroy(plan);
|
||||||
EsHeapFree(textRuns);
|
EsHeapFree(textRuns);
|
||||||
EsHeapFree(string);
|
EsHeapFree(string);
|
||||||
} else {
|
} else {
|
||||||
EsTextPlan *plan = EsTextPlanCreate(&properties, textBounds, text, textRun, 1);
|
EsTextPlan *plan = EsTextPlanCreate(element, &properties, textBounds, text, textRun, 1);
|
||||||
PaintTextLayers(painter, plan, textBounds, selectionProperties);
|
PaintTextLayers(painter, plan, textBounds, selectionProperties);
|
||||||
EsTextPlanDestroy(plan);
|
EsTextPlanDestroy(plan);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1433,7 +1433,6 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_SYSTEM_GET_CONSTANTS) {
|
||||||
systemConstants[ES_SYSTEM_CONSTANT_WINDOW_INSET] = WINDOW_INSET;
|
systemConstants[ES_SYSTEM_CONSTANT_WINDOW_INSET] = WINDOW_INSET;
|
||||||
systemConstants[ES_SYSTEM_CONSTANT_CONTAINER_TAB_BAND_HEIGHT] = CONTAINER_TAB_BAND_HEIGHT;
|
systemConstants[ES_SYSTEM_CONSTANT_CONTAINER_TAB_BAND_HEIGHT] = CONTAINER_TAB_BAND_HEIGHT;
|
||||||
systemConstants[ES_SYSTEM_CONSTANT_UI_SCALE] = UI_SCALE;
|
systemConstants[ES_SYSTEM_CONSTANT_UI_SCALE] = UI_SCALE;
|
||||||
systemConstants[ES_SYSTEM_CONSTANT_BORDER_THICKNESS] = BORDER_THICKNESS;
|
|
||||||
systemConstants[ES_SYSTEM_CONSTANT_OPTIMAL_WORK_QUEUE_THREAD_COUNT] = scheduler.currentProcessorID; // TODO Update this as processors are added/removed.
|
systemConstants[ES_SYSTEM_CONSTANT_OPTIMAL_WORK_QUEUE_THREAD_COUNT] = scheduler.currentProcessorID; // TODO Update this as processors are added/removed.
|
||||||
SYSCALL_WRITE(argument0, systemConstants, sizeof(systemConstants));
|
SYSCALL_WRITE(argument0, systemConstants, sizeof(systemConstants));
|
||||||
SYSCALL_RETURN(ES_SUCCESS, false);
|
SYSCALL_RETURN(ES_SUCCESS, false);
|
||||||
|
|
|
@ -161,7 +161,6 @@ void SendMessageToWindow(Window *window, EsMessage *message);
|
||||||
|
|
||||||
#define WINDOW_INSET (19 * UI_SCALE / 100)
|
#define WINDOW_INSET (19 * UI_SCALE / 100)
|
||||||
#define CONTAINER_TAB_BAND_HEIGHT (33 * UI_SCALE / 100)
|
#define CONTAINER_TAB_BAND_HEIGHT (33 * UI_SCALE / 100)
|
||||||
#define BORDER_THICKNESS (9 * UI_SCALE / 100)
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ default_user_documents_path=0:/
|
||||||
click_chain_timeout_ms=500
|
click_chain_timeout_ms=500
|
||||||
show_cursor_shadow=1
|
show_cursor_shadow=1
|
||||||
scroll_lines_per_notch=3
|
scroll_lines_per_notch=3
|
||||||
|
ui_scale=100
|
||||||
|
|
||||||
[ui]
|
[ui]
|
||||||
font_fallback=Inter
|
font_fallback=Inter
|
||||||
|
|
|
@ -237,7 +237,7 @@ void EsDrawInvert(EsPainter *painter, EsRectangle bounds) {
|
||||||
int j = bounds.r - bounds.l;
|
int j = bounds.r - bounds.l;
|
||||||
|
|
||||||
while (j >= 4) {
|
while (j >= 4) {
|
||||||
*(__m128i *) destination = _mm_xor_si128(*(__m128i *) destination, mask);
|
_mm_storeu_si128((__m128i *) destination, _mm_xor_si128(_mm_loadu_si128((__m128i *) destination), mask));
|
||||||
destination += 4;
|
destination += 4;
|
||||||
j -= 4;
|
j -= 4;
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,7 @@ DEFINE_INTERFACE_STRING(CommonAnnouncementPasteErrorOther, "Could not paste");
|
||||||
|
|
||||||
DEFINE_INTERFACE_STRING(CommonEmpty, "empty");
|
DEFINE_INTERFACE_STRING(CommonEmpty, "empty");
|
||||||
|
|
||||||
|
DEFINE_INTERFACE_STRING(CommonUnitPercent, "%");
|
||||||
DEFINE_INTERFACE_STRING(CommonUnitBytes, " B");
|
DEFINE_INTERFACE_STRING(CommonUnitBytes, " B");
|
||||||
DEFINE_INTERFACE_STRING(CommonUnitKilobytes, " KB");
|
DEFINE_INTERFACE_STRING(CommonUnitKilobytes, " KB");
|
||||||
DEFINE_INTERFACE_STRING(CommonUnitMegabytes, " MB");
|
DEFINE_INTERFACE_STRING(CommonUnitMegabytes, " MB");
|
||||||
|
@ -127,7 +128,7 @@ DEFINE_INTERFACE_STRING(DesktopSettingsMouseSpeedFast, "Fast");
|
||||||
DEFINE_INTERFACE_STRING(DesktopSettingsMouseCursorTrailsNone, "None");
|
DEFINE_INTERFACE_STRING(DesktopSettingsMouseCursorTrailsNone, "None");
|
||||||
DEFINE_INTERFACE_STRING(DesktopSettingsMouseCursorTrailsMany, "Many");
|
DEFINE_INTERFACE_STRING(DesktopSettingsMouseCursorTrailsMany, "Many");
|
||||||
|
|
||||||
DEFINE_INTERFACE_STRING(DesktopSettingsApplicationSelectItem, "Select an application to view its information or manage it.");
|
DEFINE_INTERFACE_STRING(DesktopSettingsDisplayUIScale, "Interface scale:");
|
||||||
|
|
||||||
// File operations.
|
// File operations.
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,6 @@ EsStringAllocateAndFormat=153
|
||||||
EsStringAllocateAndFormatV=154
|
EsStringAllocateAndFormatV=154
|
||||||
EsStringCompare=155
|
EsStringCompare=155
|
||||||
EsStringCompareRaw=156
|
EsStringCompareRaw=156
|
||||||
EsTextGetLineHeight=157
|
|
||||||
EsStringFormat=158
|
EsStringFormat=158
|
||||||
EsStringFormatTemporary=159
|
EsStringFormatTemporary=159
|
||||||
EsStringFormatV=160
|
EsStringFormatV=160
|
||||||
|
@ -198,8 +197,7 @@ EsCRTmemset=196
|
||||||
EsCRTqsort=197
|
EsCRTqsort=197
|
||||||
EsCRTrealloc=198
|
EsCRTrealloc=198
|
||||||
EsCRTsinf=199
|
EsCRTsinf=199
|
||||||
EsTextboxSetTextStyle=200
|
EsElementGetScaleFactor=200
|
||||||
EsTextboxGetTextStyle=201
|
|
||||||
EsCRTsqrt=202
|
EsCRTsqrt=202
|
||||||
EsCRTsqrtf=203
|
EsCRTsqrtf=203
|
||||||
EsSplitterCreate=204
|
EsSplitterCreate=204
|
||||||
|
@ -436,3 +434,5 @@ EsUserTaskStart=434
|
||||||
EsElementIsHidden=435
|
EsElementIsHidden=435
|
||||||
EsUserTaskSetProgress=436
|
EsUserTaskSetProgress=436
|
||||||
EsUserTaskIsRunning=437
|
EsUserTaskIsRunning=437
|
||||||
|
EsTextboxSetFont=438
|
||||||
|
EsTextboxSetTextSize=439
|
||||||
|
|
Loading…
Reference in New Issue