diff --git a/data/gtk/help-overlay.blp b/data/gtk/help-overlay.blp index 4d8c3dd008b9711ce4dde6d99d08280aa2406a87..e38269136858ab36e9fa0018e12ff76d86608e8c 100644 --- a/data/gtk/help-overlay.blp +++ b/data/gtk/help-overlay.blp @@ -27,11 +27,6 @@ ShortcutsWindow help_overlay { title: "Decrement score"; accelerator: "<Ctrl>Down <Ctrl>Left"; } - - ShortcutsShortcut { - title: "Show try filter"; - accelerator: "<Ctrl>f"; - } } } } diff --git a/data/gtk/window.blp b/data/gtk/window.blp index 4b9c9ce8cf20419d296199490cebb1a2e475fff9..01915c1b7c0cb3ef673faed8beecb2ff2aee827e 100644 --- a/data/gtk/window.blp +++ b/data/gtk/window.blp @@ -22,12 +22,6 @@ template $RugbyAppWindow : Adw.ApplicationWindow { tooltip-text: "Score"; } - ToggleButton filter_toggle { - action-name: "win.show-try-filter"; - icon-name: "funnel"; - tooltip-text: "Show Try Filter (Ctrl+F)"; - } - [end] MenuButton { direction: none; @@ -40,25 +34,6 @@ template $RugbyAppWindow : Adw.ApplicationWindow { content: Box { orientation: vertical; - Revealer { - halign: center; - margin-top: 6; - reveal-child: bind filter_toggle.active; - transition-type: slide_down; - - SpinButton tryspin { - adjustment: Adjustment { - step-increment: 1; - lower: 0; - upper: 40; - }; - focusable: true; - tooltip-text: "Tries"; - - value-changed => $try_spin_value_changed_cb(); - } - } - Stack stack { StackPage { @@ -79,8 +54,6 @@ template $RugbyAppWindow : Adw.ApplicationWindow { tightening-threshold: 400; ListView listview { - styles ["rich-list", "card"] - factory: BuilderListItemFactory { template ListItem { child: $RugbyPossibilityWidget { @@ -89,16 +62,23 @@ template $RugbyAppWindow : Adw.ApplicationWindow { }; } }; - model: NoSelection { - model: FilterListModel { - filter: CustomFilter try_filter {}; - model: $RugbyListStore list_store { - score: bind scorespin.value; + header-factory: BuilderListItemFactory { + template ListHeader { + child: Label { + label: bind $header_label_cb(template.item) as <string>; + halign: start; }; + } + }; + model: NoSelection { + model: $RugbyListStore list_store { + score: bind scorespin.value; items-changed => $list_store_items_changed_cb(); }; }; + + styles ["rich-list", "card"] } } }; @@ -120,10 +100,6 @@ template $RugbyAppWindow : Adw.ApplicationWindow { arguments: "'down'"; trigger: "<Ctrl>Down|<Ctrl>Left"; } - Shortcut { - action: "action(win.show-try-filter)"; - trigger: "<Ctrl>F"; - } } } diff --git a/meson.build b/meson.build index c4a606e1c008067ee24852033cff25e5eb741eda..7d65473ad4a602258edb0d3c7390080757627934 100644 --- a/meson.build +++ b/meson.build @@ -19,7 +19,7 @@ desktopdir = datadir / 'applications' gnome = import('gnome') gio_dep = dependency('gio-2.0', version: '>= 2.76') -gtk_dep = dependency('gtk4', version: '>= 4.11.3') +gtk_dep = dependency('gtk4', version: '>= 4.12') libadwaita_dep = dependency('libadwaita-1', version: '>=1.5.beta') conf = configuration_data() @@ -52,4 +52,3 @@ gnome.post_install( glib_compile_schemas: true, update_desktop_database: true, ) - diff --git a/src/rugby-app-window.c b/src/rugby-app-window.c index c3c41c44c5ddab6070d3b94c31ae7a2c4dacc422..c78d12d190f9727cd32696bb534f2c18069e99ec 100644 --- a/src/rugby-app-window.c +++ b/src/rugby-app-window.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2023 Bruce Cowan <bruce@bcowan.me.uk> + * SPDX-FileCopyrightText: 2017-2024 Bruce Cowan <bruce@bcowan.me.uk> * * SPDX-License-Identifier: GPL-3.0-or-later */ @@ -18,12 +18,9 @@ struct _RugbyAppWindow AdwApplicationWindow parent; GtkWidget *scorespin; - GtkWidget *tryspin; GtkWidget *stack; GSettings *win_settings; - - GtkCustomFilter *try_filter; }; G_DEFINE_FINAL_TYPE (RugbyAppWindow, rugby_app_window, ADW_TYPE_APPLICATION_WINDOW) @@ -93,6 +90,22 @@ item_tooltip_cb (GtkListItem *item) return g_string_free (tooltip, FALSE); } +static char * +header_label_cb (GtkListItem *item) +{ + RugbyPossibility *possibility = gtk_list_header_get_item (GTK_LIST_HEADER (item)); + if (!possibility) + return NULL; + + int tries, utries; + g_object_get (possibility, + "tries", &tries, + "utries", &utries, + NULL); + int total_tries = tries + utries; + return g_strdup_printf (ngettext ("%d try", "%d tries", total_tries), total_tries); +} + static void activate_score_changed (G_GNUC_UNUSED GSimpleAction *action, GVariant *parameter, @@ -111,14 +124,6 @@ activate_score_changed (G_GNUC_UNUSED GSimpleAction *action, g_assert_not_reached (); } -static void -try_spin_value_changed_cb (G_GNUC_UNUSED GtkSpinButton *btn, - void *user_data) -{ - RugbyAppWindow *self = RUGBY_APP_WINDOW (user_data); - gtk_filter_changed (GTK_FILTER (self->try_filter), GTK_FILTER_CHANGE_DIFFERENT); -} - static void rugby_app_window_dispose (GObject *object) { @@ -128,47 +133,6 @@ rugby_app_window_dispose (GObject *object) G_OBJECT_CLASS (rugby_app_window_parent_class)->dispose (object); } -static gboolean -try_filter_func (void *item, - void *user_data) -{ - RugbyPossibility *possibility = RUGBY_POSSIBILITY (item); - RugbyAppWindow *self = RUGBY_APP_WINDOW (user_data); - - int tries, utries; - - g_object_get (possibility, - "tries", &tries, - "utries", &utries, - NULL); - - if ((tries + utries) == gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (self->tryspin))) - return TRUE; - - return FALSE; -} - -static void -show_try_filter_change_state (GSimpleAction *action, - GVariant *value, - void *user_data) -{ - RugbyAppWindow *self = RUGBY_APP_WINDOW (user_data); - - if (g_variant_get_boolean (value)) - { - gtk_custom_filter_set_filter_func (self->try_filter, try_filter_func, self, NULL); - gtk_filter_changed (GTK_FILTER (self->try_filter), GTK_FILTER_CHANGE_MORE_STRICT); - } - else - { - gtk_custom_filter_set_filter_func (self->try_filter, NULL, NULL, NULL); - gtk_filter_changed (GTK_FILTER (self->try_filter), GTK_FILTER_CHANGE_LESS_STRICT); - } - - g_simple_action_set_state (action, value); -} - static void rugby_app_window_init (RugbyAppWindow *self) { @@ -176,7 +140,6 @@ rugby_app_window_init (RugbyAppWindow *self) const GActionEntry win_entries[] = { { .name = "score-changed", .activate = activate_score_changed, .parameter_type = "s" }, - { .name = "show-try-filter", .state = "false", .change_state = show_try_filter_change_state }, }; g_action_map_add_action_entries (G_ACTION_MAP (self), @@ -208,12 +171,9 @@ rugby_app_window_class_init (RugbyAppWindowClass *klass) "/uk/me/bcowan/Rugby/gtk/window.ui"); gtk_widget_class_bind_template_child (widget_class, RugbyAppWindow, scorespin); - gtk_widget_class_bind_template_child (widget_class, RugbyAppWindow, tryspin); gtk_widget_class_bind_template_child (widget_class, RugbyAppWindow, stack); - gtk_widget_class_bind_template_child (widget_class, RugbyAppWindow, try_filter); - - gtk_widget_class_bind_template_callback (widget_class, try_spin_value_changed_cb); + gtk_widget_class_bind_template_callback (widget_class, header_label_cb); gtk_widget_class_bind_template_callback (widget_class, item_tooltip_cb); gtk_widget_class_bind_template_callback (widget_class, list_store_items_changed_cb); } diff --git a/src/rugby-list-store.c b/src/rugby-list-store.c index 5e518929a002efdb85a32261680c4dfcef734ed5..57ccda29ad43f35bc07477ed04683e6bfddc6c34 100644 --- a/src/rugby-list-store.c +++ b/src/rugby-list-store.c @@ -9,6 +9,7 @@ #include "rugby-possibility.h" #include <gio/gio.h> +#include <gtk/gtk.h> struct _RugbyListStore { @@ -21,10 +22,14 @@ struct _RugbyListStore }; static void rugby_list_store_list_model_iface_init (GListModelInterface *iface); +static void rugby_list_store_section_model_iface_init (GtkSectionModelInterface *iface); G_DEFINE_FINAL_TYPE_WITH_CODE (RugbyListStore, rugby_list_store, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, - rugby_list_store_list_model_iface_init)) + rugby_list_store_list_model_iface_init) + G_IMPLEMENT_INTERFACE (GTK_TYPE_SECTION_MODEL, + rugby_list_store_section_model_iface_init)) + enum { @@ -108,6 +113,18 @@ process_data (RugbyListStore *self) g_list_model_get_n_items (G_LIST_MODEL (self->items))); } +static int +get_total_tries (RugbyPossibility *possibility) +{ + int tries, utries; + + g_object_get (possibility, + "tries", &tries, + "utries", &utries, + NULL); + return tries + utries; +} + // GListModel implementation static GType @@ -141,6 +158,63 @@ rugby_list_store_list_model_iface_init (GListModelInterface *iface) iface->get_item = rugby_list_store_get_item; } +// SectionModel implementation + +static void +rugby_list_store_get_section (GtkSectionModel *model, + unsigned position, + unsigned *out_start, + unsigned *out_end) +{ + RugbyListStore *self = RUGBY_LIST_STORE (model); + + unsigned n_items = g_list_model_get_n_items (G_LIST_MODEL (self->items)); + RugbyPossibility *possibility = g_list_model_get_item (G_LIST_MODEL (self->items), + position); + if (!possibility) + { + *out_start = n_items; + *out_end = G_MAXUINT; + return; + } + + int target_tries = get_total_tries (possibility); + + // Find start + for (unsigned i = 0; i < n_items; i++) + { + possibility = g_list_model_get_item (G_LIST_MODEL (self->items), i); + int total = get_total_tries (possibility); + + if (total == target_tries) + { + *out_start = i; + break; + } + } + + // Find end + for (unsigned i = *out_start + 1; i < n_items; i++) + { + possibility = g_list_model_get_item (G_LIST_MODEL (self->items), i); + int total = get_total_tries (possibility); + + if (total != target_tries) + { + *out_end = i; + return; + } + } + + *out_end = n_items; +} + +static void +rugby_list_store_section_model_iface_init (GtkSectionModelInterface *iface) +{ + iface->get_section = rugby_list_store_get_section; +} + // Class functions static void