modes can now print stuff on the screen.

main
bog 2023-10-09 19:31:21 +02:00
parent 7b6f0b45f4
commit 924a6323a1
17 changed files with 350 additions and 16 deletions

View File

@ -10,5 +10,8 @@ tests: build
install: tests install: tests
meson install -C build meson install -C build
install-no-test: build
meson install -C build
doc: doc:
doxygen doxygen

View File

@ -25,6 +25,9 @@ pwq_lib = static_library('pywiq',
# View # View
# ---- # ----
'src/UI_Node.cpp',
'src/VBoxUI.cpp',
'src/View.cpp',
# Command # Command
# ------- # -------

View File

@ -7,9 +7,11 @@ namespace pwq
{ {
/*explicit*/ Mode::Mode(std::string const& name, /*explicit*/ Mode::Mode(std::string const& name,
Pywiq& pywiq, Pywiq& pywiq,
std::shared_ptr<UI_Node> ui,
std::shared_ptr<Executor> executor) std::shared_ptr<Executor> executor)
: m_name { name } : m_name { name }
, m_pywiq { pywiq } , m_pywiq { pywiq }
, m_ui { ui }
, m_executor { executor } , m_executor { executor }
{ {
} }
@ -28,6 +30,11 @@ namespace pwq
return m_executor; return m_executor;
} }
/*virtual*/ void Mode::update(KeyMod const& keymod)
{
m_executor->update(keymod);
}
void Mode::bind_action(std::vector<KeyMod> keys, void Mode::bind_action(std::vector<KeyMod> keys,
std::shared_ptr<Action> action) std::shared_ptr<Action> action)
{ {
@ -36,5 +43,4 @@ namespace pwq
Binding binding {keys, action}; Binding binding {keys, action};
m_executor->bind(binding); m_executor->bind(binding);
} }
} }

View File

@ -2,7 +2,8 @@
#define pwq_MODE_HPP #define pwq_MODE_HPP
#include "commons.hpp" #include "commons.hpp"
#include "src/KeyMod.hpp" #include "KeyMod.hpp"
#include "UI_Node.hpp"
namespace pwq namespace pwq
{ {
@ -19,13 +20,18 @@ namespace pwq
public: public:
explicit Mode(std::string const& name, explicit Mode(std::string const& name,
Pywiq& pywiq, Pywiq& pywiq,
std::shared_ptr<UI_Node> ui,
std::shared_ptr<Executor> executor); std::shared_ptr<Executor> executor);
virtual ~Mode(); virtual ~Mode();
Pywiq& pywiq(); Pywiq& pywiq();
std::weak_ptr<UI_Node> ui() const { return m_ui; }
std::weak_ptr<Executor> executor(); std::weak_ptr<Executor> executor();
virtual void update(KeyMod const& keymod);
void bind_action(std::vector<KeyMod> keys, void bind_action(std::vector<KeyMod> keys,
std::shared_ptr<Action> action); std::shared_ptr<Action> action);
@ -35,6 +41,7 @@ namespace pwq
private: private:
std::string m_name; std::string m_name;
Pywiq& m_pywiq; Pywiq& m_pywiq;
std::shared_ptr<UI_Node> m_ui;
std::shared_ptr<Executor> m_executor; std::shared_ptr<Executor> m_executor;
std::vector<std::shared_ptr<Action>> m_actions; std::vector<std::shared_ptr<Action>> m_actions;
}; };

View File

