implement table activate/selection events (WinUI3) newapi

Sat, 14 Oct 2023 10:55:11 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sat, 14 Oct 2023 10:55:11 +0200
branch
newapi
changeset 218
d06e7e8e53e1
parent 217
b9798109c7d2
child 219
527a66c0afb2

implement table activate/selection events (WinUI3)

make/vs/testapp/main.c file | annotate | diff | comparison | revisions
ui/winui/icons.cpp 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	Sat Oct 14 10:01:22 2023 +0200
+++ b/make/vs/testapp/main.c	Sat Oct 14 10:55:11 2023 +0200
@@ -270,7 +270,7 @@
 
             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_table(obj, .colspan = 3, .model = model, .list = wdata->list2, .onactivate = action_onactivate, .onselection = action_listselection_changed);
             ui_model_free(obj->ctx, model);
         }
     }   
--- a/ui/winui/icons.cpp	Sat Oct 14 10:01:22 2023 +0200
+++ b/ui/winui/icons.cpp	Sat Oct 14 10:55:11 2023 +0200
@@ -348,6 +348,8 @@
 
 		// convert icon to (gdi) bitmap
 		ICONINFO info;
+		info.hbmColor = nullptr;
+		info.hbmMask = nullptr;
 		if (GetIconInfo(hicon, &info)) {
 			BITMAP bitmap;
 			if (GetObjectW(info.hbmColor, sizeof(BITMAP), &bitmap) != 0) {
@@ -361,11 +363,15 @@
 					memcpy(wb_data, bitmap_data, bitmap_size);
 					wbitmap = wb;
 				}
-				DeleteObject(info.hbmColor);
 				free(bitmap_data);
 			}
+			if (info.hbmMask) {
+				DeleteObject(info.hbmMask);
+			}
+			if (info.hbmColor) {
+				DeleteObject(info.hbmColor);
+			}
 		}
-		DeleteObject(info.hbmMask);
 
 		DestroyIcon(hicon_small);
 		DestroyIcon(hicon_large);
--- a/ui/winui/table.cpp	Sat Oct 14 10:01:22 2023 +0200
+++ b/ui/winui/table.cpp	Sat Oct 14 10:55:11 2023 +0200
@@ -51,6 +51,8 @@
 using namespace winrt::Microsoft::UI::Xaml::Media;
 using namespace winrt::Windows::UI::Xaml::Input;
 
+static UINT ui_double_click_time = GetDoubleClickTime();
+
 extern "C" void reg_table_destructor(UiContext * ctx, UiTable * table) {
 	// TODO:
 }
@@ -66,11 +68,14 @@
 	ScrollViewer scrollW = ScrollViewer();
 	Grid grid = Grid();
 	scrollW.Content(grid);
-	UiTable* uitable = new UiTable(scrollW, grid);
+	UiTable* uitable = new UiTable(obj, scrollW, grid);
 	reg_table_destructor(current->ctx, uitable);
-
 	
 	uitable->getvalue = args.model->getvalue ? args.model->getvalue : args.getvalue;
+	uitable->onselection = args.onselection;
+	uitable->onselectiondata = args.onselectiondata;
+	uitable->onactivate = args.onactivate;
+	uitable->onactivatedata = args.onactivatedata;
 
 	// grid styling
 	winrt::Windows::UI::Color bg = { 255, 255, 255, 255 }; // test color
@@ -108,7 +113,9 @@
 	table->update(list, i);
 }
 
