summaryrefslogtreecommitdiff
path: root/ui/src/windows/tracker.cpp
blob: e64eb185131f9cafc15e4612f14378862c8e5c60 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#include "turns/ui/windows/tracker.hpp"

#include "turns/core/turn_order.hpp"
#include "turns/lang/messages.hpp"
#include "turns/ui/widgets/turn_order_view.hpp"

#include <sigc++/adaptors/bind.h>
#include <sigc++/functors/mem_fun.h>

#include <glibmm/binding.h>
#include <glibmm/i18n.h>
#include <glibmm/refptr.h>
#include <glibmm/varianttype.h>

#include <giomm/liststore.h>

#include <gtkmm/applicationwindow.h>
#include <gtkmm/builder.h>
#include <gtkmm/button.h>
#include <gtkmm/error.h>
#include <gtkmm/filedialog.h>
#include <gtkmm/object.h>
#include <gtkmm/revealer.h>
#include <gtkmm/stack.h>
#include <gtkmm/widget.h>

#include <adwaita.h>
#include <nlohmann/json.hpp>

#include <exception>
#include <format>
#include <string>

namespace turns::ui::windows
{

  tracker::tracker(BaseObjectType * base, Glib::RefPtr<Gtk::Builder> const builder)
      : Gtk::ApplicationWindow{base}
      , m_controls{builder->get_widget<Gtk::Revealer>("controls")}
      , m_empty{builder->get_widget<Gtk::Widget>("empty")}
      , m_overlay{builder->get_widget<Gtk::Widget>("overlay")}
      , m_stack{builder->get_widget<Gtk::Stack>("stack")}
      , m_start{builder->get_widget<Gtk::Button>("start")}
      , m_title{builder->get_widget<Gtk::Widget>("title")}
      , m_turn_order{core::turn_order::create()}
      , m_turn_order_view{Gtk::make_managed<widgets::turn_order_view>(m_turn_order)}
      , m_subtitle{m_title, "subtitle"}
  {
    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
  }

  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
    {
      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));
    }

    // 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::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
  {
    auto toast = adw_toast_new(message.c_str());
    adw_toast_overlay_add_toast(ADW_TOAST_OVERLAY(m_overlay->gobj()), toast);
  }

  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));
    }
  }

}  // namespace turns::ui::windows