add support for icons in the table widget (WinUI3) newapi

Fri, 13 Oct 2023 15:20:54 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 13 Oct 2023 15:20:54 +0200
branch
newapi
changeset 215
1bd5534c395d
parent 214
279c0c81d3b1
child 216
391c2c723029

add support for icons in the table widget (WinUI3)

make/vs/testapp/main.c file | annotate | diff | comparison | revisions
ui/common/types.c file | annotate | diff | comparison | revisions
ui/common/types.h file | annotate | diff | comparison | revisions
ui/ui/image.h file | annotate | diff | comparison | revisions
ui/ui/toolkit.h file | annotate | diff | comparison | revisions
ui/ui/tree.h file | annotate | diff | comparison | revisions
ui/winui/icons.cpp file | annotate | diff | comparison | revisions
ui/winui/icons.h file | annotate | diff | comparison | revisions
ui/winui/table.cpp file | annotate | diff | comparison | revisions
ui/winui/table.h file | annotate | diff | comparison | revisions
--- a/make/vs/testapp/main.c	Fri Oct 13 11:26:47 2023 +0200
+++ b/make/vs/testapp/main.c	Fri Oct 13 15:20:54 2023 +0200
@@ -48,6 +48,8 @@
     UiList* list3;
 } WindowData;
 
+static UiIcon* folder_icon;
+
 void action1(UiEvent* event, void* data) {
     char* action = data;
     
@@ -105,9 +107,10 @@
 void* table_getvalue(void* data, int i) {
     TableData* t = data;
     switch (i) {
-    case 0: return t->col1;
-    case 1: return t->col2;
-    case 2: return t->col3;
+    case 0: return folder_icon;
+    case 1: return t->col1;
+    case 2: return t->col2;
+    case 3: return t->col3;
     }
     return NULL;
 }
@@ -160,6 +163,7 @@
     ui_list_append(wdata->list3, "test");
     ui_list_append(wdata->list3, "dir");
 
+    folder_icon = ui_icon("Folder", 32);
 
     TableData* td1 = malloc(sizeof(TableData));
     TableData* td2 = malloc(sizeof(TableData));
@@ -263,7 +267,7 @@
 
             ui_newline(obj);
 
-            UiModel* model = ui_model(obj->ctx, UI_STRING, "Col 1", UI_STRING, "Col 2", UI_STRING, "Col 3", -1);
+            UiModel* model = ui_model(obj->ctx, UI_ICON_TEXT, "Col 1", UI_STRING, "Col 2", UI_STRING, "Col 3", -1);
             model->getvalue = table_getvalue;
             ui_table(obj, .colspan = 3, .model = model, .list = wdata->list2);
             ui_model_free(obj->ctx, model);
--- a/ui/common/types.c	Fri Oct 13 11:26:47 2023 +0200
+++ b/ui/common/types.c	Fri Oct 13 15:20:54 2023 +0200
@@ -204,10 +204,28 @@
     return info;
 }
 
+UiModel* ui_model_copy(UiContext *ctx, UiModel* model) {
+    const CxAllocator* a = ctx ? ctx->allocator : cxDefaultAllocator;
+
+    UiModel* newmodel = cxMalloc(a, sizeof(UiModel));
+    *newmodel = *model;
+
+    newmodel->types = cxCalloc(a, model->columns, sizeof(UiModelType));
+    memcpy(newmodel->types, model->types, model->columns);
+
+    newmodel->titles = cxCalloc(a, model->columns, sizeof(char*));
+    for (int i = 0; i < model->columns; i++) {
+        newmodel->titles[i] = model->titles[i] ? cx_strdup_a(a, cx_str(model->titles[i])).ptr : NULL;
+    }
+
+    return newmodel;
+}
+
 void ui_model_free(UiContext *ctx, UiModel *mi) {
-    cxFree(ctx->allocator, mi->types);
-    cxFree(ctx->allocator, mi->titles);
-    cxFree(ctx->allocator, mi);
+    const CxAllocator* a = ctx ? ctx->allocator : cxDefaultAllocator;
+    cxFree(a, mi->types);
+    cxFree(a, mi->titles);
+    cxFree(a, mi);
 }
 
 // types
