#include "turns/domain/turn_order.hpp" #include "turns/domain/participant.hpp" #include #include #include #include #include namespace turns::domain { namespace { auto constexpr comparator = [](auto lhs, auto rhs) { return *lhs > *rhs; }; auto constexpr equal_comparator = [](auto lhs, auto rhs) { return (lhs->get_name() == rhs->get_name()) && (lhs->get_priority() && rhs->get_priority()); }; } // namespace /** Construction */ turn_order::turn_order() : Glib::ObjectBase{typeid(turn_order)} , Gio::ListModel{} { } auto turn_order::create() -> Glib::RefPtr { return Glib::make_refptr_for_instance(new turn_order{}); } /** Queries */ auto turn_order::is_empty() const -> Glib::PropertyProxy_ReadOnly { return m_is_empty.get_proxy(); } auto turn_order::has_next() const -> Glib::PropertyProxy_ReadOnly { return m_has_next.get_proxy(); } auto turn_order::has_previous() const -> Glib::PropertyProxy_ReadOnly { return m_has_previous.get_proxy(); } auto turn_order::is_running() const -> Glib::PropertyProxy_ReadOnly { return m_is_running.get_proxy(); } auto turn_order::round_number() const -> Glib::PropertyProxy_ReadOnly { return m_round_number.get_proxy(); } /** Modifiers */ auto turn_order::add(Glib::ustring const & name, float priority, disposition disposition) -> void { 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 (get_n_items() == 1) { m_is_empty = false; m_has_next = true; } } auto turn_order::clear() -> void { m_is_running = false; m_is_empty = true; m_has_next = false; m_has_previous = 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 { 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_number = m_round_number + 1; } } auto turn_order::previous() -> void { if (!(m_has_previous && m_is_running)) { return; } 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_number > 0) { m_round_number = m_round_number - 1; } } auto turn_order::remove(unsigned index) -> void { if (index >= get_n_items()) { return; } auto position = m_data.begin() + index; m_data.erase(position); items_changed(index, 1, 0); if (get_n_items() == 0) { m_is_empty = true; m_is_running = false; m_has_next = false; } } auto turn_order::start() -> void { if (!m_active) { m_active = 0; m_data[*m_active]->is_active() = true; } if (m_round_number == invalid_round_number) { m_round_number = 0; } m_is_running = true; } auto turn_order::stop() -> void { m_is_running = false; } /** ListModel implementation */ auto turn_order::get_item_type_vfunc() -> GType { return participant::get_type(); } auto turn_order::get_n_items_vfunc() -> unsigned { return m_data.size(); } auto turn_order::get_item_vfunc(unsigned position) -> void * { if (position >= get_n_items()) { return nullptr; } auto item = m_data[position]; item->reference(); return item->gobj(); } /** Signal handlers */ auto turn_order::handle_priority_changed(value_type entry) -> void { auto original_position = find(entry); auto original_index = distance(m_data.cbegin(), original_position); auto target_position = std::ranges::upper_bound(m_data, entry, comparator); if (original_position == target_position) { return; } m_data.erase(original_position); auto inserted_position = insert(entry); items_changed(0, get_n_items(), get_n_items()); if (m_active == original_index) { m_active = distance(m_data.cbegin(), inserted_position); m_has_previous = m_round_number > 0 || m_active > 0; } } /** Data management */ auto turn_order::find(value_type entry) const -> const_iterator { return std::ranges::find(m_data, entry); } auto turn_order::insert(value_type entry) -> const_iterator { return m_data.insert(std::ranges::upper_bound(m_data, entry, comparator), entry); } } // namespace turns::domain