From a4374b3aa528070fceeee066d14e52e0415c8af3 Mon Sep 17 00:00:00 2001 From: nakst <> Date: Sat, 20 Nov 2021 21:16:43 +0000 Subject: [PATCH] replace EsListViewSetColumns --- apps/file_manager/main.cpp | 5 -- apps/file_manager/ui.cpp | 25 +++--- apps/samples/list.cpp | 12 +-- apps/system_monitor.cpp | 38 +++------ desktop/gui.cpp | 13 ++- desktop/list_view.cpp | 166 +++++++++++++++++++++---------------- desktop/os.header | 11 +-- desktop/styles.header | 1 + res/Theme Source.dat | Bin 528564 -> 529648 bytes res/Theme.dat | Bin 30560 -> 30756 bytes util/api_table.ini | 3 +- 11 files changed, 131 insertions(+), 143 deletions(-) diff --git a/apps/file_manager/main.cpp b/apps/file_manager/main.cpp index 834b237..32417d9 100644 --- a/apps/file_manager/main.cpp +++ b/apps/file_manager/main.cpp @@ -41,14 +41,9 @@ const char *errorTypeStrings[] = { #include "string.cpp" -EsListViewColumn folderOutputColumns[] = { #define COLUMN_NAME (0) - { INTERFACE_STRING(FileManagerColumnName), ES_LIST_VIEW_COLUMN_HAS_MENU }, #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_TEXT_H_RIGHT }, -}; #define LOAD_FOLDER_BACK (1) #define LOAD_FOLDER_FORWARD (2) diff --git a/apps/file_manager/ui.cpp b/apps/file_manager/ui.cpp index 00be54f..2a4da35 100644 --- a/apps/file_manager/ui.cpp +++ b/apps/file_manager/ui.cpp @@ -167,24 +167,16 @@ bool InstanceLoadFolder(Instance *instance, String path /* takes ownership */, i } void InstanceRefreshViewType(Instance *instance) { + EsCommandSetCheck(&instance->commandViewDetails, instance->viewSettings.viewType == VIEW_DETAILS ? ES_CHECK_CHECKED : ES_CHECK_UNCHECKED, false); + EsCommandSetCheck(&instance->commandViewTiles, instance->viewSettings.viewType == VIEW_TILES ? ES_CHECK_CHECKED : ES_CHECK_UNCHECKED, false); + EsCommandSetCheck(&instance->commandViewThumbnails, instance->viewSettings.viewType == VIEW_THUMBNAILS ? ES_CHECK_CHECKED : ES_CHECK_UNCHECKED, false); + if (instance->viewSettings.viewType == VIEW_DETAILS) { - EsCommandSetCheck(&instance->commandViewDetails, ES_CHECK_CHECKED, false); - EsCommandSetCheck(&instance->commandViewTiles, ES_CHECK_UNCHECKED, false); - EsCommandSetCheck(&instance->commandViewThumbnails, ES_CHECK_UNCHECKED, false); - EsListViewChangeStyles(instance->list, &styleFolderView, ES_STYLE_LIST_ITEM, nullptr, nullptr, ES_LIST_VIEW_COLUMNS, ES_LIST_VIEW_TILED); - EsListViewSetColumns(instance->list, folderOutputColumns, sizeof(folderOutputColumns) / sizeof(folderOutputColumns[0])); + EsListViewAddAllColumns(instance->list); } else if (instance->viewSettings.viewType == VIEW_TILES) { - EsCommandSetCheck(&instance->commandViewTiles, ES_CHECK_CHECKED, false); - EsCommandSetCheck(&instance->commandViewDetails, ES_CHECK_UNCHECKED, false); - EsCommandSetCheck(&instance->commandViewThumbnails, ES_CHECK_UNCHECKED, false); - EsListViewChangeStyles(instance->list, &styleFolderViewTiled, ES_STYLE_LIST_ITEM_TILE, nullptr, nullptr, ES_LIST_VIEW_TILED, ES_LIST_VIEW_COLUMNS); } else if (instance->viewSettings.viewType == VIEW_THUMBNAILS) { - EsCommandSetCheck(&instance->commandViewThumbnails, ES_CHECK_CHECKED, false); - EsCommandSetCheck(&instance->commandViewTiles, ES_CHECK_UNCHECKED, false); - EsCommandSetCheck(&instance->commandViewDetails, ES_CHECK_UNCHECKED, false); - EsListViewChangeStyles(instance->list, &styleFolderViewTiled, &styleFolderItemThumbnail, nullptr, nullptr, ES_LIST_VIEW_TILED, ES_LIST_VIEW_COLUMNS); } } @@ -738,7 +730,7 @@ int ListCallback(EsElement *element, EsMessage *message) { EsCommandSetCallback(EsCommandByID(instance, ES_COMMAND_PASTE), nullptr); return 0; } else if (message->type == ES_MSG_LIST_VIEW_GET_CONTENT) { - int column = message->getContent.column, index = message->getContent.index; + int column = message->getContent.columnID, index = message->getContent.index; EsAssert(index < (int) instance->listContents.Length() && index >= 0); ListEntry *listEntry = &instance->listContents[index]; FolderEntry *entry = listEntry->entry; @@ -1084,7 +1076,10 @@ void InstanceCreateUI(Instance *instance) { instance->list = EsListViewCreate(splitter, ES_CELL_FILL | ES_LIST_VIEW_COLUMNS | ES_LIST_VIEW_MULTI_SELECT, &styleFolderView); instance->list->accessKey = 'L'; instance->list->messageUser = ListCallback; - EsListViewSetColumns(instance->list, folderOutputColumns, sizeof(folderOutputColumns) / sizeof(folderOutputColumns[0])); + EsListViewRegisterColumn(instance->list, COLUMN_NAME, INTERFACE_STRING(FileManagerColumnName), ES_LIST_VIEW_COLUMN_HAS_MENU); + EsListViewRegisterColumn(instance->list, COLUMN_TYPE, INTERFACE_STRING(FileManagerColumnType), ES_LIST_VIEW_COLUMN_HAS_MENU); + EsListViewRegisterColumn(instance->list, COLUMN_SIZE, INTERFACE_STRING(FileManagerColumnSize), ES_LIST_VIEW_COLUMN_HAS_MENU | ES_TEXT_H_RIGHT); + EsListViewAddAllColumns(instance->list); EsListViewInsertGroup(instance->list, 0); // Toolbar: diff --git a/apps/samples/list.cpp b/apps/samples/list.cpp index 524dbd5..c556394 100644 --- a/apps/samples/list.cpp +++ b/apps/samples/list.cpp @@ -1,12 +1,5 @@ #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); @@ -26,7 +19,10 @@ void _start() { 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])); + EsListViewRegisterColumn(list, 0, "Name", -1, ES_FLAGS_DEFAULT, 150); + EsListViewRegisterColumn(list, 1, "Age", -1, ES_TEXT_H_RIGHT, 100); + EsListViewRegisterColumn(list, 2, "Favorite color", -1, ES_DRAW_CONTENT_RICH_TEXT, 150); + EsListViewAddAllColumns(list); 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/system_monitor.cpp b/apps/system_monitor.cpp index 9322861..f3d2f23 100644 --- a/apps/system_monitor.cpp +++ b/apps/system_monitor.cpp @@ -26,23 +26,6 @@ struct Instance : EsInstance { #define DISPLAY_GENERAL_LOG (3) #define DISPLAY_MEMORY (12) -EsListViewColumn listViewProcessesColumns[] = { - { "Name", -1, 0, 150 }, - { "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_TEXT_H_RIGHT, 150 }, - { "CPU", -1, ES_TEXT_H_RIGHT, 150 }, - { "Process", -1, 0, 150 }, - { "Thread", -1, 0, 150 }, - { "Count", -1, 0, 150 }, -}; - const EsStyle styleMonospacedTextbox = { .inherit = ES_STYLE_TEXTBOX_NO_BORDER, @@ -323,7 +306,7 @@ void UpdateDisplay(Instance *instance, int index) { int ListViewProcessesCallback(EsElement *element, EsMessage *message) { if (message->type == ES_MSG_LIST_VIEW_GET_CONTENT) { - int column = message->getContent.column, index = message->getContent.index; + int column = message->getContent.columnID, index = message->getContent.index; ProcessItem *item = &processes[index]; if (column == 0) GET_CONTENT("%s", item->data.nameBytes, item->data.name); else if (column == 1) { if (item->data.pid == -1) GET_CONTENT("n/a"); else GET_CONTENT("%d", item->data.pid); } @@ -357,13 +340,6 @@ void AddTab(EsElement *toolbar, uintptr_t index, const char *label, bool asDefau if (asDefault) EsButtonSetCheck(button, ES_CHECK_CHECKED); } -void AddListView(EsListView **pointer, EsElement *switcher, EsUICallback callback, EsListViewColumn *columns, size_t columnsSize, uint64_t additionalFlags) { - *pointer = EsListViewCreate(switcher, ES_CELL_FILL | ES_LIST_VIEW_COLUMNS | additionalFlags); - (*pointer)->messageUser = callback; - EsListViewSetColumns(*pointer, columns, columnsSize / sizeof(EsListViewColumn)); - EsListViewInsertGroup(*pointer, 0); -} - void TerminateProcess(Instance *instance, EsElement *, EsCommand *) { if (selectedPID == 0 /* Kernel */) { // Terminating the kernel process is a meaningless action; the closest equivalent is shutting down. @@ -394,8 +370,16 @@ void ProcessApplicationMessage(EsMessage *message) { instance->textboxGeneralLog = EsTextboxCreate(switcher, ES_TEXTBOX_MULTILINE | ES_CELL_FILL | ES_ELEMENT_DISABLED, &styleMonospacedTextbox); - AddListView(&instance->listViewProcesses, switcher, ListViewProcessesCallback, - listViewProcessesColumns, sizeof(listViewProcessesColumns), ES_LIST_VIEW_SINGLE_SELECT); + instance->listViewProcesses = EsListViewCreate(switcher, ES_CELL_FILL | ES_LIST_VIEW_COLUMNS | ES_LIST_VIEW_SINGLE_SELECT); + instance->listViewProcesses->messageUser = ListViewProcessesCallback; + EsListViewRegisterColumn(instance->listViewProcesses, 0, "Name", -1, 0, 150); + EsListViewRegisterColumn(instance->listViewProcesses, 1, "PID", -1, ES_TEXT_H_RIGHT, 120); + EsListViewRegisterColumn(instance->listViewProcesses, 2, "Memory", -1, ES_TEXT_H_RIGHT, 120); + EsListViewRegisterColumn(instance->listViewProcesses, 3, "CPU", -1, ES_TEXT_H_RIGHT, 120); + EsListViewRegisterColumn(instance->listViewProcesses, 4, "Handles", -1, ES_TEXT_H_RIGHT, 120); + EsListViewRegisterColumn(instance->listViewProcesses, 5, "Threads", -1, ES_TEXT_H_RIGHT, 120); + EsListViewAddAllColumns(instance->listViewProcesses); + EsListViewInsertGroup(instance->listViewProcesses, 0); instance->panelMemoryStatistics = EsPanelCreate(switcher, ES_CELL_FILL | ES_PANEL_TABLE | ES_PANEL_HORIZONTAL | ES_PANEL_V_SCROLL_AUTO, &stylePanelMemoryStatistics); diff --git a/desktop/gui.cpp b/desktop/gui.cpp index 34f9712..da60c47 100644 --- a/desktop/gui.cpp +++ b/desktop/gui.cpp @@ -7559,12 +7559,6 @@ struct InspectorWindow : EsInstance { EsTextbox *textboxCategoryFilter; }; -EsListViewColumn inspectorElementListColumns[] = { - { "Name", -1, 0, 300 }, - { "Bounds", -1, 0, 200 }, - { "Information", -1, 0, 200 }, -}; - int InspectorElementItemCallback(EsElement *element, EsMessage *message) { InspectorWindow *inspector = (InspectorWindow *) element->instance; @@ -7670,7 +7664,7 @@ int InspectorElementListCallback(EsElement *element, EsMessage *message) { InspectorWindow *inspector = (InspectorWindow *) element->instance; if (message->type == ES_MSG_LIST_VIEW_GET_CONTENT) { - int column = message->getContent.column, index = message->getContent.index; + int column = message->getContent.columnID, index = message->getContent.index; EsAssert(index >= 0 && index < (int) inspector->elements.Length()); InspectorElementEntry *entry = &inspector->elements[index]; @@ -8047,7 +8041,10 @@ void InspectorSetup(EsWindow *window) { inspector->elementList = EsListViewCreate(panel1, ES_CELL_FILL | ES_LIST_VIEW_COLUMNS | ES_LIST_VIEW_SINGLE_SELECT); inspector->elementList->messageUser = InspectorElementListCallback; - EsListViewSetColumns(inspector->elementList, inspectorElementListColumns, sizeof(inspectorElementListColumns) / sizeof(EsListViewColumn)); + EsListViewRegisterColumn(inspector->elementList, 0, "Name", -1, 0, 300); + EsListViewRegisterColumn(inspector->elementList, 1, "Bounds", -1, 0, 200); + EsListViewRegisterColumn(inspector->elementList, 2, "Information", -1, 0, 200); + EsListViewAddAllColumns(inspector->elementList); EsListViewInsertGroup(inspector->elementList, 0); { diff --git a/desktop/list_view.cpp b/desktop/list_view.cpp index 4154872..cbe6adb 100644 --- a/desktop/list_view.cpp +++ b/desktop/list_view.cpp @@ -39,11 +39,20 @@ struct ListViewFixedString { struct ListViewFixedItem { ListViewFixedString firstColumn; + // TODO Store the strings in an array per-ListViewColumn. Array otherColumns; EsGeneric data; uint32_t iconID; }; +struct ListViewColumn { + char *title; + size_t titleBytes; + uint32_t id; + uint32_t flags; + double width; +}; + int ListViewProcessItemMessage(EsElement *element, EsMessage *message); struct EsListView : EsElement { @@ -88,8 +97,8 @@ struct EsListView : EsElement { size_t emptyMessageBytes; EsElement *columnHeader; - EsListViewColumn *columns; - size_t columnCount; + Array registeredColumns; + Array activeColumns; // Indices into registeredColumns. int columnResizingOriginalWidth; int64_t totalColumnWidth; @@ -685,7 +694,7 @@ struct EsListView : EsElement { position += visibleItem->element->width; } else if ((flags & ES_LIST_VIEW_COLUMNS) && ((~flags & ES_LIST_VIEW_CHOICE_SELECT) || (this->scroll.enabled[0]))) { int indent = visibleItem->indent * style->gapWrap; - int firstColumn = columns[0].width * theming.scale + secondaryCellStyle->gapMajor; + int firstColumn = activeColumns.Length() ? (registeredColumns[activeColumns[0]].width * theming.scale + secondaryCellStyle->gapMajor) : 0; visibleItem->startAtSecondColumn = indent > firstColumn; if (indent > firstColumn) indent = firstColumn; visibleItem->element->InternalMove(totalColumnWidth - indent, visibleItem->size, @@ -1174,12 +1183,12 @@ struct EsListView : EsElement { if (flags & ES_LIST_VIEW_COLUMNS) { EsRectangle bounds = EsRectangleAddBorder(element->GetBounds(), element->style->insets); - for (uintptr_t i = item->startAtSecondColumn ? 1 : 0; i < columnCount; i++) { - m.getContent.column = i; + for (uintptr_t i = item->startAtSecondColumn ? 1 : 0; i < activeColumns.Length(); i++) { + m.getContent.columnID = registeredColumns[activeColumns[i]].id; m.getContent.icon = 0; buffer.position = 0; - bounds.r = bounds.l + columns[i].width * theming.scale + bounds.r = bounds.l + registeredColumns[activeColumns[i]].width * theming.scale - element->style->insets.r - element->style->insets.l; if (i == 0) { @@ -1195,10 +1204,10 @@ struct EsListView : EsElement { UIStyle *style = useSelectedCellStyle ? selectedCellStyle : i ? secondaryCellStyle : primaryCellStyle; style->PaintText(message->painter, element, bounds, (char *) _buffer, buffer.position, m.getContent.icon, - columns[i].flags, i ? nullptr : &selection); + registeredColumns[activeColumns[i]].flags, i ? nullptr : &selection); } - bounds.l += columns[i].width * theming.scale + secondaryCellStyle->gapMajor; + bounds.l += registeredColumns[activeColumns[i]].width * theming.scale + secondaryCellStyle->gapMajor; if (i == 0) { bounds.l -= item->indent * style->gapWrap; @@ -1580,7 +1589,7 @@ struct EsListView : EsElement { if (flags & ES_LIST_VIEW_COLUMNS) { int offset = primaryCellStyle->metrics->iconSize + primaryCellStyle->gapMinor + style->insets.l - inlineTextbox->style->insets.l; - inlineTextbox->InternalMove(columns[0].width * theming.scale - offset, item->element->height, + inlineTextbox->InternalMove(registeredColumns[activeColumns[0]].width * theming.scale - offset, item->element->height, item->element->offsetX + offset, item->element->offsetY); } else if (flags & ES_LIST_VIEW_TILED) { if (style->metrics->layoutVertical) { @@ -1669,6 +1678,10 @@ struct EsListView : EsElement { visibleItems[i].element->Destroy(); } + for (uintptr_t i = 0; i < registeredColumns.Length(); i++) { + EsHeapFree(registeredColumns[i].title); + } + for (uintptr_t i = 0; i < fixedItems.Length(); i++) { for (uintptr_t j = 0; j < fixedItems[i].otherColumns.Length(); j++) { EsHeapFree(fixedItems[i].otherColumns[j].string); @@ -1685,6 +1698,8 @@ struct EsListView : EsElement { fixedItems.Free(); visibleItems.Free(); groups.Free(); + activeColumns.Free(); + registeredColumns.Free(); } else if (message->type == ES_MSG_KEY_UP) { if (message->keyboard.scancode == ES_SCANCODE_LEFT_CTRL || message->keyboard.scancode == ES_SCANCODE_RIGHT_CTRL) { SelectPreview(); @@ -1874,10 +1889,10 @@ struct EsListView : EsElement { EsAssert(index < fixedItems.Length()); ListViewFixedString emptyString = {}; ListViewFixedItem *item = &fixedItems[index]; - ListViewFixedString *string = message->getContent.column == 0 ? &item->firstColumn - : message->getContent.column <= item->otherColumns.Length() ? &item->otherColumns[message->getContent.column - 1] : &emptyString; + ListViewFixedString *string = message->getContent.columnID == 0 ? &item->firstColumn + : message->getContent.columnID <= item->otherColumns.Length() ? &item->otherColumns[message->getContent.columnID - 1] : &emptyString; EsBufferFormat(message->getContent.buffer, "%s", string->bytes, string->string); - if (message->getContent.column == 0) message->getContent.icon = item->iconID; + if (!activeColumns.Length() || message->getContent.columnID == registeredColumns[activeColumns[0]].id) message->getContent.icon = item->iconID; } else if (message->type == ES_MSG_LIST_VIEW_IS_SELECTED && (flags & ES_LIST_VIEW_FIXED_ITEMS)) { message->selectItem.isSelected = message->selectItem.index == fixedItemSelection; } else { @@ -1900,11 +1915,30 @@ int ListViewProcessItemMessage(EsElement *_element, EsMessage *message) { 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; + for (uintptr_t i = 0; i < view->activeColumns.Length(); i++) { + view->totalColumnWidth += view->registeredColumns[view->activeColumns[i]].width * theming.scale + view->secondaryCellStyle->gapMajor; } } +int ListViewColumnHeaderMessage(EsElement *element, EsMessage *message) { + EsListView *view = (EsListView *) element->userData.p; + + if (message->type == ES_MSG_LAYOUT) { + int x = view->style->insets.l - view->scroll.position[0]; + + for (uintptr_t i = 0; i < element->children.Length(); i += 2) { + EsElement *item = element->children[i], *splitter = element->children[i + 1]; + ListViewColumn *column = &view->registeredColumns[item->userData.u]; + int splitterLeft = splitter->style->preferredWidth - view->secondaryCellStyle->gapMajor; + item->InternalMove(column->width * theming.scale - splitterLeft, element->height, x, 0); + splitter->InternalMove(splitter->style->preferredWidth, element->height, x + column->width * theming.scale - splitterLeft, 0); + x += column->width * theming.scale + view->secondaryCellStyle->gapMajor; + } + } + + return 0; +} + void EsListViewChangeStyles(EsListView *view, const EsStyle *style, const EsStyle *itemStyle, const EsStyle *headerItemStyle, const EsStyle *footerItemStyle, uint32_t addFlags, uint32_t removeFlags) { // TODO Animating changes. @@ -1938,29 +1972,11 @@ void EsListViewChangeStyles(EsListView *view, const EsStyle *style, const EsStyl view->columnHeader = EsCustomElementCreate(view, ES_CELL_FILL, ES_STYLE_LIST_COLUMN_HEADER); view->columnHeader->cName = "column header"; view->columnHeader->userData = view; - - view->columnHeader->messageUser = [] (EsElement *element, EsMessage *message) { - EsListView *view = (EsListView *) element->userData.p; - - if (message->type == ES_MSG_LAYOUT) { - int x = view->style->insets.l - view->scroll.position[0]; - - for (uintptr_t i = 0; i < element->children.Length(); i += 2) { - EsElement *item = element->children[i], *splitter = element->children[i + 1]; - EsListViewColumn *column = view->columns + item->userData.u; - int splitterLeft = splitter->style->preferredWidth - view->secondaryCellStyle->gapMajor; - item->InternalMove(column->width * theming.scale - splitterLeft, element->height, x, 0); - splitter->InternalMove(splitter->style->preferredWidth, element->height, x + column->width * theming.scale - splitterLeft, 0); - x += column->width * theming.scale + view->secondaryCellStyle->gapMajor; - } - } - - return 0; - }; - + view->columnHeader->messageUser = ListViewColumnHeaderMessage; view->scroll.fixedViewport[1] = view->columnHeader->style->preferredHeight; } else if ((~view->flags & ES_LIST_VIEW_COLUMNS) && view->columnHeader) { EsElementDestroy(view->columnHeader); + view->activeColumns.Free(); view->columnHeader = nullptr; view->scroll.fixedViewport[1] = 0; } @@ -2245,7 +2261,7 @@ void EsListViewRemoveAll(EsListView *view, EsListViewIndex group) { int ListViewColumnHeaderItemMessage(EsElement *element, EsMessage *message) { EsListView *view = (EsListView *) element->parent->parent; - EsListViewColumn *column = view->columns + element->userData.u; + ListViewColumn *column = &view->registeredColumns[element->userData.u]; if (message->type == ES_MSG_PAINT) { EsMessage m = { ES_MSG_LIST_VIEW_GET_COLUMN_SORT }; @@ -2267,59 +2283,67 @@ int ListViewColumnHeaderItemMessage(EsElement *element, EsMessage *message) { return ES_HANDLED; } -void EsListViewSetColumns(EsListView *view, EsListViewColumn *columns, size_t columnCount) { - EsMessageMutexCheck(); +int ListViewColumnSplitterMessage(EsElement *element, EsMessage *message) { + EsListView *view = (EsListView *) element->parent->parent; + ListViewColumn *column = &view->registeredColumns[element->userData.u]; - EsAssert(view->flags & ES_LIST_VIEW_COLUMNS); // List view does not have columns flag set. + if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { + view->columnResizingOriginalWidth = column->width * theming.scale; + } else if (message->type == ES_MSG_MOUSE_LEFT_DRAG) { + int width = message->mouseDragged.newPositionX - message->mouseDragged.originalPositionX + view->columnResizingOriginalWidth; + int minimumWidth = element->style->metrics->minimumWidth; + if (width < minimumWidth) width = minimumWidth; + column->width = width / theming.scale; + ListViewCalculateTotalColumnWidth(view); + EsElementRelayout(element->parent); + EsElementRelayout(view); + } else { + return 0; + } + return ES_HANDLED; +} + +void EsListViewAddAllColumns(EsListView *view) { EsElementDestroyContents(view->columnHeader); + view->activeColumns.Free(); - view->columns = columns; - view->columnCount = columnCount; - - for (uintptr_t i = 0; i < columnCount; i++) { - EsElement *columnHeaderItem = EsCustomElementCreate(view->columnHeader, ES_CELL_FILL, - (columns[i].flags & ES_LIST_VIEW_COLUMN_HAS_MENU) ? ES_STYLE_LIST_COLUMN_HEADER_ITEM_HAS_MENU : ES_STYLE_LIST_COLUMN_HEADER_ITEM); + for (uintptr_t i = 0; i < view->registeredColumns.Length(); i++) { + view->activeColumns.Add(i); + EsStyle *style = (view->registeredColumns[i].flags & ES_LIST_VIEW_COLUMN_HAS_MENU) ? ES_STYLE_LIST_COLUMN_HEADER_ITEM_HAS_MENU : ES_STYLE_LIST_COLUMN_HEADER_ITEM; + EsElement *columnHeaderItem = EsCustomElementCreate(view->columnHeader, ES_CELL_FILL, style); columnHeaderItem->messageUser = ListViewColumnHeaderItemMessage; columnHeaderItem->cName = "column header item"; columnHeaderItem->userData = i; - if (!columns[i].width) { - columns[i].width = (i ? view->secondaryCellStyle : view->primaryCellStyle)->preferredWidth / theming.scale; - } - EsElement *splitter = EsCustomElementCreate(view->columnHeader, ES_CELL_FILL, ES_STYLE_LIST_COLUMN_HEADER_SPLITTER); - - splitter->messageUser = [] (EsElement *element, EsMessage *message) { - EsListViewColumn *column = (EsListViewColumn *) element->userData.p; - EsListView *view = (EsListView *) element->parent->parent; - - if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { - view->columnResizingOriginalWidth = column->width * theming.scale; - } else if (message->type == ES_MSG_MOUSE_LEFT_DRAG) { - int width = message->mouseDragged.newPositionX - message->mouseDragged.originalPositionX + view->columnResizingOriginalWidth; - int minimumWidth = element->style->metrics->minimumWidth; - if (width < minimumWidth) width = minimumWidth; - column->width = width / theming.scale; - ListViewCalculateTotalColumnWidth(view); - EsElementRelayout(element->parent); - EsElementRelayout(view); - } else { - return 0; - } - - return ES_HANDLED; - }, - + splitter->messageUser = ListViewColumnSplitterMessage; splitter->cName = "column header splitter"; - splitter->userData = columns + i; + splitter->userData = i; } ListViewCalculateTotalColumnWidth(view); view->scroll.Refresh(); } +void EsListViewRegisterColumn(EsListView *view, uint32_t id, const char *title, ptrdiff_t titleBytes, uint32_t flags, double initialWidth) { + EsMessageMutexCheck(); + EsAssert(view->flags & ES_LIST_VIEW_COLUMNS); // List view does not have columns flag set. + + if (!initialWidth) { + initialWidth = (view->registeredColumns.Length() ? view->secondaryCellStyle : view->primaryCellStyle)->preferredWidth / theming.scale; + } + + ListViewColumn column = {}; + column.id = id; + column.flags = flags; + column.width = initialWidth; + if (titleBytes == -1) titleBytes = EsCStringLength(title); + HeapDuplicate((void **) &column.title, &column.titleBytes, title, titleBytes); + view->registeredColumns.Add(column); +} + void EsListViewContentChanged(EsListView *view) { EsMessageMutexCheck(); diff --git a/desktop/os.header b/desktop/os.header index 46989d9..8da9e55 100644 --- a/desktop/os.header +++ b/desktop/os.header @@ -1417,12 +1417,6 @@ struct EsCommand { STRING title; }; -struct EsListViewColumn { - STRING title; - uint32_t flags; - double width; -}; - struct EsApplicationStartupRequest { int64_t id; STRING filePath; @@ -1642,8 +1636,8 @@ struct EsMessageGetContent { EsListViewIndex group; uint32_t icon; uint32_t drawContentFlags; + uint32_t columnID; EsBuffer *buffer; - uint8_t column; }; struct EsMessageGetIndent { @@ -2570,7 +2564,8 @@ function EsListView *EsListViewCreate(EsElement *parent, uint64_t flags = ES_FLA function EsListViewIndex EsListViewGetIndexFromItem(EsElement *element, EsListViewIndex *group = ES_NULL); function void EsListViewEnumerateVisibleItems(EsListView *view, EsListViewEnumerateVisibleItemsCallback callback); -function void EsListViewSetColumns(EsListView *view, EsListViewColumn *columns, size_t columnCount); +function void EsListViewRegisterColumn(EsListView *view, uint32_t id, STRING title = BLANK_STRING, uint32_t flags = ES_FLAGS_DEFAULT, double initialWidth = 0); +function void EsListViewAddAllColumns(EsListView *view); // Call after registering the columns to add them to the header. Call again after EsListViewChangeStyles, as needed. function void EsListViewSetEmptyMessage(EsListView *view, STRING message = BLANK_STRING); function void EsListViewSetMaximumItemsPerBand(EsListView *view, int maximumItemsPerBand); function void EsListViewSelectNone(EsListView *view); diff --git a/desktop/styles.header b/desktop/styles.header index d5df4d6..615a2f7 100644 --- a/desktop/styles.header +++ b/desktop/styles.header @@ -119,3 +119,4 @@ private define ES_STYLE_SCROLLBAR_THUMB_VERTICAL (ES_STYLE_CAST(1369)) define ES_STYLE_TOOLBAR_SPACER (ES_STYLE_CAST(5)) define ES_STYLE_TOOLBAR_BUTTON_GROUP_SEPARATOR (ES_STYLE_CAST(7)) define ES_STYLE_TOOLBAR_SPACER_SMALL (ES_STYLE_CAST(3)) +define ES_STYLE_LIST_CHOICE_ITEM_2X (ES_STYLE_CAST(9)) diff --git a/res/Theme Source.dat b/res/Theme Source.dat index 2c75f1e840e0f179313a634abe79141431ddf188..6651c749bc7e69c05f65bab393d9fa6b952aad79 100644 GIT binary patch delta 349 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 delta 5653 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