-UiTable::UiTable(winrt::Microsoft::UI::Xaml::Controls::ScrollViewer scrollW, winrt::Microsoft::UI::Xaml::Controls::Grid grid) {
+UiTable::UiTable(UiObject *obj, winrt::Microsoft::UI::Xaml::Controls::ScrollViewer scrollW, winrt::Microsoft::UI::Xaml::Controls::Grid grid) {
+	this->obj = obj;
+
 	this->scrollw = scrollw;
 	this->grid = grid;
 
@@ -196,6 +203,18 @@
 	t.Text(winrt::hstring(buf));
 }
 
+static ULONG64 getsystime() {
+	SYSTEMTIME st;
+	GetSystemTime(&st);
+	return st.wYear   * 10000000000000 +
+		   st.wMonth  * 100000000000   +
+		   st.wDay    * 1000000000     +
+		   st.wHour   * 10000000       +
+		   st.wMinute * 100000         +
+		   st.wSecond * 1000           +
+		   st.wMilliseconds;
+}
+
 void UiTable::update(UiList* list,  int i) {
 	if (getvalue == nullptr) {
 		return;
@@ -209,6 +228,7 @@
 	gl.Value = 0;
 	gl.GridUnitType = GridUnitType::Auto;
 
+	// iterate model
 	int row = 1;
 	void* elm = list->first(list);
 	while (elm) {
@@ -221,14 +241,26 @@
 
 		Thickness cellpadding = { 10,0,4,0 };
 
+		// model column, usually the same as col, however UI_ICON_TEXT uses two columns in the model
 		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);
+			cellBorder.BorderBrush(defaultBrush);
+			if (col == 0) {
+				cellBorder.BorderThickness(b1);
+			}
+			else if (col + 1 == header.size()) {
+				cellBorder.BorderThickness(b3);
+			}
+			else {
+				cellBorder.BorderThickness(b2);
+			}
 
 			// set the cell value
+			// depending on the type, we create different cell controls
 			UiModelType type = model->types[col];
 			switch (type) {
 				case UI_STRING: {
@@ -278,23 +310,13 @@
 					break;
 				}
 			}
-			
-			cellBorder.BorderBrush(defaultBrush);
-			if (col == 0) {
-				cellBorder.BorderThickness(b1);
-			}
-			else if (col + 1 == header.size()) {
-				cellBorder.BorderThickness(b3);
-			}
-			else {
-				cellBorder.BorderThickness(b2);
-			}
 
 			// event handler
 			cellBorder.PointerPressed(
 				winrt::Microsoft::UI::Xaml::Input::PointerEventHandler(
 					[=](IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& args) {
 						winrt::Windows::System::VirtualKeyModifiers modifiers = args.KeyModifiers();
+						bool update_selection = true;
 
 						if (modifiers == winrt::Windows::System::VirtualKeyModifiers::Control) {
 							// add/remove current row
@@ -315,6 +337,35 @@
 							
 							row_background(row, selectedBrush, selectedBorderBrush);
 							selection = { row };
+							if (modifiers == winrt::Windows::System::VirtualKeyModifiers::None) {
+								SYSTEMTIME st;
+								GetSystemTime(&st);
+								
+								ULONG64 now = getsystime();
+								ULONG64 tdiff = now - lastPointerPress;
+								if (tdiff < ui_double_click_time && onactivate != nullptr) {
+									// two pointer presse events in short time and we have an onactivate handler
+									update_selection = false; // we don't want an additional selection event
+									lastPointerPress = 0; // reset double-click
+
+									int selectedrow = row - 1; // subtract header row
+
+									UiListSelection selection;
+									selection.count = 1;
+									selection.rows = &selectedrow;
+
+									UiEvent evt;
+									evt.obj = obj;
+									evt.window = obj->window;
+									evt.document = obj->ctx->document;
+									evt.eventdata = &selection;
+									evt.intval = selectedrow;
+									onactivate(&evt, onactivatedata);
+								}
+								else {
+									lastPointerPress = now;
+								}
+							}
 						}
 						else if (modifiers == winrt::Windows::System::VirtualKeyModifiers::Shift) {
 							// select everything between the first selection and the current row
@@ -337,6 +388,10 @@
 							selection = newselection;
 							change_rows_bg(selection, selectedBrush, selectedBorderBrush);
 						}
+
+						if (update_selection) {
+							call_handler(onselection, onselectiondata);
+						}
 					})
 			);
 			cellBorder.PointerReleased(
@@ -380,6 +435,8 @@
 			grid.Children().RemoveAt(i);
 		}
 	}
+
+	// TODO: should we clean row definitions?
 }
 
 void UiTable::row_background(int row, winrt::Microsoft::UI::Xaml::Media::Brush brush, winrt::Microsoft::UI::Xaml::Media::Brush borderBrush) {
@@ -410,3 +467,30 @@
 	selection.erase(std::remove(selection.begin(), selection.end(), row), selection.end());
 	selection.shrink_to_fit();
 }
+
+void UiTable::call_handler(ui_callback cb, void* cbdata) {
+	if (!cb) {
+		return;
+	}
+
+	std::sort(selection.begin(), selection.end());
+
+	UiListSelection selobj;
+	selobj.count = selection.size();
+	selobj.rows = nullptr;
+	if (selobj.count > 0) {
+		selobj.rows = (int*)calloc(selobj.count, sizeof(int));
+		memcpy(selobj.rows, selection.data(), selobj.count * sizeof(int));
+		for (int i = 0; i < selobj.count; i++) {
+			selobj.rows[i]--;
+		}
+	}
+
+	UiEvent evt;
+	evt.obj = obj;
+	evt.window = obj->window;
+	evt.document = obj->ctx->document;
+	evt.eventdata = &selobj;
+	evt.intval = 0;
+	cb(&evt, cbdata);
+}
--- a/ui/winui/table.h	Sat Oct 14 10:01:22 2023 +0200
+++ b/ui/winui/table.h	Sat Oct 14 10:55:11 2023 +0200
@@ -33,6 +33,7 @@
 
 #include "../ui/container.h"
 
+
 typedef struct UiTableColumn {
 	winrt::Microsoft::UI::Xaml::Controls::Button header;
 
@@ -45,14 +46,20 @@
 	winrt::Microsoft::UI::Xaml::Media::SolidColorBrush highlightBrush;
 	winrt::Microsoft::UI::Xaml::Media::SolidColorBrush selectedBrush;
 	winrt::Microsoft::UI::Xaml::Media::SolidColorBrush selectedBorderBrush;
+	UiObject* obj;
+	ui_callback onactivate;
+	void* onactivatedata;
+	ui_callback onselection;
+	void* onselectiondata;
 	UiModel* model = nullptr;
 	std::vector<UiTableColumn> header;
 	ui_getvaluefunc getvalue = nullptr;
 	int maxrows = 0;
 	int lastSelection = 0;
+	ULONG64 lastPointerPress = 0;
 	std::vector<int> selection;
 
-	UiTable(winrt::Microsoft::UI::Xaml::Controls::ScrollViewer scrollW, winrt::Microsoft::UI::Xaml::Controls::Grid grid);
+	UiTable(UiObject *obj, winrt::Microsoft::UI::Xaml::Controls::ScrollViewer scrollW, winrt::Microsoft::UI::Xaml::Controls::Grid grid);
 
 	~UiTable();
 	
@@ -69,6 +76,8 @@
 	bool is_row_selected(int row);
 
 	void remove_from_selection(int row);
+
+	void call_handler(ui_callback cb, void *cbdata);
 } UiTable;
 
 extern "C" void ui_table_update(UiList * list, int i);

mercurial