Newer
Older
* SPDX-FileCopyrightText: 2018-2024 Bruce Cowan <bruce@bcowan.me.uk>
* SPDX-License-Identifier: GPL-3.0-or-later
struct _RugbyListStore
{
GObject parent_instance;
GListStore *items;
GSettings *settings;
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)
G_IMPLEMENT_INTERFACE (GTK_TYPE_SECTION_MODEL,
rugby_list_store_section_model_iface_init))
static GParamSpec *properties[N_PROPS];
sort_func ( gconstpointer a,
gconstpointer b,
G_GNUC_UNUSED void *user_data)
int atries = rugby_possibility_get_tries ((void *) a);
int autries = rugby_possibility_get_utries ((void *) a);
int btries = rugby_possibility_get_tries ((void *) b);
int butries = rugby_possibility_get_utries ((void *) b);
int trydiff = (btries + butries) - (atries + autries);
// Sort by total tries first, then converted
if (trydiff != 0)
return trydiff;
else
return btries - atries;
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);
if (self->score == 0)
{
g_list_model_items_changed (G_LIST_MODEL (self), 0, old_length, 0);
return;
}
int max_tries = self->score / try_points;
int max_utries = self->score / utry_points;
for (int utries = 0; utries <= max_utries; utries++)
int left = self->score - (tries * try_points) - (utries * utry_points);
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;
}
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));
rugby_list_store_get_item (GListModel *list,
{
RugbyListStore *self = RUGBY_LIST_STORE (list);
return g_list_model_get_item (G_LIST_MODEL (self->items), position);
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;
// 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 = rugby_possibility_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 = rugby_possibility_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 = rugby_possibility_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;
}
static void
rugby_list_store_dispose (GObject *object)
{
RugbyListStore *self = RUGBY_LIST_STORE (object);
g_clear_object (&self->settings);
G_OBJECT_CLASS (rugby_list_store_parent_class)->dispose (object);
}
static void
rugby_list_store_get_property (GObject *object,
GValue *value,
GParamSpec *pspec)
{
RugbyListStore *self = RUGBY_LIST_STORE (object);
switch (prop_id)
{
case PROP_SCORE:
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
rugby_list_store_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec)
{
RugbyListStore *self = RUGBY_LIST_STORE (object);
switch (prop_id)
{
score = g_value_get_int (value);
if (score != self->score)
{
self->score = score;
process_data (self);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SCORE]);
}
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", "", "",
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->items = g_list_store_new (RUGBY_TYPE_POSSIBILITY);