diff options
Diffstat (limited to 'lib/src/turns-turn-order.c')
| -rw-r--r-- | lib/src/turns-turn-order.c | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/lib/src/turns-turn-order.c b/lib/src/turns-turn-order.c new file mode 100644 index 0000000..071e4c5 --- /dev/null +++ b/lib/src/turns-turn-order.c @@ -0,0 +1,227 @@ +/* + * SPDX-FileCopyrightText: 2025 Felix Morgner <felix.morgner@gmail.com> + * SPDX-License-Identifier: LGPL-2.1-only + */ + +#include "turns-turn-order.h" + +#include "turns-participant.h" + +#include <gio/gio.h> +#include <glib-object.h> +#include <glib.h> + +enum +{ + PROP_RUNNING = 1, + PROP_SORT_MODE, + N_PROPERTIES, +}; + +struct _TurnsTurnOrder +{ + GObject parent_instance; + + GSList * participants; + gboolean running; + TurnsTurnOrderSortMode sort_mode; +}; + +static GParamSpec * properties[N_PROPERTIES] = { + nullptr, +}; + +static void turns_turn_order_list_model_init(GListModelInterface * iface); + +G_DEFINE_FINAL_TYPE_WITH_CODE(TurnsTurnOrder, + turns_turn_order, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(G_TYPE_LIST_MODEL, turns_turn_order_list_model_init)) + +static gint compare_participant(void const * lhs, void const * rhs, void * sort_mode) +{ + auto left_priority = turns_participant_get_priority(lhs); + auto right_priority = turns_participant_get_priority(rhs); + + auto result = 0; + + if (left_priority < right_priority) + { + result = -1; + } + else if (left_priority > right_priority) + { + result = 1; + } + + if ((TurnsTurnOrderSortMode)(long long)sort_mode == TURNS_TURN_ORDER_SORT_MODE_DESCENDING) + { + return result * -1; + } + + return result; +} + +static void sort_participants(TurnsTurnOrder * self) +{ + auto const sort_mode = turns_turn_order_get_sort_mode(self); + + self->participants = g_slist_sort_with_data(self->participants, &compare_participant, (void *)sort_mode); + + auto const participant_count = turns_turn_order_get_participant_count(self); + + g_list_model_items_changed(G_LIST_MODEL(self), 0, participant_count, participant_count); +} + +static void handle_participant_property_changed(TurnsParticipant const *, GParamSpec *, TurnsTurnOrder * self) +{ + sort_participants(self); +} + +static void turns_turn_order_get_property(GObject * self, guint id, GValue * value, GParamSpec * specification) +{ + auto instance = TURNS_TURN_ORDER(self); + + switch (id) + { + case PROP_RUNNING: + g_value_set_boolean(value, turns_turn_order_get_running(instance)); + return; + case PROP_SORT_MODE: + g_value_set_enum(value, turns_turn_order_get_sort_mode(instance)); + return; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(self, id, specification); + } +} + +static void turns_turn_order_set_property(GObject * self, guint id, GValue const * value, GParamSpec * specification) +{ + auto instance = TURNS_TURN_ORDER(self); + + switch (id) + { + case PROP_SORT_MODE: + turns_turn_order_set_sort_mode(instance, g_value_get_enum(value)); + return; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(self, id, specification); + } +} + +static void turns_turn_order_init(TurnsTurnOrder * self) +{ + self->participants = nullptr; + self->running = false; + self->sort_mode = TURNS_TURN_ORDER_SORT_MODE_DESCENDING; +} + +static void turns_turn_order_finalize(GObject * self) +{ + auto instance = TURNS_TURN_ORDER(self); + + g_slist_free_full(instance->participants, g_object_unref); + + G_OBJECT_CLASS(turns_turn_order_parent_class)->finalize(self); +} + +static void turns_turn_order_class_init(TurnsTurnOrderClass * klass) +{ + auto object_class = G_OBJECT_CLASS(klass); + + object_class->finalize = turns_turn_order_finalize; + object_class->get_property = turns_turn_order_get_property; + object_class->set_property = turns_turn_order_set_property; + + properties[PROP_RUNNING] = g_param_spec_boolean("running", + "Running", + "Whether or not the turn order is running (e.g. has been started)", + false, + G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY); + + properties[PROP_SORT_MODE] = g_param_spec_enum("sort-mode", + "Sort Mode", + "The sort mode applied to the turn order", + TURNS_TYPE_TURN_ORDER_SORT_MODE, + TURNS_TURN_ORDER_SORT_MODE_DESCENDING, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties(object_class, N_PROPERTIES, properties); +} + +static gpointer turns_turn_order_list_model_get_item(GListModel * self, guint position) +{ + g_return_val_if_fail(position < turns_turn_order_get_participant_count(TURNS_TURN_ORDER(self)), nullptr); + return g_object_ref(g_slist_nth_data(TURNS_TURN_ORDER(self)->participants, position)); +} + +static guint turns_turn_order_list_model_get_n_items(GListModel * self) +{ + return turns_turn_order_get_participant_count(TURNS_TURN_ORDER(self)); +} + +static GType turns_turn_order_list_model_get_item_type(GListModel * self) +{ + (void)self; + return TURNS_TYPE_PARTICIPANT; +} + +static void turns_turn_order_list_model_init(GListModelInterface * iface) +{ + iface->get_item = turns_turn_order_list_model_get_item; + iface->get_item_type = turns_turn_order_list_model_get_item_type; + iface->get_n_items = turns_turn_order_list_model_get_n_items; +} + +TurnsTurnOrder * turns_turn_order_new() +{ + return TURNS_TURN_ORDER(g_object_new(TURNS_TYPE_TURN_ORDER, nullptr)); +} + +void turns_turn_order_add(TurnsTurnOrder * self, TurnsParticipant * participant) +{ + g_return_if_fail(participant != nullptr); + + g_signal_connect(participant, "notify::priority", (GCallback)&handle_participant_property_changed, self); + + auto sort_mode = turns_turn_order_get_sort_mode(self); + + self->participants = g_slist_insert_sorted_with_data(self->participants, g_object_ref(participant), compare_participant, (void *)sort_mode); + + auto position = g_slist_index(self->participants, participant); + + g_list_model_items_changed(G_LIST_MODEL(self), position, 0, 1); +} + +gsize turns_turn_order_get_participant_count(TurnsTurnOrder const * self) +{ + g_return_val_if_fail(TURNS_IS_TURN_ORDER((TurnsTurnOrder *)self), 0); + return g_slist_length(self->participants); +} + +gboolean turns_turn_order_get_running(TurnsTurnOrder const * self) +{ + g_return_val_if_fail(TURNS_IS_TURN_ORDER((TurnsTurnOrder *)self), false); + return self->running; +} + +TurnsTurnOrderSortMode turns_turn_order_get_sort_mode(TurnsTurnOrder const * self) +{ + g_return_val_if_fail(TURNS_IS_TURN_ORDER((TurnsTurnOrder *)self), TURNS_TURN_ORDER_SORT_MODE_ASCENDING); + return self->sort_mode; +} + +void turns_turn_order_set_sort_mode(TurnsTurnOrder * self, TurnsTurnOrderSortMode sort_mode) +{ + g_return_if_fail(TURNS_IS_TURN_ORDER(self)); + + if (sort_mode == self->sort_mode) + { + return; + } + + self->sort_mode = sort_mode; + g_object_notify_by_pspec(G_OBJECT(self), properties[PROP_SORT_MODE]); + + sort_participants(self); +} |
