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 2c75f1e..6651c74 100644 Binary files a/res/Theme Source.dat and b/res/Theme Source.dat differ diff --git a/res/Theme.dat b/res/Theme.dat index e969d98..6301413 100644 Binary files a/res/Theme.dat and b/res/Theme.dat differ diff --git a/util/api_table.ini b/util/api_table.ini index 51a6db8..d44df41 100644 --- a/util/api_table.ini +++ b/util/api_table.ini @@ -137,9 +137,11 @@ EsEventReset=135 EsEventSet=136 EsInstanceCloseReference=137 EsInstanceClose=138 +EsListViewRegisterColumn=139 EsMutexAcquire=140 EsMutexDestroy=141 EsMutexRelease=142 +EsListViewAddAllColumns=143 EsSchedulerYield=145 EsSleep=146 EsSpinlockAcquire=147 @@ -309,7 +311,6 @@ EsFileDelete=311 EsBufferReadInto=312 EsListViewRemoveAll=313 EsSystemShowShutdownDialog=314 -EsListViewSetColumns=315 EsListViewSelect=316 EsUndoClear=317 EsMessageReceive=318