summaryrefslogtreecommitdiff
path: root/lib/src/turns-turn-order.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/src/turns-turn-order.c')
-rw-r--r--lib/src/turns-turn-order.c227
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);
+}