summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@gmail.com>2025-05-23 12:26:50 +0200
committerFelix Morgner <felix.morgner@gmail.com>2025-05-23 12:26:50 +0200
commitd1d171775f768be1dcdee194be5134f334c63347 (patch)
tree46e3ddc8d84c68d86293462f8d0c7eb8ffa85473
parent260df0a1158385736b2da24a2e4a14e365d1ec92 (diff)
downloadturns-d1d171775f768be1dcdee194be5134f334c63347.tar.xz
turns-d1d171775f768be1dcdee194be5134f334c63347.zip
lib: add empty property to TurnOrder
-rw-r--r--core/include/turns/core/turn_order_model.hpp18
-rw-r--r--lib/src/turns-turn-order.c33
-rw-r--r--lib/src/turns-turn-order.h21
-rw-r--r--lib/src/turnsmm/turn-order.cpp20
-rw-r--r--lib/src/turnsmm/turn-order.hpp2
-rw-r--r--lib/tests/turns-turn-order.cpp82
6 files changed, 157 insertions, 19 deletions
diff --git a/core/include/turns/core/turn_order_model.hpp b/core/include/turns/core/turn_order_model.hpp
index 7d9947d..b7ce484 100644
--- a/core/include/turns/core/turn_order_model.hpp
+++ b/core/include/turns/core/turn_order_model.hpp
@@ -38,17 +38,17 @@ namespace turns::core
using round_number_type = unsigned int;
using skip_defeated_type = bool;
- auto static constexpr invalid_participant_index = std::numeric_limits<active_participant_type>::max();
- auto static constexpr invalid_round_number = std::numeric_limits<round_number_type>::max();
+ // auto static constexpr invalid_participant_index = std::numeric_limits<active_participant_type>::max();
+ // auto static constexpr invalid_round_number = std::numeric_limits<round_number_type>::max();
/** Life-time */
- TurnOderModel();
+ // TurnOderModel();
- auto static create() -> Glib::RefPtr<TurnOderModel>;
- auto static create(nlohmann::json const & from) -> Glib::RefPtr<TurnOderModel>;
+ // auto static create() -> Glib::RefPtr<TurnOderModel>;
+ // auto static create(nlohmann::json const & from) -> Glib::RefPtr<TurnOderModel>;
/** Properties */
- auto is_empty() const -> Glib::PropertyProxy_ReadOnly<is_empty_type>;
+ // auto is_empty() const -> Glib::PropertyProxy_ReadOnly<is_empty_type>;
auto has_next() const -> Glib::PropertyProxy_ReadOnly<has_next_type>;
auto has_previous() const -> Glib::PropertyProxy_ReadOnly<has_previous_type>;
auto is_running() const -> Glib::PropertyProxy_ReadOnly<is_running_type>;
@@ -57,9 +57,9 @@ namespace turns::core
auto skip_defeated() -> Glib::PropertyProxy<skip_defeated_type>;
/** Element Modifications */
- auto add(Glib::ustring const & name, float priority, Disposition disposition) -> void;
- auto clear() -> void;
- auto remove(unsigned index) -> void;
+ // auto add(Glib::ustring const & name, float priority, Disposition disposition) -> void;
+ // auto clear() -> void;
+ // auto remove(unsigned index) -> void;
/** Turn Modification */
auto next() -> void;
diff --git a/lib/src/turns-turn-order.c b/lib/src/turns-turn-order.c
index 9a08d2e..abc22c4 100644
--- a/lib/src/turns-turn-order.c
+++ b/lib/src/turns-turn-order.c
@@ -13,7 +13,8 @@
enum
{
- PROP_RUNNING = 1,
+ PROP_EMPTY = 1,
+ PROP_RUNNING,
PROP_SORT_MODE,
N_PROPERTIES,
};
@@ -79,6 +80,8 @@ static void clear_participants(TurnsTurnOrder * self)
g_slist_free_full(self->participants, g_object_unref);
self->participants = nullptr;
+
+ g_object_notify_by_pspec(G_OBJECT(self), properties[PROP_EMPTY]);
}
static void set_running(TurnsTurnOrder * self, gboolean value)
@@ -105,6 +108,9 @@ static void turns_turn_order_get_property(GObject * self, guint id, GValue * val
switch (id)
{
+ case PROP_EMPTY:
+ g_value_set_boolean(value, turns_turn_order_get_empty(instance));
+ return;
case PROP_RUNNING:
g_value_set_boolean(value, turns_turn_order_get_running(instance));
return;
@@ -154,6 +160,12 @@ static void turns_turn_order_class_init(TurnsTurnOrderClass * klass)
object_class->get_property = turns_turn_order_get_property;
object_class->set_property = turns_turn_order_set_property;
+ properties[PROP_EMPTY] = g_param_spec_boolean("empty",
+ "Empty",
+ "Whether the turn order is empty.",
+ TRUE,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY);
+
properties[PROP_RUNNING] = g_param_spec_boolean("running",
"Running",
"Whether or not the turn order is running (e.g. has been started)",
@@ -207,10 +219,16 @@ void turns_turn_order_add(TurnsTurnOrder * self, TurnsParticipant * participant)
auto sort_mode = turns_turn_order_get_sort_mode(self);
+ auto old_head = self->participants;
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);
+ if (old_head == nullptr && !turns_turn_order_get_empty(self))
+ {
+ g_object_notify_by_pspec(G_OBJECT(self), properties[PROP_EMPTY]);
+ }
+
g_list_model_items_changed(G_LIST_MODEL(self), position, 0, 1);
}
@@ -242,11 +260,24 @@ void turns_turn_order_remove_at(TurnsTurnOrder * self, guint position)
}
g_object_unref(element->data);
+ auto old_head = self->participants;
self->participants = g_slist_delete_link(self->participants, element);
+ if (old_head != nullptr && turns_turn_order_get_empty(self))
+ {
+ g_object_notify_by_pspec(G_OBJECT(self), properties[PROP_EMPTY]);
+ set_running(self, false);
+ }
+
g_list_model_items_changed(G_LIST_MODEL(self), position, 1, 0);
}
+gboolean turns_turn_order_get_empty(TurnsTurnOrder const * self)
+{
+ g_return_val_if_fail(TURNS_IS_TURN_ORDER((TurnsTurnOrder *)self), true);
+ return self->participants == nullptr;
+}
+
gsize turns_turn_order_get_participant_count(TurnsTurnOrder const * self)
{
g_return_val_if_fail(TURNS_IS_TURN_ORDER((TurnsTurnOrder *)self), 0);
diff --git a/lib/src/turns-turn-order.h b/lib/src/turns-turn-order.h
index 91220b9..5e34405 100644
--- a/lib/src/turns-turn-order.h
+++ b/lib/src/turns-turn-order.h
@@ -47,7 +47,8 @@ G_DECLARE_FINAL_TYPE(TurnsTurnOrder, turns_turn_order, TURNS, TURN_ORDER, GObjec
*
* Returns: (transfer full): a new `TurnsTurnOrder`.
*/
-TurnsTurnOrder * turns_turn_order_new(void) G_GNUC_WARN_UNUSED_RESULT;
+G_GNUC_WARN_UNUSED_RESULT
+TurnsTurnOrder * turns_turn_order_new(void);
/**
* turns_turn_order_add:
@@ -75,12 +76,22 @@ void turns_turn_order_clear(TurnsTurnOrder * self);
void turns_turn_order_remove_at(TurnsTurnOrder * self, guint position);
/**
+ * turns_turn_order_get_empty: (get-property empty):
+ * @self: a turn order.
+ *
+ * Gets whether the turn order is empty.
+ */
+G_GNUC_WARN_UNUSED_RESULT
+gboolean turns_turn_order_get_empty(TurnsTurnOrder const * self);
+
+/**
* turns_turn_order_get_participant_count:
* @self: a turn order.
*
* Gets the number of participants in the turn order.
*/
-gsize turns_turn_order_get_participant_count(TurnsTurnOrder const * self) G_GNUC_WARN_UNUSED_RESULT;
+G_GNUC_WARN_UNUSED_RESULT
+gsize turns_turn_order_get_participant_count(TurnsTurnOrder const * self);
/**
* turns_turn_order_get_running: (get-property running):
@@ -88,7 +99,8 @@ gsize turns_turn_order_get_participant_count(TurnsTurnOrder const * self) G_GNUC
*
* Gets whether the turn order is currently running.
*/
-gboolean turns_turn_order_get_running(TurnsTurnOrder const * self) G_GNUC_WARN_UNUSED_RESULT;
+G_GNUC_WARN_UNUSED_RESULT
+gboolean turns_turn_order_get_running(TurnsTurnOrder const * self);
/**
* turns_turn_order_get_sort_mode: (get-property sort-mode):
@@ -96,7 +108,8 @@ gboolean turns_turn_order_get_running(TurnsTurnOrder const * self) G_GNUC_WARN_U
*
* Gets whether higher priority values are sorted before or after lower ones.
*/
-TurnsTurnOrderSortMode turns_turn_order_get_sort_mode(TurnsTurnOrder const * self) G_GNUC_WARN_UNUSED_RESULT;
+G_GNUC_WARN_UNUSED_RESULT
+TurnsTurnOrderSortMode turns_turn_order_get_sort_mode(TurnsTurnOrder const * self);
/**
* turns_turn_order_set_sort_mode: (set-property sort-mode):
diff --git a/lib/src/turnsmm/turn-order.cpp b/lib/src/turnsmm/turn-order.cpp
index 3767817..5f38ded 100644
--- a/lib/src/turnsmm/turn-order.cpp
+++ b/lib/src/turnsmm/turn-order.cpp
@@ -104,6 +104,11 @@ namespace Turns
return turns_turn_order_remove_at(unwrap(this), position);
}
+ auto TurnOrder::get_empty() const noexcept -> bool
+ {
+ return turns_turn_order_get_empty(Glib::unwrap(this));
+ }
+
auto TurnOrder::get_participant_count() const noexcept -> std::size_t
{
return turns_turn_order_get_participant_count(unwrap(this));
@@ -114,11 +119,6 @@ namespace Turns
return turns_turn_order_get_running(unwrap(this));
}
- auto TurnOrder::property_running() const noexcept -> Glib::PropertyProxy_ReadOnly<bool>
- {
- return {this, "running"};
- }
-
auto TurnOrder::get_sort_mode() const noexcept -> SortMode
{
return static_cast<SortMode>(turns_turn_order_get_sort_mode(unwrap(this)));
@@ -129,6 +129,16 @@ namespace Turns
turns_turn_order_set_sort_mode(unwrap(this), static_cast<TurnsTurnOrderSortMode>(value));
}
+ auto TurnOrder::property_empty() const noexcept -> Glib::PropertyProxy_ReadOnly<bool>
+ {
+ return {this, "empty"};
+ }
+
+ auto TurnOrder::property_running() const noexcept -> Glib::PropertyProxy_ReadOnly<bool>
+ {
+ return {this, "running"};
+ }
+
auto TurnOrder::property_sort_mode() noexcept -> Glib::PropertyProxy<SortMode>
{
return {this, "sort_mode"};
diff --git a/lib/src/turnsmm/turn-order.hpp b/lib/src/turnsmm/turn-order.hpp
index fe8c756..3fb55e4 100644
--- a/lib/src/turnsmm/turn-order.hpp
+++ b/lib/src/turnsmm/turn-order.hpp
@@ -53,12 +53,14 @@ namespace Turns
auto clear() noexcept -> void;
auto remove_at(guint position) noexcept -> void;
+ [[nodiscard]] auto get_empty() const noexcept -> bool;
[[nodiscard]] auto get_participant_count() const noexcept -> std::size_t;
[[nodiscard]] auto get_running() const noexcept -> bool;
[[nodiscard]] auto get_sort_mode() const noexcept -> SortMode;
auto set_sort_mode(SortMode value) noexcept -> void;
+ [[nodiscard]] auto property_empty() const noexcept -> Glib::PropertyProxy_ReadOnly<bool>;
[[nodiscard]] auto property_running() const noexcept -> Glib::PropertyProxy_ReadOnly<bool>;
[[nodiscard]] auto property_sort_mode() noexcept -> Glib::PropertyProxy<SortMode>;
[[nodiscard]] auto property_sort_mode() const noexcept -> Glib::PropertyProxy_ReadOnly<SortMode>;
diff --git a/lib/tests/turns-turn-order.cpp b/lib/tests/turns-turn-order.cpp
index 2e11b52..0c1afcc 100644
--- a/lib/tests/turns-turn-order.cpp
+++ b/lib/tests/turns-turn-order.cpp
@@ -24,6 +24,13 @@ namespace
{
list_model_notification = std::tuple{position, removed, added};
}
+
+ auto empty_notification = std::optional<bool>{};
+
+ auto on_empty_notification(TurnsTurnOrder const * instance, GParamSpec *, void *) -> void
+ {
+ empty_notification = turns_turn_order_get_empty(instance);
+ }
} // namespace
SCENARIO("Creating a turn order", "[lib][object][lifetime]")
@@ -62,6 +69,16 @@ SCENARIO("Creating a turn order", "[lib][object][lifetime]")
REQUIRE(g_list_model_get_item(G_LIST_MODEL(instance), 0) == nullptr);
REQUIRE(g_list_model_get_object(G_LIST_MODEL(instance), 0) == nullptr);
}
+
+ THEN("it's empty")
+ {
+ REQUIRE(turns_turn_order_get_empty(instance));
+
+ auto property_value = decltype(turns_turn_order_get_empty(instance)){};
+ g_object_get(instance, "empty", &property_value, nullptr);
+
+ REQUIRE(property_value);
+ }
}
}
@@ -73,10 +90,12 @@ SCENARIO("Modifying a turn order", "[lib][object][data]")
CHECK(turns_turn_order_get_participant_count(instance) == 0);
g_signal_connect(instance, "items-changed", reinterpret_cast<GCallback>(on_list_model_notification), nullptr);
+ g_signal_connect(instance, "notify::empty", reinterpret_cast<GCallback>(on_empty_notification), nullptr);
WHEN("a participant is added")
{
g_autoptr(TurnsParticipant) participant = turns_participant_new_with("Test Participant", 10.0f, TURNS_PARTICIPANT_DISPOSITION_FRIENDLY);
+ empty_notification.reset();
turns_turn_order_add(instance, participant);
THEN("its participant count is 1")
@@ -103,9 +122,25 @@ SCENARIO("Modifying a turn order", "[lib][object][data]")
REQUIRE(TURNS_PARTICIPANT(object) == participant);
}
+ THEN("it's not empty")
+ {
+ REQUIRE_FALSE(turns_turn_order_get_empty(instance));
+
+ auto property_value = decltype(turns_turn_order_get_empty(instance)){};
+ g_object_get(instance, "empty", &property_value, nullptr);
+
+ REQUIRE_FALSE(property_value);
+ }
+
+ THEN("the empty property is notified")
+ {
+ REQUIRE(empty_notification.has_value());
+ }
+
AND_WHEN("calling clear")
{
list_model_notification.reset();
+ empty_notification.reset();
turns_turn_order_clear(instance);
THEN("its participant count is 0")
@@ -142,11 +177,27 @@ SCENARIO("Modifying a turn order", "[lib][object][data]")
REQUIRE(removed == 1);
REQUIRE(added == 0);
}
+
+ THEN("it's empty")
+ {
+ REQUIRE(turns_turn_order_get_empty(instance));
+
+ auto property_value = decltype(turns_turn_order_get_empty(instance)){};
+ g_object_get(instance, "empty", &property_value, nullptr);
+
+ REQUIRE(property_value);
+ }
+
+ THEN("the empty property is notified")
+ {
+ REQUIRE(empty_notification.has_value());
+ }
}
AND_WHEN("removing the first element")
{
list_model_notification.reset();
+ empty_notification.reset();
turns_turn_order_remove_at(instance, 0);
THEN("its participant count is 0")
@@ -168,9 +219,25 @@ SCENARIO("Modifying a turn order", "[lib][object][data]")
REQUIRE(added == 0);
}
+ THEN("it's empty")
+ {
+ REQUIRE(turns_turn_order_get_empty(instance));
+
+ auto property_value = decltype(turns_turn_order_get_empty(instance)){};
+ g_object_get(instance, "empty", &property_value, nullptr);
+
+ REQUIRE(property_value);
+ }
+
+ THEN("the empty property is notified")
+ {
+ REQUIRE(empty_notification.has_value());
+ }
+
AND_WHEN("removing the first element again")
{
list_model_notification.reset();
+ empty_notification.reset();
turns_turn_order_remove_at(instance, 0);
THEN("its participant count is 0")
@@ -182,6 +249,21 @@ SCENARIO("Modifying a turn order", "[lib][object][data]")
{
REQUIRE(!list_model_notification.has_value());
}
+
+ THEN("it's empty")
+ {
+ REQUIRE(turns_turn_order_get_empty(instance));
+
+ auto property_value = decltype(turns_turn_order_get_empty(instance)){};
+ g_object_get(instance, "empty", &property_value, nullptr);
+
+ REQUIRE(property_value);
+ }
+
+ THEN("the empty property is not notified")
+ {
+ REQUIRE_FALSE(empty_notification.has_value());
+ }
}
}
}