roundabout,
created on Thursday, 24 April 2025, 15:44:22 (1745509462),
received on Thursday, 24 April 2025, 15:44:28 (1745509468)
Author identity: vlad <vlad.muntoiu@gmail.com>
121c4a47ed4b2ac0e04e855a29272b2f30e9091d
CMakeLists.txt
@@ -8,10 +8,12 @@ add_library(gpanthera SHARED gpanthera.cc)
add_executable(panthera-www panthera-www.cc) target_link_libraries(panthera-www gpanthera) target_link_libraries(panthera-www webkitgtk-6.0) target_link_libraries(panthera-www nlohmann_json::nlohmann_json)find_package(PkgConfig REQUIRED) pkg_check_modules(GTKMM REQUIRED gtkmm-4.0) pkg_check_modules(WebKit REQUIRED webkitgtk-6.0) find_package(nlohmann_json 3.10.0 REQUIRED)include_directories(${GTKMM_INCLUDE_DIRS}) link_directories(${GTKMM_LIBRARY_DIRS})
gpanthera.cc
@@ -7,6 +7,9 @@
#include <locale.h> #include <filesystem> #include <ranges> #include <nlohmann/json.hpp> #include <unordered_set>#define _(STRING) gettext(STRING) namespace gPanthera {
@@ -76,7 +79,8 @@ namespace gPanthera {
if(stack) { this->stack = stack; } this->layout = std::move(layout);this->layout = layout; this->layout->add_pane(this);this->label.set_text(label); // This should be replaced with a custom class in the future header = std::make_unique<Gtk::HeaderBar>();
@@ -172,6 +176,7 @@ namespace gPanthera {
action->set_enabled(true); this->header->get_style_context()->remove_class("gpanthera-dock-titlebar-popout"); } layout->signal_pane_moved.emit(this);} void DockablePane::pop_out() {
@@ -193,6 +198,7 @@ namespace gPanthera {
this->header->get_style_context()->add_class("gpanthera-dock-titlebar-popout"); } this->window->present(); layout->signal_pane_moved.emit(this);} Glib::ustring DockablePane::get_identifier() const {
@@ -1063,4 +1069,48 @@ namespace gPanthera {
this->last_operated_page = page; this->signal_page_operated.emit(page); } DockWindow *DockablePane::get_window() const { return this->window; } std::string LayoutManager::get_layout_as_json() const { nlohmann::json json; std::unordered_set<DockablePane*> panes_set; for(auto pane: panes) { panes_set.insert(pane); } for(auto stack: stacks) { for(auto pane: collect_children(*stack)) { if(dynamic_cast<DockablePane*>(pane)) { panes_set.erase(dynamic_cast<DockablePane*>(pane)); json[stack->id].push_back(dynamic_cast<DockablePane*>(pane)->get_identifier()); } } } for(auto pane: panes_set) { if(pane->get_window()) { json[""].push_back(pane->get_identifier()); } } return json.dump(); } void LayoutManager::restore_json_layout(const std::string &json_string) { nlohmann::json json = nlohmann::json::parse(json_string); for(auto stack: stacks) { if(json.contains(stack->id)) { for(auto const &pane_id: json[stack->id]) { for(auto pane: panes) { // TODO: could probably be done with a better complexity if there are // many panes if(pane->get_identifier() == static_cast<Glib::ustring>(pane_id.get<std::string>())) { stack->add_pane(*pane); break; } } } } } }} // namespace gPanthera
gpanthera.hh
@@ -28,6 +28,7 @@ namespace gPanthera {
Gtk::Widget *child; Glib::RefPtr<Gio::SimpleActionGroup> action_group; public: DockWindow *get_window() const;std::shared_ptr<LayoutManager> layout; Glib::RefPtr<Gio::Menu> header_menu = Gio::Menu::create(); DockStack *last_stack = nullptr;
@@ -53,7 +54,11 @@ namespace gPanthera {
public: std::vector<DockablePane*> panes; std::vector<DockStack*> stacks; sigc::signal<void(DockablePane*)> signal_pane_moved;LayoutManager(); std::string get_layout_as_json() const; void restore_json_layout(const std::string& json_string);void add_pane(DockablePane *pane);
panthera-www.cc
@@ -9,6 +9,7 @@
#include <gtk/gtk.h> #include <gdk/gdk.h> #include <webkit/webkit.h> #include <fstream>class PantheraWww : public Gtk::Application { Gtk::Window *window = Gtk::make_managed<Gtk::Window>();
@@ -78,10 +79,6 @@ protected:
dock_stack_2->set_transition_duration(125); dock_stack_2->set_expand(true); dock_stack_1->add_pane(*pane_1);dock_stack_1->add_pane(*pane_3);dock_stack_2->add_pane(*pane_2);auto outer_grid = Gtk::make_managed<Gtk::Grid>(); outer_grid->attach(*switcher_2, 0, 1, 1, 1); outer_grid->attach(*switcher_1, 1, 2, 1, 1);
@@ -139,7 +136,32 @@ protected:
debug_button->signal_clicked().connect([this]() { std::cout << "Last operated page: " << content_manager->get_last_operated_page()->get_name() << std::endl; }); // TODO: Use the last operated page and allow opening tabs next to the last operated page using panes// TODO: Use the last operated page and allow opening tabs next to the last operated page using certain panes // Load the existing layout, if it exists std::ifstream layout_file_in("layout.json"); if(layout_file_in) { std::string layout_json((std::istreambuf_iterator<char>(layout_file_in)), std::istreambuf_iterator<char>()); layout_file_in.close(); layout_manager->restore_json_layout(layout_json); } else { // Create a new layout if the file doesn't exist layout_file_in.close(); dock_stack_1->add_pane(*pane_1); dock_stack_1->add_pane(*pane_3); dock_stack_2->add_pane(*pane_2); std::ofstream layout_file_out("layout.json"); layout_file_out << layout_manager->get_layout_as_json(); layout_file_out.close(); } // Save the layout when changed layout_manager->signal_pane_moved.connect([this](gPanthera::DockablePane *pane) { std::ofstream layout_file_out("layout.json"); layout_file_out << layout_manager->get_layout_as_json(); layout_file_out.close(); std::cout << "Layout changed: " << layout_manager->get_layout_as_json() << std::endl; });} void on_activate() override {