gpanthera.cc
C++ source, ASCII text
1
#include "gpanthera.hh"
2
#include <iostream>
3
#include <utility>
4
#include <gtk/gtk.h>
5
#include <libintl.h>
6
#include <locale.h>
7
#include <filesystem>
8
#define _(STRING) gettext(STRING)
9
10
namespace gPanthera {
11
void init() {
12
setlocale(LC_ALL, "ro_RO.utf8");
13
14
bindtextdomain("gpanthera", "./locales");
15
textdomain("gpanthera");
16
}
17
DockablePane::DockablePane(std::shared_ptr<LayoutManager> layout, Gtk::Widget &child, const Glib::ustring &name, const Glib::ustring &label, Gtk::Image *icon, DockStack *stack, Gtk::Widget *custom_header)
18
: Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0), name(name) {
19
if(icon) {
20
this->icon = icon;
21
}
22
if(stack) {
23
this->stack = stack;
24
}
25
this->layout = std::move(layout);
26
this->label.set_text(label);
27
header = std::make_unique<Gtk::HeaderBar>();
28
header->set_show_close_button(false);
29
if(custom_header) {
30
header->set_custom_title(*custom_header);
31
} else {
32
header->set_custom_title(this->label);
33
}
34
auto header_menu_button = Gtk::make_managed<Gtk::MenuButton>();
35
auto header_menu = Gtk::make_managed<Gtk::Menu>();
36
header_menu_button->set_direction(Gtk::ARROW_NONE);
37
header_menu_button->set_popup(*header_menu);
38
auto close_menu_item = Gtk::make_managed<Gtk::MenuItem>(_("Close"));
39
auto pop_out_menu_item = Gtk::make_managed<Gtk::MenuItem>(_("Pop out"));
40
auto move_menu = Gtk::make_managed<Gtk::Menu>();
41
close_menu_item->signal_activate().connect([this]() {
42
if(this->stack) {
43
this->stack->set_visible_child("empty");
44
}
45
});
46
pop_out_menu_item->signal_activate().connect([this]() {
47
if(this->stack) {
48
this->pop_out();
49
}
50
});
51
for(auto &this_stack: this->layout->stacks) {
52
auto menu_item = Gtk::make_managed<Gtk::MenuItem>(this_stack->name);
53
menu_item->signal_activate().connect([this, this_stack]() {
54
this_stack->add_pane(*this);
55
});
56
move_menu->append(*menu_item);
57
}
58
auto move_menu_item = Gtk::make_managed<Gtk::MenuItem>(_("Move"));
59
move_menu_item->set_submenu(*move_menu);
60
header_menu->append(*close_menu_item);
61
header_menu->append(*pop_out_menu_item);
62
header_menu->append(*move_menu_item);
63
header_menu->show_all();
64
header->pack_end(*header_menu_button);
65
this->pack_start(*header, Gtk::PACK_SHRINK);
66
this->child = &child;
67
this->pack_end(child, Gtk::PACK_EXPAND_WIDGET);
68
show_all_children();
69
}
70
71
void DockablePane::redock(DockStack *stack) {
72
if(this->window != nullptr) {
73
this->window->hide();
74
gtk_window_set_titlebar(GTK_WINDOW(this->window->gobj()), nullptr);
75
this->header->get_style_context()->remove_class("titlebar");
76
this->header->unset_background_color();
77
this->window->remove();
78
this->window->set_decorated(false);
79
this->window->close();
80
delete this->window;
81
this->window = nullptr;
82
this->pack_start(*this->header, Gtk::PACK_SHRINK);
83
this->header->show_all();
84
} else if(this->stack == this->get_parent()) {
85
this->stack->remove(*this);
86
}
87
this->stack = stack;
88
this->stack->add(*this, this->get_identifier());
89
this->show_all();
90
}
91
92
void DockablePane::pop_out() {
93
if(this->stack != nullptr) {
94
this->stack->remove(*this);
95
this->stack = nullptr;
96
}
97
98
if(this->window == nullptr) {
99
this->remove(*this->header);
100
this->window = new DockWindow(this);
101
this->window->set_titlebar(*this->header);
102
this->window->show_all();
103
}
104
}
105
106
Glib::ustring DockablePane::get_identifier() const {
107
return name;
108
}
109
110
Gtk::Image *DockablePane::get_icon() const {
111
return icon;
112
}
113
114
Gtk::Widget *DockablePane::get_child() const {
115
return child;
116
}
117
118
Gtk::Label *DockablePane::get_label() {
119
return &label;
120
}
121
122
LayoutManager::LayoutManager() : Glib::ObjectBase("LayoutManager") {
123
}
124
125
void LayoutManager::add_pane(DockablePane *pane) {
126
panes.push_back(pane);
127
}
128
129
void LayoutManager::add_stack(DockStack *stack) {
130
stacks.push_back(stack);
131
}
132
133
DockStack::DockStack(std::shared_ptr<LayoutManager> layout, const Glib::ustring &name) : Gtk::Stack(), layout(layout), name(name) {
134
auto *empty_child = Gtk::make_managed<Gtk::Box>(Gtk::ORIENTATION_VERTICAL, 0);
135
add(*empty_child, "empty");
136
// Add the stack to a layout manager
137
this->layout->add_stack(this);
138
}
139
140
DockWindow::DockWindow(DockablePane *pane) {
141
this->pane = pane;
142
this->add(*pane);
143
}
144
145
DockStackSwitcher::DockStackSwitcher(DockStack *stack) : Gtk::ButtonBox(Gtk::ORIENTATION_HORIZONTAL), stack(stack) {
146
add_handler = this->stack->signal_add().connect([this](Gtk::Widget *child) {
147
this->update_buttons();
148
});
149
remove_handler = this->stack->signal_remove().connect([this](Gtk::Widget *child) {
150
this->update_buttons();
151
});
152
this->set_layout(Gtk::BUTTONBOX_START);
153
}
154
155
DockStackSwitcher::~DockStackSwitcher() {
156
add_handler.disconnect();
157
remove_handler.disconnect();
158
}
159
160
DockButton::DockButton(DockablePane *pane) : Gtk::Button(), pane(pane) {
161
if(pane->get_icon()) {
162
this->set_image(*pane->get_icon());
163
}
164
this->set_tooltip_text(pane->get_label()->get_text());
165
this->set_halign(Gtk::ALIGN_CENTER);
166
}
167
168
void DockStackSwitcher::update_buttons() {
169
auto children = get_children();
170
for(auto &child: children) {
171
if(child) {
172
remove(*child);
173
}
174
}
175
for(auto const &widget : stack->get_children()) {
176
if(auto pane = dynamic_cast<DockablePane*>(widget)) {
177
auto *button = Gtk::make_managed<DockButton>(pane);
178
button->signal_clicked().connect([this, pane]() {
179
if(stack->get_visible_child_name() == pane->get_identifier()) {
180
stack->set_visible_child("empty");
181
} else {
182
stack->set_visible_child(pane->get_identifier());
183
}
184
});
185
if(pane->get_identifier() != Glib::ustring("empty")) {
186
pack_start(*button, Gtk::PACK_SHRINK, 0);
187
set_child_non_homogeneous(*button, true);
188
}
189
}
190
}
191
this->show_all();
192
}
193
194
void DockStack::add_pane(DockablePane &child) {
195
child.redock(this);
196
}
197
} // namespace gPanthera
198