diff --git a/apps/file_manager/main.cpp b/apps/file_manager/main.cpp index c4b71f2..792d338 100644 --- a/apps/file_manager/main.cpp +++ b/apps/file_manager/main.cpp @@ -47,7 +47,7 @@ EsListViewColumn folderOutputColumns[] = { #define COLUMN_TYPE (1) { INTERFACE_STRING(FileManagerColumnType), ES_LIST_VIEW_COLUMN_HAS_MENU }, #define COLUMN_SIZE (2) - { INTERFACE_STRING(FileManagerColumnSize), ES_LIST_VIEW_COLUMN_HAS_MENU | ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED }, + { INTERFACE_STRING(FileManagerColumnSize), ES_LIST_VIEW_COLUMN_HAS_MENU | ES_TEXT_H_RIGHT }, }; #define LOAD_FOLDER_BACK (1) diff --git a/apps/samples/list.cpp b/apps/samples/list.cpp new file mode 100644 index 0000000..524dbd5 --- /dev/null +++ b/apps/samples/list.cpp @@ -0,0 +1,35 @@ +#include + +EsListViewColumn columns[] = { + // Title Flags Initial width + { "Name", -1, ES_FLAGS_DEFAULT, 150 }, + { "Age", -1, ES_TEXT_H_RIGHT, 100 }, + { "Favorite color", -1, ES_DRAW_CONTENT_RICH_TEXT, 150 }, +}; + +void AddPerson(EsListView *list, const char *name, int age, const char *favoriteColor) { + char ageString[16]; + EsStringFormat(ageString, sizeof(ageString), "%d%c", age, 0); + + EsListViewIndex index = EsListViewFixedItemInsert(list, name); + EsListViewFixedItemAddString(list, index, ageString); + EsListViewFixedItemAddString(list, index, favoriteColor); +} + +void _start() { + _init(); + + while (true) { + EsMessage *message = EsMessageReceive(); + + if (message->type == ES_MSG_INSTANCE_CREATE) { + EsInstance *instance = EsInstanceCreate(message, "List", -1); + EsPanel *wrapper = EsPanelCreate(instance->window, ES_CELL_FILL, ES_STYLE_PANEL_WINDOW_DIVIDER); + EsListView *list = EsListViewCreate(wrapper, ES_CELL_FILL | ES_LIST_VIEW_COLUMNS | ES_LIST_VIEW_FIXED_ITEMS); + EsListViewSetColumns(list, columns, sizeof(columns) / sizeof(columns[0])); + AddPerson(list, "Alice", 20, "\a#e00]Red"); + AddPerson(list, "Bob", 30, "\a#080]Green"); + AddPerson(list, "Cameron", 40, "\a#00f]Blue"); + } + } +} diff --git a/apps/samples/list.ini b/apps/samples/list.ini new file mode 100644 index 0000000..9e3236f --- /dev/null +++ b/apps/samples/list.ini @@ -0,0 +1,5 @@ +[general] +name=List + +[build] +source=apps/samples/list.cpp diff --git a/apps/system_monitor.cpp b/apps/system_monitor.cpp index 1530822..2698322 100644 --- a/apps/system_monitor.cpp +++ b/apps/system_monitor.cpp @@ -28,16 +28,16 @@ struct Instance : EsInstance { EsListViewColumn listViewProcessesColumns[] = { { "Name", -1, 0, 150 }, - { "PID", -1, ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED, 120 }, - { "Memory", -1, ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED, 120 }, - { "CPU", -1, ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED, 120 }, - { "Handles", -1, ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED, 120 }, - { "Threads", -1, ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED, 120 }, + { "PID", -1, ES_TEXT_H_RIGHT, 120 }, + { "Memory", -1, ES_TEXT_H_RIGHT, 120 }, + { "CPU", -1, ES_TEXT_H_RIGHT, 120 }, + { "Handles", -1, ES_TEXT_H_RIGHT, 120 }, + { "Threads", -1, ES_TEXT_H_RIGHT, 120 }, }; EsListViewColumn listViewContextSwitchesColumns[] = { - { "Time stamp (ms)", -1, ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED, 150 }, - { "CPU", -1, ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED, 150 }, + { "Time stamp (ms)", -1, ES_TEXT_H_RIGHT, 150 }, + { "CPU", -1, ES_TEXT_H_RIGHT, 150 }, { "Process", -1, 0, 150 }, { "Thread", -1, 0, 150 }, { "Count", -1, 0, 150 }, diff --git a/desktop/desktop.cpp b/desktop/desktop.cpp index 79fe1cc..648a3c9 100644 --- a/desktop/desktop.cpp +++ b/desktop/desktop.cpp @@ -193,6 +193,15 @@ const EsStyle styleButtonGroupContainer = { }, }; +const EsStyle styleClockButton = { + .inherit = ES_STYLE_TASK_BAR_EXTRA, + + .metrics = { + .mask = ES_THEME_METRICS_TEXT_FIGURES, + .textFigures = ES_TEXT_FIGURE_TABULAR, + }, +}; + struct { Array installedApplications; Array allApplicationInstances; @@ -371,10 +380,6 @@ int ReorderListLayout(ReorderList *list, int additionalRightMargin, bool clampDr size_t childCount = list->items.Length(); - if (!childCount) { - return 0; - } - int totalWidth = 0; uintptr_t nonExitingChildCount = 0; @@ -394,8 +399,8 @@ int ReorderListLayout(ReorderList *list, int additionalRightMargin, bool clampDr widthClamped = true; } - int targetWidth = totalWidth / nonExitingChildCount; - int extraWidth = totalWidth % nonExitingChildCount; + int targetWidth = nonExitingChildCount ? totalWidth / nonExitingChildCount : -1; + int extraWidth = nonExitingChildCount ? totalWidth % nonExitingChildCount : 0; list->targetWidth = targetWidth; list->extraWidth = extraWidth; @@ -575,7 +580,7 @@ void WindowTabDestroy(WindowTab *tab) { if (container->taskBarButton) { container->taskBarButton->exiting = true; container->taskBarButton->containerWindow = nullptr; - EsElementRelayout(&desktop.taskBar); + EsElementRelayout(container->taskBarButton->parent); // The button is destroyed by ReorderItemAnimate, once the exit animation completes. } @@ -2652,7 +2657,7 @@ void DesktopSetup() { desktop.tasksButton = EsButtonCreate(panel, ES_ELEMENT_HIDDEN, ES_STYLE_TASK_BAR_BUTTON); desktop.tasksButton->messageUser = TaskBarTasksButtonMessage; - EsButton *clockButton = EsButtonCreate(panel, ES_BUTTON_TABULAR | ES_BUTTON_COMPACT, ES_STYLE_TASK_BAR_EXTRA); + EsButton *clockButton = EsButtonCreate(panel, ES_BUTTON_COMPACT, &styleClockButton); clockButton->cName = "current time"; EsThreadCreate(TaskBarClockUpdateThread, nullptr, clockButton); diff --git a/desktop/gui.cpp b/desktop/gui.cpp index 66206d0..cd564f3 100644 --- a/desktop/gui.cpp +++ b/desktop/gui.cpp @@ -3920,8 +3920,7 @@ int ProcessButtonMessage(EsElement *element, EsMessage *message) { EsDrawContent(message->painter, element, ES_RECT_2S(message->painter->width, message->painter->height), button->label, button->labelBytes, button->iconID, - ((button->flags & ES_BUTTON_DROPDOWN) ? ES_DRAW_CONTENT_MARKER_DOWN_ARROW : 0) - | ((button->flags & ES_BUTTON_TABULAR) ? ES_DRAW_CONTENT_TABULAR : 0)); + ((button->flags & ES_BUTTON_DROPDOWN) ? ES_DRAW_CONTENT_MARKER_DOWN_ARROW : 0)); } else if (message->type == ES_MSG_PAINT_ICON) { if (button->imageDisplay) { EsRectangle imageSize = ES_RECT_2S(button->imageDisplay->width, button->imageDisplay->height); @@ -4233,7 +4232,7 @@ int ProcessMenuItemMessage(EsElement *element, EsMessage *message) { EsDrawContent(message->painter, element, ES_RECT_2S(message->painter->width, message->painter->height), - (const char *) _buffer, buffer.position, 0, ES_DRAW_CONTENT_CHANGE_ALIGNMENT | ES_TEXT_H_RIGHT | ES_TEXT_V_CENTER); + (const char *) _buffer, buffer.position, 0, ES_TEXT_H_RIGHT); } else if (message->type == ES_MSG_GET_WIDTH) { uint8_t _buffer[64]; EsBuffer buffer = { .out = _buffer, .bytes = sizeof(_buffer) }; diff --git a/desktop/list_view.cpp b/desktop/list_view.cpp index 171d604..4154872 100644 --- a/desktop/list_view.cpp +++ b/desktop/list_view.cpp @@ -1193,18 +1193,9 @@ struct EsListView : EsElement { && ES_HANDLED == EsMessageSend(this, &m)) { bool useSelectedCellStyle = (item->element->customStyleState & THEME_STATE_SELECTED) && (flags & ES_LIST_VIEW_CHOICE_SELECT); UIStyle *style = useSelectedCellStyle ? selectedCellStyle : i ? secondaryCellStyle : primaryCellStyle; - - uint8_t previousTextAlign = style->textAlign; - - if (columns[i].flags & ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED) { - style->textAlign ^= ES_TEXT_H_RIGHT | ES_TEXT_H_LEFT; - } - style->PaintText(message->painter, element, bounds, (char *) _buffer, buffer.position, m.getContent.icon, - (columns[i].flags & ES_LIST_VIEW_COLUMN_TABULAR) ? ES_DRAW_CONTENT_TABULAR : ES_FLAGS_DEFAULT, - i ? nullptr : &selection); - style->textAlign = previousTextAlign; + columns[i].flags, i ? nullptr : &selection); } bounds.l += columns[i].width * theming.scale + secondaryCellStyle->gapMajor; diff --git a/desktop/os.header b/desktop/os.header index 991764c..c0402b7 100644 --- a/desktop/os.header +++ b/desktop/os.header @@ -379,13 +379,15 @@ define ES_TEXT_PLAN_CLIP_UNBREAKABLE_LINES (1 << 11) define ES_TEXT_PLAN_NO_FONT_SUBSTITUTION (1 << 12) // ...plus alignment flags. -define ES_DRAW_CONTENT_CHANGE_ALIGNMENT (1 << 8) +define ES_DRAW_CONTENT_TABULAR (1 << 8) define ES_DRAW_CONTENT_MARKER_DOWN_ARROW (1 << 9) define ES_DRAW_CONTENT_MARKER_UP_ARROW (1 << 10) -define ES_DRAW_CONTENT_TABULAR (1 << 11) define ES_DRAW_CONTENT_RICH_TEXT (1 << 12) // ...plus alignment flags, if CHANGE_ALIGNMENT set. +define ES_LIST_VIEW_COLUMN_HAS_MENU (1 << 16) // The header can be clicked to open a menu. +// ...plus draw content flags and alignment flags. + define ES_FILE_READ_SHARED (0x1) // Read-only. The file can still be opened for writing. define ES_FILE_READ (0x2) // Read-only. The file will not openable for writing. This will fail if the file is already opened for writing. define ES_FILE_WRITE_SHARED (0x4) // Read-write. The file can still be opened for writing. This will fail if the file is already opened for exclusive writing. @@ -514,7 +516,6 @@ define ES_BUTTON_CHECKBOX (1 << 10) define ES_BUTTON_RADIOBOX (1 << 11) define ES_BUTTON_CANCEL (1 << 12) define ES_BUTTON_PUSH (1 << 13) -define ES_BUTTON_TABULAR (1 << 14) // Use tabular text figures. define ES_MENU_ITEM_CHECKED (ES_CHECK_CHECKED) define ES_COLOR_WELL_HAS_OPACITY (1 << 0) @@ -542,10 +543,6 @@ define ES_LIST_VIEW_GROUP_HAS_FOOTER (1 << 1) // The last item in the group is define ES_LIST_VIEW_GROUP_INDENT (1 << 2) // Indent the group's items (excluding the header and footer). define ES_LIST_VIEW_GROUP_COLLAPSABLE (1 << 3) // The group can be collapsed. -define ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED (1 << 0) // The column's contents is right-aligned. -define ES_LIST_VIEW_COLUMN_HAS_MENU (1 << 1) // The header can be clicked to open a menu. -define ES_LIST_VIEW_COLUMN_TABULAR (1 << 2) // Use tabular text figures (so that digits are aligned). - define ES_MENU_AT_CURSOR (1 << 0) define ES_MENU_MAXIMUM_HEIGHT (1 << 1) @@ -627,6 +624,7 @@ define ES_THEME_METRICS_FONT_WEIGHT (1 << 20) define ES_THEME_METRICS_ICON_SIZE (1 << 21) define ES_THEME_METRICS_IS_ITALIC (1 << 22) define ES_THEME_METRICS_LAYOUT_VERTICAL (1 << 23) +define ES_THEME_METRICS_TEXT_FIGURES (1 << 24) define ES_WINDOW_MOVE_MAXIMIZED (1 << 0) define ES_WINDOW_MOVE_ADJUST_TO_FIT_SCREEN (1 << 1) @@ -1331,7 +1329,8 @@ struct EsThemeMetrics { int32_t maximumWidth, maximumHeight; int32_t gapMajor, gapMinor, gapWrap; uint32_t textColor, selectedBackground, selectedText, iconColor; - int textAlign, textSize, fontFamily, fontWeight, iconSize; + int32_t textAlign, textSize, fontFamily, fontWeight, iconSize; + uint8_t textFigures; bool isItalic, layoutVertical; }; diff --git a/desktop/text.cpp b/desktop/text.cpp index 67f459d..fe3d721 100644 --- a/desktop/text.cpp +++ b/desktop/text.cpp @@ -2686,6 +2686,17 @@ void EsRichTextParse(const char *inString, ptrdiff_t inStringBytes, textRun->style.decorations |= ES_TEXT_DECORATION_UNDERLINE; } else if (c == '2' /* secondary color */) { textRun->style.color = GetConstantNumber("textSecondary"); + } else if (c == '#' /* custom color */) { + char string[9]; + size_t bytes = 0; + + while (bytes < sizeof(string)) { + if (i >= inStringBytes || inString[i] == ']') break; + string[bytes++] = inString[i++]; + } + + textRun->style.color = EsColorParse(string, bytes); + goto parsedFormat; } } diff --git a/desktop/theme.cpp b/desktop/theme.cpp index 8d15f53..919f132 100644 --- a/desktop/theme.cpp +++ b/desktop/theme.cpp @@ -207,6 +207,7 @@ typedef struct ThemeMetrics { uint32_t textColor, selectedBackground, selectedText, iconColor; int8_t textAlign, fontWeight; int16_t textSize, iconSize; + uint8_t textFigures; bool isItalic, layoutVertical; } ThemeMetrics; @@ -1200,24 +1201,16 @@ typedef struct ThemeAnimation { struct UIStyle { intptr_t referenceCount; - uint32_t observedStyleStateMask; - bool IsStateChangeObserved(uint16_t state1, uint16_t state2); - // General information. uint8_t textAlign; - uint16_t textSize; - uint32_t textColor; EsFont font; - EsRectangle insets, borders; uint16_t preferredWidth, preferredHeight; int16_t gapMajor, gapMinor, gapWrap; - + uint32_t observedStyleStateMask; EsRectangle paintOutsets, opaqueInsets; - float scale; - EsThemeAppearance *appearance; // An optional, custom appearance provided by the application. // Data. @@ -1242,7 +1235,7 @@ struct UIStyle { // Misc. bool IsRegionCompletelyOpaque(EsRectangle region, int width, int height); - + bool IsStateChangeObserved(uint16_t state1, uint16_t state2); inline void GetTextStyle(EsTextStyle *style); }; @@ -1326,8 +1319,6 @@ bool ThemeInitialise() { } void ThemeStyleCopyInlineMetrics(UIStyle *style) { - style->textSize = style->metrics->textSize; - style->textColor = style->metrics->textColor; style->font.family = style->metrics->fontFamily; style->font.weight = style->metrics->fontWeight; style->font.italic = style->metrics->isItalic; @@ -1547,6 +1538,7 @@ void ThemeStylePrepare(UIStyle *style, UIStyleKey key) { 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_TEXT_FIGURES) style->metrics->textFigures = customMetrics->textFigures; 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; @@ -1933,13 +1925,18 @@ void UIStyle::PaintText(EsPainter *painter, EsElement *element, EsRectangle rect if (textBytes) { EsTextPlanProperties properties = {}; - properties.flags = (flags & ES_DRAW_CONTENT_CHANGE_ALIGNMENT) ? (flags & 0xFF) : textAlign; + properties.flags = textAlign; + + if (flags & ES_TEXT_H_LEFT) properties.flags = (properties.flags & ~(ES_TEXT_H_CENTER | ES_TEXT_H_RIGHT)) | ES_TEXT_H_LEFT; + if (flags & ES_TEXT_H_CENTER) properties.flags = (properties.flags & ~(ES_TEXT_H_LEFT | ES_TEXT_H_RIGHT)) | ES_TEXT_H_CENTER; + if (flags & ES_TEXT_H_RIGHT) properties.flags = (properties.flags & ~(ES_TEXT_H_LEFT | ES_TEXT_H_CENTER)) | ES_TEXT_H_RIGHT; + if (flags & ES_TEXT_V_TOP) properties.flags = (properties.flags & ~(ES_TEXT_V_CENTER | ES_TEXT_V_BOTTOM)) | ES_TEXT_V_TOP; + if (flags & ES_TEXT_V_CENTER) properties.flags = (properties.flags & ~(ES_TEXT_V_TOP | ES_TEXT_V_BOTTOM)) | ES_TEXT_V_CENTER; + if (flags & ES_TEXT_V_BOTTOM) properties.flags = (properties.flags & ~(ES_TEXT_V_TOP | ES_TEXT_V_CENTER)) | ES_TEXT_V_BOTTOM; EsTextRun textRun[2] = {}; textRun[1].offset = textBytes; - textRun[0].style.font = font; - textRun[0].style.size = textSize; - textRun[0].style.color = textColor; + GetTextStyle(&textRun[0].style); if (flags & ES_DRAW_CONTENT_TABULAR) { textRun[0].style.figures = ES_TEXT_FIGURE_TABULAR; @@ -2038,6 +2035,7 @@ inline void UIStyle::GetTextStyle(EsTextStyle *style) { style->font = font; style->size = metrics->textSize; style->color = metrics->textColor; + style->figures = metrics->textFigures; } bool UIStyle::IsStateChangeObserved(uint16_t state1, uint16_t state2) { diff --git a/res/Theme.dat b/res/Theme.dat index b675896..563c885 100644 Binary files a/res/Theme.dat and b/res/Theme.dat differ