--- a/ui/common/types.h	Fri Oct 13 11:26:47 2023 +0200
+++ b/ui/common/types.h	Fri Oct 13 15:20:54 2023 +0200
@@ -55,7 +55,7 @@
 void uic_text_unbind(UiText *t);
 void uic_range_unbind(UiRange *r);
 void uic_list_unbind(UiList *l);
-    
+  
 #ifdef	__cplusplus
 }
 #endif
--- a/ui/ui/image.h	Fri Oct 13 11:26:47 2023 +0200
+++ b/ui/ui/image.h	Fri Oct 13 15:20:54 2023 +0200
@@ -35,6 +35,13 @@
 extern "C" {
 #endif
 
+	/*
+UIEXPORT UiIcon* ui_icon(const char* name, size_t size);
+UIEXPORT UiIcon* ui_imageicon(const char* file);
+UIEXPORT void ui_icon_free(UiIcon* icon);
+*/
+
+/*
 UiIcon* ui_icon(const char *name, int size);
 UiIcon* ui_icon_unscaled(const char *name, int size);
 void ui_free_icon(UiIcon *icon);
@@ -44,6 +51,7 @@
 UiImage* ui_named_image(const char *filename, const char *name);
 UiImage* ui_load_image_from_path(const char *path, const char *name);
 void ui_free_image(UiImage *img);
+*/
 
 
 #ifdef __cplusplus
--- a/ui/ui/toolkit.h	Fri Oct 13 11:26:47 2023 +0200
+++ b/ui/ui/toolkit.h	Fri Oct 13 15:20:54 2023 +0200
@@ -433,6 +433,14 @@
 UIEXPORT void ui_set_visible(UIWIDGET widget, int visible);
 
 
+
+
+
+UIEXPORT UiIcon* ui_icon(const char* name, size_t size);
+UIEXPORT UiIcon* ui_imageicon(const char* file);
+UIEXPORT void ui_icon_free(UiIcon* icon);
+
+
 #ifdef	__cplusplus
 }
 #endif
--- a/ui/ui/tree.h	Fri Oct 13 11:26:47 2023 +0200
+++ b/ui/ui/tree.h	Fri Oct 13 15:20:54 2023 +0200
@@ -129,6 +129,7 @@
 };
 
 UIEXPORT UiModel* ui_model(UiContext *ctx, ...);
+UIEXPORT UiModel* ui_model_copy(UiContext *ctx, UiModel* model);
 UIEXPORT void ui_model_free(UiContext *ctx, UiModel *mi);
 
 #define ui_listview(obj, ...) ui_listview_create(obj, (UiListArgs) { __VA_ARGS__ } )
--- a/ui/winui/icons.cpp	Fri Oct 13 11:26:47 2023 +0200
+++ b/ui/winui/icons.cpp	Fri Oct 13 15:20:54 2023 +0200
@@ -33,6 +33,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "util.h"
 
 using namespace winrt;
 using namespace Microsoft::UI::Xaml;
@@ -252,3 +253,50 @@
 	SymbolIcon icon = SymbolIcon(symbol);
 	return icon;
 }
