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++ • 5.99 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
}
75
this->stack = stack;
76
this->stack->add(*this, this->get_identifier());
77
this->show_all();
78
}
79
80
void DockablePane::pop_out() {
81
if(this->stack != nullptr) {
82
this->stack->remove(*this);
83
this->stack = nullptr;
84
}
85
86
if(this->window == nullptr) {
87
this->remove(*this->header);
88
this->window = new DockWindow(this);
89
this->window->set_titlebar(*this->header);
90
this->window->show_all();
91
}
92
}
93
94
Glib::ustring DockablePane::get_identifier() const {
95
return name;
96
}
97
98
Gtk::Image *DockablePane::get_icon() const {
99
return icon;
100
}
101
102
Gtk::Widget *DockablePane::get_child() const {
103
return child;
104
}
105
106
Gtk::Label *DockablePane::get_label() {
107
return &label;
108
}
109
110
LayoutManager::LayoutManager() : Glib::ObjectBase("LayoutManager") {
111
}
112
113
void LayoutManager::add_pane(DockablePane *pane) {
114
panes.push_back(pane);
115
}
116
117
void LayoutManager::add_stack(DockStack *stack) {
118
stacks.push_back(stack);
119
}
120
121
DockStack::DockStack(std::shared_ptr<LayoutManager> layout, const Glib::ustring &name) : Gtk::Stack(), layout(layout), name(name) {
122
auto *empty_child = Gtk::make_managed<Gtk::Box>(Gtk::ORIENTATION_VERTICAL, 0);
123
add(*empty_child, "empty");
124
// Add the stack to a layout manager
125
this->layout->add_stack(this);
126
}
127
128
DockWindow::DockWindow(DockablePane *pane) {
129
this->pane = pane;
130
this->add(*pane);
131
}
132
133
DockStackSwitcher::DockStackSwitcher(DockStack *stack) : Gtk::ButtonBox(Gtk::ORIENTATION_HORIZONTAL), stack(stack) {
134
this->stack->signal_add().connect([this](Gtk::Widget *child) {
135
this->update_buttons();
136
});
137
this->stack->signal_remove().connect([this](Gtk::Widget *child) {
138
this->update_buttons();
139
});
140
}
141
142
void DockStackSwitcher::update_buttons() {
143
for(auto &child: get_children()) {
144
if(child) {
145
remove(*child);
146
}
147
}
148
for(auto const &widget : stack->get_children()) {
149
if(auto pane = dynamic_cast<DockablePane*>(widget)) {
150
auto *button = Gtk::make_managed<Gtk::Button>();
151
if(pane->get_icon()) {
152
button->set_image(*pane->get_icon());
153
}
154
button->signal_clicked().connect([this, pane]() {
155
if(stack->get_visible_child_name() == pane->get_identifier()) {
156
stack->set_visible_child("empty");
157
} else {
158
stack->set_visible_child(pane->get_identifier());
159
}
160
});
161
if(pane->get_identifier() != Glib::ustring("empty")) {
162
pack_start(*button);
163
}
164
}
165
}
166
this->show_all();
167
}
168
169
void DockStack::add_pane(DockablePane &child) {
170
child.redock(this);
171
}
172
} // namespace gPanthera
173