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