+
+
+// symbol icon implementation
+UiSymbolIcon::UiSymbolIcon(winrt::Microsoft::UI::Xaml::Controls::Symbol sym) {
+	symbol = sym;
+}
+
+UiSymbolIcon::~UiSymbolIcon() {
+	
+}
+
+winrt::Microsoft::UI::Xaml::Controls::IconElement UiSymbolIcon::getIcon() {
+	return SymbolIcon(symbol);
+}
+
+// image icon implementation
+UiImageIcon::UiImageIcon(const char* uristr) {
+	wchar_t* wuri = str2wstr(uristr, nullptr);
+	Windows::Foundation::Uri uri{ wuri };
+	this->uri = uri;
+	free(wuri);
+}
+
+UiImageIcon::~UiImageIcon() {
+
+}
+
+winrt::Microsoft::UI::Xaml::Controls::IconElement UiImageIcon::getIcon() {
+	BitmapIcon icon = BitmapIcon();
+	icon.UriSource(uri);
+	return icon;
+}
+
+UIEXPORT UiIcon* ui_icon(const char* name, size_t size) {
+	Symbol symbol = ui_symbol_icons[name];
+	UiSymbolIcon* icon = new UiSymbolIcon(symbol);
+	return icon;
+}
+
+
+UIEXPORT UiIcon* ui_imageicon(const char* file) {
+	return new UiImageIcon(file);
+}
+
+UIEXPORT void ui_icon_free(UiIcon* icon) {
+	delete icon;
+}
--- a/ui/winui/icons.h	Fri Oct 13 11:26:47 2023 +0200
+++ b/ui/winui/icons.h	Fri Oct 13 15:20:54 2023 +0200
@@ -30,12 +30,33 @@
 
 #include "../ui/toolkit.h"
 
+
+
 struct UiIcon {
-	winrt::Microsoft::UI::Xaml::Controls::IconElement icon;
+	//virtual ~UiIcon() = 0;
+	
+	virtual winrt::Microsoft::UI::Xaml::Controls::IconElement getIcon() = 0;
 };
 
-void ui_init_symbol_icons();
+struct UiSymbolIcon : UiIcon {
+	winrt::Microsoft::UI::Xaml::Controls::Symbol symbol;
+
+	UiSymbolIcon(winrt::Microsoft::UI::Xaml::Controls::Symbol sym);
+
+	~UiSymbolIcon();
+
+	winrt::Microsoft::UI::Xaml::Controls::IconElement getIcon();
+};
 
-void ui_add_symbol_icon(std::string name, winrt::Microsoft::UI::Xaml::Controls::Symbol symbol);
+struct UiImageIcon : UiIcon {
+	winrt::Windows::Foundation::Uri uri{ nullptr };
+
+	UiImageIcon(const char* uristr);
+
+	~UiImageIcon();
+
+	winrt::Microsoft::UI::Xaml::Controls::IconElement getIcon();
+};
+
 
 winrt::Microsoft::UI::Xaml::Controls::IconElement ui_get_icon(const char* name);
--- a/ui/winui/table.cpp	Fri Oct 13 11:26:47 2023 +0200
+++ b/ui/winui/table.cpp	Fri Oct 13 15:20:54 2023 +0200
@@ -31,9 +31,11 @@
 #include "table.h"
 #include "container.h"
 #include "util.h"
+#include "icons.h"
 
 #include "../common/context.h"
 #include "../common/object.h"
+#include "../common/types.h"
 
 #include <winrt/Microsoft.UI.Xaml.Data.h>
 #include <winrt/Microsoft.UI.Xaml.Media.h>
@@ -130,7 +132,13 @@
 	);
 }
 
+UiTable::~UiTable() {
+	ui_model_free(NULL, model);
+}
+
 void UiTable::add_header(UiModel* model) {
+	this->model = ui_model_copy(NULL, model);
+
 	GridLength gl;
 	gl.Value = 0;
 	gl.GridUnitType = GridUnitType::Auto;
@@ -174,6 +182,20 @@
 	maxrows = 1;
 }
 
