# HG changeset patch # User Olaf Wintermann # Date 1697189207 -7200 # Node ID 279c0c81d3b12dcf230dfff268e3a0e1c5052b98 # Parent 7e39db525fd923bbecf10fb30697f54ab9888728 improve table row selection, add support for multiple selections (WinUI3) diff -r 7e39db525fd9 -r 279c0c81d3b1 make/vs/testapp/main.c --- a/make/vs/testapp/main.c Thu Oct 12 16:03:35 2023 +0200 +++ b/make/vs/testapp/main.c Fri Oct 13 11:26:47 2023 +0200 @@ -164,6 +164,9 @@ TableData* td1 = malloc(sizeof(TableData)); TableData* td2 = malloc(sizeof(TableData)); TableData* td3 = malloc(sizeof(TableData)); + TableData* td4 = malloc(sizeof(TableData)); + TableData* td5 = malloc(sizeof(TableData)); + TableData* td6 = malloc(sizeof(TableData)); td1->col1 = "a1"; td1->col2 = "b1"; td1->col3 = "c1"; @@ -173,10 +176,22 @@ td3->col1 = "a3"; td3->col2 = "b3"; td3->col3 = "c3"; + td4->col1 = "a3"; + td4->col2 = "b3"; + td4->col3 = "c3"; + td5->col1 = "a3"; + td5->col2 = "b3"; + td5->col3 = "c3"; + td6->col1 = "a3"; + td6->col2 = "b3"; + td6->col3 = "c3"; ui_list_append(wdata->list2, td1); ui_list_append(wdata->list2, td2); ui_list_append(wdata->list2, td3); + ui_list_append(wdata->list2, td4); + ui_list_append(wdata->list2, td5); + ui_list_append(wdata->list2, td6); ui_scrolledwindow0(obj) { ui_grid(obj, .margin = 10, .columnspacing = 5, .rowspacing = 20) { @@ -263,7 +278,7 @@ { ui_init("app1", 0, NULL); ui_onstartup(application_startup, NULL); - + ui_menu("File") { ui_menuitem(.label = "Item 1"); ui_menuitem(.label = "Item 2"); diff -r 7e39db525fd9 -r 279c0c81d3b1 ui/winui/table.cpp --- a/ui/winui/table.cpp Thu Oct 12 16:03:35 2023 +0200 +++ b/ui/winui/table.cpp Fri Oct 13 11:26:47 2023 +0200 @@ -38,6 +38,7 @@ #include #include #include +#include using namespace winrt; using namespace Microsoft::UI::Xaml; @@ -120,6 +121,13 @@ winrt::Windows::UI::Color selectedFg = { 255, 0, 90, 158 }; // test color selectedBorderBrush = SolidColorBrush(selectedFg); + + grid.KeyDown( + winrt::Microsoft::UI::Xaml::Input::KeyEventHandler( + [=](IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::KeyRoutedEventArgs const& args) { + // key event for hanling the table cursor or enter + }) + ); } void UiTable::add_header(UiModel* model) { @@ -190,6 +198,8 @@ } for (int col = 0; col < header.size(); col++) { + // create ui elements with the correct cell border + // dependeing on the column Border cellBorder = Border(); cellBorder.Background(defaultBrush); TextBlock cell = TextBlock(); @@ -204,26 +214,60 @@ 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); } - Thickness padding = { 10,0,4,0 }; - cell.Padding(padding); - cell.VerticalAlignment(VerticalAlignment::Stretch); // event handler cellBorder.PointerPressed( winrt::Microsoft::UI::Xaml::Input::PointerEventHandler( [=](IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& args) { - if (selection > 0) { - row_background(selection, defaultBrush, defaultBrush); + winrt::Windows::System::VirtualKeyModifiers modifiers = args.KeyModifiers(); + + if (modifiers == winrt::Windows::System::VirtualKeyModifiers::Control) { + // add/remove current row + if (!is_row_selected(row)) { + row_background(row, selectedBrush, selectedBorderBrush); + selection.push_back(row); + } + else { + row_background(row, highlightBrush, highlightBrush); + remove_from_selection(row); + } } - row_background(row, selectedBrush, selectedBorderBrush); - selection = row; + else if (modifiers == winrt::Windows::System::VirtualKeyModifiers::None || selection.size() == 0) { + // no modifier or shift is pressed but there is no selection + if (selection.size() > 0) { + change_rows_bg(selection, defaultBrush, defaultBrush); + } + + row_background(row, selectedBrush, selectedBorderBrush); + selection = { row }; + } + else if (modifiers == winrt::Windows::System::VirtualKeyModifiers::Shift) { + // select everything between the first selection and the current row + std::sort(selection.begin(), selection.end()); + int first = selection.front(); + + // clear previous selection + change_rows_bg(selection, defaultBrush, defaultBrush); + + // create new selection + std::vector newselection; + for (int s = first; s <= row; s++) { + newselection.push_back(s); + } + selection = newselection; + change_rows_bg(selection, selectedBrush, selectedBorderBrush); + } }) ); cellBorder.PointerReleased( @@ -235,7 +279,7 @@ cellBorder.PointerEntered( winrt::Microsoft::UI::Xaml::Input::PointerEventHandler( [=](IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& args) { - if (selection != row) { + if (!is_row_selected(row)) { row_background(row, highlightBrush, highlightBrush); } }) @@ -243,7 +287,7 @@ cellBorder.PointerExited( winrt::Microsoft::UI::Xaml::Input::PointerEventHandler( [=](IInspectable const& sender, winrt::Microsoft::UI::Xaml::Input::PointerRoutedEventArgs const& args) { - if (selection != row) { + if (!is_row_selected(row)) { row_background(row, defaultBrush, defaultBrush); } }) @@ -284,3 +328,16 @@ } } } + +void UiTable::change_rows_bg(std::vector rows, winrt::Microsoft::UI::Xaml::Media::Brush brush, winrt::Microsoft::UI::Xaml::Media::Brush borderBrush) { + std::for_each(rows.cbegin(), rows.cend(), [&](const int& row) {row_background(row, brush, borderBrush); }); +} + +bool UiTable::is_row_selected(int row) { + return std::find(selection.begin(), selection.end(), row) != selection.end() ? true : false; +} + +void UiTable::remove_from_selection(int row) { + selection.erase(std::remove(selection.begin(), selection.end(), row), selection.end()); + selection.shrink_to_fit(); +} diff -r 7e39db525fd9 -r 279c0c81d3b1 ui/winui/table.h --- a/ui/winui/table.h Thu Oct 12 16:03:35 2023 +0200 +++ b/ui/winui/table.h Fri Oct 13 11:26:47 2023 +0200 @@ -48,7 +48,8 @@ std::vector header; ui_getvaluefunc getvalue; int maxrows; - int selection = 0; + int lastSelection; + std::vector selection; UiTable(winrt::Microsoft::UI::Xaml::Controls::ScrollViewer scrollW, winrt::Microsoft::UI::Xaml::Controls::Grid grid); @@ -59,6 +60,12 @@ void clear(); void row_background(int row, winrt::Microsoft::UI::Xaml::Media::Brush brush, winrt::Microsoft::UI::Xaml::Media::Brush borderBrush); + + void change_rows_bg(std::vector rows, winrt::Microsoft::UI::Xaml::Media::Brush brush, winrt::Microsoft::UI::Xaml::Media::Brush borderBrush); + + bool is_row_selected(int row); + + void remove_from_selection(int row); } UiTable; extern "C" void ui_table_update(UiList * list, int i);