# HG changeset patch # User Olaf Wintermann # Date 1697273711 -7200 # Node ID d06e7e8e53e108a9f64eae93b06f836fd5b098d0 # Parent b9798109c7d28feee94ba59f0a7e7dc6344f636a implement table activate/selection events (WinUI3) diff -r b9798109c7d2 -r d06e7e8e53e1 make/vs/testapp/main.c --- 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); } } diff -r b9798109c7d2 -r d06e7e8e53e1 ui/winui/icons.cpp --- 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); diff -r b9798109c7d2 -r d06e7e8e53e1 ui/winui/table.cpp --- 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); +} diff -r b9798109c7d2 -r d06e7e8e53e1 ui/winui/table.h --- 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 header; ui_getvaluefunc getvalue = nullptr; int maxrows = 0; int lastSelection = 0; + ULONG64 lastPointerPress = 0; std::vector 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);