From 8038808f1968b663e351a66023fabe0ed1b019f1 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 22 May 2025 17:45:44 +0200 Subject: lib: enable gir generation --- cmake/Modules/GlibIntrospection.cmake | 82 ++++++++++ lib/CMakeLists.txt | 16 +- lib/src/turns-init.c | 20 +++ lib/src/turns-init.cpp | 24 --- lib/src/turns-participant.c | 264 +++++++++++++++++++++++++++++++++ lib/src/turns-participant.cpp | 272 ---------------------------------- lib/src/turns-turn-order.c | 227 ++++++++++++++++++++++++++++ lib/src/turns-turn-order.cpp | 268 --------------------------------- lib/src/turns-turn-order.h | 69 +++++---- 9 files changed, 640 insertions(+), 602 deletions(-) create mode 100644 cmake/Modules/GlibIntrospection.cmake create mode 100644 lib/src/turns-init.c delete mode 100644 lib/src/turns-init.cpp create mode 100644 lib/src/turns-participant.c delete mode 100644 lib/src/turns-participant.cpp create mode 100644 lib/src/turns-turn-order.c delete mode 100644 lib/src/turns-turn-order.cpp diff --git a/cmake/Modules/GlibIntrospection.cmake b/cmake/Modules/GlibIntrospection.cmake new file mode 100644 index 0000000..c6b0752 --- /dev/null +++ b/cmake/Modules/GlibIntrospection.cmake @@ -0,0 +1,82 @@ +include_guard() + +find_program(G_IR_SCANNER_BIN + NAMES "g-ir-scanner" + REQUIRED +) + +function(target_glib_generate_gir TARGET) + if(NOT BUILD_SHARED_LIBS) + message(STATUS "GlibIntrospection: skipping GIR generation for static library target '${TARGET}'") + return() + endif() + + set(SINGLE_VALUE_ARGS + "NAMESPACE" + "OUTPUT" + "VERSION" + ) + set(MULTI_VALUE_ARGS + "DEPENDENCIES" + "SOURCES" + ) + cmake_parse_arguments( + PARSE_ARGV 1 + "" + "${OPTIONS}" + "${SINGLE_VALUE_ARGS}" + "${MULTI_VALUE_ARGS}" + ) + + if(NOT TARGET "${TARGET}") + message(FATAL_ERROR "GlibIntrospection: Target '${TARGET}' does not exist") + endif() + + if(NOT _NAMESPACE) + set(_NAMESPACE "${PROJECT_NAME}") + message(WARNING "GlibIntrospection: defaulting to namespace ${_NAMESPACE}") + endif() + + if(NOT _OUTPUT_DIR) + get_target_property(_OUTPUT_DIR "${TARGET}" BINARY_DIR) + endif() + + if(NOT _VERSION) + set(_VERSION "${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}") + message(WARNING "GlibIntrospection: defaulting to version ${_VERSION}") + endif() + + if(NOT _DEPENDENCIES) + message(FATAL_ERROR "GlibIntrospection: no dependencies specified") + endif() + + if(NOT _SOURCES) + get_target_property(SOURCES "${TARGET}" SOURCES) + get_target_property(HEADERS "${TARGET}" HEADER_SET) + set(_SOURCES ${HEADERS} ${SOURCES}) + endif() + + get_target_property(TARGET_OUTPUT_NAME "${TARGET}" OUTPUT_NAME) + set(_OUTPUT_FILE "${_OUTPUT_DIR}/$/${TARGET_OUTPUT_NAME}.gir") + + add_custom_command(TARGET "${TARGET}" + POST_BUILD + BYPRODUCTS "${_OUTPUT_FILE}" + COMMENT "Generating GIR file for ${TARGET}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + COMMAND "${G_IR_SCANNER_BIN}" + ARGS + "--warn-all" + "--namespace=${_NAMESPACE}" + "--nsversion=${_VERSION}" + "--library=$" + "--library-path=$" + "$,PREPEND,-I>" + "$,PREPEND,--pkg=>" + "$" + "--output=${_OUTPUT_FILE}" + ${_SOURCES} + COMMAND_EXPAND_LISTS + ) + +endfunction() \ No newline at end of file diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 61e35b0..d00e804 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -11,6 +11,7 @@ project("libturns" include("FetchContent") include("GlibMkenums") +include("GlibIntrospection") find_package("PkgConfig" REQUIRED) @@ -56,9 +57,9 @@ set(HEADERS ) set(SOURCES - "src/turns-init.cpp" - "src/turns-participant.cpp" - "src/turns-turn-order.cpp" + "src/turns-init.c" + "src/turns-participant.c" + "src/turns-turn-order.c" ) add_library("lib" ${SOURCES}) @@ -108,6 +109,15 @@ target_add_glib_enums("lib" HEADERS ${HEADERS} ) +target_glib_generate_gir("lib" + NAMESPACE "Turns" + VERSION "${PROJECT_VERSION_MAJOR}.0" + DEPENDENCIES + "GLib-2.0" + "Gio-2.0" + "GObject-2.0" +) + enable_coverage("lib") install(TARGETS "lib" FILE_SET HEADERS DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/turns") diff --git a/lib/src/turns-init.c b/lib/src/turns-init.c new file mode 100644 index 0000000..0cf5a97 --- /dev/null +++ b/lib/src/turns-init.c @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: 2025 Felix Morgner + * SPDX-License-Identifier: LGPL-2.1-only + */ + +#include "turns-init.h" + +#include "turns-participant.h" +#include "turns-turn-order.h" + +#include +#include + +void turns_init(void) +{ + g_type_ensure(TURNS_TYPE_PARTICIPANT); + g_type_ensure(TURNS_TYPE_PARTICIPANT_DISPOSITION); + g_type_ensure(TURNS_TYPE_TURN_ORDER); + g_type_ensure(TURNS_TYPE_TURN_ORDER_SORT_MODE); +} diff --git a/lib/src/turns-init.cpp b/lib/src/turns-init.cpp deleted file mode 100644 index 13a42cc..0000000 --- a/lib/src/turns-init.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 Felix Morgner - * SPDX-License-Identifier: LGPL-2.1-only - */ - -#include "turns-init.h" - -#include "turns-participant.h" -#include "turns-turn-order.h" - -#include -#include - -G_BEGIN_DECLS - -auto turns_init() -> void -{ - g_type_ensure(TURNS_TYPE_PARTICIPANT); - g_type_ensure(TURNS_TYPE_PARTICIPANT_DISPOSITION); - g_type_ensure(TURNS_TYPE_TURN_ORDER); - g_type_ensure(TURNS_TYPE_TURN_ORDER_SORT_MODE); -} - -G_END_DECLS \ No newline at end of file diff --git a/lib/src/turns-participant.c b/lib/src/turns-participant.c new file mode 100644 index 0000000..18785db --- /dev/null +++ b/lib/src/turns-participant.c @@ -0,0 +1,264 @@ +/* + * SPDX-FileCopyrightText: 2025 Felix Morgner + * SPDX-License-Identifier: LGPL-2.1-only + */ + +#include "turns-participant.h" + +#include +#include +#include + +struct _TurnsParticipant +{ + GObject parent_instance; + + gboolean active; + gboolean defeated; + TurnsParticipantDisposition disposition; + gchar * id; + gchar * name; + gfloat priority; +}; + +G_DEFINE_TYPE(TurnsParticipant, turns_participant, G_TYPE_OBJECT) + +enum PROPERTIES +{ + PROP_ACTIVE = 1, + PROP_DEFEATED, + PROP_DISPOSITION, + PROP_NAME, + PROP_PRIORITY, + N_PROPERTIES, +}; + +static GParamSpec * properties[N_PROPERTIES] = { + nullptr, +}; + +static void turns_participant_finalize(GObject * self) +{ + auto participant = TURNS_PARTICIPANT(self); + + g_free(participant->id); + g_free(participant->name); + + G_OBJECT_CLASS(turns_participant_parent_class)->finalize(self); +} + +static void turns_participant_get_property(GObject * self, guint id, GValue * value, GParamSpec * specification) +{ + auto participant = TURNS_PARTICIPANT(self); + + switch ((enum PROPERTIES)id) + { + case PROP_ACTIVE: + g_value_set_boolean(value, turns_participant_get_active(participant)); + return; + case PROP_DEFEATED: + g_value_set_boolean(value, turns_participant_get_defeated(participant)); + return; + case PROP_NAME: + g_value_set_string(value, turns_participant_get_name(participant)); + return; + case PROP_PRIORITY: + g_value_set_float(value, turns_participant_get_priority(participant)); + return; + case PROP_DISPOSITION: + g_value_set_enum(value, turns_participant_get_disposition(participant)); + return; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(self, id, specification); + }; +} + +static void turns_participant_set_property(GObject * self, guint id, GValue const * value, GParamSpec * specification) +{ + auto participant = TURNS_PARTICIPANT(self); + + switch ((enum PROPERTIES)id) + { + case PROP_ACTIVE: + turns_participant_set_active(participant, g_value_get_boolean(value)); + return; + case PROP_DEFEATED: + turns_participant_set_defeated(participant, g_value_get_boolean(value)); + return; + case PROP_NAME: + turns_participant_set_name(participant, g_value_get_string(value)); + return; + case PROP_PRIORITY: + turns_participant_set_priority(participant, g_value_get_float(value)); + return; + case PROP_DISPOSITION: + turns_participant_set_disposition(participant, (TurnsParticipantDisposition)g_value_get_enum(value)); + return; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(self, id, specification); + } +} + +static void turns_participant_class_init(TurnsParticipantClass * klass) +{ + GObjectClass * object_class = G_OBJECT_CLASS(klass); + + (void)object_class; + + object_class->get_property = turns_participant_get_property; + object_class->set_property = turns_participant_set_property; + object_class->finalize = turns_participant_finalize; + + properties[PROP_ACTIVE] = g_param_spec_boolean("active", + "Active", + "Whether or not the participant is currently active (taking their turn)", + false, + G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + + properties[PROP_DEFEATED] = g_param_spec_boolean("defeated", + "Defeated", + "Whether or not the participant has been defeated", + false, + G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + + properties[PROP_NAME] = g_param_spec_string("name", + "Name", + "The Name of the participant", + "", + G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + + properties[PROP_PRIORITY] = g_param_spec_float("priority", + "Priority", + "The turn priority of the participant", + -INFINITY, + +INFINITY, + 0.0f, + G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + + properties[PROP_DISPOSITION] = g_param_spec_enum("disposition", + "Disposition", + "Disposition of the participant toward the players", + turns_participant_disposition_get_type(), + TURNS_PARTICIPANT_DISPOSITION_NEUTRAL, + G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties(object_class, N_PROPERTIES, properties); +} + +static void turns_participant_init(TurnsParticipant * self) +{ + self->id = g_uuid_string_random(); +} + +TurnsParticipant * turns_participant_new() +{ + return TURNS_PARTICIPANT(g_object_new(TURNS_TYPE_PARTICIPANT, nullptr)); +} + +TurnsParticipant * turns_participant_new_with(gchar const * name, gfloat priority, TurnsParticipantDisposition disposition) +{ + g_return_val_if_fail(name != nullptr, nullptr); + + return TURNS_PARTICIPANT(g_object_new(TURNS_TYPE_PARTICIPANT, "name", name, "priority", priority, "disposition", disposition, nullptr)); +} + +gboolean turns_participant_get_active(TurnsParticipant const * self) +{ + g_return_val_if_fail(TURNS_IS_PARTICIPANT((TurnsParticipant *)self), false); + return self->active; +} + +gboolean turns_participant_get_defeated(TurnsParticipant const * self) +{ + g_return_val_if_fail(TURNS_IS_PARTICIPANT((TurnsParticipant *)self), false); + return self->defeated; +} + +TurnsParticipantDisposition turns_participant_get_disposition(TurnsParticipant const * self) +{ + g_return_val_if_fail(TURNS_IS_PARTICIPANT((TurnsParticipant *)self), TURNS_PARTICIPANT_DISPOSITION_NEUTRAL); + return self->disposition; +} + +gchar const * turns_participant_get_id(TurnsParticipant const * self) +{ + g_return_val_if_fail(TURNS_IS_PARTICIPANT((TurnsParticipant *)self), nullptr); + return self->id; +} + +gchar const * turns_participant_get_name(TurnsParticipant const * self) +{ + g_return_val_if_fail(TURNS_IS_PARTICIPANT((TurnsParticipant *)self), nullptr); + return self->name; +} + +gfloat turns_participant_get_priority(TurnsParticipant const * self) +{ + g_return_val_if_fail(TURNS_IS_PARTICIPANT((TurnsParticipant *)self), 0.0f); + return self->priority; +} + +void turns_participant_set_active(TurnsParticipant * self, gboolean value) +{ + g_return_if_fail(TURNS_IS_PARTICIPANT(self)); + + if (value == self->active) + { + return; + } + + self->active = value; + g_object_notify_by_pspec(G_OBJECT(self), properties[PROP_ACTIVE]); +} + +void turns_participant_set_defeated(TurnsParticipant * self, gboolean value) +{ + g_return_if_fail(TURNS_IS_PARTICIPANT(self)); + + if (value == self->defeated) + { + return; + } + + self->defeated = value; + g_object_notify_by_pspec(G_OBJECT(self), properties[PROP_DEFEATED]); +} + +void turns_participant_set_disposition(TurnsParticipant * self, TurnsParticipantDisposition value) +{ + g_return_if_fail(TURNS_IS_PARTICIPANT(self)); + + if (value == self->disposition) + { + return; + } + + self->disposition = value; + g_object_notify_by_pspec(G_OBJECT(self), properties[PROP_DISPOSITION]); +} + +void turns_participant_set_name(TurnsParticipant * self, gchar const * value) +{ + g_return_if_fail(TURNS_IS_PARTICIPANT(self)); + g_return_if_fail(value != nullptr); + + if (!g_set_str(&self->name, value)) + { + return; + } + + g_object_notify_by_pspec(G_OBJECT(self), properties[PROP_NAME]); +} + +void turns_participant_set_priority(TurnsParticipant * self, gfloat value) +{ + g_return_if_fail(TURNS_IS_PARTICIPANT(self)); + + if (value == self->priority) + { + return; + } + + self->priority = value; + g_object_notify_by_pspec(G_OBJECT(self), properties[PROP_PRIORITY]); +} diff --git a/lib/src/turns-participant.cpp b/lib/src/turns-participant.cpp deleted file mode 100644 index e69de6e..0000000 --- a/lib/src/turns-participant.cpp +++ /dev/null @@ -1,272 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 Felix Morgner - * SPDX-License-Identifier: LGPL-2.1-only - */ - -#include "turns-participant.h" - -#include -#include - -#include -#include -#include - -G_BEGIN_DECLS - -struct _TurnsParticipant -{ - GObject parent_instance; - - gboolean active; - gboolean defeated; - TurnsParticipantDisposition disposition; - gchar * id; - gchar * name; - gfloat priority; -}; - -G_DEFINE_TYPE(TurnsParticipant, turns_participant, G_TYPE_OBJECT) - -G_END_DECLS - -namespace -{ - enum struct property - { - Active = 1, - Defeated, - Disposition, - Name, - Priority, - N_PROPERTIES, - }; - - auto static constinit properties = std::array(property::N_PROPERTIES)>{}; - - auto finalize(GObject * self) - { - auto participant = TURNS_PARTICIPANT(self); - - g_free(participant->id); - g_free(participant->name); - - G_OBJECT_CLASS(turns_participant_parent_class)->finalize(self); - } - - auto get_property(GObject * self, guint id, GValue * value, GParamSpec * specification) -> void - { - auto participant = TURNS_PARTICIPANT(self); - - switch (static_cast(id)) - { - case property::Active: - return g_value_set_boolean(value, turns_participant_get_active(participant)); - case property::Defeated: - return g_value_set_boolean(value, turns_participant_get_defeated(participant)); - case property::Name: - return g_value_set_string(value, turns_participant_get_name(participant)); - case property::Priority: - return g_value_set_float(value, turns_participant_get_priority(participant)); - case property::Disposition: - return g_value_set_enum(value, turns_participant_get_disposition(participant)); - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(self, id, specification); - }; - } - - auto set_property(GObject * self, guint id, GValue const * value, GParamSpec * specification) -> void - { - auto participant = TURNS_PARTICIPANT(self); - - switch (static_cast(id)) - { - case property::Active: - return turns_participant_set_active(participant, g_value_get_boolean(value)); - case property::Defeated: - return turns_participant_set_defeated(participant, g_value_get_boolean(value)); - case property::Name: - return turns_participant_set_name(participant, g_value_get_string(value)); - case property::Priority: - return turns_participant_set_priority(participant, g_value_get_float(value)); - case property::Disposition: - return turns_participant_set_disposition(participant, static_cast(g_value_get_enum(value))); - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(self, id, specification); - } - } -} // namespace - -G_BEGIN_DECLS - -static void turns_participant_class_init(TurnsParticipantClass * klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - - (void)object_class; - - object_class->get_property = get_property; - object_class->set_property = set_property; - object_class->finalize = finalize; - - properties[static_cast(property::Active)] = - g_param_spec_boolean("active", - "Active", - "Whether or not the participant is currently active (taking their turn)", - false, - static_cast(G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY)); - - properties[static_cast(property::Defeated)] = - g_param_spec_boolean("defeated", - "Defeated", - "Whether or not the participant has been defeated", - false, - static_cast(G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY)); - - properties[static_cast(property::Name)] = - g_param_spec_string("name", - "Name", - "The Name of the participant", - "", - static_cast(G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY)); - - properties[static_cast(property::Priority)] = - g_param_spec_float("priority", - "Priority", - "The turn priority of the participant", - -std::numeric_limits::infinity(), - +std::numeric_limits::infinity(), - 0.0f, - static_cast(G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY)); - - properties[static_cast(property::Disposition)] = - g_param_spec_enum("disposition", - "Disposition", - "Disposition of the participant toward the players", - turns_participant_disposition_get_type(), - TURNS_PARTICIPANT_DISPOSITION_NEUTRAL, - static_cast(G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY)); - - g_object_class_install_properties(object_class, static_cast(property::N_PROPERTIES), properties.data()); -} - -static void turns_participant_init(TurnsParticipant * self) -{ - self->id = g_uuid_string_random(); -} - -TurnsParticipant * turns_participant_new() -{ - return static_cast(g_object_new(TURNS_TYPE_PARTICIPANT, nullptr)); -} - -TurnsParticipant * turns_participant_new_with(gchar const * name, gfloat priority, TurnsParticipantDisposition disposition) -{ - g_return_val_if_fail(name != nullptr, nullptr); - - return static_cast( - g_object_new(TURNS_TYPE_PARTICIPANT, "name", name, "priority", priority, "disposition", static_cast(disposition), nullptr)); -} - -gboolean turns_participant_get_active(TurnsParticipant const * self) -{ - g_return_val_if_fail(TURNS_IS_PARTICIPANT(const_cast(self)), false); - return self->active; -} - -gboolean turns_participant_get_defeated(TurnsParticipant const * self) -{ - g_return_val_if_fail(TURNS_IS_PARTICIPANT(const_cast(self)), false); - return self->defeated; -} - -TurnsParticipantDisposition turns_participant_get_disposition(TurnsParticipant const * self) -{ - g_return_val_if_fail(TURNS_IS_PARTICIPANT(const_cast(self)), TurnsParticipantDisposition::TURNS_PARTICIPANT_DISPOSITION_NEUTRAL); - return self->disposition; -} - -gchar const * turns_participant_get_id(TurnsParticipant const * self) -{ - g_return_val_if_fail(TURNS_IS_PARTICIPANT(const_cast(self)), nullptr); - return self->id; -} - -gchar const * turns_participant_get_name(TurnsParticipant const * self) -{ - g_return_val_if_fail(TURNS_IS_PARTICIPANT(const_cast(self)), nullptr); - return self->name; -} - -gfloat turns_participant_get_priority(TurnsParticipant const * self) -{ - g_return_val_if_fail(TURNS_IS_PARTICIPANT(const_cast(self)), 0.0f); - return self->priority; -} - -void turns_participant_set_active(TurnsParticipant * self, gboolean value) -{ - g_return_if_fail(TURNS_IS_PARTICIPANT(self)); - - if (value == self->active) - { - return; - } - - self->active = value; - g_object_notify_by_pspec(G_OBJECT(self), properties[static_cast(property::Active)]); -} - -void turns_participant_set_defeated(TurnsParticipant * self, gboolean value) -{ - g_return_if_fail(TURNS_IS_PARTICIPANT(self)); - - if (value == self->defeated) - { - return; - } - - self->defeated = value; - g_object_notify_by_pspec(G_OBJECT(self), properties[static_cast(property::Defeated)]); -} - -void turns_participant_set_disposition(TurnsParticipant * self, TurnsParticipantDisposition value) -{ - g_return_if_fail(TURNS_IS_PARTICIPANT(self)); - - if (value == self->disposition) - { - return; - } - - self->disposition = value; - g_object_notify_by_pspec(G_OBJECT(self), properties[static_cast(property::Disposition)]); -} - -void turns_participant_set_name(TurnsParticipant * self, gchar const * value) -{ - g_return_if_fail(TURNS_IS_PARTICIPANT(self)); - g_return_if_fail(value != nullptr); - - if (!g_set_str(&self->name, value)) - { - return; - } - - g_object_notify_by_pspec(G_OBJECT(self), properties[static_cast(property::Name)]); -} - -void turns_participant_set_priority(TurnsParticipant * self, gfloat value) -{ - g_return_if_fail(TURNS_IS_PARTICIPANT(self)); - - if (value == self->priority) - { - return; - } - - self->priority = value; - g_object_notify_by_pspec(G_OBJECT(self), properties[static_cast(property::Priority)]); -} - -G_END_DECLS 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 + * SPDX-License-Identifier: LGPL-2.1-only + */ + +#include "turns-turn-order.h" + +#include "turns-participant.h" + +#include +#include +#include + +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); +} diff --git a/lib/src/turns-turn-order.cpp b/lib/src/turns-turn-order.cpp deleted file mode 100644 index 7c8b5cf..0000000 --- a/lib/src/turns-turn-order.cpp +++ /dev/null @@ -1,268 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 Felix Morgner - * SPDX-License-Identifier: LGPL-2.1-only - */ - -#include "turns-turn-order.h" - -#include "turns-participant.h" - -#include -#include -#include - -#include -#include -#include - -G_BEGIN_DECLS - -struct _TurnsTurnOrder -{ - GObject parent_instance; - - GSList * participants; - gboolean running; - TurnsTurnOrderSortMode sort_mode; -}; - -auto static turns_turn_order_list_model_init(GListModelInterface * iface) -> void; - -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)); - -G_END_DECLS - -namespace -{ - enum struct property - { - Running = 1, - SortMode, - N_PROPERTIES, - }; - - auto static constinit properties = std::array(property::N_PROPERTIES)>{}; - - /* Private Functions */ - - auto static inline compare_participant(TurnsParticipant const * lhs, TurnsParticipant const * rhs, TurnsTurnOrderSortMode sort_mode) - { - auto left_priority = turns_participant_get_priority(lhs); - auto right_priority = turns_participant_get_priority(rhs); - - auto ascending_result = [&] { - if (left_priority < right_priority) - { - return -1; - } - else if (left_priority > right_priority) - { - return 1; - } - else - { - return 0; - } - }(); - - if (sort_mode == TURNS_TURN_ORDER_SORT_MODE_DESCENDING) - { - return ascending_result * -1; - } - - return ascending_result; - } - - auto static inline sort_participants(TurnsTurnOrder * self) - { - auto const sort_mode = turns_turn_order_get_sort_mode(self); - auto const sort_data = std::bit_cast(static_cast(sort_mode)); - auto const sort_function = std::bit_cast(&compare_participant); - - self->participants = g_slist_sort_with_data(self->participants, sort_function, sort_data); - - 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); - } - - /* Signal Handlers */ - - auto handle_participant_property_changed(TurnsParticipant const *, GParamSpec *, TurnsTurnOrder * self) - { - sort_participants(self); - } - -} // namespace - -G_BEGIN_DECLS - -/* GObject Construction / Destruction */ - -auto static turns_turn_order_init(TurnsTurnOrder * self) -> void -{ - self->participants = nullptr; - self->running = false; - self->sort_mode = TURNS_TURN_ORDER_SORT_MODE_DESCENDING; -} - -auto static turns_turn_order_finalize(GObject * self) -> void -{ - 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); -} - -/* GObject Property Accessors */ - -auto static turns_turn_order_get_property(GObject * self, guint id, GValue * value, GParamSpec * specification) -> void -{ - auto instance = TURNS_TURN_ORDER(self); - - switch (static_cast(id)) - { - case property::Running: - return g_value_set_boolean(value, turns_turn_order_get_running(instance)); - case property::SortMode: - return g_value_set_enum(value, turns_turn_order_get_sort_mode(instance)); - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(self, id, specification); - } -} - -auto static turns_turn_order_set_property(GObject * self, guint id, GValue const * value, GParamSpec * specification) -> void -{ - auto instance = TURNS_TURN_ORDER(self); - - switch (static_cast(id)) - { - case property::SortMode: - return turns_turn_order_set_sort_mode(instance, static_cast(g_value_get_enum(value))); - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(self, id, specification); - } -} - -/* GType Class Initialization */ - -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[static_cast(property::Running)] = - g_param_spec_boolean("running", - "Running", - "Whether or not the turn order is running (e.g. has been started)", - false, - static_cast(G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY)); - - properties[static_cast(property::SortMode)] = - 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, - static_cast(G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY)); - - g_object_class_install_properties(object_class, properties.size(), properties.data()); -} - -/* GListModel Implementation */ - -auto static turns_turn_order_list_model_get_item(TurnsTurnOrder * self, guint position) -> gpointer -{ - g_return_val_if_fail(position < turns_turn_order_get_participant_count(self), nullptr); - return g_object_ref(g_slist_nth_data(self->participants, position)); -} - -auto static turns_turn_order_list_model_get_n_items(TurnsTurnOrder * self) -> guint -{ - return turns_turn_order_get_participant_count(self); -} - -auto static turns_turn_order_list_model_get_item_type(TurnsTurnOrder * self) -> GType -{ - static_cast(self); - return TURNS_TYPE_PARTICIPANT; -} - -auto static turns_turn_order_list_model_init(GListModelInterface * iface) -> void -{ - iface->get_item = std::bit_castget_item)>(&turns_turn_order_list_model_get_item); - iface->get_item_type = std::bit_castget_item_type)>(&turns_turn_order_list_model_get_item_type); - iface->get_n_items = std::bit_castget_n_items)>(&turns_turn_order_list_model_get_n_items); -} - -/* Constructors */ - -auto turns_turn_order_new() -> TurnsTurnOrder * -{ - return TURNS_TURN_ORDER(g_object_new(TURNS_TYPE_TURN_ORDER, nullptr)); -} - -/* Functions */ - -auto turns_turn_order_add(TurnsTurnOrder * self, TurnsParticipant * participant) -> void -{ - g_return_if_fail(participant != nullptr); - - g_signal_connect(participant, "notify::priority", std::bit_cast(&handle_participant_property_changed), self); - - auto sort_mode = turns_turn_order_get_sort_mode(self); - auto sort_data = std::bit_cast(static_cast(sort_mode)); - auto sort_function = std::bit_cast(&compare_participant); - - self->participants = g_slist_insert_sorted_with_data(self->participants, g_object_ref(participant), sort_function, sort_data); - - auto position = g_slist_index(self->participants, participant); - - g_list_model_items_changed(G_LIST_MODEL(self), position, 0, 1); -} - -/* Getters */ - -auto turns_turn_order_get_participant_count(TurnsTurnOrder const * self) -> gsize -{ - g_return_val_if_fail(TURNS_IS_TURN_ORDER(const_cast(self)), 0); - return g_slist_length(self->participants); -} - -auto turns_turn_order_get_running(TurnsTurnOrder const * self) -> gboolean -{ - g_return_val_if_fail(TURNS_IS_TURN_ORDER(const_cast(self)), false); - return self->running; -} - -auto turns_turn_order_get_sort_mode(TurnsTurnOrder const * self) -> TurnsTurnOrderSortMode -{ - g_return_val_if_fail(TURNS_IS_TURN_ORDER(const_cast(self)), TURNS_TURN_ORDER_SORT_MODE_ASCENDING); - return self->sort_mode; -} - -/* Setters */ - -auto turns_turn_order_set_sort_mode(TurnsTurnOrder * self, TurnsTurnOrderSortMode sort_mode) -> void -{ - 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[static_cast(property::SortMode)]); - - sort_participants(self); -} - -G_END_DECLS \ No newline at end of file diff --git a/lib/src/turns-turn-order.h b/lib/src/turns-turn-order.h index cc524c6..ce4d992 100644 --- a/lib/src/turns-turn-order.h +++ b/lib/src/turns-turn-order.h @@ -3,7 +3,7 @@ * SPDX-License-Identifier: LGPL-2.1-only */ - #ifndef TURNS_TURN_ORDER_H +#ifndef TURNS_TURN_ORDER_H #define TURNS_TURN_ORDER_H #include "turns-participant.h" @@ -13,18 +13,18 @@ G_BEGIN_DECLS +/** + * TurnsTurnOrderSortMode: + * @TURNS_TURN_ORDER_SORT_MODE_DESCENDING: Sort higher priorities before lower ones + * @TURNS_TURN_ORDER_SORT_MODE_ASCENDING: Sort higher priorities after lower ones + * + * Orderings that can be applied to the turn order. + * + * See [property@Turns.TurnOrder.sort-mode] + */ typedef enum { - /** - * @brief Sorting is in descending order. - * @since 1.0.0 - */ TURNS_TURN_ORDER_SORT_MODE_DESCENDING, - - /** - * @brief Sorting is in ascending order. - * @since 1.0.0 - */ TURNS_TURN_ORDER_SORT_MODE_ASCENDING, } TurnsTurnOrderSortMode; @@ -35,60 +35,59 @@ GType turns_turn_order_sort_mode_get_type(void) G_GNUC_CONST; G_DECLARE_FINAL_TYPE(TurnsTurnOrder, turns_turn_order, TURNS, TURN_ORDER, GObject) /** - * @class TurnsTurnOrder turns-turn-order.h "turns-turn-order.h" - * @since 1.0.0 - * @brief Manages the order of turns for a given set of participants. + * TurnsTurnOrder: + * + * Manages the order of turns for a given set of `TurnsParticipant`s. */ /** - * @brief Creates a new turn order. - * @since 1.0.0 + * turns_turn_order_new: + * + * Creates a new turn order. * - * @return A new @p Turns.TurnOrder + * Returns: (transfer full): a new `TurnsTurnOrder`. */ TurnsTurnOrder * turns_turn_order_new(void) G_GNUC_WARN_UNUSED_RESULT; /** - * @brief Adds a participant to the turn order. - * @since 1.0.0 + * turns_turn_order_add: + * @self: a turn order. + * @participant: (transfer full): A participant to be added. * - * @param participant The participant to be added. - * - * @note (transfer none) - The data is owned by the caller of the method. + * Adds a participant to a turn-order. */ void turns_turn_order_add(TurnsTurnOrder * self, TurnsParticipant * participant); /** - * @brief Gets the number of participants in the turn order. - * @since 1.0.0 + * turns_turn_order_get_participant_count: + * @self: a turn order. * - * @return The current number of participants in the 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; /** - * @brief Gets whether the turn order is currently running. - * @since 1.0.0 + * turns_turn_order_get_running: (get-property running): + * @self: a turn order. * - * @return The current value of the @p Turns.TurnOrder:running property. + * Gets whether the turn order is currently running. */ gboolean turns_turn_order_get_running(TurnsTurnOrder const * self) G_GNUC_WARN_UNUSED_RESULT; /** - * @brief Gets the current sort mode of the turn order. - * @since 1.0.0 + * turns_turn_order_get_sort_mode: (get-property sort-mode): + * @self: a turn order. * - * @return The current value of the @p Turns.TurnOrder:sort-mode property. + * 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; /** - * @brief Sets whether to sort lower priorities before larger ones. - * @since 1.0.0 - * - * Sets property @p Turns.TurnOrder:sort-mode + * turns_turn_order_set_sort_mode: (set-property sort-mode): + * @self: a turn order. + * @sort_mode: whether higher priorities should be sorted before or after lower ones. * - * @param sort_mode Whether to sort smaller priorities first. + * Sets whether higher priority values are sorted before or after lower ones. */ void turns_turn_order_set_sort_mode(TurnsTurnOrder * self, TurnsTurnOrderSortMode sort_mode); -- cgit v1.2.3