#include "turns/ui/windows/tracker.hpp" #include "turns/adw/toast.hpp" #include "turns/adw/toastoverlay.hpp" #include "turns/core/turn_order.hpp" #include "turns/lang/messages.hpp" #include "turns/ui/widgets/turn_order_view.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace turns::ui::windows { tracker::tracker(BaseObjectType * base, Glib::RefPtr const builder, Glib::RefPtr settings) : Gtk::ApplicationWindow{base} , m_controls{builder->get_widget("controls")} , m_empty{builder->get_widget("empty")} , m_overlay{builder->get_widget("overlay")} , m_stack{builder->get_widget("stack")} , m_start{builder->get_widget("start")} , m_title{builder->get_widget("title")} , m_turn_order{core::turn_order::create()} , m_turn_order_view{Gtk::make_managed(m_turn_order)} , m_settings{std::move(settings)} , m_subtitle{m_title, "subtitle"} , m_css{Gtk::CssProvider::create()} { setup_colors(); setup_actions(); m_stack->add(*m_turn_order_view); m_turn_order->is_empty().signal_changed().connect(sigc::mem_fun(*this, &tracker::update_subtitle)); m_turn_order->round_number().signal_changed().connect(sigc::mem_fun(*this, &tracker::update_subtitle)); update_subtitle(); // clang-format off 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->is_running(), m_controls->property_reveal_child(), Glib::Binding::Flags::SYNC_CREATE); // clang-format on m_settings->bind("skip-defeated", m_turn_order->skip_defeated()); } auto tracker::setup_actions() -> void { // win.add_participant // depends-on: turn_order:state == stopped { auto action = add_action("add_participant", sigc::mem_fun(*this, &tracker::add_participant)); 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:is_empty == false { auto action = add_action("clear", sigc::mem_fun(*m_turn_order, &core::turn_order::clear)); Glib::Binding::bind_property(m_turn_order->is_empty(), action->property_enabled(), Glib::Binding::Flags::SYNC_CREATE | Glib::Binding::Flags::INVERT_BOOLEAN); } // win.next // depends-on: turn_order:state == running { auto action = add_action("next", sigc::mem_fun(*m_turn_order, &core::turn_order::next)); Glib::Binding::bind_property(m_turn_order->is_running(), action->property_enabled(), Glib::Binding::Flags::SYNC_CREATE); } // win.previous // depends-on: turn_order:has_previous == true { auto action = add_action("previous", sigc::mem_fun(*m_turn_order, &core::turn_order::previous)); Glib::Binding::bind_property(m_turn_order->has_previous(), action->property_enabled(), Glib::Binding::Flags::SYNC_CREATE); } // win.start // depends-on: turn_order:is_empty == false { auto action = add_action("start", sigc::mem_fun(*m_turn_order, &core::turn_order::start)); Glib::Binding::bind_property(m_turn_order->is_empty(), action->property_enabled(), Glib::Binding::Flags::SYNC_CREATE | Glib::Binding::Flags::INVERT_BOOLEAN); Glib::Binding::bind_property(m_turn_order->is_running(), m_start->property_visible(), Glib::Binding::Flags::SYNC_CREATE | Glib::Binding::Flags::INVERT_BOOLEAN); } // win.stop // depends-on: turn_order:running == true { auto action = add_action("stop", sigc::mem_fun(*this, &tracker::stop)); Glib::Binding::bind_property(m_turn_order->is_running(), action->property_enabled(), Glib::Binding::Flags::SYNC_CREATE); } // win.delete // win.edit // win.open // win.preferences { add_action_with_parameter("delete", Glib::VARIANT_TYPE_INT32, sigc::mem_fun(*this, &tracker::delete_participant)); add_action_with_parameter("edit", Glib::VARIANT_TYPE_INT32, sigc::mem_fun(*this, &tracker::edit_participant)); add_action("open", sigc::mem_fun(*this, &tracker::open)); add_action("preferences", sigc::mem_fun(*this, &tracker::preferences)); } // win.save // depends-on: turn_order:is_empty == false { auto action = add_action("save", sigc::bind(sigc::mem_fun(*this, &tracker::save), false)); Glib::Binding::bind_property(m_turn_order->is_empty(), action->property_enabled(), Glib::Binding::Flags::SYNC_CREATE | Glib::Binding::Flags::INVERT_BOOLEAN); } // win.save-as // depends-on: turn_order:is_empty == false { auto action = add_action("save-as", sigc::bind(sigc::mem_fun(*this, &tracker::save), true)); Glib::Binding::bind_property(m_turn_order->is_empty(), action->property_enabled(), Glib::Binding::Flags::SYNC_CREATE | Glib::Binding::Flags::INVERT_BOOLEAN); } } auto tracker::setup_colors() -> void { Gtk::CssProvider::add_provider_for_display(get_display(), m_css, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); m_settings->signal_changed().connect(sigc::mem_fun(*this, &tracker::on_settings_changed)); update_colors(); } auto tracker::start_replace_content() -> void { m_file_buffer = m_turn_order->serialize().dump(2); m_file->replace_contents_async(sigc::mem_fun(*this, &tracker::on_replace_content_done), m_file_buffer, m_file_etag); } auto tracker::show_error(std::exception const & e) -> void { auto error = e.what(); show_toast(std::vformat(_(lang::saving_failed_format), std::make_format_args(error))); } auto tracker::show_toast(std::string const & message) -> void { m_overlay->add(adw::Toast{message}); } auto tracker::update_colors() -> void { auto friendly_color = m_settings->get_string("disposition-color-friendly"); auto hostile_color = m_settings->get_string("disposition-color-hostile"); auto secret_color = m_settings->get_string("disposition-color-secret"); m_css->load_from_string(std::format("@define-color friendly {};\n" "@define-color hostile {};\n" "@define-color secret {};\n", friendly_color.c_str(), hostile_color.c_str(), secret_color.c_str())); } auto tracker::update_subtitle() -> void { if (m_turn_order->is_empty()) { m_subtitle = _(lang::no_active_turn_order); } else { auto round_number = m_turn_order->round_number() + 1; m_subtitle = round_number == 0 ? "" : std::vformat(_(lang::round_number), std::make_format_args(round_number)); } } auto tracker::load(Glib::RefPtr file) -> void { if (file->query_exists()) { m_file = file; m_file->load_contents_async(sigc::mem_fun(*this, &tracker::on_load_content_done)); set_sensitive(false); } } } // namespace turns::ui::windows