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

 panthera-www.cc

View raw Download
text/x-c++ • 10.44 kiB
C++ source, ASCII text
        
            
1
#include "gpanthera.hh"
2
#include <gtkmm.h>
3
#include <glibmm.h>
4
#include <glibmm/ustring.h>
5
#include <iostream>
6
#include <memory>
7
#include <libintl.h>
8
#include <locale.h>
9
#include <gtk/gtk.h>
10
#include <gdk/gdk.h>
11
#include <webkit/webkit.h>
12
#include <fstream>
13
14
class PantheraWww : public Gtk::Application {
15
Gtk::Window *window = Gtk::make_managed<Gtk::Window>();
16
protected:
17
std::shared_ptr<gPanthera::LayoutManager> layout_manager;
18
std::shared_ptr<gPanthera::ContentManager> content_manager;
19
20
static void notify_callback(GObject *object, GParamSpec *pspec, gpointer data) {
21
if(!gtk_widget_get_parent(GTK_WIDGET(object))) {
22
return;
23
}
24
auto parent = gtk_widget_get_parent(gtk_widget_get_parent(GTK_WIDGET(object)));
25
if(auto page = dynamic_cast<gPanthera::ContentPage*>(Glib::wrap(parent))) {
26
if(g_strcmp0(pspec->name, "title") == 0) {
27
if(auto label = dynamic_cast<Gtk::Label*>(page->tab_widget)) {
28
label->set_label(webkit_web_view_get_title(WEBKIT_WEB_VIEW(object)));
29
}
30
}
31
}
32
}
33
34
void on_new_tab(gPanthera::ContentStack *stack) {
35
if(!stack) {
36
// Find the current area
37
stack = content_manager->get_last_operated_page()->get_stack();
38
}
39
40
WebKitWebView *webview = WEBKIT_WEB_VIEW(webkit_web_view_new());
41
gtk_widget_set_hexpand(GTK_WIDGET(webview), true);
42
gtk_widget_set_vexpand(GTK_WIDGET(webview), true);
43
auto page_content = Gtk::make_managed<Gtk::Box>();
44
gtk_box_append(page_content->gobj(), GTK_WIDGET(webview));
45
auto page_tab = new Gtk::Label("Untitled");
46
auto page = Gtk::make_managed<gPanthera::ContentPage>(content_manager, stack, page_content, page_tab);
47
g_signal_connect(webview, "notify", G_CALLBACK(notify_callback), page->gobj());
48
webkit_web_view_load_uri(webview, "about:blank");
49
stack->add_page(*page);
50
stack->set_visible_child(*page);
51
content_manager->set_last_operated_page(page);
52
}
53
54
void on_startup() override {
55
Gtk::Application::on_startup();
56
add_window(*window);
57
window->set_default_size(600, 400);
58
layout_manager = std::make_shared<gPanthera::LayoutManager>();
59
auto dock_stack_1 = Gtk::make_managed<gPanthera::DockStack>(layout_manager, "One", "one");
60
auto switcher_1 = Gtk::make_managed<gPanthera::DockStackSwitcher>(dock_stack_1, Gtk::Orientation::HORIZONTAL);
61
auto dock_stack_2 = Gtk::make_managed<gPanthera::DockStack>(layout_manager, "Two", "two");
62
auto switcher_2 = Gtk::make_managed<gPanthera::DockStackSwitcher>(dock_stack_2, Gtk::Orientation::VERTICAL);
63
auto pane_1_content = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 0);
64
auto debug_button = Gtk::make_managed<Gtk::Button>("Debug");
65
pane_1_content->append(*debug_button);
66
auto pane_2_content = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 0);
67
pane_2_content->append(*Gtk::make_managed<Gtk::Label>("Pane 2 content"));
68
auto pane_3_content = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 0);
69
pane_3_content->append(*Gtk::make_managed<Gtk::Label>("Pane 3 content"));
70
auto pane_1_icon = Gtk::make_managed<Gtk::Image>();
71
pane_1_icon->set_from_icon_name("go-home-symbolic");
72
auto pane_2_icon = Gtk::make_managed<Gtk::Image>();
73
pane_2_icon->set_from_icon_name("folder-symbolic");
74
auto pane_3_icon = Gtk::make_managed<Gtk::Image>();
75
pane_3_icon->set_from_icon_name("network-transmit-receive-symbolic");
76
auto pane_1 = Gtk::make_managed<gPanthera::DockablePane>(layout_manager, *pane_1_content, "pane1", "Pane 1", pane_1_icon);
77
auto pane_2 = Gtk::make_managed<gPanthera::DockablePane>(layout_manager, *pane_2_content, "pane2", "Pane 2", pane_2_icon);
78
auto pane_3 = Gtk::make_managed<gPanthera::DockablePane>(layout_manager, *pane_3_content, "pane3", "Pane 3", pane_3_icon);
79
80
dock_stack_1->set_transition_type(Gtk::StackTransitionType::SLIDE_LEFT_RIGHT);
81
dock_stack_1->set_transition_duration(125);
82
dock_stack_1->set_expand(true);
83
dock_stack_2->set_transition_type(Gtk::StackTransitionType::SLIDE_UP_DOWN);
84
dock_stack_2->set_transition_duration(125);
85
dock_stack_2->set_expand(true);
86
87
auto outer_grid = Gtk::make_managed<Gtk::Grid>();
88
outer_grid->attach(*switcher_2, 0, 1, 1, 1);
89
outer_grid->attach(*switcher_1, 1, 2, 1, 1);
90
auto outer_paned = Gtk::make_managed<Gtk::Paned>(Gtk::Orientation::HORIZONTAL);
91
outer_paned->set_start_child(*dock_stack_2);
92
auto inner_paned = Gtk::make_managed<Gtk::Paned>(Gtk::Orientation::VERTICAL);
93
auto content = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 0);
94
content_manager = std::make_shared<gPanthera::ContentManager>();
95
std::function<bool(gPanthera::ContentPage*)> detach_handler;
96
detach_handler = [](gPanthera::ContentPage *widget) {
97
auto new_stack = Gtk::make_managed<gPanthera::ContentStack>(widget->content_manager, widget->get_stack()->get_detach_handler());
98
auto new_switcher = Gtk::make_managed<gPanthera::ContentTabBar>(new_stack, Gtk::Orientation::HORIZONTAL, dynamic_cast<gPanthera::ContentTabBar*>(widget->get_stack()->get_parent()->get_first_child())->get_extra_child_function());
99
auto new_notebook = Gtk::make_managed<gPanthera::ContentNotebook>(new_stack, new_switcher);
100
auto window = new gPanthera::ContentWindow(new_notebook);
101
widget->redock(new_stack);
102
window->present();
103
new_stack->signal_leave_empty.connect([window]() {
104
window->close();
105
delete window;
106
});
107
return true;
108
};
109
110
auto return_extra_child = [this](gPanthera::ContentTabBar *switcher) {
111
auto new_tab_button = Gtk::make_managed<Gtk::Button>();
112
new_tab_button->set_child(*Gtk::make_managed<Gtk::Image>(Gio::Icon::create("list-add-symbolic")));
113
new_tab_button->set_tooltip_text("New tab");
114
new_tab_button->signal_clicked().connect([this, switcher]() {
115
on_new_tab(switcher->get_stack());
116
});
117
return new_tab_button;
118
};
119
auto content_stack = Gtk::make_managed<gPanthera::ContentStack>(content_manager, detach_handler);
120
auto content_stack_switcher = Gtk::make_managed<gPanthera::ContentTabBar>(content_stack, Gtk::Orientation::HORIZONTAL, return_extra_child);
121
content_manager->add_stack(content_stack);
122
WebKitWebView *webview = WEBKIT_WEB_VIEW(webkit_web_view_new());
123
webkit_web_view_load_uri(webview, "https://www.example.com");
124
gtk_widget_set_hexpand(GTK_WIDGET(webview), true);
125
gtk_widget_set_vexpand(GTK_WIDGET(webview), true);
126
auto page_1_content = Gtk::make_managed<Gtk::Box>();
127
gtk_box_append(page_1_content->gobj(), GTK_WIDGET(webview));
128
auto page_1_tab = new Gtk::Label("Page 1");
129
auto page_1 = Gtk::make_managed<gPanthera::ContentPage>(content_manager, content_stack, page_1_content, page_1_tab);
130
auto page_2_content = Gtk::make_managed<Gtk::Label>("Page 2...");
131
auto page_2_tab = new Gtk::Label("Page 2");
132
auto page_2 = Gtk::make_managed<gPanthera::ContentPage>(content_manager, content_stack, page_2_content, page_2_tab);
133
content->set_name("content_box");
134
auto content_notebook = Gtk::make_managed<gPanthera::ContentNotebook>(content_stack, content_stack_switcher, Gtk::PositionType::TOP);
135
content->append(*content_notebook);
136
inner_paned->set_start_child(*content);
137
inner_paned->set_end_child(*dock_stack_1);
138
outer_paned->set_end_child(*inner_paned);
139
outer_grid->attach(*outer_paned, 1, 1, 1, 1);
140
window->set_child(*outer_grid);
141
debug_button->signal_clicked().connect([this]() {
142
if(content_manager->get_last_operated_page()) {
143
std::cout << "Last operated page: " << content_manager->get_last_operated_page()->get_name() << std::endl;
144
} else {
145
std::cout << "No page operated!" << std::endl;
146
}
147
});
148
// TODO: Use the last operated page and allow opening tabs next to the last operated page using certain panes
149
// Load the existing layout, if it exists
150
std::ifstream layout_file_in("layout.json");
151
if(layout_file_in) {
152
std::string layout_json((std::istreambuf_iterator<char>(layout_file_in)), std::istreambuf_iterator<char>());
153
layout_file_in.close();
154
layout_manager->restore_json_layout(layout_json);
155
} else {
156
// Create a new layout if the file doesn't exist
157
layout_file_in.close();
158
159
dock_stack_1->add_pane(*pane_1);
160
dock_stack_1->add_pane(*pane_3);
161
dock_stack_2->add_pane(*pane_2);
162
163
std::ofstream layout_file_out("layout.json");
164
layout_file_out << layout_manager->get_layout_as_json();
165
layout_file_out.close();
166
}
167
// Save the layout when changed
168
layout_manager->signal_pane_moved.connect([this](gPanthera::DockablePane *pane) {
169
std::ofstream layout_file_out("layout.json");
170
layout_file_out << layout_manager->get_layout_as_json();
171
layout_file_out.close();
172
std::cout << "Layout changed: " << layout_manager->get_layout_as_json() << std::endl;
173
});
174
175
auto new_tab_action = Gio::SimpleAction::create("new_tab");
176
new_tab_action->signal_activate().connect([this](const Glib::VariantBase&) {
177
on_new_tab(nullptr);
178
});
179
add_action(new_tab_action);
180
set_accels_for_action("app.new_tab", {"<Primary>T"});
181
auto close_tab_action = Gio::SimpleAction::create("close_tab");
182
close_tab_action->signal_activate().connect([this](const Glib::VariantBase&) {
183
auto page = content_manager->get_last_operated_page();
184
if(page) {
185
page->close();
186
}
187
});
188
add_action(close_tab_action);
189
set_accels_for_action("app.close_tab", {"<Primary>W"});
190
}
191
192
void on_activate() override {
193
window->present();
194
}
195
public:
196
static Glib::RefPtr<PantheraWww> create() {
197
return Glib::make_refptr_for_instance<PantheraWww>(new PantheraWww());
198
}
199
};
200
201
int main(int argc, char *argv[]) {
202
gPanthera::init();
203
auto app = PantheraWww::create();
204
return app->run(argc, argv);
205
}
206