GTK docking interfaces and more

By using this site, you agree to have cookies stored on your device, strictly for functional purposes, such as storing your session and preferences.

Dismiss

 gpanthera.cc

View raw Download
text/x-c++ • 6.27 kiB
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
add_handler = this->stack->signal_add().connect([this](Gtk::Widget *child) {
137
this->update_buttons();
138
});
139
remove_handler = this->stack->signal_remove().connect([this](Gtk::Widget *child) {
140
this->update_buttons();
141
});
142
}
143
144
DockStackSwitcher::~DockStackSwitcher() {
145
add_handler.disconnect();
146
remove_handler.disconnect();
147
}
148
149
void DockStackSwitcher::update_buttons() {
150
auto children = get_children();
151
for(auto &child: children) {
152
if(child) {
153
remove(*child);
154
}
155
}
156
for(auto const &widget : stack->get_children()) {
157
if(auto pane = dynamic_cast<DockablePane*>(widget)) {
158
auto *button = Gtk::make_managed<Gtk::Button>();
159
if(pane->get_icon()) {
160
button->set_image(*pane->get_icon());
161
}
162
button->signal_clicked().connect([this, pane]() {
163
if(stack->get_visible_child_name() == pane->get_identifier()) {
164
stack->set_visible_child("empty");
165
} else {
166
stack->set_visible_child(pane->get_identifier());
167
}
168
});
169
if(pane->get_identifier() != Glib::ustring("empty")) {
170
pack_start(*button);
171
}
172
}
173
}
174
this->show_all();
175
}
176
177
void DockStack::add_pane(DockablePane &child) {
178
child.redock(this);
179
}
180
} // namespace gPanthera
181