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
meson install -C build
install-no-test: build
meson install -C build
doc:
doxygen

View File

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

View File

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

View File

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

View File

@ -1,14 +1,22 @@
#include "Pywiq.hpp"
#include "UI_Node.hpp"
#include "Controller.hpp"
#include "View.hpp"
#include "KeyMod.hpp"
#include "Mode.hpp"
#include "Executor.hpp"
namespace pwq
{
/*explicit*/ Pywiq::Pywiq(Controller& controller)
/*explicit*/ Pywiq::Pywiq(Controller& controller, View& view)
: 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()
@ -17,20 +25,25 @@ namespace pwq
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_ui->add_child(m_modes.back()->ui().lock());
}
bool Pywiq::exec()
{
m_view.clear_screen();
m_view.draw(*m_ui);
KeyMod keymod = m_controller.wait_keymod();
for (auto mode: m_modes)
{
if (auto executor=mode->executor().lock();
executor)
{
executor->update(keymod);
}
mode->update(keymod);
}
return m_running;

View File

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

View File

@ -81,4 +81,41 @@ namespace pwq
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 "Controller.hpp"
#include "View.hpp"
namespace pwq
{
@ -12,7 +13,7 @@ namespace pwq
* Abstraction over NCurses.
* @see Controller
**/
class Term: public Controller
class Term: public Controller, public View
{
public:
explicit Term();
@ -20,6 +21,10 @@ namespace pwq
KeyMod wait_keymod() override;
std::pair<int, int> size() const override;
void clear_screen() override;
void draw(UI_Node const& ui) override;
private:
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) {} \
}
#define PWQ_ASSERT(COND, ...) \
if ( !(COND) ) \
{ \
std::vector<std::string> msgs = {__VA_ARGS__}; \
\
for (auto const& msg: msgs) \
{ \
std::cerr << msg; \
} \
\
abort(); \
}
#endif

View File

@ -5,16 +5,25 @@
#include "Executor.hpp"
#include "Term.hpp"
#include "actions/Quit.hpp"
#include "VBoxUI.hpp"
int main(int, char**)
{
pwq::Term term;
pwq::Pywiq pywiq {term};
pwq::Pywiq pywiq {term, term};
auto executor = std::make_shared<pwq::Executor>();
auto default_mode = std::make_shared<pwq::Mode>("default",
pywiq,
executor);
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,
default_ui,
executor);
auto quit = default_mode->make_action<pwq::actions::Quit>();

View File

@ -3,6 +3,7 @@
#include "../src/Action.hpp"
#include "../src/Binding.hpp"
#include "../src/Executor.hpp"
#include "../src/View.hpp"
#include "../src/Controller.hpp"
#include "../src/Pywiq.hpp"
@ -12,6 +13,12 @@ struct MockController : public Controller {
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
{
public:
@ -21,8 +28,12 @@ public:
protected:
std::shared_ptr<Executor> exec;
MockController m_ctrl;
Pywiq m_pywiq = Pywiq(m_ctrl);
Mode m_mode = Mode("executor_test", m_pywiq, exec);
MockView m_view;
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