+static void textblock_set_str(TextBlock &t, const char *str) {
+	if (str) {
+		wchar_t* wstr = str2wstr(str, nullptr);
+		t.Text(winrt::hstring(wstr));
+		free(wstr);
+	}
+}
+
+static void textblock_set_int(TextBlock& t, int i) {
+	wchar_t buf[16];
+	swprintf(buf, 16, L"%d", i);
+	t.Text(winrt::hstring(buf));
+}
+
 void UiTable::update(UiList* list,  int i) {
 	if (getvalue == nullptr) {
 		return;
@@ -197,13 +219,66 @@
 			maxrows = row;
 		}
 
-		for (int col = 0; col < header.size(); col++) {
+		Thickness cellpadding = { 10,0,4,0 };
+
+		int model_col = 0;
+		for (int col = 0; col < header.size(); col++, model_col++) {
 			// create ui elements with the correct cell border
 			// dependeing on the column
 			Border cellBorder = Border();
 			cellBorder.Background(defaultBrush);
-			TextBlock cell = TextBlock();
-			cellBorder.Child(cell);
+
+			// set the cell value
+			UiModelType type = model->types[col];
+			switch (type) {
+				case UI_STRING: {
+					TextBlock cell = TextBlock();
+					cell.Padding(cellpadding);
+					cell.VerticalAlignment(VerticalAlignment::Stretch);
+					textblock_set_str(cell, (char*)getvalue(elm, model_col));
+					cellBorder.Child(cell);
+					break;
+				}
+				case UI_INTEGER: {
+					TextBlock cell = TextBlock();
+					cell.Padding(cellpadding);
+					cell.VerticalAlignment(VerticalAlignment::Stretch);
+					int *value = (int*)getvalue(elm, model_col);
+					if (value) {
+						textblock_set_int(cell, *value);
+					}
+					cellBorder.Child(cell);
+					break;
+				}
+				case UI_ICON: {
+					UiIcon* iconConstr = (UiIcon*)getvalue(elm, model_col);
+					if (iconConstr) {
+						IconElement icon = iconConstr->getIcon();
+						cellBorder.Child(icon);
+					}
+					break;
+				}
+				case UI_ICON_TEXT: {
+					StackPanel cellPanel = StackPanel();
+					cellPanel.Spacing(2);
+					cellPanel.Padding(cellpadding);
+					cellPanel.VerticalAlignment(VerticalAlignment::Stretch);
+
+					cellPanel.Orientation(Orientation::Horizontal);
+					UiIcon* iconConstr = (UiIcon*)getvalue(elm, model_col++);
+					char* str = (char*)getvalue(elm, model_col);
+					if (iconConstr) {
+						IconElement icon = iconConstr->getIcon();
+						cellPanel.Children().Append(icon);
+					}
+					TextBlock cell = TextBlock();
+					textblock_set_str(cell, str);
+					cellPanel.Children().Append(cell);
+					cellBorder.Child(cellPanel);
+					break;
+				}
+			}
+			
 			cellBorder.BorderBrush(defaultBrush);
 			if (col == 0) {
 				cellBorder.BorderThickness(b1);
@@ -214,17 +289,6 @@
 			else {
 				cellBorder.BorderThickness(b2);
 			}
-			Thickness padding = { 10,0,4,0 };
-			cell.Padding(padding);
-			cell.VerticalAlignment(VerticalAlignment::Stretch);
-
-			// set cell value
-			char* value = (char*)getvalue(elm, col);
-			if (value) {
-				wchar_t* wstr = str2wstr(value, nullptr);
-				cell.Text(winrt::hstring(wstr));
-				free(wstr);
-			}
 
 			// event handler
 			cellBorder.PointerPressed(
--- a/ui/winui/table.h	Fri Oct 13 11:26:47 2023 +0200
+++ b/ui/winui/table.h	Fri Oct 13 15:20:54 2023 +0200
@@ -45,13 +45,16 @@
 	winrt::Microsoft::UI::Xaml::Media::SolidColorBrush highlightBrush;
 	winrt::Microsoft::UI::Xaml::Media::SolidColorBrush selectedBrush;
 	winrt::Microsoft::UI::Xaml::Media::SolidColorBrush selectedBorderBrush;
+	UiModel* model = nullptr;
 	std::vector<UiTableColumn> header;
-	ui_getvaluefunc getvalue;
-	int maxrows;
-	int lastSelection;
+	ui_getvaluefunc getvalue = nullptr;
+	int maxrows = 0;
+	int lastSelection = 0;
 	std::vector<int> selection;
 
 	UiTable(winrt::Microsoft::UI::Xaml::Controls::ScrollViewer scrollW, winrt::Microsoft::UI::Xaml::Controls::Grid grid);
+
+	~UiTable();
 	
 	void add_header(UiModel* model);
 

mercurial