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