/* Copyright (c) 2021 Alex Diener This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Alex Diener alex@ludobloom.com */ #include "shell/ShellKeyCodes.h" #include "uitoolkit/UITextListView.h" #include "uitoolkit/UIToolkitAppearance.h" #include "uitoolkit/UIToolkitContext.h" #include "uitoolkit/UIToolkitDrawing.h" #include #define stemobject_implementation UITextListView stemobject_vtable_begin(); stemobject_vtable_entry(dispose); stemobject_vtable_entry(getLineCount); stemobject_vtable_entry(drawLine); stemobject_vtable_entry(setItems); stemobject_vtable_entry(setSelectedItemIdentifier); stemobject_vtable_entry(getSelectedItemIdentifier); stemobject_vtable_entry(selectItemWithIdentifier); stemobject_vtable_entry(deselectItemWithIdentifier); stemobject_vtable_entry(getSelectedItemIdentifiers); stemobject_vtable_entry(getSelectedItemIdentifierAtIndex); stemobject_vtable_end(); #define TEXT_X_PADDING 4 UITextListView * UITextListView_create(unsigned int itemCount, struct UITextListView_item * items, Vector2f position, Vector2f relativeOrigin, float width, unsigned int displayedLineCount, UIListViewSelectMode selectMode, UIListViewActionCallback actionCallback, UIListViewSelectionChangedCallback selectionChangedCallback, UIListViewDeleteLineCallback deleteLineCallback, void * callbackContext, UIAppearance appearance) { stemobject_create_implementation(init, itemCount, items, position, relativeOrigin, width, displayedLineCount, selectMode, actionCallback, selectionChangedCallback, deleteLineCallback, callbackContext, appearance) } static void disposeItems(UITextListView * self) { for (unsigned int itemIndex = 0; itemIndex < self->itemCount; itemIndex++) { String_free(self->items[itemIndex].text); } free(self->items); } static void assignItems(UITextListView * self, unsigned int itemCount, struct UITextListView_item * items) { self->itemCount = itemCount; self->items = malloc(itemCount * sizeof(*self->items)); for (unsigned int itemIndex = 0; itemIndex < itemCount; itemIndex++) { self->items[itemIndex].text = String_copy(items[itemIndex].text); self->items[itemIndex].identifier = items[itemIndex].identifier; } } bool UITextListView_init(UITextListView * self, unsigned int itemCount, struct UITextListView_item * items, Vector2f position, Vector2f relativeOrigin, float width, unsigned int displayedLineCount, UIListViewSelectMode selectMode, UIListViewActionCallback actionCallback, UIListViewSelectionChangedCallback selectionChangedCallback, UIListViewDeleteLineCallback deleteLineCallback, void * callbackContext, UIAppearance appearance) { UITypeface * typeface = UIToolkit_getUITypeface(appearance, UIToolkit_currentContext()->drawingInterface); float lineHeight = call_virtual(getLineHeight, typeface); call_super(init, self, position, relativeOrigin, width, lineHeight + getAppearanceFloat(appearance, UITextListView_linePadding), displayedLineCount, selectMode, actionCallback, selectionChangedCallback, deleteLineCallback, callbackContext, appearance); assignItems(self, itemCount, items); return true; } void UITextListView_dispose(UITextListView * self) { disposeItems(self); call_super_virtual(dispose, self); } unsigned int UITextListView_getLineCount(UITextListView * self) { return self->itemCount; } void UITextListView_drawLine(UITextListView * self, unsigned int lineIndex, Rect4f lineBounds, UIDrawingInterface * drawingInterface, VertexIO * vertexIO) { call_super_virtual(drawLine, self, lineIndex, lineBounds, drawingInterface, vertexIO); unsigned int lastIndex = vertexIO->indexCount; UITypeface * typeface = UIToolkit_getUITypeface(self->appearance, drawingInterface); call_virtual(drawString, drawingInterface, typeface, self->items[lineIndex].text, VECTOR2f(lineBounds.xMin + TEXT_X_PADDING, lineBounds.yMin + self->lineHeight / 2), VECTOR2f(0.0f, 0.5f), 1.0f, getAppearanceColor4f(self->appearance, UITextListView_textColor), vertexIO); clipVerticesInsideRect(lastIndex, vertexIO->indexCount - lastIndex, lineBounds, vertexIO); } void UITextListView_setItems(UITextListView * self, unsigned int itemCount, struct UITextListView_item * items) { int selectedIdentifier = UITextListView_getSelectedItemIdentifier(self); unsigned int selectedItemCount = 0; int * selectedItemIdentifiers = NULL; if (self->selectMode == SELECT_MODE_MULTIPLE) { selectedItemCount = UITextListView_getSelectedItemIdentifiers(self, NULL, self->itemCount, 0); selectedItemIdentifiers = malloc(selectedItemCount * sizeof(*selectedItemIdentifiers)); UITextListView_getSelectedItemIdentifiers(self, selectedItemIdentifiers, selectedItemCount, 0); } disposeItems(self); assignItems(self, itemCount, items); if (self->selectMode == SELECT_MODE_MULTIPLE) { call_virtual(clearSelection, self); for (unsigned int identifierIndex = 0; identifierIndex < selectedItemCount; identifierIndex++) { UITextListView_selectItemWithIdentifier(self, selectedItemIdentifiers[identifierIndex]); } free(selectedItemIdentifiers); } else { UITextListView_setSelectedItemIdentifier(self, selectedIdentifier); } } void UITextListView_setSelectedItemIdentifier(UITextListView * self, int identifier) { IndexSelection_deselectAll(self->selection); for (unsigned int itemIndex = 0; itemIndex < self->itemCount; itemIndex++) { if (self->items[itemIndex].identifier == identifier) { self->selectedLineIndex = itemIndex; IndexSelection_selectIndex(self->selection, itemIndex, true); return; } } self->selectedLineIndex = ITEM_INDEX_NONE; } int UITextListView_getSelectedItemIdentifier(UITextListView * self) { if (self->selectedLineIndex >= self->itemCount) { return ITEM_IDENTIFIER_NONE; } return self->items[self->selectedLineIndex].identifier; } void UITextListView_selectItemWithIdentifier(UITextListView * self, int identifier) { if (self->selectMode == SELECT_MODE_MULTIPLE) { for (unsigned int itemIndex = 0; itemIndex < self->itemCount; itemIndex++) { if (self->items[itemIndex].identifier == identifier) { call_virtual(selectLineAtIndex, self, itemIndex); } } } } void UITextListView_deselectItemWithIdentifier(UITextListView * self, int identifier) { if (self->selectMode == SELECT_MODE_MULTIPLE) { for (unsigned int itemIndex = 0; itemIndex < self->itemCount; itemIndex++) { if (self->items[itemIndex].identifier == identifier) { call_virtual(deselectLineAtIndex, self, itemIndex); } } } } unsigned int UITextListView_getSelectedItemIdentifiers(UITextListView * self, int * outItemIdentifiers, unsigned int countMax, unsigned int offset) { switch (self->selectMode) { case SELECT_MODE_NONE: return 0; case SELECT_MODE_SINGLE: case SELECT_MODE_SINGLE_NO_DESELECT: if (self->selectedLineIndex >= self->itemCount) { return 0; } if (outItemIdentifiers != NULL) { outItemIdentifiers[0] = self->items[self->selectedLineIndex].identifier; } return 1; case SELECT_MODE_MULTIPLE: { unsigned int selectedCount = 0; unsigned int itemsWritten = 0; for (unsigned int itemIndex = 0; itemIndex < self->itemCount; itemIndex++) { if (call_virtual(isLineSelected, self, itemIndex)) { if (selectedCount >= offset) { if (outItemIdentifiers != NULL) { outItemIdentifiers[itemsWritten] = self->items[itemIndex].identifier; } itemsWritten++; } selectedCount++; } } return itemsWritten; } } return 0; } int UITextListView_getSelectedItemIdentifierAtIndex(UITextListView * self, unsigned int index) { switch (self->selectMode) { case SELECT_MODE_NONE: return ITEM_IDENTIFIER_NONE; case SELECT_MODE_SINGLE: case SELECT_MODE_SINGLE_NO_DESELECT: if (index == 0) { return UITextListView_getSelectedItemIdentifier(self); } return ITEM_IDENTIFIER_NONE; case SELECT_MODE_MULTIPLE: { unsigned int selectedCount = 0; for (unsigned int itemIndex = 0; itemIndex < self->itemCount; itemIndex++) { if (call_virtual(isLineSelected, self, itemIndex)) { if (selectedCount == index) { return self->items[itemIndex].identifier; } selectedCount++; } } } } return ITEM_IDENTIFIER_NONE; }