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