From 2e6940b63a5e4675750c81877d07677df2a70f66 Mon Sep 17 00:00:00 2001 From: hippoz <10706925-hippoz@users.noreply.gitlab.com> Date: Thu, 28 Jul 2022 18:51:56 +0300 Subject: [PATCH] add top bar with functional back and forward buttons --- src/AppWidget.cpp | 26 ++++++++++++++++++++++++++ src/AppWidget.hpp | 12 ++++++++++++ src/CheckpointStack.hpp | 37 +++++++++++++++++++++++++++++++++++++ src/DirectoryView.cpp | 29 +++++++++++++++++++++++------ src/DirectoryView.hpp | 9 ++++++++- src/FileButton.cpp | 2 +- src/TopBar.cpp | 34 ++++++++++++++++++++++++++++++++++ src/TopBar.hpp | 21 +++++++++++++++++++++ src/main.cpp | 4 ++-- 9 files changed, 164 insertions(+), 10 deletions(-) create mode 100644 src/AppWidget.cpp create mode 100644 src/AppWidget.hpp create mode 100644 src/CheckpointStack.hpp create mode 100644 src/TopBar.cpp create mode 100644 src/TopBar.hpp diff --git a/src/AppWidget.cpp b/src/AppWidget.cpp new file mode 100644 index 0000000..3d59749 --- /dev/null +++ b/src/AppWidget.cpp @@ -0,0 +1,26 @@ +#include "AppWidget.hpp" +#include "Box.hpp" +#include "BoxLayout.hpp" +#include "DirectoryView.hpp" +#include "TopBar.hpp" + +void AppWidget::on_init() { + auto layout = set_layout(Raven::Direction::Vertical); + layout->slot_pixel(32); // TopBar + layout->slot_percent(100); // DirectoryView + + auto top_bar = add(); + auto directory_view = add(); + + top_bar->on_action = [directory_view](TopBar::Action action) { + if (action == TopBar::Action::Back) { + directory_view->back(); + } else if (action == TopBar::Action::Forward) { + directory_view->forward(); + } else if (action == TopBar::Action::Home) { + directory_view->home(); + } + }; + + set_did_init(true); +} diff --git a/src/AppWidget.hpp b/src/AppWidget.hpp new file mode 100644 index 0000000..b07b9e5 --- /dev/null +++ b/src/AppWidget.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "Widget.hpp" + +class AppWidget : public Raven::Widget { +public: + AppWidget() + : Raven::Widget() {} +protected: + void on_init(); +private: +}; diff --git a/src/CheckpointStack.hpp b/src/CheckpointStack.hpp new file mode 100644 index 0000000..3a6d344 --- /dev/null +++ b/src/CheckpointStack.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include + +template +class CheckpointStack { +public: + CheckpointStack() {} + + void undo() { + if (m_history_index > 0) { + checkpoint_changed(m_history[--m_history_index]); + } + } + + void redo() { + if (!m_history.empty() && m_history_index != (m_history.size() - 1)) { + checkpoint_changed(m_history[++m_history_index]); + } + } + + void push(Entry entry) { + while (!m_history.empty() && (m_history.size() - 1) != m_history_index) { + m_history.erase(m_history.end()); + } + + m_history.push_back(entry); + m_history_index = m_history.size() - 1; + } + + std::function checkpoint_changed; +private: + std::vector m_history; + unsigned int m_history_index { 0 }; +}; diff --git a/src/DirectoryView.cpp b/src/DirectoryView.cpp index 25417ad..74140a6 100644 --- a/src/DirectoryView.cpp +++ b/src/DirectoryView.cpp @@ -3,7 +3,9 @@ DirectoryView::~DirectoryView() {} -void DirectoryView::update() { +void DirectoryView::set_current_path(std::filesystem::path path) { + m_current_path = path; + // microtasks defer execution of the callback until all external events are processed. // if they're not used here and update() is called in a click or hover handler, // chaos will ensue, as the widget tree will be updated during event propagation @@ -16,18 +18,33 @@ void DirectoryView::update() { } void DirectoryView::navigate(std::string path) { - m_current_path = path; - update(); + set_current_path(path); + m_checkpoint_stack.push(m_current_path); } void DirectoryView::navigate_relative(std::string path) { - m_current_path /= path; - update(); + navigate(m_current_path / path); } void DirectoryView::on_init() { + m_checkpoint_stack.checkpoint_changed = [this](std::filesystem::path go) { + set_current_path(go); + }; + m_target = make_target(); m_target->set_layout(12.0); - update(); + navigate("/"); set_did_init(true); } + +void DirectoryView::back() { + m_checkpoint_stack.undo(); +} + +void DirectoryView::forward() { + m_checkpoint_stack.redo(); +} + +void DirectoryView::home() { + std::cerr << "home(): not implemented" << std::endl; +} diff --git a/src/DirectoryView.hpp b/src/DirectoryView.hpp index f2daea5..566da66 100644 --- a/src/DirectoryView.hpp +++ b/src/DirectoryView.hpp @@ -1,11 +1,13 @@ #pragma once +#include #include #include #include "raven/Widget.hpp" #include "raven/ScrollContainer.hpp" #include "raven/DocumentLayout.hpp" #include "FileButton.hpp" +#include "CheckpointStack.hpp" class DirectoryView : public Raven::ScrollContainer { public: @@ -14,12 +16,17 @@ public: ~DirectoryView(); - void update(); void navigate(std::string path); void navigate_relative(std::string path); + void back(); + void forward(); + void home(); protected: + void set_current_path(std::filesystem::path path); + void on_init(); private: std::filesystem::path m_current_path { "/" }; std::shared_ptr m_target; + CheckpointStack m_checkpoint_stack {}; }; diff --git a/src/FileButton.cpp b/src/FileButton.cpp index 21a3c80..00f1346 100644 --- a/src/FileButton.cpp +++ b/src/FileButton.cpp @@ -22,7 +22,7 @@ void FileButton::on_init() { layout->slot_percent(100); // icon layout->slot_pixel(24); // name (text) - add("folder-adwaita.svg"); + add("/usr/share/icons/Papirus/128x128/places/folder-adwaita.svg"); auto label = add(m_name, Raven::PaintTextAlign::Center); label->rect().set_max_width(rect().width()); label->rect().set_max_height(24); diff --git a/src/TopBar.cpp b/src/TopBar.cpp new file mode 100644 index 0000000..b1172a5 --- /dev/null +++ b/src/TopBar.cpp @@ -0,0 +1,34 @@ +#include "TopBar.hpp" +#include "raven/Styles.hpp" +#include "raven/Box.hpp" +#include "raven/BoxLayout.hpp" +#include "raven/SvgWidget.hpp" +#include "raven/RowLayout.hpp" + +void TopBar::on_init() { + set_style(&Raven::accent_widget_style); + + auto layout = set_layout(Raven::Direction::Horizontal); + layout->slot_pixel(24, 3); + layout->set_margin(4); + layout->set_spacing(8); + + auto back_button = add("/usr/share/icons/Papirus/24x24/actions/back.svg"); + back_button->set_style(&Raven::default_button_style); + auto forward_button = add("/usr/share/icons/Papirus/24x24/actions/next.svg"); + forward_button->set_style(&Raven::default_button_style); + auto home_button = add("/usr/share/icons/Papirus/24x24/actions/go-home.svg"); + home_button->set_style(&Raven::default_button_style); + + back_button->on_click = [this]() { + on_action(Action::Back); + }; + forward_button->on_click = [this]() { + on_action(Action::Forward); + }; + home_button->on_click = [this]() { + on_action(Action::Home); + }; + + set_did_init(true); +} diff --git a/src/TopBar.hpp b/src/TopBar.hpp new file mode 100644 index 0000000..abc3959 --- /dev/null +++ b/src/TopBar.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "Widget.hpp" +#include + +class TopBar : public Raven::Widget { +public: +enum class Action { + Back = 0, + Forward, + Home +}; +public: + TopBar() + : Raven::Widget() {} + + std::function on_action { [](Action _){} }; +protected: + void on_init(); +private: +}; diff --git a/src/main.cpp b/src/main.cpp index b813ec5..630a00f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,10 +1,10 @@ -#include "DirectoryView.hpp" +#include "AppWidget.hpp" int main() { Raven::Window window {}; window.spawn_window(); - window.set_main_widget(); + window.set_main_widget(); window.run(true); return 0;