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