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