summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@gmail.com>2024-07-23 15:08:19 +0200
committerFelix Morgner <felix.morgner@gmail.com>2024-07-23 15:08:19 +0200
commit4ec6a2ae12b6adb843c0777649ff45a741ca6cbc (patch)
tree93dc2ba99dbcb42b2af73f0a3c4cd4f0c0f091c4
parent5f4249a37ce816b8deceb299bc841190fbb15983 (diff)
downloadturns-4ec6a2ae12b6adb843c0777649ff45a741ca6cbc.tar.xz
turns-4ec6a2ae12b6adb843c0777649ff45a741ca6cbc.zip
domain: redesign turn_order
-rw-r--r--.vscode/settings.json3
-rw-r--r--app/include/turns/app/widgets/turn_order_view.hpp1
-rw-r--r--app/include/turns/app/windows/participant_editor.hpp6
-rw-r--r--app/src/widgets/participant_row.cpp19
-rw-r--r--app/src/widgets/turn_order_view.cpp20
-rw-r--r--app/src/windows/participant_editor.cpp12
-rw-r--r--app/src/windows/tracker.cpp26
-rw-r--r--app/tests/windows/participant_editor.cpp4
-rw-r--r--domain/CMakeLists.txt2
-rw-r--r--domain/include/turns/domain/participant.hpp46
-rw-r--r--domain/include/turns/domain/turn_order.hpp111
-rw-r--r--domain/src/participant.cpp76
-rw-r--r--domain/src/turn_order.cpp237
-rw-r--r--domain/tests/participant.cpp90
-rw-r--r--domain/tests/register_types.cpp13
-rw-r--r--domain/tests/turn_order.cpp434
-rw-r--r--test_support/CMakeLists.txt1
-rw-r--r--test_support/src/glib_main.cpp9
18 files changed, 390 insertions, 720 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 3073d74..b1a65b9 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -9,7 +9,8 @@
"gobj",
"refptr",
"sigc",
- "ustring"
+ "ustring",
+ "vfunc"
],
"editor.tabSize": 2,
diff --git a/app/include/turns/app/widgets/turn_order_view.hpp b/app/include/turns/app/widgets/turn_order_view.hpp
index 7b7556f..15524a9 100644
--- a/app/include/turns/app/widgets/turn_order_view.hpp
+++ b/app/include/turns/app/widgets/turn_order_view.hpp
@@ -27,7 +27,6 @@ namespace turns::app::widgets
explicit turn_order_view(Glib::RefPtr<model_type> model = {});
private:
- auto handle_active_participant_changed() -> void;
auto handle_create_row(Glib::RefPtr<Glib::Object> const item) -> Gtk::Widget *;
Glib::RefPtr<model_type> m_model;
diff --git a/app/include/turns/app/windows/participant_editor.hpp b/app/include/turns/app/windows/participant_editor.hpp
index 764b9ba..23d0569 100644
--- a/app/include/turns/app/windows/participant_editor.hpp
+++ b/app/include/turns/app/windows/participant_editor.hpp
@@ -21,9 +21,9 @@ namespace turns::app::windows
struct participant_editor : Gtk::Widget
{
- using signal_finished_type = sigc::signal<void(decltype(std::declval<domain::participant const>().get_name()),
- decltype(std::declval<domain::participant const>().get_priority()),
- decltype(std::declval<domain::participant const>().get_disposition()))>;
+ using signal_finished_type = sigc::signal<void(decltype(std::declval<domain::participant const>().name().get_value()),
+ decltype(std::declval<domain::participant const>().priority().get_value()),
+ decltype(std::declval<domain::participant const>().disposition().get_value()))>;
participant_editor(BaseObjectType * base, Glib::RefPtr<Gtk::Builder> const builder, Glib::RefPtr<domain::participant> obj = {});
diff --git a/app/src/widgets/participant_row.cpp b/app/src/widgets/participant_row.cpp
index 3494834..87cc217 100644
--- a/app/src/widgets/participant_row.cpp
+++ b/app/src/widgets/participant_row.cpp
@@ -73,14 +73,14 @@ namespace turns::app::widgets
if (participant)
{
- Glib::Binding::bind_property(participant->property_name(), m_title->property_label(), Glib::Binding::Flags::SYNC_CREATE);
+ Glib::Binding::bind_property(participant->name(), m_title->property_label(), Glib::Binding::Flags::SYNC_CREATE);
- Glib::Binding::bind_property(participant->property_priority(),
+ Glib::Binding::bind_property(participant->priority(),
m_subtitle->property_label(),
Glib::Binding::Flags::SYNC_CREATE,
[](auto n) { return std::vformat(_(lang::priority_number), std::make_format_args(n)); });
- Glib::Binding::bind_property(participant->property_disposition(),
+ Glib::Binding::bind_property(participant->disposition(),
m_toggle_defeated->property_css_classes(),
Glib::Binding::Flags::SYNC_CREATE,
[this](auto value) {
@@ -92,6 +92,19 @@ namespace turns::app::widgets
classes.push_back(css_class_for(value));
return classes;
});
+
+ Glib::Binding::bind_property(participant->is_active(), property_css_classes(), Glib::Binding::Flags::SYNC_CREATE, [this](auto value) {
+ auto classes = get_css_classes();
+ if (!value)
+ {
+ std::erase(classes, "active-participant");
+ }
+ else
+ {
+ classes.push_back("active-participant");
+ }
+ return classes;
+ });
}
}
diff --git a/app/src/widgets/turn_order_view.cpp b/app/src/widgets/turn_order_view.cpp
index ccc6d25..67e0afa 100644
--- a/app/src/widgets/turn_order_view.cpp
+++ b/app/src/widgets/turn_order_view.cpp
@@ -25,35 +25,21 @@ namespace turns::app::widgets
{
if (model)
{
- m_view->bind_model(m_model->list_model(), sigc::mem_fun(*this, &turn_order_view::handle_create_row));
- m_model->property_active_participant().signal_changed().connect(
- sigc::mem_fun(*this, &turn_order_view::handle_active_participant_changed));
+ m_view->bind_model(m_model, sigc::mem_fun(*this, &turn_order_view::handle_create_row));
}
}
- auto turn_order_view::handle_active_participant_changed() -> void
- {
- std::ranges::for_each(m_view->get_children(), [](auto c) { c->remove_css_class("active-participant"); });
-
- auto index = m_model->active_participant();
- if (index != std::numeric_limits<domain::turn_order::active_participant_type>::max())
- {
- auto row = m_view->get_row_at_index(index);
- row->add_css_class("active-participant");
- row->grab_focus();
- }
- }
auto turn_order_view::handle_create_row(Glib::RefPtr<Glib::Object> const item) -> Gtk::Widget *
{
auto participant = std::dynamic_pointer_cast<domain::participant>(item);
auto row = Gtk::make_managed<widgets::participant_row>(participant);
- Glib::Binding::bind_property(m_model->property_running(),
+ Glib::Binding::bind_property(m_model->is_running(),
row->property_delete_enabled(),
Glib::Binding::Flags::SYNC_CREATE | Glib::Binding::Flags::INVERT_BOOLEAN);
- Glib::Binding::bind_property(m_model->property_running(),
+ Glib::Binding::bind_property(m_model->is_running(),
row->property_edit_enabled(),
Glib::Binding::Flags::SYNC_CREATE | Glib::Binding::Flags::INVERT_BOOLEAN);
diff --git a/app/src/windows/participant_editor.cpp b/app/src/windows/participant_editor.cpp
index 1c97442..0b35c72 100644
--- a/app/src/windows/participant_editor.cpp
+++ b/app/src/windows/participant_editor.cpp
@@ -42,9 +42,9 @@ namespace turns::app::windows
if (m_participant)
{
- gtk_editable_set_text(GTK_EDITABLE(m_name), m_participant->property_name().get_value().c_str());
- adw_spin_row_set_value(m_priority, m_participant->property_priority().get_value());
- adw_combo_row_set_selected(m_disposition, static_cast<unsigned>(m_participant->get_disposition()));
+ gtk_editable_set_text(GTK_EDITABLE(m_name), m_participant->name().get_value().c_str());
+ adw_spin_row_set_value(m_priority, m_participant->priority());
+ adw_combo_row_set_selected(m_disposition, static_cast<unsigned>(m_participant->disposition().get_value()));
}
}
@@ -66,9 +66,9 @@ namespace turns::app::windows
if (m_participant)
{
- m_participant->set_name(name);
- m_participant->set_priority(priority);
- m_participant->set_disposition(disposition);
+ m_participant->name() = name;
+ m_participant->priority() = priority;
+ m_participant->disposition() = disposition;
}
m_signal_finished.emit(name, priority, disposition);
diff --git a/app/src/windows/tracker.cpp b/app/src/windows/tracker.cpp
index b7520dd..11f4642 100644
--- a/app/src/windows/tracker.cpp
+++ b/app/src/windows/tracker.cpp
@@ -51,16 +51,16 @@ namespace turns::app::windows
m_stack->add(*m_turn_order_view);
// clang-format off
- Glib::Binding::bind_property(m_turn_order->property_empty(),
+ Glib::Binding::bind_property(m_turn_order->is_empty(),
m_stack->property_visible_child(),
Glib::Binding::Flags::SYNC_CREATE,
[this](auto empty) { return empty ? m_empty : m_turn_order_view; });
- Glib::Binding::bind_property(m_turn_order->property_running(),
+ Glib::Binding::bind_property(m_turn_order->is_running(),
m_controls->property_reveal_child(),
Glib::Binding::Flags::SYNC_CREATE);
- Glib::Binding::bind_property(m_turn_order->property_empty(),
+ Glib::Binding::bind_property(m_turn_order->is_empty(),
m_subtitle,
Glib::Binding::Flags::SYNC_CREATE,
[](auto empty) { return empty ? _(lang::no_active_turn_order) : ""; });
@@ -84,7 +84,7 @@ namespace turns::app::windows
{
static_cast<void>(param);
auto index = Glib::VariantBase::cast_dynamic<Glib::Variant<int>>(param);
- auto participant = m_turn_order->get(index.get());
+ auto participant = m_turn_order->get_typed_object<domain::participant>(index.get());
auto [lifeline, dialog] = editor_for(participant);
dialog->present(this);
}
@@ -112,17 +112,17 @@ namespace turns::app::windows
{
auto action = add_action("add_participant", sigc::mem_fun(*this, &tracker::handle_add_participant));
- Glib::Binding::bind_property(m_turn_order->property_running(),
+ Glib::Binding::bind_property(m_turn_order->is_running(),
action->property_enabled(),
Glib::Binding::Flags::SYNC_CREATE | Glib::Binding::Flags::INVERT_BOOLEAN);
}
// win.clear
- // depends-on: turn_order:empty == false
+ // depends-on: turn_order:is_empty == false
{
auto action = add_action("clear", sigc::mem_fun(*m_turn_order, &domain::turn_order::clear));
- Glib::Binding::bind_property(m_turn_order->property_empty(),
+ Glib::Binding::bind_property(m_turn_order->is_empty(),
action->property_enabled(),
Glib::Binding::Flags::SYNC_CREATE | Glib::Binding::Flags::INVERT_BOOLEAN);
}
@@ -132,7 +132,7 @@ namespace turns::app::windows
{
auto action = add_action("next", sigc::mem_fun(*m_turn_order, &domain::turn_order::next));
- Glib::Binding::bind_property(m_turn_order->property_running(), action->property_enabled(), Glib::Binding::Flags::SYNC_CREATE);
+ Glib::Binding::bind_property(m_turn_order->is_running(), action->property_enabled(), Glib::Binding::Flags::SYNC_CREATE);
}
// win.previous
@@ -140,19 +140,19 @@ namespace turns::app::windows
{
auto action = add_action("previous", sigc::mem_fun(*m_turn_order, &domain::turn_order::previous));
- Glib::Binding::bind_property(m_turn_order->property_has_previous(), action->property_enabled(), Glib::Binding::Flags::SYNC_CREATE);
+ Glib::Binding::bind_property(m_turn_order->has_previous(), action->property_enabled(), Glib::Binding::Flags::SYNC_CREATE);
}
// win.start
- // depends-on: turn_order:empty == false
+ // depends-on: turn_order:is_empty == false
{
auto action = add_action("start", sigc::mem_fun(*m_turn_order, &domain::turn_order::start));
- Glib::Binding::bind_property(m_turn_order->property_empty(),
+ Glib::Binding::bind_property(m_turn_order->is_running(),
action->property_enabled(),
Glib::Binding::Flags::SYNC_CREATE | Glib::Binding::Flags::INVERT_BOOLEAN);
- Glib::Binding::bind_property(m_turn_order->property_running(),
+ Glib::Binding::bind_property(m_turn_order->is_running(),
m_start->property_visible(),
Glib::Binding::Flags::SYNC_CREATE | Glib::Binding::Flags::INVERT_BOOLEAN);
}
@@ -162,7 +162,7 @@ namespace turns::app::windows
{
auto action = add_action("stop", sigc::mem_fun(*this, &tracker::handle_stop));
- Glib::Binding::bind_property(m_turn_order->property_running(), action->property_enabled(), Glib::Binding::Flags::SYNC_CREATE);
+ Glib::Binding::bind_property(m_turn_order->is_running(), action->property_enabled(), Glib::Binding::Flags::SYNC_CREATE);
}
// win.delete
diff --git a/app/tests/windows/participant_editor.cpp b/app/tests/windows/participant_editor.cpp
index 5808740..9f73861 100644
--- a/app/tests/windows/participant_editor.cpp
+++ b/app/tests/windows/participant_editor.cpp
@@ -95,13 +95,13 @@ namespace turns::app::windows::tests
SECTION("has its name field set according to its participant")
{
auto widget = GTK_EDITABLE(builder->get_widget<Gtk::ListBoxRow>("name")->gobj());
- REQUIRE(gtk_editable_get_text(widget) == participant->get_name());
+ REQUIRE(gtk_editable_get_text(widget) == participant->name().get_value());
}
SECTION("has its priority field set according to its participant")
{
auto widget = ADW_SPIN_ROW(builder->get_widget<Gtk::ListBoxRow>("priority")->gobj());
- REQUIRE(adw_spin_row_get_value(widget) == participant->get_priority());
+ REQUIRE(adw_spin_row_get_value(widget) == participant->priority());
}
SECTION("allows binding to the finished signal")
diff --git a/domain/CMakeLists.txt b/domain/CMakeLists.txt
index 58a7900..ec9eb62 100644
--- a/domain/CMakeLists.txt
+++ b/domain/CMakeLists.txt
@@ -37,6 +37,8 @@ target_link_options("domain" PRIVATE
# Tests
add_executable("domain-tests"
+ "tests/register_types.cpp"
+
"tests/disposition.cpp"
"tests/participant.cpp"
"tests/turn_order.cpp"
diff --git a/domain/include/turns/domain/participant.hpp b/domain/include/turns/domain/participant.hpp
index d845c77..b51425d 100644
--- a/domain/include/turns/domain/participant.hpp
+++ b/domain/include/turns/domain/participant.hpp
@@ -13,34 +13,44 @@
namespace turns::domain
{
-
struct participant : Glib::Object
{
auto static create(Glib::ustring name, float priority, disposition disposition) -> Glib::RefPtr<participant>;
+ participant();
participant(Glib::ustring name, float priority, disposition disposition);
auto operator<=>(participant const & other) const noexcept -> std::partial_ordering;
- auto property_disposition() -> Glib::PropertyProxy<disposition>;
- auto property_disposition() const -> Glib::PropertyProxy_ReadOnly<disposition>;
- auto get_disposition() const noexcept -> disposition;
- auto set_disposition(disposition value) -> void;
-
- auto property_name() -> Glib::PropertyProxy<Glib::ustring>;
- auto property_name() const -> Glib::PropertyProxy_ReadOnly<Glib::ustring>;
- auto get_name() const -> Glib::ustring;
- auto set_name(Glib::ustring value) -> void;
-
- auto property_priority() -> Glib::PropertyProxy<float>;
- auto property_priority() const -> Glib::PropertyProxy_ReadOnly<float>;
- auto get_priority() const noexcept -> float;
- auto set_priority(float value) -> void;
+ template<typename Self>
+ auto disposition(this Self && self)
+ {
+ return self.m_disposition.get_proxy();
+ }
+
+ template<typename Self>
+ auto is_active(this Self && self)
+ {
+ return self.m_is_active.get_proxy();
+ }
+
+ template<typename Self>
+ auto name(this Self && self)
+ {
+ return self.m_name.get_proxy();
+ }
+
+ template<typename Self>
+ auto priority(this Self && self)
+ {
+ return self.m_priority.get_proxy();
+ }
private:
- Glib::Property<disposition> m_disposition;
- Glib::Property<Glib::ustring> m_name;
- Glib::Property<float> m_priority;
+ Glib::Property<domain::disposition> m_disposition{*this, "disposition", domain::disposition::neutral};
+ Glib::Property<bool> m_is_active{*this, "active", false};
+ Glib::Property<Glib::ustring> m_name{*this, "name", ""};
+ Glib::Property<float> m_priority{*this, "priority", 0.0f};
};
} // namespace turns::domain
diff --git a/domain/include/turns/domain/turn_order.hpp b/domain/include/turns/domain/turn_order.hpp
index 3b42562..ca44b62 100644
--- a/domain/include/turns/domain/turn_order.hpp
+++ b/domain/include/turns/domain/turn_order.hpp
@@ -4,9 +4,12 @@
#include "turns/domain/disposition.hpp"
#include "turns/domain/participant.hpp"
+#include <initializer_list>
#include <limits>
+#include <optional>
+#include <vector>
-#include <giomm/liststore.h>
+#include <giomm/listmodel.h>
#include <glibmm/property.h>
#include <glibmm/refptr.h>
#include <glibmm/ustring.h>
@@ -14,91 +17,67 @@
namespace turns::domain
{
- struct turn_order : Glib::Object
+ struct turn_order : Gio::ListModel,
+ Glib::Object
{
+ using value_type = Glib::RefPtr<participant>;
+ using container_type = std::vector<value_type>;
+ using iterator = container_type::iterator;
+ using const_iterator = container_type::const_iterator;
+
using active_participant_type = unsigned int;
- using empty_type = bool;
+ using is_empty_type = bool;
using has_next_type = bool;
using has_previous_type = bool;
- using running_type = bool;
- using round_type = unsigned int;
+ using is_running_type = bool;
+ using round_number_type = unsigned int;
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 create() -> Glib::RefPtr<turn_order>;
-
+ /** Life-time */
turn_order();
- /** Modifiers */
+ auto static create() -> Glib::RefPtr<turn_order>;
+
+ /** Properties */
+ 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>;
+ auto round_number() const -> Glib::PropertyProxy_ReadOnly<round_number_type>;
+ /** Element Modifications */
auto add(Glib::ustring const & name, float priority, disposition disposition) -> void;
auto clear() -> void;
+ auto remove(unsigned index) -> void;
+
+ /** Turn Modification */
auto next() -> void;
auto previous() -> void;
- auto remove(unsigned int index) -> void;
- auto reset() -> void;
auto start() -> void;
auto stop() -> void;
- /** Querries */
-
- /**
- * Get the index of the currently active participant of this turn order, if any.
- *
- * @returns an unsigned integer in the range [0, size()) if there is an active participant, or turn_order::invalid_participant_index otherwise.
- */
- auto active_participant() const noexcept -> active_participant_type;
-
- /**
- * Check if this turn order is empty.
- */
- auto empty() const noexcept -> empty_type;
-
- /**
- * Get the actor at the specified position in this turn order.
- *
- * @return a valid pointer to a participant object if the index was valid, nullptr otherwise.
- */
- auto get(unsigned int index) const noexcept -> Glib::RefPtr<participant>;
-
- /**
- * Get the underlying list model, to be used with list views.
- */
- auto list_model() -> Glib::RefPtr<Gio::ListModel>;
-
- /**
- * Get the current round.
- */
- auto round() const noexcept -> round_type;
-
- /**
- * Check if this turn order is currently running.
- */
- auto running() const noexcept -> running_type;
-
- /**
- * Get the size of this turn order
- */
- auto size() const noexcept -> unsigned int;
+ private:
+ auto get_item_type_vfunc() -> GType override;
+ auto get_n_items_vfunc() -> unsigned override;
+ auto get_item_vfunc(unsigned position) -> void * override;
- /** Properties */
+ /** Signal handlers */
+ auto handle_priority_changed(value_type entry) -> void;
- auto property_active_participant() const -> Glib::PropertyProxy_ReadOnly<active_participant_type>;
- auto property_empty() const -> Glib::PropertyProxy_ReadOnly<empty_type>;
- auto property_has_next() const -> Glib::PropertyProxy_ReadOnly<has_next_type>;
- auto property_has_previous() const -> Glib::PropertyProxy_ReadOnly<has_previous_type>;
- auto property_running() const -> Glib::PropertyProxy_ReadOnly<running_type>;
- auto property_round() const -> Glib::PropertyProxy_ReadOnly<round_type>;
+ /** Data management */
+ auto find(value_type entry) const -> const_iterator;
+ auto insert(value_type entry) -> const_iterator;
- private:
- Glib::RefPtr<Gio::ListStore<participant>> m_model;
-
- Glib::Property<active_participant_type> m_active_participant;
- Glib::Property<empty_type> m_empty;
- Glib::Property<has_next_type> m_has_next;
- Glib::Property<has_previous_type> m_has_previous;
- Glib::Property<running_type> m_running;
- Glib::Property<round_type> m_round;
+ container_type m_data{};
+ std::optional<unsigned> m_active{};
+
+ Glib::Property<has_next_type> m_has_next{*this, "has-next", false};
+ Glib::Property<has_previous_type> m_has_previous{*this, "has-previous", false};
+ Glib::Property<is_empty_type> m_is_empty{*this, "is-empty", true};
+ Glib::Property<is_running_type> m_is_running{*this, "is-running", false};
+ Glib::Property<round_number_type> m_round_number{*this, "round-number", invalid_round_number};
};
} // namespace turns::domain
diff --git a/domain/src/participant.cpp b/domain/src/participant.cpp
index 5265eb3..6f0efb1 100644
--- a/domain/src/participant.cpp
+++ b/domain/src/participant.cpp
@@ -3,87 +3,33 @@
#include <typeinfo>
#include <utility>
+#include <glibmm/class.h>
#include <glibmm/refptr.h>
namespace turns::domain
{
-
- auto participant::create(Glib::ustring name, float priority, disposition disposition) -> Glib::RefPtr<participant>
+ auto participant::create(Glib::ustring name, float priority, domain::disposition disposition) -> Glib::RefPtr<participant>
{
return Glib::make_refptr_for_instance(new participant{name, priority, disposition});
}
- participant::participant(Glib::ustring name, float priority, disposition disposition)
+ participant::participant()
: Glib::ObjectBase{typeid(participant)}
- , m_disposition{*this, "disposition", disposition}
- , m_name{*this, "name", name}
- , m_priority{*this, "priority", priority}
- {
- }
-
- auto participant::operator<=>(participant const & other) const noexcept -> std::partial_ordering
- {
- return m_priority <=> other.m_priority;
- }
-
- auto participant::get_disposition() const noexcept -> disposition
- {
- return m_disposition;
- }
-
- auto participant::set_disposition(disposition value) -> void
- {
- m_disposition = value;
- }
-
- auto participant::get_name() const -> Glib::ustring
- {
- return m_name;
- }
-
- auto participant::set_name(Glib::ustring value) -> void
- {
- m_name = value;
- }
-
- auto participant::get_priority() const noexcept -> float
- {
- return m_priority;
- }
-
- auto participant::set_priority(float value) -> void
+ , Glib::Object{}
{
- m_priority = value;
}
- auto participant::property_disposition() -> Glib::PropertyProxy<disposition>
+ participant::participant(Glib::ustring name, float priority, domain::disposition disposition)
+ : participant()
{
- return m_disposition.get_proxy();
+ m_name = name;
+ m_priority = priority;
+ m_disposition = disposition;
}
- auto participant::property_disposition() const -> Glib::PropertyProxy_ReadOnly<disposition>
- {
- return m_disposition.get_proxy();
- }
-
- auto participant::property_name() -> Glib::PropertyProxy<Glib::ustring>
- {
- return m_name.get_proxy();
- }
-
- auto participant::property_name() const -> Glib::PropertyProxy_ReadOnly<Glib::ustring>
- {
- return m_name.get_proxy();
- }
-
- auto participant::property_priority() -> Glib::PropertyProxy<float>
- {
- return m_priority.get_proxy();
- }
-
- auto participant::property_priority() const -> Glib::PropertyProxy_ReadOnly<float>
+ auto participant::operator<=>(participant const & other) const noexcept -> std::partial_ordering
{
- return m_priority.get_proxy();
+ return m_priority <=> other.m_priority;
}
} // namespace turns::domain \ No newline at end of file
diff --git a/domain/src/turn_order.cpp b/domain/src/turn_order.cpp
index 61ccdca..0f8b6e8 100644
--- a/domain/src/turn_order.cpp
+++ b/domain/src/turn_order.cpp
@@ -2,11 +2,11 @@
#include "turns/domain/participant.hpp"
+#include <algorithm>
#include <compare>
#include <limits>
#include <typeinfo>
-#include <glibmm/binding.h>
#include <glibmm/refptr.h>
namespace turns::domain
@@ -32,194 +32,203 @@ namespace turns::domain
};
} // namespace
+ /** Construction */
+
+ turn_order::turn_order()
+ : Glib::ObjectBase{typeid(turn_order)}
+ , Gio::ListModel{}
+ {
+ }
+
auto turn_order::create() -> Glib::RefPtr<turn_order>
{
return Glib::make_refptr_for_instance(new turn_order{});
}
- turn_order::turn_order()
- : Glib::ObjectBase{typeid(turn_order)}
- , m_model{Gio::ListStore<participant>::create()}
- , m_active_participant(*this, "active_participant", invalid_participant_index)
- , m_empty{*this, "empty", true}
- , m_has_next{*this, "has-next", false}
- , m_has_previous{*this, "has-previous", false}
- , m_running{*this, "running", false}
- , m_round{*this, "round", 0}
+ /** Queries */
+
+ auto turn_order::is_empty() const -> Glib::PropertyProxy_ReadOnly<is_empty_type>
+ {
+ return m_is_empty.get_proxy();
+ }
+
+ auto turn_order::has_next() const -> Glib::PropertyProxy_ReadOnly<has_next_type>
+ {
+ return m_has_next.get_proxy();
+ }
+
+ auto turn_order::has_previous() const -> Glib::PropertyProxy_ReadOnly<has_previous_type>
+ {
+ return m_has_previous.get_proxy();
+ }
+
+ auto turn_order::is_running() const -> Glib::PropertyProxy_ReadOnly<is_running_type>
{
- Glib::Binding::bind_property(m_model->property_n_items(), m_empty.get_proxy(), Glib::Binding::Flags::DEFAULT, [](auto n) {
- return n == 0;
- });
+ return m_is_running.get_proxy();
+ }
+
+ auto turn_order::round_number() const -> Glib::PropertyProxy_ReadOnly<round_number_type>
+ {
+ return m_round_number.get_proxy();
}
/** Modifiers */
auto turn_order::add(Glib::ustring const & name, float priority, disposition disposition) -> void
{
- auto participant = participant::create(name, priority, disposition);
- if (auto [found, index] = m_model->find(participant, equal_comparator); !found)
- {
- auto position = m_model->insert_sorted(participant, comparator);
- participant->property_priority().signal_changed().connect([this] { m_model->sort(comparator); });
+ auto entry = participant::create(name, priority, disposition);
+ entry->priority().signal_changed().connect(sigc::bind(sigc::mem_fun(*this, &turn_order::handle_priority_changed), entry));
+ auto position = std::distance(m_data.cbegin(), insert(entry));
+ items_changed(position, 0, 1);
- if (m_active_participant != invalid_participant_index && position <= m_active_participant)
- {
- m_active_participant = m_active_participant + 1;
- }
+ if (get_n_items() == 1)
+ {
+ m_is_empty = false;
+ m_has_next = true;
}
}
auto turn_order::clear() -> void
{
- m_model->remove_all();
- m_active_participant = invalid_participant_index;
+ m_is_running = false;
+ m_is_empty = true;
m_has_next = false;
m_has_previous = false;
- m_running = false;
+ m_active.reset();
+ m_round_number = invalid_round_number;
+
+ auto old_size = get_n_items();
+ m_data.clear();
+ items_changed(0, old_size, 0);
}
auto turn_order::next() -> void
{
- m_active_participant = (m_active_participant + 1) % size();
- if (!m_active_participant)
+ auto old_active = *m_active;
+ m_active = m_active.transform([this](auto index) { return (index + 1) % get_n_items(); });
+
+ m_has_previous = true;
+ m_data[old_active]->is_active() = false;
+ m_data[*m_active]->is_active() = true;
+
+ if (m_active == 0)
{
- m_round = round() + 1;
+ m_round_number = m_round_number + 1;
}
- m_has_previous = m_active_participant || m_round;
}
auto turn_order::previous() -> void
{
- if (!m_has_previous)
+ if (!(m_has_previous && m_is_running))
{
return;
}
- if (m_active_participant)
- {
- m_active_participant = m_active_participant - 1;
- }
- else if (m_round)
+ auto old_active = *m_active;
+ m_active = m_active.transform([this](auto index) { return index ? index - 1 : get_n_items() - 1; });
+
+ m_has_previous = m_round_number > 0 || m_active > 0;
+ m_data[old_active]->is_active() = false;
+ m_data[*m_active]->is_active() = true;
+
+ if (m_active == 0)
{
- m_round = round() - 1;
- m_active_participant = size() - 1;
+ m_round_number = m_round_number - 1;
}
-
- m_has_previous = m_active_participant || m_round;
}
- auto turn_order::remove(unsigned int index) -> void
+ auto turn_order::remove(unsigned index) -> void
{
- m_model->remove(index);
- if (empty())
+ if (index >= get_n_items())
{
- m_active_participant = invalid_participant_index;
- m_has_next = false;
- m_has_previous = false;
- m_running = false;
+ return;
}
- else if (m_active_participant != invalid_participant_index)
+
+ auto position = m_data.begin() + index;
+ m_data.erase(position);
+ items_changed(index, 1, 0);
+ if (get_n_items() == 0)
{
- if (m_active_participant > size() - 1)
- {
- m_active_participant = size() - 1;