introduce EsListViewFixedItemSortAll; use fixed item API in System Monitor

This commit is contained in:
nakst 2021-11-26 18:05:09 +00:00
parent 8a3bd28c92
commit b5692266f7
6 changed files with 105 additions and 69 deletions

View File

@ -63,7 +63,7 @@ void _start() {
"Age", -1, // Its title string.
ES_LIST_VIEW_COLUMN_HAS_MENU // Column header has a menu.
| ES_TEXT_H_RIGHT // Align the text in the column to the right.
| ES_DRAW_CONTENT_TABULAR // Use the tabular digits style, so that digits between items line up.
| ES_DRAW_CONTENT_TABULAR // Use the tabular digits style, so that digits line up between rows.
| ES_LIST_VIEW_COLUMN_FIXED_DATA_INTEGERS // We're storing integers in this column (the default is strings).
| ES_LIST_VIEW_COLUMN_FIXED_SORT_SIZE, // The items in the column can be sorted by their size.
100); // Initial width.

View File

@ -26,6 +26,13 @@ struct Instance : EsInstance {
#define DISPLAY_GENERAL_LOG (3)
#define DISPLAY_MEMORY (12)
#define PROCESSES_COLUMN_NAME (0)
#define PROCESSES_COLUMN_PID (1)
#define PROCESSES_COLUMN_MEMORY (2)
#define PROCESSES_COLUMN_CPU (3)
#define PROCESSES_COLUMN_HANDLES (4)
#define PROCESSES_COLUMN_THREADS (5)
const EsStyle styleMonospacedTextbox = {
.inherit = ES_STYLE_TEXTBOX_NO_BORDER,
@ -156,7 +163,8 @@ void UpdateProcesses(Instance *instance) {
for (uintptr_t i = 0; i < previous.Length(); i++) {
if (!FindProcessByPID(processes, previous[i].data.pid)) {
EsListViewRemove(instance->listViewProcesses, 0, i, 1);
bool found = EsListViewFixedItemRemove(instance->listViewProcesses, previous[i].data.pid);
EsAssert(found);
previous.Delete(i--);
}
}
@ -194,11 +202,21 @@ void UpdateProcesses(Instance *instance) {
for (uintptr_t i = 0; i < processes.Length(); i++) {
if (!FindProcessByPID(previous, processes[i].data.pid)) {
EsListViewInsert(instance->listViewProcesses, 0, i, 1);
EsListViewIndex index = EsListViewFixedItemInsert(instance->listViewProcesses, processes[i].data.pid);
EsAssert(index == (EsListViewIndex) i);
}
}
EsListViewInvalidateAll(instance->listViewProcesses);
for (uintptr_t i = 0; i < processes.Length(); i++) {
EsListViewFixedItemSetString (instance->listViewProcesses, i, PROCESSES_COLUMN_NAME, processes[i].data.name, processes[i].data.nameBytes);
EsListViewFixedItemSetInteger(instance->listViewProcesses, i, PROCESSES_COLUMN_PID, processes[i].data.pid);
EsListViewFixedItemSetInteger(instance->listViewProcesses, i, PROCESSES_COLUMN_MEMORY, processes[i].data.memoryUsage);
EsListViewFixedItemSetInteger(instance->listViewProcesses, i, PROCESSES_COLUMN_CPU, processes[i].cpuUsage);
EsListViewFixedItemSetInteger(instance->listViewProcesses, i, PROCESSES_COLUMN_HANDLES, processes[i].data.handleCount);
EsListViewFixedItemSetInteger(instance->listViewProcesses, i, PROCESSES_COLUMN_THREADS, processes[i].data.threadCount);
}
EsListViewFixedItemSortAll(instance->listViewProcesses);
EsCommandSetDisabled(&instance->commandTerminateProcess, selectedPID < 0 || !FindProcessByPID(processes, selectedPID));
EsTimerSet(REFRESH_INTERVAL, [] (EsGeneric context) {
@ -305,17 +323,7 @@ void UpdateDisplay(Instance *instance, int index) {
#define GET_CONTENT(...) EsBufferFormat(message->getContent.buffer, __VA_ARGS__)
int ListViewProcessesCallback(EsElement *element, EsMessage *message) {
if (message->type == ES_MSG_LIST_VIEW_GET_CONTENT) {
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); }
else if (column == 2) GET_CONTENT("%D", item->data.memoryUsage);
else if (column == 3) GET_CONTENT("%d%%", item->cpuUsage);
else if (column == 4) GET_CONTENT("%d", item->data.handleCount);
else if (column == 5) GET_CONTENT("%d", item->data.threadCount);
else EsAssert(false);
} else if (message->type == ES_MSG_LIST_VIEW_IS_SELECTED) {
if (message->type == ES_MSG_LIST_VIEW_IS_SELECTED) {
message->selectItem.isSelected = processes[message->selectItem.index].data.pid == selectedPID;
} else if (message->type == ES_MSG_LIST_VIEW_SELECT && message->selectItem.isSelected) {
selectedPID = processes[message->selectItem.index].data.pid;
@ -370,16 +378,17 @@ void ProcessApplicationMessage(EsMessage *message) {
instance->textboxGeneralLog = EsTextboxCreate(switcher, ES_TEXTBOX_MULTILINE | ES_CELL_FILL | ES_ELEMENT_DISABLED, &styleMonospacedTextbox);
instance->listViewProcesses = EsListViewCreate(switcher, ES_CELL_FILL | ES_LIST_VIEW_COLUMNS | ES_LIST_VIEW_SINGLE_SELECT);
instance->listViewProcesses = EsListViewCreate(switcher, ES_CELL_FILL | ES_LIST_VIEW_COLUMNS | ES_LIST_VIEW_SINGLE_SELECT | ES_LIST_VIEW_FIXED_ITEMS);
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);
EsListViewRegisterColumn(instance->listViewProcesses, PROCESSES_COLUMN_NAME, "Name", -1, ES_LIST_VIEW_COLUMN_HAS_MENU, 150);
uint32_t numericColumnFlags = ES_LIST_VIEW_COLUMN_HAS_MENU | ES_TEXT_H_RIGHT | ES_DRAW_CONTENT_TABULAR
| ES_LIST_VIEW_COLUMN_FIXED_DATA_INTEGERS | ES_LIST_VIEW_COLUMN_FIXED_SORT_SIZE;
EsListViewRegisterColumn(instance->listViewProcesses, PROCESSES_COLUMN_PID, "PID", -1, numericColumnFlags, 120);
EsListViewRegisterColumn(instance->listViewProcesses, PROCESSES_COLUMN_MEMORY, "Memory", -1, numericColumnFlags | ES_LIST_VIEW_COLUMN_FIXED_FORMAT_BYTES, 120);
EsListViewRegisterColumn(instance->listViewProcesses, PROCESSES_COLUMN_CPU, "CPU", -1, numericColumnFlags | ES_LIST_VIEW_COLUMN_FIXED_FORMAT_PERCENTAGE, 120);
EsListViewRegisterColumn(instance->listViewProcesses, PROCESSES_COLUMN_HANDLES, "Handles", -1, numericColumnFlags, 120);
EsListViewRegisterColumn(instance->listViewProcesses, PROCESSES_COLUMN_THREADS, "Threads", -1, numericColumnFlags, 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);

View File

@ -11,12 +11,11 @@
// TODO Close menus within menus (bug).
// TODO Keyboard navigation - menus; escape to restore default focus.
// TODO Middle click panning.
// TODO Scrollbar middle click and zooming; scroll wheel.
// TODO Scrollbar middle click and zooming.
// TODO Textboxes: date/time overlays, keyboard shortcut overlay, custom overlays.
// TODO Breadcrumb bar overflow menu; keep hover after recreating UI.
// TODO Textbox embedded objects.
// TODO Closing windows in menu/access key mode.
// TODO Ignore ES_MSG_LAYOUT in panels if layout.sizeChanged is false?
// 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.

View File

@ -61,6 +61,8 @@ struct ListViewColumn {
size_t enumStringCount;
};
typedef void (*ListViewSortFunction)(EsListViewIndex *, size_t, ListViewColumn *);
int ListViewProcessItemMessage(EsElement *element, EsMessage *message);
void ListViewSetSortAscending(EsMenu *menu, EsGeneric context);
void ListViewSetSortDescending(EsMenu *menu, EsGeneric context);
@ -2582,6 +2584,42 @@ void EsListViewInvalidateContent(EsListView *view, EsListViewIndex group, EsList
}
}
#define LIST_VIEW_SORT_FUNCTION(_name, _line) \
ES_MACRO_SORT(_name, EsListViewIndex, { \
ListViewFixedItemData *left = (ListViewFixedItemData *) &context->items[*_left]; \
ListViewFixedItemData *right = (ListViewFixedItemData *) &context->items[*_right]; \
result = _line; \
}, ListViewColumn *)
LIST_VIEW_SORT_FUNCTION(ListViewSortByStringsAscending, EsStringCompare(left->s.string, left->s.bytes, right->s.string, right->s.bytes));
LIST_VIEW_SORT_FUNCTION(ListViewSortByStringsDescending, -EsStringCompare(left->s.string, left->s.bytes, right->s.string, right->s.bytes));
LIST_VIEW_SORT_FUNCTION(ListViewSortByEnumsAscending, EsStringCompare(context->enumStrings[left->i].string, context->enumStrings[left->i].stringBytes,
context->enumStrings[right->i].string, context->enumStrings[right->i].stringBytes));
LIST_VIEW_SORT_FUNCTION(ListViewSortByEnumsDescending, -EsStringCompare(context->enumStrings[left->i].string, context->enumStrings[left->i].stringBytes,
context->enumStrings[right->i].string, context->enumStrings[right->i].stringBytes));
LIST_VIEW_SORT_FUNCTION(ListViewSortByIntegersAscending, left->i > right->i ? 1 : left->i == right->i ? 0 : -1);
LIST_VIEW_SORT_FUNCTION(ListViewSortByIntegersDescending, left->i < right->i ? 1 : left->i == right->i ? 0 : -1);
LIST_VIEW_SORT_FUNCTION(ListViewSortByDoublesAscending, left->d > right->d ? 1 : left->d == right->d ? 0 : -1);
LIST_VIEW_SORT_FUNCTION(ListViewSortByDoublesDescending, left->d < right->d ? 1 : left->d == right->d ? 0 : -1);
ListViewSortFunction ListViewGetSortFunction(ListViewColumn *column, uint8_t direction) {
if ((column->flags & ES_LIST_VIEW_COLUMN_FIXED_DATA_MASK) == ES_LIST_VIEW_COLUMN_FIXED_DATA_STRINGS) {
return (direction == LIST_SORT_DIRECTION_DESCENDING ? ListViewSortByStringsDescending : ListViewSortByStringsAscending);
} else if ((column->flags & ES_LIST_VIEW_COLUMN_FIXED_DATA_MASK) == ES_LIST_VIEW_COLUMN_FIXED_DATA_INTEGERS) {
if ((column->flags & ES_LIST_VIEW_COLUMN_FIXED_FORMAT_MASK) == ES_LIST_VIEW_COLUMN_FIXED_FORMAT_ENUM_STRING) {
return (direction == LIST_SORT_DIRECTION_DESCENDING ? ListViewSortByEnumsDescending : ListViewSortByEnumsAscending);
} else {
return (direction == LIST_SORT_DIRECTION_DESCENDING ? ListViewSortByIntegersDescending : ListViewSortByIntegersAscending);
}
} else if ((column->flags & ES_LIST_VIEW_COLUMN_FIXED_DATA_MASK) == ES_LIST_VIEW_COLUMN_FIXED_DATA_DOUBLES) {
return (direction == LIST_SORT_DIRECTION_DESCENDING ? ListViewSortByDoublesDescending : ListViewSortByDoublesAscending);
} else {
EsAssert(false);
}
return nullptr;
}
EsListViewIndex EsListViewFixedItemInsert(EsListView *view, EsGeneric data, EsListViewIndex index, uint32_t iconID) {
EsAssert(view->flags & ES_LIST_VIEW_FIXED_ITEMS);
@ -2643,12 +2681,32 @@ void ListViewFixedItemSetInternal(EsListView *view, EsListViewIndex index, uint3
EsMemoryZero(&column->items[oldLength], (view->fixedItems.Length() - oldLength) * sizeof(column->items[0]));
}
bool changed = false;
if (dataType == ES_LIST_VIEW_COLUMN_FIXED_DATA_STRINGS) {
changed = EsStringCompareRaw(column->items[index].s.string, column->items[index].s.bytes, data.s.string, data.s.bytes);
} else if (dataType == ES_LIST_VIEW_COLUMN_FIXED_DATA_DOUBLES) {
changed = column->items[index].d != data.d;
} else if (dataType == ES_LIST_VIEW_COLUMN_FIXED_DATA_INTEGERS) {
changed = column->items[index].i != data.i;
} else {
EsAssert(false);
}
if (dataType == ES_LIST_VIEW_COLUMN_FIXED_DATA_STRINGS) {
EsHeapFree(column->items[index].s.string);
}
column->items[index] = data;
EsListViewInvalidateContent(view, 0, index);
if (changed) {
for (uintptr_t i = 0; i < view->fixedItemIndices.Length(); i++) {
if (view->fixedItemIndices[i] == index) {
EsListViewInvalidateContent(view, 0, i);
break;
}
}
}
}
void EsListViewFixedItemSetString(EsListView *view, EsListViewIndex index, uint32_t columnID, const char *string, ptrdiff_t stringBytes) {
@ -2765,29 +2823,11 @@ void EsListViewFixedItemSetEnumStringsForColumn(EsListView *view, uint32_t colum
EsAssert(false);
}
#define LIST_VIEW_SORT_FUNCTION(_name, _line) \
ES_MACRO_SORT(_name, EsListViewIndex, { \
ListViewFixedItemData *left = (ListViewFixedItemData *) &context->items[*_left]; \
ListViewFixedItemData *right = (ListViewFixedItemData *) &context->items[*_right]; \
result = _line; \
}, ListViewColumn *)
LIST_VIEW_SORT_FUNCTION(ListViewSortByStringsAscending, EsStringCompare(left->s.string, left->s.bytes, right->s.string, right->s.bytes));
LIST_VIEW_SORT_FUNCTION(ListViewSortByStringsDescending, -EsStringCompare(left->s.string, left->s.bytes, right->s.string, right->s.bytes));
LIST_VIEW_SORT_FUNCTION(ListViewSortByEnumsAscending, EsStringCompare(context->enumStrings[left->i].string, context->enumStrings[left->i].stringBytes,
context->enumStrings[right->i].string, context->enumStrings[right->i].stringBytes));
LIST_VIEW_SORT_FUNCTION(ListViewSortByEnumsDescending, -EsStringCompare(context->enumStrings[left->i].string, context->enumStrings[left->i].stringBytes,
context->enumStrings[right->i].string, context->enumStrings[right->i].stringBytes));
LIST_VIEW_SORT_FUNCTION(ListViewSortByIntegersAscending, left->i > right->i ? 1 : left->i == right->i ? 0 : -1);
LIST_VIEW_SORT_FUNCTION(ListViewSortByIntegersDescending, left->i < right->i ? 1 : left->i == right->i ? 0 : -1);
LIST_VIEW_SORT_FUNCTION(ListViewSortByDoublesAscending, left->d > right->d ? 1 : left->d == right->d ? 0 : -1);
LIST_VIEW_SORT_FUNCTION(ListViewSortByDoublesDescending, left->d < right->d ? 1 : left->d == right->d ? 0 : -1);
void ListViewSetSortDirection(EsListView *view, uint32_t columnID, uint8_t direction) {
void EsListViewFixedItemSortAll(EsListView *view) {
ListViewColumn *column = nullptr;
for (uintptr_t i = 0; i < view->registeredColumns.Length(); i++) {
if (view->registeredColumns[i].id == columnID) {
if (view->registeredColumns[i].id == view->fixedItemSortColumnID) {
column = &view->registeredColumns[i];
break;
}
@ -2795,34 +2835,12 @@ void ListViewSetSortDirection(EsListView *view, uint32_t columnID, uint8_t direc
EsAssert(column);
if (view->fixedItemSortColumnID == columnID && view->fixedItemSortDirection == direction) {
return;
}
view->fixedItemSortColumnID = columnID;
view->fixedItemSortDirection = direction;
EsAssert(view->fixedItems.Length() == view->fixedItemIndices.Length());
void (*sortFunction)(EsListViewIndex *, size_t, ListViewColumn *) = nullptr;
if ((column->flags & ES_LIST_VIEW_COLUMN_FIXED_DATA_MASK) == ES_LIST_VIEW_COLUMN_FIXED_DATA_STRINGS) {
sortFunction = (direction == LIST_SORT_DIRECTION_DESCENDING ? ListViewSortByStringsDescending : ListViewSortByStringsAscending);
} else if ((column->flags & ES_LIST_VIEW_COLUMN_FIXED_DATA_MASK) == ES_LIST_VIEW_COLUMN_FIXED_DATA_INTEGERS) {
if ((column->flags & ES_LIST_VIEW_COLUMN_FIXED_FORMAT_MASK) == ES_LIST_VIEW_COLUMN_FIXED_FORMAT_ENUM_STRING) {
sortFunction = (direction == LIST_SORT_DIRECTION_DESCENDING ? ListViewSortByEnumsDescending : ListViewSortByEnumsAscending);
} else {
sortFunction = (direction == LIST_SORT_DIRECTION_DESCENDING ? ListViewSortByIntegersDescending : ListViewSortByIntegersAscending);
}
} else if ((column->flags & ES_LIST_VIEW_COLUMN_FIXED_DATA_MASK) == ES_LIST_VIEW_COLUMN_FIXED_DATA_DOUBLES) {
sortFunction = (direction == LIST_SORT_DIRECTION_DESCENDING ? ListViewSortByDoublesDescending : ListViewSortByDoublesAscending);
} else {
EsAssert(false);
}
EsListViewIndex previousSelectionIndex = view->fixedItemSelection >= 0 && (uintptr_t) view->fixedItemSelection < view->fixedItemIndices.Length()
? view->fixedItemIndices[view->fixedItemSelection] : -1;
ListViewSortFunction sortFunction = ListViewGetSortFunction(column, view->fixedItemSortDirection);
sortFunction(view->fixedItemIndices.array, view->fixedItems.Length(), column);
EsListViewInvalidateAll(view);
@ -2838,6 +2856,14 @@ void ListViewSetSortDirection(EsListView *view, uint32_t columnID, uint8_t direc
}
}
void ListViewSetSortDirection(EsListView *view, uint32_t columnID, uint8_t direction) {
if (view->fixedItemSortColumnID != columnID || view->fixedItemSortDirection != direction) {
view->fixedItemSortColumnID = columnID;
view->fixedItemSortDirection = direction;
EsListViewFixedItemSortAll(view);
}
}
void ListViewSetSortAscending(EsMenu *menu, EsGeneric context) {
ListViewSetSortDirection((EsListView *) menu->userData.p, context.u, LIST_SORT_DIRECTION_ASCENDING);
}

View File

@ -2626,3 +2626,4 @@ function void EsListViewFixedItemSetInteger(EsListView *view, EsListViewIndex in
function bool EsListViewFixedItemSelect(EsListView *view, EsGeneric data); // Returns false if the item was not found.
function bool EsListViewFixedItemGetSelected(EsListView *view, EsGeneric *data); // Returns false if no item was selected.
function void EsListViewFixedItemSetEnumStringsForColumn(EsListView *view, uint32_t columnID, const EsListViewEnumString *strings, size_t stringCount);
function void EsListViewFixedItemSortAll(EsListView *view); // Re-sort the list after inserting new items or modifying existing items. TODO EsListViewFixedItemSortSingleItem.

View File

@ -142,6 +142,7 @@ EsMutexAcquire=140
EsMutexDestroy=141
EsMutexRelease=142
EsListViewAddAllColumns=143
EsListViewFixedItemSortAll=144
EsSchedulerYield=145
EsSleep=146
EsSpinlockAcquire=147