✨ modes can now print stuff on the screen.
parent
7b6f0b45f4
commit
924a6323a1
3
Makefile
3
Makefile
|
@ -10,5 +10,8 @@ tests: build
|
|||
install: tests
|
||||
meson install -C build
|
||||
|
||||
install-no-test: build
|
||||
meson install -C build
|
||||
|
||||
doc:
|
||||
doxygen
|
||||
|
|
|
@ -25,6 +25,9 @@ pwq_lib = static_library('pywiq',
|
|||
|
||||
# View
|
||||
# ----
|
||||
'src/UI_Node.cpp',
|
||||
'src/VBoxUI.cpp',
|
||||
'src/View.cpp',
|
||||
|
||||
# Command
|
||||
# -------
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
37
src/Term.cpp
37
src/Term.cpp
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -0,0 +1,12 @@
|
|||
#include "View.hpp"
|
||||
|
||||
namespace pwq
|
||||
{
|
||||
/*explicit*/ View::View()
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/ View::~View()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
17
src/main.cpp
17
src/main.cpp
|
@ -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>();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue