/* * SPDX-FileCopyrightText: 2018-2022 Bruce Cowan <bruce@bcowan.me.uk> * * SPDX-License-Identifier: GPL-3.0-or-later */ #include "rugby-list-store.h" #include "rugby-possibility.h" #include <gio/gio.h> struct _RugbyListStore { GObject parent_instance; int score; GListStore *items; GSettings *settings; }; static void rugby_list_store_list_model_iface_init (GListModelInterface *iface); G_DEFINE_TYPE_WITH_CODE (RugbyListStore, rugby_list_store, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, rugby_list_store_list_model_iface_init)) enum { PROP_SCORE = 1, N_PROPS }; static GParamSpec *properties[N_PROPS]; // Helper functions static int sort_func ( gconstpointer a, gconstpointer b, G_GNUC_UNUSED gpointer user_data) { int atries, autries; int btries, butries; g_object_get ((gpointer) a, "tries", &atries, "utries", &autries, NULL); g_object_get ((gpointer) b, "tries", &btries, "utries", &butries, NULL); int trydiff = (btries + butries) - (atries + autries); // Sort by total tries first, then converted if (trydiff != 0) return trydiff; else return btries - atries; } static void process_data (RugbyListStore *self) { int try_points = g_settings_get_int (self->settings, "try-points"); int utry_points = g_settings_get_int (self->settings, "utry-points"); int kick_points = g_settings_get_int (self->settings, "kick-points"); unsigned old_length = g_list_model_get_n_items (G_LIST_MODEL (self->items)); g_list_store_remove_all (self->items); int max_tries = self->score / try_points; int max_utries = self->score / utry_points; for (int tries = 0; tries <= max_tries; tries++) { for (int utries = 0; utries <= max_utries; utries++) { int left = self->score - (tries * try_points) - (utries * utry_points); if (left < 0) break; if (left % kick_points == 0) { int kicks = left / kick_points; RugbyPossibility *possibility = rugby_possibility_new (tries, utries, kicks); g_list_store_append (self->items, possibility); g_object_unref (possibility); } } } g_list_store_sort (self->items, sort_func, NULL); g_list_model_items_changed (G_LIST_MODEL (self), 0, old_length, g_list_model_get_n_items (G_LIST_MODEL (self->items))); } // GListModel implementation static GType rugby_list_store_get_item_type (G_GNUC_UNUSED GListModel *list) { return RUGBY_TYPE_POSSIBILITY; } static unsigned rugby_list_store_get_n_items (GListModel *list) { RugbyListStore *self = RUGBY_LIST_STORE (list); return g_list_model_get_n_items (G_LIST_MODEL (self->items)); } static gpointer rugby_list_store_get_item (GListModel *list, unsigned position) { RugbyListStore *self = RUGBY_LIST_STORE (list); return g_list_model_get_item (G_LIST_MODEL (self->items), position); } static void rugby_list_store_list_model_iface_init (GListModelInterface *iface) { iface->get_item_type = rugby_list_store_get_item_type; iface->get_n_items = rugby_list_store_get_n_items; iface->get_item = rugby_list_store_get_item; } // Class functions static void rugby_list_store_dispose (GObject *object) { RugbyListStore *self = RUGBY_LIST_STORE (object); g_clear_object (&self->settings); g_clear_object (&self->items); G_OBJECT_CLASS (rugby_list_store_parent_class)->dispose (object); } static void rugby_list_store_get_property (GObject *object, unsigned prop_id, GValue *value, GParamSpec *pspec) { RugbyListStore *self = RUGBY_LIST_STORE (object); switch (prop_id) { case PROP_SCORE: g_value_set_int (value, rugby_list_store_get_score (self)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void rugby_list_store_set_property (GObject *object, unsigned prop_id, const GValue *value, GParamSpec *pspec) { RugbyListStore *self = RUGBY_LIST_STORE (object); switch (prop_id) { case PROP_SCORE: rugby_list_store_set_score (self, g_value_get_int (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void rugby_list_store_class_init (RugbyListStoreClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = rugby_list_store_dispose; object_class->get_property = rugby_list_store_get_property; object_class->set_property = rugby_list_store_set_property; properties[PROP_SCORE] = g_param_spec_int ("score", "", "", 0, 200, 0, G_PARAM_READWRITE); g_object_class_install_properties (object_class, N_PROPS, properties); } static void rugby_list_store_init (RugbyListStore *self) { self->settings = g_settings_new ("uk.me.bcowan.Rugby"); g_signal_connect_swapped (self->settings, "changed::try-points", G_CALLBACK (process_data), self); g_signal_connect_swapped (self->settings, "changed::utry-points", G_CALLBACK (process_data), self); g_signal_connect_swapped (self->settings, "changed::kick-points", G_CALLBACK (process_data), self); self->score = 0; self->items = g_list_store_new (RUGBY_TYPE_POSSIBILITY); } // Public functions int rugby_list_store_get_score (RugbyListStore *self) { g_assert (RUGBY_IS_LIST_STORE (self)); return self->score; } void rugby_list_store_set_score (RugbyListStore *self, int score) { g_assert (RUGBY_IS_LIST_STORE (self)); if (score != self->score) { self->score = score; process_data (self); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SCORE]); } }