/* * SPDX-FileCopyrightText: 2018-2020 Bruce Cowan <bruce@bcowan.me.uk> * SPDX-License-Identifier: GPL-3.0-or-later */ #include "config.h" #include "rugby-list-store.h" #include "rugby-possibility.h" #include <gio/gio.h> struct _RugbyListStore { GObject parent_instance; GPtrArray *items; int score; }; 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_0, PROP_SCORE, N_PROPS }; static GParamSpec *properties[N_PROPS]; // Helper functions static int sort_func (gconstpointer a, gconstpointer b) { 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 on_score_changed (RugbyListStore *self) { int max_tries = self->score / TRY_POINTS; int max_utries = self->score / UTRY_POINTS; unsigned old_length = self->items->len; g_ptr_array_remove_range (self->items, 0, self->items->len); 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_ptr_array_add (self->items, possibility); } } } g_ptr_array_sort (self->items, sort_func); g_list_model_items_changed (G_LIST_MODEL (self), 0, old_length, self->items->len); } // 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 self->items->len; } static gpointer rugby_list_store_get_item (GListModel *list, unsigned position) { RugbyListStore *self = RUGBY_LIST_STORE (list); g_assert (position < self->items->len); return g_object_ref (g_ptr_array_index (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_finalize (GObject *object) { RugbyListStore *self = RUGBY_LIST_STORE (object); g_ptr_array_unref (self->items); G_OBJECT_CLASS (rugby_list_store_parent_class)->finalize (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->finalize = rugby_list_store_finalize; 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", "Score", "Score of the match", 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->score = 0; self->items = g_ptr_array_new_with_free_func (g_object_unref); } // 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; on_score_changed (self); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SCORE]); } } RugbyListStore * rugby_list_store_new (void) { return g_object_new (RUGBY_TYPE_LIST_STORE, NULL); }