@ -1,14 +1,22 @@
#include "Pywiq.hpp" #include "Pywiq.hpp"
#include "UI_Node.hpp"
#include "Controller.hpp" #include "Controller.hpp"
#include "View.hpp"
#include "KeyMod.hpp" #include "KeyMod.hpp"
#include "Mode.hpp" #include "Mode.hpp"
#include "Executor.hpp" #include "Executor.hpp"
namespace pwq namespace pwq
{ {
/*explicit*/ Pywiq::Pywiq(Controller& controller) /*explicit*/ Pywiq::Pywiq(Controller& controller, View& view)
: m_controller { controller } : m_controller { controller }
, m_view { view }
, m_ui { std::make_shared<UI_Node>(nullptr)}
{ {
auto sz = m_view.size();
m_ui->reshape(0, 0, sz.first, sz.second);
} }
/*virtual*/ Pywiq::~Pywiq() /*virtual*/ Pywiq::~Pywiq()
@ -17,20 +25,25 @@ namespace pwq
void Pywiq::add_mode(std::shared_ptr<Mode> mode) void Pywiq::add_mode(std::shared_ptr<Mode> mode)
{ {
if (!m_modes.empty())
{
m_ui->rem_child(m_modes.back()->ui().lock());
}
m_modes.push_back(mode); m_modes.push_back(mode);
m_ui->add_child(m_modes.back()->ui().lock());
} }
bool Pywiq::exec() bool Pywiq::exec()
{ {
m_view.clear_screen();
m_view.draw(*m_ui);
KeyMod keymod = m_controller.wait_keymod(); KeyMod keymod = m_controller.wait_keymod();
for (auto mode: m_modes) for (auto mode: m_modes)
{ {
if (auto executor=mode->executor().lock(); mode->update(keymod);
executor)
{
executor->update(keymod);
}
} }
return m_running; return m_running;

View File

@ -7,6 +7,8 @@ namespace pwq
{ {
class Mode; class Mode;
class Controller; class Controller;
class View;
class UI_Node;
/** /**
* Manage the editor modes. * Manage the editor modes.
@ -14,7 +16,7 @@ namespace pwq
class Pywiq class Pywiq
{ {
public: public:
explicit Pywiq(Controller& controller); explicit Pywiq(Controller& controller, View& view);
virtual ~Pywiq(); virtual ~Pywiq();
void add_mode(std::shared_ptr<Mode> mode); void add_mode(std::shared_ptr<Mode> mode);
@ -24,7 +26,9 @@ namespace pwq
private: private:
Controller& m_controller; Controller& m_controller;
View& m_view;
std::vector<std::shared_ptr<Mode>> m_modes; std::vector<std::shared_ptr<Mode>> m_modes;
std::shared_ptr<UI_Node> m_ui;
bool m_running = true; bool m_running = true;
}; };
} }

View File

@ -81,4 +81,41 @@ namespace pwq
return *km; return *km;
} }
std::pair<int, int> Term::size() const /*override*/
{
int x, y;
getmaxyx(stdscr, y, x);
return {x, y};
}
void Term::clear_screen() /*override*/
{
clear();
}
void Term::draw(UI_Node const& ui) /*override*/
{
if (auto txt=ui.text();
txt)
{
int len = std::min((int) txt->size(), ui.global_size().first)
- ui.global_pos().first;
if (len > 0)
{
std::wstring text = txt->substr(0, len);
mvprintw(ui.global_pos().second,
ui.global_pos().first,
"%ls", text.c_str());
}
}
for (size_t i=0; i<ui.count(); i++)
{
draw(*ui.child(i).lock());
}
}
} }

View File

@ -5,6 +5,7 @@
#include "commons.hpp" #include "commons.hpp"
#include "Controller.hpp" #include "Controller.hpp"
#include "View.hpp"
namespace pwq namespace pwq
{ {
@ -12,7 +13,7 @@ namespace pwq
* Abstraction over NCurses. * Abstraction over NCurses.
* @see Controller * @see Controller
**/ **/
class Term: public Controller class Term: public Controller, public View
{ {
public: public:
explicit Term(); explicit Term();
@ -20,6 +21,10 @@ namespace pwq
KeyMod wait_keymod() override; KeyMod wait_keymod() override;
std::pair<int, int> size() const override;
void clear_screen() override;
void draw(UI_Node const& ui) override;
private: private:
std::unordered_map<std::string, KeyType> m_mapping; std::unordered_map<std::string, KeyType> m_mapping;
}; };

84
src/UI_Node.cpp Normal file
View File

@ -0,0 +1,84 @@
#include "UI_Node.hpp"
#include <string>
namespace pwq
{
/*explicit*/ UI_Node::UI_Node(std::shared_ptr<UI_Node> parent)
: m_parent { parent }
{
}
/*virtual*/ UI_Node::~UI_Node()
{
}
std::pair<int, int> UI_Node::global_pos() const
{
if (!m_parent)
{
return pos();
}
return {m_parent->global_pos().first + pos().first,
m_parent->global_pos().second + pos().second};
}
std::pair<int, int> UI_Node::global_size() const
{
if (!m_parent)
{
return size();
}
return {m_parent->global_size().first + size().first,
m_parent->global_size().second + size().second};
}
void UI_Node::set_text(std::wstring const& text)
{
m_text = text;
}
void UI_Node::reshape(int x, int y, int w, int h)
{
m_x = x;
m_y = y;
m_w = w;
m_h = h;
for (size_t i=0; i<m_children.size(); i++)
{
place(m_children[i], i);
}
}
/*virtual*/ void UI_Node::place(std::shared_ptr<UI_Node>, size_t)
{
}
std::weak_ptr<UI_Node> UI_Node::child(size_t index) const
{
PWQ_ASSERT(index < count(),
"cannot access ui node child at index '",
std::to_string(index), "'");
return m_children[index];
}
void UI_Node::add_child(std::shared_ptr<UI_Node> node)
{
m_children.push_back(node);
place(node, m_children.size() - 1);
}
void UI_Node::rem_child(std::shared_ptr<UI_Node> node)
{
auto itr = std::remove_if(std::begin(m_children),
std::end(m_children),
[&](auto child){
return child.get() == node.get();
});
m_children.erase(itr, std::end(m_children));
}
}

49
src/UI_Node.hpp Normal file
View File

@ -0,0 +1,49 @@
#ifndef pwq_UI_NODE_HPP
#define pwq_UI_NODE_HPP
#include "commons.hpp"
namespace pwq
{
/**
* Represents an element of the ui tree drawn by a view.
* @see View
**/
class UI_Node
{
public:
explicit UI_Node(std::shared_ptr<UI_Node> parent);
virtual ~UI_Node();
std::pair<int, int> pos() const { return {m_x, m_y}; }
std::pair<int, int> size() const { return {m_w, m_h}; }
size_t count() const { return m_children.size(); }
std::optional<std::wstring> text() const { return m_text; }
std::pair<int, int> global_pos() const;
std::pair<int, int> global_size() const;
void set_text(std::wstring const& text);
std::weak_ptr<UI_Node> child(size_t index) const;
virtual void add_child(std::shared_ptr<UI_Node> node);
virtual void reshape(int x, int y, int w, int h);
virtual void place(std::shared_ptr<UI_Node> node, size_t index);
void rem_child(std::shared_ptr<UI_Node> node);
protected:
std::shared_ptr<UI_Node> m_parent;
int m_x = 0;
int m_y = 0;
int m_w = 0;
int m_h = 0;
std::optional<std::wstring> m_text;
std::vector<std::shared_ptr<UI_Node>> m_children;
};
}
#endif

27
src/VBoxUI.cpp Normal file
View File

@ -0,0 +1,27 @@
#include "VBoxUI.hpp"
namespace pwq
{
/*explicit*/ VBoxUI::VBoxUI(std::shared_ptr<UI_Node> parent)
: UI_Node(parent)
{
}
/*virtual*/ VBoxUI::~VBoxUI()
{
}
void VBoxUI::place(std::shared_ptr<UI_Node> node, size_t index)
{
int const x = node->pos().first;
int y = node->pos().second;;
if (index > 0)
{
y = m_children[index - 1]->pos().second
+ m_children[index - 1]->size().second;
}
node->reshape(x, y, m_w, node->size().second);
}
}

24
src/VBoxUI.hpp Normal file
View File

@ -0,0 +1,24 @@
#ifndef pwq_VBOXUI_HPP
#define pwq_VBOXUI_HPP
#include "commons.hpp"
#include "UI_Node.hpp"
namespace pwq
{
/**
* Arrange its children verticaly.
* @see UI_Node
**/
class VBoxUI: public UI_Node
{
public:
explicit VBoxUI(std::shared_ptr<UI_Node> parent);
virtual ~VBoxUI();
virtual void place(std::shared_ptr<UI_Node> node, size_t index);
private:
};
}
#endif

12
src/View.cpp Normal file
View File

@ -0,0 +1,12 @@
#include "View.hpp"
namespace pwq
{
/*explicit*/ View::View()
{
}
/*virtual*/ View::~View()
{
}
}

27
src/View.hpp Normal file
View File

@ -0,0 +1,27 @@
#ifndef pwq_VIEW_HPP
#define pwq_VIEW_HPP
#include "commons.hpp"
#include "UI_Node.hpp"
namespace pwq
{
/**
* Interface used to draw ui nodes.
* @see UI_Node
**/
class View
{
public:
explicit View();
virtual ~View();
virtual void clear_screen() = 0;
virtual void draw(UI_Node const& node) = 0;
virtual std::pair<int, int> size() const = 0;
private:
};
}
#endif

View File

@ -22,4 +22,17 @@
NAME (std::string const& what): std::runtime_error(what) {} \ NAME (std::string const& what): std::runtime_error(what) {} \
} }
#define PWQ_ASSERT(COND, ...) \
if ( !(COND) ) \
{ \
std::vector<std::string> msgs = {__VA_ARGS__}; \
\
for (auto const& msg: msgs) \
{ \
std::cerr << msg; \
} \
\
abort(); \
}
#endif #endif

View File

@ -5,15 +5,24 @@
#include "Executor.hpp" #include "Executor.hpp"
#include "Term.hpp" #include "Term.hpp"
#include "actions/Quit.hpp" #include "actions/Quit.hpp"
#include "VBoxUI.hpp"
int main(int, char**) int main(int, char**)
{ {
pwq::Term term; pwq::Term term;
pwq::Pywiq pywiq {term}; pwq::Pywiq pywiq {term, term};
auto executor = std::make_shared<pwq::Executor>(); auto executor = std::make_shared<pwq::Executor>();
auto default_mode = std::make_shared<pwq::Mode>("default",
auto default_ui = std::make_shared<pwq::VBoxUI>(nullptr);
std::wstring msg = L"Hello World!";
default_ui->reshape(0, 0, msg.size(), 1);
default_ui->set_text(msg);
auto default_mode = std::make_shared<pwq::Mode>
("default",
pywiq, pywiq,
default_ui,
executor); executor);
auto quit = default_mode->make_action<pwq::actions::Quit>(); auto quit = default_mode->make_action<pwq::actions::Quit>();

View File

@ -3,6 +3,7 @@
#include "../src/Action.hpp" #include "../src/Action.hpp"
#include "../src/Binding.hpp" #include "../src/Binding.hpp"
#include "../src/Executor.hpp" #include "../src/Executor.hpp"
#include "../src/View.hpp"
#include "../src/Controller.hpp" #include "../src/Controller.hpp"
#include "../src/Pywiq.hpp" #include "../src/Pywiq.hpp"
@ -12,6 +13,12 @@ struct MockController : public Controller {
virtual KeyMod wait_keymod() override { return KeyMod(L"a"); } virtual KeyMod wait_keymod() override { return KeyMod(L"a"); }
}; };
struct MockView : public View {
virtual void clear_screen() override {}
virtual void draw(UI_Node const&) override { }
virtual std::pair<int, int> size() const override { return {0, 0}; }
};
class ExecutorTest class ExecutorTest
{ {
public: public:
@ -21,8 +28,12 @@ public:
protected: protected:
std::shared_ptr<Executor> exec; std::shared_ptr<Executor> exec;
MockController m_ctrl; MockController m_ctrl;
Pywiq m_pywiq = Pywiq(m_ctrl); MockView m_view;
Mode m_mode = Mode("executor_test", m_pywiq, exec); Pywiq m_pywiq = Pywiq(m_ctrl, m_view);
Mode m_mode = Mode("executor_test",
m_pywiq,
std::make_shared<UI_Node>(nullptr),
exec);
}; };
struct ActionMock: public Action struct ActionMock: public Action