rewrite how events are held

This commit is contained in:
Andrea Blankenstijn 2021-08-15 20:04:53 +02:00
parent 07f7061c20
commit d9eccc940a
23 changed files with 396 additions and 248 deletions

View file

@ -34,11 +34,11 @@ EmptyLineBeforeAccessModifier: Always
FixNamespaceComments: false FixNamespaceComments: false
IncludeBlocks: Regroup IncludeBlocks: Regroup
IncludeCategories: IncludeCategories:
- Regex: '<[[:alnum:].]+>' - Regex: '<[[:alnum:]._]+>'
Priority: -10 Priority: -10
- Regex: '^<fontconfig/' - Regex: '^<fontconfig'
Priority: -5 Priority: -5
- Regex: '^<SDL2/' - Regex: '^<SDL'
Priority: -5 Priority: -5
- Regex: '^<basic_widgets/' - Regex: '^<basic_widgets/'
Priority: 0 Priority: 0

View file

@ -9,9 +9,9 @@ using bwidgets::Button;
auto main() -> int auto main() -> int
{ {
run_example<Button>([](auto w, auto f, auto x, auto y) { run_example<Button>([](auto w, auto f, auto x, auto y) {
w->click_handler = [x, y](const SDL_MouseButtonEvent&) { w->click_handler([x, y](const SDL_MouseButtonEvent&) {
std::cout << "button(" << x << ',' << y << "):click!" << std::endl; std::cout << "button(" << x << ',' << y << "):click!" << std::endl;
}; });
w->font(f); w->font(f);
w->text("+"); w->text("+");
}); });

View file

@ -13,8 +13,8 @@
#include <basic_widgets/core/math.hpp> #include <basic_widgets/core/math.hpp>
#include <basic_widgets/core/type/concepts.hpp> #include <basic_widgets/core/type/concepts.hpp>
#include <basic_widgets/w/caption.hpp> #include <basic_widgets/w/caption.hpp>
#include <basic_widgets/w/feat/keyboard_handler.hpp> #include <basic_widgets/w/feat/keyboard_handler_impl.hpp>
#include <basic_widgets/w/feat/mouse_handler.hpp> #include <basic_widgets/w/feat/mouse_handler_impl.hpp>
namespace bwidgets namespace bwidgets
{ {
@ -22,29 +22,57 @@ namespace bwidgets
template<typename T> template<typename T>
class Input : public Widget, class Input : public Widget,
public FontHandler, public FontHandler,
public KeyboardHandler, public KeyboardHandlerImpl,
public MouseHandler public MouseHandlerImpl
{ {
protected: protected:
Caption _input_caption; Caption _input_caption;
Input(Widget* parent = nullptr) : Widget {parent}, _input_caption {this} Input(Widget* parent = nullptr) : Widget {parent}, _input_caption {this}
{ {
FocusHandler::_focus_area = &_widget_area; FocusHandlerImpl::focus_handler([this](bool focus) {
MouseHandler::_click_area = &_widget_area; if (focus) {
_input_caption.text(value_to_string(value)); SDL_StartTextInput();
} }
// focus loss.
else if (FocusHandlerImpl::focus()) {
value = value_from_string(input_text());
input_text(value_to_string(value));
SDL_StopTextInput();
_input_caption.text(value_to_string(value));
}
});
void _handle_focus_change(bool focus) override KeyboardHandlerImpl::key_handler([this](const SDL_KeyboardEvent& key) {
{ if (key.type == SDL_KEYDOWN) {
if (focus) { switch (key.keysym.sym) {
SDL_StartTextInput(); case SDLK_BACKSPACE: {
} std::string txt = input_text();
else { if (txt.length() > 0) {
value = value_from_string(input_text()); txt.pop_back();
input_text(value_to_string(value)); input_text(txt);
SDL_StopTextInput(); }
} break;
}
case SDLK_RETURN:
case SDLK_RETURN2: // what is return2 btw?
case SDLK_KP_ENTER:
value = value_from_string(input_text());
FocusHandlerImpl::focus(false);
break;
}
}
});
KeyboardHandlerImpl::text_input_handler(
[this](const SDL_TextInputEvent& input) {
if (is_valid_input(input.text)) {
input_text(input_text() + input.text);
}
});
KeyboardHandlerImpl::enable_keyboard_handler();
MouseHandlerImpl::enable_mouse_handler(&(Input::_widget_area),
&(Input::_viewport));
} }
void _handle_font_change(const std::shared_ptr<Font>& f) override void _handle_font_change(const std::shared_ptr<Font>& f) override
@ -67,28 +95,6 @@ namespace bwidgets
{rect_margin(_widget_area, {border_width, border_width})}, vp)); {rect_margin(_widget_area, {border_width, border_width})}, vp));
} }
void _handle_key(const SDL_KeyboardEvent& key) override
{
if (key.type == SDL_KEYDOWN) {
switch (key.keysym.sym) {
case SDLK_BACKSPACE: {
std::string txt = input_text();
if (txt.length() > 0) {
txt.pop_back();
input_text(txt);
}
break;
}
case SDLK_RETURN:
case SDLK_RETURN2: // what is return2 btw?
case SDLK_KP_ENTER:
value = value_from_string(input_text());
focus(false);
break;
}
}
}
void _handle_renderer_change(const std::shared_ptr<Renderer>& r) override void _handle_renderer_change(const std::shared_ptr<Renderer>& r) override
{ {
_input_caption.renderer(r); _input_caption.renderer(r);
@ -97,27 +103,21 @@ namespace bwidgets
void _handle_rendering() override void _handle_rendering() override
{ {
for (int i = border_width - 1; i >= 0; i--) { for (int i = border_width - 1; i >= 0; i--) {
const auto factor = linear(i, 0, border_width); const auto factor = linear(i, 0, border_width);
const auto& color_end = _has_focus ? color_bg_focused : color_bg; const auto& color_end =
const auto color_start = color_end / 2; FocusHandlerImpl::focus() ? color_bg_focused : color_bg;
const auto color_start = color_end / 2;
_renderer->draw_color(lerp(color_start, color_end, factor)) _renderer->draw_color(lerp(color_start, color_end, factor))
->draw_rect(rect_margin(_widget_area, {i, i})); ->draw_rect(rect_margin(_widget_area, {i, i}));
} }
if (MouseHandler::_is_hovered || FocusHandler::_has_focus) if (hovered() || FocusHandlerImpl::focus())
_input_caption.font_color_bg(color_bg_focused); _input_caption.font_color_bg(color_bg_focused);
else _input_caption.font_color_bg(color_bg); else _input_caption.font_color_bg(color_bg);
_input_caption.render(); _input_caption.render();
} }
void _handle_text_input(const SDL_TextInputEvent& input) override
{
if (is_valid_input(input.text)) {
input_text(input_text() + input.text);
}
}
public: public:
static const int default_border_width = 3; static const int default_border_width = 3;
inline static const Color default_color_bg = {200, 200, 200, SDL_ALPHA_OPAQUE}; inline static const Color default_color_bg = {200, 200, 200, SDL_ALPHA_OPAQUE};

View file

@ -38,7 +38,7 @@ namespace bwidgets
auto operator=(const Layout&) = delete; auto operator=(const Layout&) = delete;
auto operator=(Layout&&) = delete; auto operator=(Layout&&) = delete;
auto handle_event(const SDL_Event&) -> Layout* override; void handle_event(const SDL_Event&) override;
[[nodiscard]] auto size() const noexcept -> Size override = 0; [[nodiscard]] auto size() const noexcept -> Size override = 0;
virtual auto add_widget(std::unique_ptr<Widget>) -> Layout*; virtual auto add_widget(std::unique_ptr<Widget>) -> Layout*;

View file

@ -5,6 +5,7 @@
#include <basic_widgets/core/renderer.hpp> #include <basic_widgets/core/renderer.hpp>
#include <basic_widgets/core/type/size.hpp> #include <basic_widgets/core/type/size.hpp>
#include <basic_widgets/w/feat/event_handler_impl.hpp>
union SDL_Event; union SDL_Event;
@ -12,15 +13,13 @@ struct SDL_Renderer;
namespace bwidgets namespace bwidgets
{ {
class Widget class Widget : public virtual EventHandlerImpl
{ {
protected: protected:
std::shared_ptr<Renderer> _renderer; std::shared_ptr<Renderer> _renderer;
SDL_Rect _viewport {0, 0, 0, 0}; SDL_Rect _viewport {0, 0, 0, 0};
SDL_Rect _widget_area {0, 0, 0, 0}; SDL_Rect _widget_area {0, 0, 0, 0};
explicit Widget(Widget* p = nullptr) noexcept : parent {p} {}
virtual void _handle_geometry_change(const SDL_Rect&) = 0; virtual void _handle_geometry_change(const SDL_Rect&) = 0;
virtual void _handle_renderer_change(const std::shared_ptr<Renderer>&) {} virtual void _handle_renderer_change(const std::shared_ptr<Renderer>&) {}
virtual void _handle_rendering() = 0; virtual void _handle_rendering() = 0;
@ -28,14 +27,8 @@ namespace bwidgets
public: public:
Widget* parent; Widget* parent;
Widget(const Widget&) noexcept = default; explicit Widget(Widget* p = nullptr) noexcept : parent {p} {}
Widget(Widget&&) noexcept = default;
virtual ~Widget() noexcept = default;
auto operator=(const Widget&) = delete;
auto operator=(Widget&&) = delete;
virtual auto handle_event(const SDL_Event&) -> Widget*;
[[nodiscard]] virtual auto size() const noexcept -> Size = 0; [[nodiscard]] virtual auto size() const noexcept -> Size = 0;
virtual auto render() -> Widget* final; virtual auto render() -> Widget* final;

View file

@ -6,20 +6,19 @@
#include <basic_widgets/core/type/color.hpp> #include <basic_widgets/core/type/color.hpp>
#include <basic_widgets/w/caption.hpp> #include <basic_widgets/w/caption.hpp>
#include <basic_widgets/w/feat/mouse_handler.hpp> #include <basic_widgets/w/feat/mouse_handler_impl.hpp>
namespace bwidgets namespace bwidgets
{ {
class Button : public Widget, class Button : public virtual Widget,
public FontHandler, public virtual FontHandler,
public MouseHandler public virtual MouseHandlerImpl
{ {
protected: protected:
Caption _caption; Caption _caption;
SDL_Rect _caption_area {}; SDL_Rect _caption_area {};
Color _color_foreground = default_color_fg; Color _color_foreground = default_color_fg;
void _handle_focus_change(bool) override {}
void _handle_font_change(const std::shared_ptr<Font>&) override; void _handle_font_change(const std::shared_ptr<Font>&) override;
void _handle_font_color_change(Color, Color) void _handle_font_color_change(Color, Color)
override; override;
@ -38,6 +37,10 @@ namespace bwidgets
Color color_bg = default_color_bg; Color color_bg = default_color_bg;
Color color_bg_hover = default_color_bg_hover; Color color_bg_hover = default_color_bg_hover;
using EventHandlerImpl::handle_event;
using FocusHandlerImpl::focus;
using FocusHandlerImpl::focus_handler;
Button(Widget* parent = nullptr) noexcept; Button(Widget* parent = nullptr) noexcept;
Button(const Button&) = delete; Button(const Button&) = delete;
Button(Button&&) = delete; Button(Button&&) = delete;

View file

@ -0,0 +1,32 @@
#ifndef BWIDGETS_EVENT_HANDLER_HPP
#define BWIDGETS_EVENT_HANDLER_HPP
#include <functional>
#include <utility>
#include <SDL_events.h>
namespace bwidgets
{
class EventHandler
{
public:
using handler_t =
std::pair<SDL_EventType, std::function<void(const SDL_Event&)>>;
protected:
EventHandler() = default;
public:
EventHandler(const EventHandler&) = delete;
EventHandler(EventHandler&&) = delete;
auto operator=(const EventHandler&) -> EventHandler& = delete;
auto operator=(EventHandler&&) -> EventHandler& = delete;
virtual ~EventHandler() = default;
virtual void handle_event(const SDL_Event&) = 0;
};
}
#endif

View file

@ -0,0 +1,24 @@
#ifndef BWIDGETS_EVENT_HANDLER_IMPL_HPP
#define BWIDGETS_EVENT_HANDLER_IMPL_HPP
#include <unordered_map>
#include <basic_widgets/w/feat/event_handler.hpp>
namespace bwidgets
{
class EventHandlerImpl : public virtual EventHandler
{
std::unordered_map<SDL_EventType, std::function<void(const SDL_Event&)>>
_event_handlers {};
protected:
auto _add_event_handler(handler_t) -> bool;
auto _remove_event_handler(SDL_EventType) -> std::pair<handler_t, bool>;
public:
void handle_event(const SDL_Event&) override;
};
}
#endif

View file

@ -1,32 +1,25 @@
#ifndef BWIDGETS_FOCUS_HANDLER_HPP #ifndef BWIDGETS_FOCUS_HANDLER_HPP
#define BWIDGETS_FOCUS_HANDLER_HPP #define BWIDGETS_FOCUS_HANDLER_HPP
#include <functional>
struct SDL_Rect; struct SDL_Rect;
namespace bwidgets namespace bwidgets
{ {
class FocusHandler class FocusHandler
{ {
protected:
const SDL_Rect* _focus_area = nullptr;
bool _has_focus = false;
virtual void _handle_focus_change(bool) = 0;
public: public:
FocusHandler() = default; FocusHandler() = default;
FocusHandler(const FocusHandler&) = delete; FocusHandler(const FocusHandler&) = delete;
FocusHandler(FocusHandler&&) = delete; FocusHandler(FocusHandler&&) = delete;
virtual ~FocusHandler() = default;
auto operator=(FocusHandler&&) = delete; auto operator=(FocusHandler&&) = delete;
auto operator=(const FocusHandler&) = delete; auto operator=(const FocusHandler&) = delete;
virtual void focus(bool focus) final virtual ~FocusHandler() = default;
{ virtual void focus(bool focus) = 0;
_handle_focus_change(focus); virtual bool focus() = 0;
_has_focus = focus; virtual void focus_handler(std::function<void(bool)>) = 0;
}
}; };
} }

View file

@ -0,0 +1,32 @@
#ifndef BWIDGETS_FOCUS_HANDLER_IMPL_HPP
#define BWIDGETS_FOCUS_HANDLER_IMPL_HPP
#include <basic_widgets/w/feat/focus_handler.hpp>
namespace bwidgets
{
class FocusHandlerImpl : public virtual FocusHandler
{
bool _has_focus {false};
std::function<void(bool)> _focus_handler {[](auto) {}};
public:
void focus(bool focus_) override
{
_focus_handler(focus_);
_has_focus = focus_;
}
bool focus() override
{
return _has_focus;
}
void focus_handler(decltype(_focus_handler) handler) final
{
_focus_handler = std::move(handler);
}
};
}
#endif

View file

@ -1,6 +1,7 @@
#ifndef BWIDGETS_KEYBOARD_HANDLER #ifndef BWIDGETS_KEYBOARD_HANDLER_HPP
#define BWIDGETS_KEYBOARD_HANDLER #define BWIDGETS_KEYBOARD_HANDLER_HPP
#include <basic_widgets/w/feat/event_handler.hpp>
#include <basic_widgets/w/feat/focus_handler.hpp> #include <basic_widgets/w/feat/focus_handler.hpp>
struct SDL_KeyboardEvent; struct SDL_KeyboardEvent;
@ -8,34 +9,18 @@ struct SDL_TextInputEvent;
namespace bwidgets namespace bwidgets
{ {
class KeyboardHandler : public virtual FocusHandler class KeyboardHandler : public virtual EventHandler,
public virtual FocusHandler
{ {
protected: protected:
virtual void _handle_key(const SDL_KeyboardEvent&) = 0; using EventHandler::EventHandler;
virtual void _handle_text_input(const SDL_TextInputEvent&) = 0;
public: public:
using FocusHandler::FocusHandler; virtual void disable_keyboard_handler() = 0;
virtual void enable_keyboard_handler() = 0;
KeyboardHandler(const KeyboardHandler&) = delete; virtual void key_handler(std::function<void(const SDL_KeyboardEvent&)>) = 0;
KeyboardHandler(KeyboardHandler&&) = delete; virtual void
~KeyboardHandler() override = default; text_input_handler(std::function<void(const SDL_TextInputEvent&)>) = 0;
auto operator=(const KeyboardHandler&) = delete;
auto operator=(KeyboardHandler&&) = delete;
virtual auto handle_keyboard(const SDL_KeyboardEvent& ev)
-> KeyboardHandler* final
{
if (_has_focus) _handle_key(ev);
return this;
}
virtual auto handle_keyboard(const SDL_TextInputEvent& ev)
-> KeyboardHandler* final
{
if (_has_focus) _handle_text_input(ev);
return this;
}
}; };
} }

View file

@ -0,0 +1,31 @@
#ifndef BWIDGETS_KEYBOARD_HANDLER_IMPL_HPP
#define BWIDGETS_KEYBOARD_HANDLER_IMPL_HPP
#include <basic_widgets/w/feat/event_handler_impl.hpp>
#include <basic_widgets/w/feat/focus_handler_impl.hpp>
#include <basic_widgets/w/feat/keyboard_handler.hpp>
namespace bwidgets
{
class KeyboardHandlerImpl : public KeyboardHandler,
virtual public EventHandlerImpl,
virtual public FocusHandlerImpl
{
std::function<void(const SDL_KeyboardEvent&)> _key_handler {[](auto) {}};
std::function<void(const SDL_TextInputEvent&)> _input_handler {[](auto) {}};
public:
void disable_keyboard_handler() override;
void enable_keyboard_handler() override;
void key_handler(decltype(_key_handler) handler) override
{
_key_handler = std::move(handler);
}
void text_input_handler(decltype(_input_handler) handler) override
{
_input_handler = std::move(handler);
}
};
}
#endif

View file

@ -1,8 +1,7 @@
#ifndef BWIDGETS_MOUSE_HANDLER_HPP #ifndef BWIDGETS_MOUSE_HANDLER_HPP
#define BWIDGETS_MOUSE_HANDLER_HPP #define BWIDGETS_MOUSE_HANDLER_HPP
#include <functional> #include <basic_widgets/w/feat/event_handler.hpp>
#include <basic_widgets/w/feat/focus_handler.hpp> #include <basic_widgets/w/feat/focus_handler.hpp>
struct SDL_MouseButtonEvent; struct SDL_MouseButtonEvent;
@ -10,35 +9,22 @@ struct SDL_MouseMotionEvent;
namespace bwidgets namespace bwidgets
{ {
class MouseHandler : public virtual FocusHandler class MouseHandler : virtual public FocusHandler,
virtual public EventHandler
{ {
protected: protected:
const SDL_Rect* _click_area = nullptr; using EventHandler::EventHandler;
bool _is_hovered = false;
bool _is_pushed = false;
virtual void _handle_mouse_button(const SDL_MouseButtonEvent&, virtual void _on_push(bool) = 0;
const SDL_Rect&) {};
virtual void _handle_mouse_motion(const SDL_MouseMotionEvent&,
const SDL_Rect&) {};
virtual void _on_push(bool) {};
public: public:
std::function<void(const SDL_MouseButtonEvent&)> click_handler = nullptr; virtual void click_handler(std::function<void(const SDL_MouseButtonEvent&)>) = 0;
virtual void disable_mouse_handler() = 0;
using FocusHandler::FocusHandler; virtual void enable_mouse_handler(const SDL_Rect*, const SDL_Rect*) = 0;
[[nodiscard]] virtual bool hovered() const = 0;
MouseHandler(const MouseHandler&) = delete; virtual void
MouseHandler(MouseHandler&&) = delete; mouse_motion_handler(std::function<void(const SDL_MouseMotionEvent&)>) = 0;
~MouseHandler() override = default; [[nodiscard]] virtual bool pushed() const = 0;
auto operator=(const MouseHandler&) = delete;
auto operator=(MouseHandler&&) = delete;
virtual auto handle_mouse(const SDL_MouseButtonEvent&, const SDL_Rect&)
-> MouseHandler* final;
virtual auto handle_mouse(const SDL_MouseMotionEvent&, const SDL_Rect&)
-> MouseHandler* final;
virtual auto push(bool) -> MouseHandler* final;
}; };
} }

View file

@ -0,0 +1,54 @@
#ifndef BWIDGETS_MOUSE_HANDLER_IMPL_HPP
#define BWIDGETS_MOUSE_HANDLER_IMPL_HPP
#include <basic_widgets/w/feat/event_handler_impl.hpp>
#include <basic_widgets/w/feat/focus_handler_impl.hpp>
#include <basic_widgets/w/feat/mouse_handler.hpp>
namespace bwidgets
{
class MouseHandlerImpl : public MouseHandler,
virtual public EventHandlerImpl,
virtual public FocusHandlerImpl
{
private:
bool _hovered {false};
bool _pushed {false};
std::function<void(const SDL_MouseButtonEvent&)> _click_handler {[](auto) {}};
std::function<void(const SDL_MouseMotionEvent&)> _motion_handler {[](auto) {}};
protected:
using MouseHandler::MouseHandler;
void _on_push(bool) override {}
public:
void
click_handler(std::function<void(const SDL_MouseButtonEvent&)> handler) override
{
_click_handler = std::move(handler);
}
void disable_mouse_handler() override;
void enable_mouse_handler(const SDL_Rect*, const SDL_Rect*) override;
[[nodiscard]] bool hovered() const override
{
return _hovered;
}
void mouse_motion_handler(
std::function<void(const SDL_MouseMotionEvent&)> handler) override
{
_motion_handler = std::move(handler);
}
[[nodiscard]] bool pushed() const override
{
return _pushed;
}
};
}
#endif

View file

@ -2,14 +2,13 @@
#define BWIDGETS_NUMERIC_INPUT_HPP #define BWIDGETS_NUMERIC_INPUT_HPP
#include <limits> #include <limits>
#include <type_traits>
#include <basic_widgets/core/math.hpp> #include <basic_widgets/core/math.hpp>
#include <basic_widgets/core/type/concepts.hpp> #include <basic_widgets/core/type/concepts.hpp>
#include <basic_widgets/w/base/input.hpp> #include <basic_widgets/w/base/input.hpp>
#include <basic_widgets/w/button.hpp> #include <basic_widgets/w/button.hpp>
#include <type_traits>
namespace bwidgets namespace bwidgets
{ {
template<Numeric T> template<Numeric T>
@ -94,25 +93,25 @@ namespace bwidgets
_increment_button.text("+"); _increment_button.text("+");
_increment_button.click_handler = [this](const SDL_MouseButtonEvent&) { _increment_button.click_handler([this](const SDL_MouseButtonEvent&) {
T new_value = this->value + button_step; T new_value = this->value + button_step;
if (_value_range.second - this->value < button_step) if (_value_range.second - this->value < button_step)
new_value = _value_range.second; new_value = _value_range.second;
this->value = new_value; this->value = new_value;
this->input_text(this->value_to_string(new_value)); this->input_text(this->value_to_string(new_value));
}; });
_decrement_button.text("-"); _decrement_button.text("-");
_decrement_button.click_handler = [this](const SDL_MouseButtonEvent&) { _decrement_button.click_handler([this](const SDL_MouseButtonEvent&) {
T new_value = this->value - button_step; T new_value = this->value - button_step;
if (this->value - _value_range.first < button_step) if (this->value - _value_range.first < button_step)
new_value = _value_range.first; new_value = _value_range.first;
this->value = new_value; this->value = new_value;
this->input_text(this->value_to_string(new_value)); this->input_text(this->value_to_string(new_value));
}; });
} }
NumericInput(const NumericInput&) = delete; NumericInput(const NumericInput&) = delete;
@ -121,12 +120,11 @@ namespace bwidgets
auto operator=(const NumericInput&) = delete; auto operator=(const NumericInput&) = delete;
auto operator=(NumericInput&&) = delete; auto operator=(NumericInput&&) = delete;
auto handle_event(const SDL_Event& ev) -> Widget* override void handle_event(const SDL_Event& ev) override
{ {
Input<T>::handle_event(ev); Input<T>::handle_event(ev);
_increment_button.handle_event(ev); _increment_button.handle_event(ev);
_decrement_button.handle_event(ev); _decrement_button.handle_event(ev);
return this;
} }
[[nodiscard]] auto is_valid_input(const std::string& input) const noexcept [[nodiscard]] auto is_valid_input(const std::string& input) const noexcept

View file

@ -9,7 +9,7 @@ project('sdl2_basic_widgets', 'cpp',
], ],
license: 'EUPL-1.2') license: 'EUPL-1.2')
add_project_arguments('-pedantic', '-Winline', language: 'cpp') add_project_arguments('-pedantic', language: 'cpp')
if (get_option('buildtype').startswith('debug')) if (get_option('buildtype').startswith('debug'))
add_project_arguments('-DBWIDGETS_DEBUG', language: 'cpp') add_project_arguments('-DBWIDGETS_DEBUG', language: 'cpp')
@ -32,7 +32,9 @@ libbasic_widgets = static_library('basic_widgets',
'src/w/base/widget.cpp', 'src/w/base/widget.cpp',
'src/w/button.cpp', 'src/w/button.cpp',
'src/w/caption.cpp', 'src/w/caption.cpp',
'src/w/feat/mouse_handler.cpp', 'src/w/feat/event_handler_impl.cpp',
'src/w/feat/keyboard_handler_impl.cpp',
'src/w/feat/mouse_handler_impl.cpp',
dependencies : [sdl, fontconfig], dependencies : [sdl, fontconfig],
include_directories : pub_api, include_directories : pub_api,
install : true) install : true)
@ -44,24 +46,28 @@ libbasic_widgets_dep = declare_dependency(
executable('button_demo', executable('button_demo',
'examples/button_example.cpp', 'examples/button_example.cpp',
dependencies: [sdl],
include_directories : pub_api, include_directories : pub_api,
link_with : libbasic_widgets, link_with : libbasic_widgets,
install : false) install : false)
executable('caption_demo', executable('caption_demo',
'examples/caption_example.cpp', 'examples/caption_example.cpp',
dependencies: [sdl],
include_directories : pub_api, include_directories : pub_api,
link_with : libbasic_widgets, link_with : libbasic_widgets,
install : false) install : false)
executable('example_demo', executable('example_demo',
'examples/example_example.cpp', 'examples/example_example.cpp',
dependencies: [sdl],
include_directories : pub_api, include_directories : pub_api,
link_with : libbasic_widgets, link_with : libbasic_widgets,
install : false) install : false)
executable('input_demo', executable('input_demo',
'examples/input_example.cpp', 'examples/input_example.cpp',
dependencies: [sdl],
include_directories : pub_api, include_directories : pub_api,
link_with : libbasic_widgets, link_with : libbasic_widgets,
install : false) install : false)

View file

@ -17,10 +17,10 @@ void Layout::for_widgets(const std::function<void(Widget*)>& f)
for (const auto& w : _widgets) f(w.get()); for (const auto& w : _widgets) f(w.get());
} }
auto Layout::handle_event(const SDL_Event& ev) -> Layout* void Layout::handle_event(const SDL_Event& ev)
{ {
EventHandlerImpl::handle_event(ev);
for (const auto& w : _widgets) w->handle_event(ev); for (const auto& w : _widgets) w->handle_event(ev);
return this;
} }
void Layout::_handle_geometry_change(const SDL_Rect& vp) void Layout::_handle_geometry_change(const SDL_Rect& vp)

View file

@ -1,41 +1,7 @@
#include <SDL2/SDL_assert.h>
#include <SDL2/SDL_events.h>
#include <basic_widgets/w/base/widget.hpp> #include <basic_widgets/w/base/widget.hpp>
#include <basic_widgets/w/feat/keyboard_handler.hpp>
#include <basic_widgets/w/feat/mouse_handler.hpp>
using namespace bwidgets; using namespace bwidgets;
auto Widget::handle_event(const SDL_Event& ev) -> Widget*
{
if (auto* handler = dynamic_cast<KeyboardHandler*>(this); handler) {
switch (ev.type) {
case SDL_KEYDOWN:
case SDL_KEYUP:
handler->handle_keyboard(ev.key);
break;
case SDL_TEXTINPUT:
handler->handle_keyboard(ev.text);
break;
}
}
if (auto* handler = dynamic_cast<MouseHandler*>(this); handler) {
switch (ev.type) {
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
handler->handle_mouse(ev.button, _viewport);
break;
case SDL_MOUSEMOTION:
handler->handle_mouse(ev.motion, _viewport);
break;
}
}
return this;
}
auto Widget::render() -> Widget* auto Widget::render() -> Widget*
{ {
if (_renderer == nullptr) return this; if (_renderer == nullptr) return this;

View file

@ -13,13 +13,13 @@ const Color Button::default_color_fg {0, 0, 0, SDL_ALPHA_OPAQUE};
Button::Button(Widget* parent) noexcept : Widget {parent}, _caption {this} Button::Button(Widget* parent) noexcept : Widget {parent}, _caption {this}
{ {
_focus_area = _click_area = &_widget_area; enable_mouse_handler(&_widget_area, &_viewport);
_caption.alignment = Caption::Alignment::CENTER; _caption.alignment = Caption::Alignment::CENTER;
_caption.render_mode(Font::RenderMode::BLENDED); _caption.render_mode(Font::RenderMode::BLENDED);
border_gradient = [this](int len, int pos, float divider) -> Color { border_gradient = [this](int len, int pos, float divider) -> Color {
const auto& end_color = _is_hovered ? color_bg_hover : color_bg; const auto& end_color = hovered() ? color_bg_hover : color_bg;
const auto start_color = end_color / divider; const auto start_color = end_color / divider;
const auto factor = linear(pos, 0, len); const auto factor = linear(pos, 0, len);
return lerp(start_color, end_color, factor); return lerp(start_color, end_color, factor);
@ -74,8 +74,8 @@ void Button::_handle_renderer_change(const std::shared_ptr<Renderer>& r)
void Button::_handle_rendering() void Button::_handle_rendering()
{ {
Color c = _is_hovered ? color_bg_hover : color_bg; Color c = hovered() ? color_bg_hover : color_bg;
const auto divider = _is_pushed ? 1.5 : 2; const auto divider = pushed() ? 1.5 : 2;
auto x = 0; auto x = 0;
auto y = 0; auto y = 0;
const auto biggest = border_size.w > border_size.h ? border_size.w : border_size.h; const auto biggest = border_size.w > border_size.h ? border_size.w : border_size.h;

View file

@ -0,0 +1,32 @@
#include <basic_widgets/w/feat/event_handler_impl.hpp>
using namespace bwidgets;
void EventHandlerImpl::handle_event(const SDL_Event& ev)
{
auto type = static_cast<SDL_EventType>(ev.type);
if (!_event_handlers.contains(type)) return;
_event_handlers[type](ev);
}
auto EventHandlerImpl::_add_event_handler(handler_t event_handler) -> bool
{
if (_event_handlers.contains(event_handler.first)) return false;
_event_handlers.emplace(event_handler);
return true;
}
auto EventHandlerImpl::_remove_event_handler(SDL_EventType ev_type)
-> std::pair<handler_t, bool>
{
handler_t handler;
auto pos = _event_handlers.find(ev_type);
if (pos == _event_handlers.end()) return {handler, false};
handler = {ev_type, _event_handlers[ev_type]};
_event_handlers.erase(pos);
return {handler, true};
}

View file

@ -0,0 +1,23 @@
#include <basic_widgets/w/feat/keyboard_handler_impl.hpp>
using namespace bwidgets;
void KeyboardHandlerImpl::disable_keyboard_handler()
{
_remove_event_handler(SDL_KEYDOWN);
_remove_event_handler(SDL_KEYUP);
_remove_event_handler(SDL_TEXTINPUT);
}
void KeyboardHandlerImpl::enable_keyboard_handler()
{
const auto keyboard_handler = [this](const SDL_Event& ev) {
if (FocusHandlerImpl::focus()) _key_handler(ev.key);
};
_add_event_handler({SDL_KEYDOWN, keyboard_handler});
_add_event_handler({SDL_KEYUP, keyboard_handler});
_add_event_handler({SDL_TEXTINPUT, [this](const SDL_Event& ev) {
if (FocusHandlerImpl::focus()) _input_handler(ev.text);
}});
}

View file

@ -1,60 +0,0 @@
#include <SDL2/SDL_events.h>
#include <SDL2/SDL_rect.h>
#include <basic_widgets/core/math.hpp>
#include <basic_widgets/w/feat/mouse_handler.hpp>
using namespace bwidgets;
auto MouseHandler::handle_mouse(const SDL_MouseButtonEvent& ev, const SDL_Rect& orig)
-> MouseHandler*
{
if (_click_area == nullptr) return this;
const SDL_Point p {ev.x, ev.y};
const SDL_Rect vp {rect_offset(*_click_area, orig)};
if (ev.type == SDL_MOUSEBUTTONDOWN) {
if (SDL_PointInRect(&p, &vp) == SDL_TRUE) {
push(true);
_handle_mouse_button(ev, vp);
}
else focus(false);
}
else {
if (_is_pushed) {
if (SDL_PointInRect(&p, &vp) == SDL_TRUE) {
focus(true);
if (click_handler != nullptr) click_handler(ev);
}
push(false);
_handle_mouse_button(ev, vp);
}
}
return this;
}
auto MouseHandler::handle_mouse(const SDL_MouseMotionEvent& ev, const SDL_Rect& orig)
-> MouseHandler*
{
if (_click_area == nullptr) return this;
const SDL_Point p {ev.x, ev.y};
const SDL_Rect vp {rect_offset(*_click_area, orig)};
_is_hovered = SDL_PointInRect(&p, &vp) != 0;
if (_is_hovered) _handle_mouse_motion(ev, orig);
return this;
}
auto MouseHandler::push(bool state) -> MouseHandler*
{
_on_push(state);
_is_pushed = state;
return this;
}

View file

@ -0,0 +1,50 @@
#include <basic_widgets/core/math.hpp>
#include <basic_widgets/w/feat/mouse_handler_impl.hpp>
using namespace bwidgets;
void MouseHandlerImpl::disable_mouse_handler()
{
EventHandlerImpl::_remove_event_handler(SDL_MOUSEBUTTONDOWN);
EventHandlerImpl::_remove_event_handler(SDL_MOUSEBUTTONUP);
_remove_event_handler(SDL_MOUSEMOTION);
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
void MouseHandlerImpl::enable_mouse_handler(const SDL_Rect* area, const SDL_Rect* vp)
{
if (!area || !vp) throw std::logic_error("ptr parameters cannot be null.");
_add_event_handler({SDL_MOUSEBUTTONDOWN, [this, area, vp](const SDL_Event& ev) {
auto absolute_area = rect_offset(*area, *vp);
SDL_Point p = {ev.button.x, ev.button.y};
if (SDL_PointInRect(&p, &absolute_area) == SDL_FALSE) {
FocusHandlerImpl::focus(false);
return;
}
_on_push(true);
_pushed = true;
}});
_add_event_handler({SDL_MOUSEBUTTONUP, [this, area, vp](const SDL_Event& ev) {
auto absolute_area = rect_offset(*area, *vp);
SDL_Point p = {ev.button.x, ev.button.y};
if (_pushed) {
_on_push(false);
_pushed = false;
}
if (SDL_PointInRect(&p, &absolute_area) == SDL_FALSE) return;
FocusHandlerImpl::focus(true);
_click_handler(ev.button);
}});
_add_event_handler({SDL_MOUSEMOTION, [this, area, vp](const SDL_Event& ev) {
auto absolute_area = rect_offset(*area, *vp);
SDL_Point p = {ev.motion.x, ev.motion.y};
if (SDL_PointInRect(&p, &absolute_area) == SDL_FALSE) {
_hovered = false;
return;
}
_hovered = true;
_motion_handler(ev.motion);
}});
}