/* rugby-list-store.c * * Copyright 2018 Bruce Cowan <bruce@bcowan.eu> * * This file is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 3 of the * License, or (at your option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see <http://www.gnu.org/licenses/>. * * SPDX-License-Identifier: LGPL-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; guint score; GPtrArray *items; }; 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 gint sort_func (gconstpointer a, gconstpointer b) { gint atries, autries; gint btries, butries; g_object_get ((gpointer) a, "tries", &atries, "utries", &autries, NULL); g_object_get ((gpointer) b, "tries", &btries, "utries", &butries, NULL); gint trydiff = (btries + butries) - (atries + autries); // Sort by total tries first, then converted if (trydiff != 0) return trydiff; else return atries - btries; } // Callbacks static void notify_score_cb (GObject *gobject, GParamSpec *pspec, gpointer user_data) { RugbyListStore *self = RUGBY_LIST_STORE (user_data); gint max_tries = self->score / TRY_POINTS; gint max_utries = self->score / UTRY_POINTS; guint old_length = self->items->len; g_ptr_array_remove_range (self->items, 0, self->items->len); for (gint tries = 0; tries <= max_tries; tries++) { for (gint utries = 0; utries <= max_utries; utries++) { gint left = self->score - (tries * TRY_POINTS) - (utries * UTRY_POINTS); if (left < 0) break; if (left % KICK_POINTS == 0) { gint 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 (GListModel *list) { return RUGBY_TYPE_POSSIBILITY; } static guint 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, guint position) { RugbyListStore *self = RUGBY_LIST_STORE (list); g_return_val_if_fail (position < self->items->len, NULL); 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, guint prop_id, GValue *value, GParamSpec *pspec) { RugbyListStore *self = RUGBY_LIST_STORE (object); switch (prop_id) { case PROP_SCORE: g_value_set_uint (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, guint 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_uint (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_uint ("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); g_signal_connect (self, "notify::score", G_CALLBACK (notify_score_cb), self); } // Public functions guint rugby_list_store_get_score (RugbyListStore *self) { g_return_val_if_fail (RUGBY_IS_LIST_STORE (self), 0); return self->score; } void rugby_list_store_set_score (RugbyListStore *self, guint score) { g_return_if_fail (RUGBY_IS_LIST_STORE (self)); if (score != self->score) { self->score = score; 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); }