some fixes and working sdl wrapper

This commit is contained in:
Andrea Blankenstijn 2021-07-19 23:50:50 +02:00
parent dd3ff9358a
commit 30c4205dab
20 changed files with 171 additions and 200 deletions

View file

@ -1,86 +1,15 @@
#include <iostream>
#include <basic_widgets/w/numeric_input.hpp>
#include <basic_widgets/horizontal_layout.hpp>
#include <basic_widgets/numeric_input.hpp>
#include <basic_widgets/utils/font.hpp>
#include <basic_widgets/vertical_layout.hpp>
#include "run.hpp"
using namespace bwidgets::utils;
using namespace bwidgets::widget;
using widget::NumericInput;
int main()
{
int width = 640;
int height = 480;
TTF_Init();
TTF_Font* font = TTF_OpenFont(font::find("Monospace").c_str(), 20);
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* win = SDL_CreateWindow(
"Widget test",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
width,
height,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE
);
auto rend = bwidgets::sdl::Renderer(win, -1, SDL_RENDERER_ACCELERATED);
rend.blend_mode(SDL_BLENDMODE_BLEND);
SDL_Rect layout_vp = {0, 0, width, height};
auto layout = new Horizontal_Layout();
for (int i = 0; i < 3; i++)
{
auto column = new Vertical_Layout();
for (int j = 0; j < 3; j++)
{
auto widget = new Numeric_Input<float>();
widget->button_step = 0.5;
widget->font(font);
widget->value_range(-2.5, 2.5);
column->add_widget(widget);
}
layout->add_widget(column);
}
layout->viewport(layout_vp);
layout->renderer(&rend);
bool quit = false;
while (!quit)
{
SDL_Event ev;
while (SDL_PollEvent(&ev) != 0)
{
switch (ev.type)
{
case SDL_QUIT:
quit = true;
break;
case SDL_WINDOWEVENT:
if (ev.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
{
auto size = rend.output_size();
layout_vp.w = size.w;
layout_vp.h = size.h;
std::cerr << "== WINDOW RESIZED == " << size.w << "x" << size.h << std::endl;
layout->viewport(layout_vp);
}
break;
}
layout->handle_event(ev);
}
rend.draw_color({75, 75, 75, SDL_ALPHA_OPAQUE});
rend.clear();
layout->render();
rend.present();
}
delete layout;
SDL_DestroyWindow(win);
SDL_Quit();
TTF_CloseFont(font);
TTF_Quit();
run_example<NumericInput<float> >([](NumericInput<float>* w, core::Font* f) {
w->font(f);
w->button_step = 0.5;
w->value_range(-3.14, 8);
});
return 0;
}

View file

@ -48,8 +48,12 @@ namespace bwidgets::core
Font(TTF_Font*);
Font(const std::string&, int);
Font(const Font&) = delete;
virtual ~Font() override;
Font& operator=(const Font) = delete;
Font& operator=(const Font&) = delete;
Hinting hinting();
Font* hinting(Hinting);
bool kerning();

View file

@ -36,7 +36,7 @@ namespace bwidgets::core
SDL_BlendMode blend_mode();
Renderer* blend_mode(SDL_BlendMode);
Renderer* clear();
Renderer* copy(Texture&, const SDL_Rect*, const SDL_Rect*);
Renderer* copy(Texture*, const SDL_Rect*, const SDL_Rect*);
SDL_Color draw_color();
Renderer* draw_color(const SDL_Color&);
Renderer* draw_line(const SDL_Point&, const SDL_Point&);
@ -47,22 +47,22 @@ namespace bwidgets::core
Renderer* draw_rects(const std::vector<SDL_Rect>);
Renderer* fill_rect(const SDL_Rect&);
Renderer* fill_rects(const std::vector<SDL_Rect>);
Size output_size();
Size output_size();
void present();
SDL_Rect viewport();
Renderer* viewport(const SDL_Rect*);
inline Renderer* copy(Texture& t, const SDL_Rect* src, const SDL_Rect& dst)
inline Renderer* copy(Texture* t, const SDL_Rect* src, const SDL_Rect& dst)
{
auto d = dst;
return copy(t, src, &d);
}
inline Renderer* copy(Texture& t, const SDL_Rect& src, const SDL_Rect* dst)
inline Renderer* copy(Texture* t, const SDL_Rect& src, const SDL_Rect* dst)
{
auto s = src;
return copy(t, &s, dst);
}
inline Renderer* copy(Texture& t, const SDL_Rect& src, const SDL_Rect& dst)
inline Renderer* copy(Texture* t, const SDL_Rect& src, const SDL_Rect& dst)
{
auto s = src, d = dst;
return copy(t, &s, &d);

View file

@ -10,11 +10,9 @@ namespace bwidgets::core
OpaqueStruct(T* ptr=nullptr) : c_pod(ptr) {}
virtual ~OpaqueStruct<T>() noexcept = default;
static inline void discard(T* t) {
if (t) {
delete t;
t = nullptr;
}
static inline void discard(T*& t) {
delete t;
t = nullptr;
}
};
}

View file

@ -10,6 +10,8 @@ namespace bwidgets::core
int h;
inline Size operator-() { return {-w, -h}; }
inline Size operator+(const Size& s) { return {w + s.w, h + s.h}; }
inline Size operator-(const Size& s) { return {w - s.w, h - s.h}; }
template<Numeric T>
inline Size operator*(T a) { return {a * w, a * h}; }

View file

@ -62,6 +62,12 @@ namespace bwidgets::widget
_handle_geometry_change(_viewport);
}
virtual void _handle_font_color_change(const SDL_Color& fg,
const SDL_Color& bg) override
{
_input_caption.color_bg(bg)->color_fg(fg);
}
virtual void _handle_geometry_change(const SDL_Rect& vp) noexcept override
{
const auto input_h = _input_caption.size().h + 2 * _border_width;
@ -134,6 +140,7 @@ namespace bwidgets::widget
else
_input_caption.color_bg(color_bg);
_input_caption.render();
}
@ -152,9 +159,10 @@ namespace bwidgets::widget
int float_precision {2};
T value {};
virtual void color_fg(const SDL_Color& c) noexcept
virtual Input<T>* color_fg(const SDL_Color& c) noexcept
{
_input_caption.color_fg(c);
return this;
}
virtual const std::string& input_text() const noexcept
@ -162,9 +170,10 @@ namespace bwidgets::widget
return _input_caption.text();
}
virtual void input_text(std::string txt) noexcept
virtual Input<T>* input_text(std::string txt) noexcept
{
_input_caption.text(txt);
return this;
}
virtual bool is_valid_input(const std::string) const noexcept

View file

@ -27,8 +27,8 @@ namespace bwidgets::widget
virtual ~Layout() noexcept;
virtual void add_widget(Widget*);
virtual void handle_event(const SDL_Event&) override;
virtual Layout* add_widget(Widget*);
virtual Layout* handle_event(const SDL_Event&) override;
virtual core::Size size() const noexcept override = 0;
};

View file

@ -14,8 +14,8 @@ namespace bwidgets::widget
{
protected:
core::Renderer* _renderer {nullptr};
SDL_Rect _viewport {0, 0, 0, 0};
SDL_Rect _widget_area {0, 0, 0, 0};
SDL_Rect _viewport {0, 0, 0, 0};
SDL_Rect _widget_area {0, 0, 0, 0};
virtual void _handle_geometry_change(const SDL_Rect&) noexcept = 0;
virtual void _handle_renderer_change(core::Renderer*) {}
@ -26,24 +26,25 @@ namespace bwidgets::widget
Widget(Widget* p=nullptr) : parent(p) {}
virtual ~Widget() noexcept = default;
virtual void handle_event(const SDL_Event&);
virtual ~Widget() noexcept = default;
virtual Widget* handle_event(const SDL_Event&);
inline virtual core::Size size() const noexcept
{
inline virtual core::Size size() const noexcept {
return {_widget_area.w, _widget_area.h};
}
virtual void render() final;
virtual inline void renderer(core::Renderer* r) final
{
virtual Widget* render() final;
virtual inline Widget* renderer(core::Renderer* r) final {
_handle_renderer_change(r);
_renderer = r;
return this;
}
virtual inline void viewport(const SDL_Rect& vp) noexcept final
{
virtual inline Widget* viewport(const SDL_Rect& vp) noexcept final {
_handle_geometry_change(vp);
_viewport = vp;
return this;
}
};
}

View file

@ -15,22 +15,23 @@ namespace bwidgets::widget
SDL_Rect _caption_area;
SDL_Color _color_foreground {0, 0, 0, SDL_ALPHA_OPAQUE};
virtual void _handle_focus_change(bool) override {}
virtual void _handle_font_change(core::Font*) override;
virtual void _handle_font_color_change(const SDL_Color&, const SDL_Color&);
virtual void _handle_font_color_change(const SDL_Color&, const SDL_Color&) override;
virtual void _handle_geometry_change(const SDL_Rect&) noexcept override;
virtual void _handle_renderer_change(core::Renderer*) override;
virtual void _handle_rendering() override;
public:
int border_width {3};
SDL_Color color_bg {150, 150, 150, SDL_ALPHA_OPAQUE};
SDL_Color color_bg_hover {175, 175, 175, SDL_ALPHA_OPAQUE};
core::Size border_size {3, 3};
SDL_Color color_bg {150, 150, 150, SDL_ALPHA_OPAQUE};
SDL_Color color_bg_hover {175, 175, 175, SDL_ALPHA_OPAQUE};
Button(Widget* parent=nullptr);
virtual core::Size size() const noexcept override;
virtual const std::string& text() const noexcept;
virtual void text(std::string);
virtual Button* text(std::string);
};
}

View file

@ -29,7 +29,7 @@ namespace bwidgets::widget
private:
SDL_Color _color_fg {0, 0, 0, SDL_ALPHA_OPAQUE};
SDL_Color _color_bg {255, 255, 255, SDL_ALPHA_OPAQUE};
SDL_Color _color_bg {255, 255, 255, SDL_ALPHA_TRANSPARENT};
std::string _text;
core::Texture* _text_texture {nullptr};
@ -51,11 +51,11 @@ namespace bwidgets::widget
Caption(Widget* parent=nullptr) : Widget(parent) {}
~Caption() noexcept;
virtual void color_bg(const SDL_Color&);
virtual void color_fg(const SDL_Color&);
virtual Caption* color_bg(const SDL_Color&);
virtual Caption* color_fg(const SDL_Color&);
virtual core::Size size() const noexcept override;
virtual const std::string& text() const noexcept;
virtual void text(const std::string&);
virtual Caption* text(const std::string&);
};
}

View file

@ -18,9 +18,9 @@ namespace bwidgets::widget
bool _is_pushed = false;
virtual void _handle_mouse_button(const SDL_MouseButtonEvent&,
const SDL_Rect&) = 0;
const SDL_Rect&) {};
virtual void _handle_mouse_motion(const SDL_MouseMotionEvent&,
const SDL_Rect&) = 0;
const SDL_Rect&) {};
public:
std::function<void (const SDL_MouseButtonEvent&)> click_handler = nullptr;

View file

@ -24,11 +24,19 @@ namespace bwidgets::widget
std::pair<T, T> _value_range {std::numeric_limits<T>::lowest(),
std::numeric_limits<T>::max()};
virtual void _handle_font_change() override
virtual void _handle_font_change(core::Font* f) override
{
_decrement_button.font(FontHandler::_font);
_increment_button.font(FontHandler::_font);
Input<T>::_handle_font_change();
_decrement_button.font(f);
_increment_button.font(f);
Input<T>::_handle_font_change(f);
}
virtual void _handle_font_color_change(const SDL_Color& fg,
const SDL_Color& bg) override
{
Input<T>::_handle_font_color_change(fg, bg);
_decrement_button.font_color_bg(bg)->font_color_fg(fg);
_increment_button.font_color_bg(bg)->font_color_fg(fg);
}
virtual void _handle_geometry_change(const SDL_Rect& vp) noexcept override
@ -79,7 +87,7 @@ namespace bwidgets::widget
));
}
virtual void _handle_renderer_change(core::Renderer* r)
virtual void _handle_renderer_change(core::Renderer* r) override
{
Input<T>::_handle_renderer_change(r);
_decrement_button.renderer(r);
@ -127,11 +135,12 @@ namespace bwidgets::widget
};
}
virtual void handle_event(const SDL_Event& ev) override
virtual Widget* handle_event(const SDL_Event& ev) override
{
Widget::handle_event(ev);
_increment_button.handle_event(ev);
_decrement_button.handle_event(ev);
return this;
}
virtual bool is_valid_input(const std::string input) const noexcept override
@ -173,12 +182,13 @@ namespace bwidgets::widget
return _value_range;
}
virtual void value_range(T min, T max)
virtual NumericInput<T>* value_range(T min, T max)
{
if (min > max)
throw std::invalid_argument("min cannot be greater than max");
_value_range = {min, max};
return this;
}
};
}

View file

@ -1,6 +1,10 @@
project('sdl2_basic_widgets', 'cpp',
version : '0.1pre',
default_options : ['warning_level=3', 'werror=true', 'cpp_std=c++20', 'd_ndebug=if-release'],
default_options : [
'warning_level=3',
'cpp_std=c++20',
'd_ndebug=if-release',
'optimization=g'],
license: 'EUPL-1.2')
add_project_arguments('-Winline', '-pedantic', language: 'cpp')
@ -36,20 +40,20 @@ libbasic_widgets_dep = declare_dependency(
link_with: libbasic_widgets,
dependencies : [sdl, fontconfig])
# executable('button_demo',
# 'examples/button_example.cpp',
# include_directories : pub_api,
# link_with : libbasic_widgets,
# install : false)
executable('button_demo',
'examples/button_example.cpp',
include_directories : pub_api,
link_with : libbasic_widgets,
install : false)
# executable('caption_demo',
# 'examples/caption_example.cpp',
# include_directories : pub_api,
# link_with : libbasic_widgets,
# install : false)
executable('caption_demo',
'examples/caption_example.cpp',
include_directories : pub_api,
link_with : libbasic_widgets,
install : false)
# executable('input_demo',
# 'examples/input_example.cpp',
# include_directories : pub_api,
# link_with : libbasic_widgets,
# install : false)
executable('input_demo',
'examples/input_example.cpp',
include_directories : pub_api,
link_with : libbasic_widgets,
install : false)

View file

@ -1,4 +1,3 @@
#include "SDL_ttf.h"
#include <any>
#include <functional>
#include <vector>

View file

@ -45,11 +45,11 @@ core::Renderer* core::Renderer::clear()
return this;
}
core::Renderer* core::Renderer::copy(core::Texture& t,
const SDL_Rect* src, const SDL_Rect* dst)
core::Renderer* core::Renderer::copy(core::Texture* t,
const SDL_Rect* src, const SDL_Rect* dst)
{
SDLError::success_or_throw(
SDL_RenderCopy(c_pod, t.c_pod, src, dst),
SDL_RenderCopy(c_pod, t->c_pod, src, dst),
__FILE__, __FUNCTION__, __LINE__
);

View file

@ -30,6 +30,7 @@ core::Texture::Texture(Renderer* r, SDL_Surface* s)
core::Texture::~Texture() noexcept
{
SDL_DestroyTexture(c_pod);
c_pod = nullptr;
}
uint8_t core::Texture::alpha_mode()

View file

@ -8,15 +8,17 @@ widget::Layout::~Layout() noexcept
delete widget_ptr;
}
void widget::Layout::add_widget(Widget *widget_ptr)
widget::Layout* widget::Layout::add_widget(Widget *widget_ptr)
{
_widgets.push_back(widget_ptr);
return this;
}
void widget::Layout::handle_event(const SDL_Event& ev)
widget::Layout* widget::Layout::handle_event(const SDL_Event& ev)
{
for (Widget* widget_ptr : _widgets)
widget_ptr->handle_event(ev);
return this;
}
void widget::Layout::_handle_geometry_change(const SDL_Rect& vp) noexcept

View file

@ -6,7 +6,7 @@
using namespace bwidgets;
void widget::Widget::handle_event(const SDL_Event &ev)
widget::Widget* widget::Widget::handle_event(const SDL_Event &ev)
{
if (auto handler = dynamic_cast<KeyboardHandler*>(this);
handler != nullptr)
@ -37,22 +37,26 @@ void widget::Widget::handle_event(const SDL_Event &ev)
break;
}
}
return this;
}
void widget::Widget::render()
widget::Widget* widget::Widget::render()
{
if (_renderer == nullptr)
return;
return this;
//#ifndef _NDEBUG
#ifndef _NDEBUG
_renderer->viewport(nullptr)
->draw_color({0, 255, 0, SDL_ALPHA_TRANSPARENT})
->fill_rect({
->draw_rect({
_viewport.x - 1, _viewport.y - 1,
_viewport.w + 2, _viewport.h + 2
});
//#endif
#endif
_renderer->viewport(_viewport);
_handle_rendering();
return this;
}

View file

@ -16,8 +16,8 @@ widget::Button::Button(Widget* parent)
core::Size widget::Button::size() const noexcept
{
return {
_caption.size().w + 2 * border_width,
_caption.size().h + 2 * border_width
_caption.size().w + 2 * border_size.w,
_caption.size().h + 2 * border_size.h
};
}
@ -26,10 +26,11 @@ const std::string& widget::Button::text() const noexcept
return _caption.text();
}
void widget::Button::text(std::string txt)
widget::Button* widget::Button::text(std::string txt)
{
_caption.text(txt);
_handle_geometry_change(_viewport);
return this;
}
void widget::Button::_handle_font_change(core::Font* f)
@ -40,17 +41,16 @@ void widget::Button::_handle_font_change(core::Font* f)
void widget::Button::_handle_font_color_change(const SDL_Color& fg, const SDL_Color& bg)
{
_caption.color_fg(fg);
_caption.color_bg(bg);
_caption.color_fg(fg)->color_bg(bg);
}
void widget::Button::_handle_geometry_change(const SDL_Rect& vp) noexcept
{
int h = _caption.size().h + 2 * border_width;
int h = _caption.size().h + 2 * border_size.h;
_widget_area = {
0,
core::center_rect(vp.h, _caption.size().h) - border_width,
core::center_rect(vp.h, _caption.size().h) - border_size.h,
vp.w,
h
};
@ -63,12 +63,7 @@ void widget::Button::_handle_geometry_change(const SDL_Rect& vp) noexcept
txt_size.w,
txt_size.h
};
_caption.viewport({
vp.x + _caption_area.x,
vp.y + _caption_area.y,
_caption_area.w,
_caption_area.h
});
_caption.viewport(core::rect_offset(_caption_area, vp));
}
void widget::Button::_handle_renderer_change(core::Renderer* r)
@ -87,46 +82,52 @@ void widget::Button::_handle_rendering()
SDL_Color c = _is_hovered ? color_bg_hover : color_bg;
if (_is_pushed)
{
for (int i = 0; i < border_width; i++)
auto x = 0, y = 0;
auto biggest = border_size.w > border_size.h ? border_size.w : border_size.h;
while (x < border_size.w || y < border_size.h)
{
auto max = x > y ? x : y;
_renderer->draw_color({
color_shade(c.r, i, border_width),
color_shade(c.g, i, border_width),
color_shade(c.b, i, border_width),
color_shade(c.r, max, biggest),
color_shade(c.g, max, biggest),
color_shade(c.b, max, biggest),
c.a
})
->draw_rect({
_widget_area.x + i,
_widget_area.y + i,
_widget_area.w - i * 2,
_widget_area.h - i * 2
_widget_area.x + x,
_widget_area.y + y,
_widget_area.w - x * 2,
_widget_area.h - y * 2
});
if (x < border_size.w)
x++;
if (y < border_size.h)
y++;
}
}
else
{
for (int i = border_width; i >= 0; i--)
auto x = 0, y = 0;
auto biggest = border_size.w > border_size.h ? border_size.w : border_size.h;
while (x < border_size.w || y < border_size.h)
{
int margin = border_width - i;
auto max = x > y ? x : y;
core::Size margin = border_size - core::Size({x, y});
_renderer->draw_color({
color_shade(c.r, i, border_width),
color_shade(c.g, i, border_width),
color_shade(c.b, i, border_width),
color_shade(c.r, max, biggest),
color_shade(c.g, max, biggest),
color_shade(c.b, max, biggest),
c.a
})->draw_rect({
_widget_area.x + margin,
_widget_area.y + margin,
_widget_area.w - margin * 2,
_widget_area.h - margin * 2
});
})->draw_rect(core::rect_margin(_widget_area, margin));
if (x < border_size.w)
x++;
if (y < border_size.h)
y++;
}
}
_renderer->draw_color(c)->fill_rect({
_widget_area.x + border_width,
_widget_area.y + border_width,
_widget_area.w - 2 * border_width,
_widget_area.h - 2 * border_width
});
_caption.render();
_renderer->draw_color(c)->fill_rect(
core::rect_margin(_widget_area, border_size)
);
_caption.color_bg(c)->render();
}

View file

@ -3,6 +3,7 @@
#include <basic_widgets/core/math.hpp>
#include <basic_widgets/core/texture.hpp>
#include <basic_widgets/w/caption.hpp>
#include <iostream>
using namespace bwidgets;
@ -11,10 +12,18 @@ widget::Caption::~Caption() noexcept
core::OpaqueStruct<core::Texture>::discard(_text_texture);
}
void widget::Caption::color_fg(const SDL_Color& c)
widget::Caption* widget::Caption::color_bg(const SDL_Color& c)
{
_color_bg = c;
core::OpaqueStruct<core::Texture>::discard(_text_texture);
return this;
}
widget::Caption* widget::Caption::color_fg(const SDL_Color& c)
{
_color_fg = c;
core::OpaqueStruct<core::Texture>::discard(_text_texture);
return this;
}
core::Size widget::Caption::size() const noexcept
@ -32,10 +41,11 @@ const std::string& widget::Caption::text() const noexcept
return _text;
}
void widget::Caption::text(const std::string& t)
widget::Caption* widget::Caption::text(const std::string& t)
{
_text = t;
core::OpaqueStruct<core::Texture>::discard(_text_texture);
return this;
}
void widget::Caption::_handle_font_change(core::Font*)
@ -61,8 +71,7 @@ void widget::Caption::_handle_geometry_change(const SDL_Rect& vp) noexcept
{
if (vp.w != _viewport.w || vp.h != _viewport.h)
{
_widget_area = {margins.w, margins.h,
vp.w - 2 * margins.w, vp.h - 2 * margins.h};
_widget_area = core::rect_margin({0, 0, vp.w, vp.h}, margins);
}
}
@ -73,11 +82,10 @@ void widget::Caption::_handle_renderer_change(core::Renderer*)
void widget::Caption::_handle_rendering()
{
if (_text_texture == nullptr)
{
_renderer->draw_color(_color_bg)->fill_rect({0, 0, _viewport.w, _viewport.h});
if (!_text_texture)
_handle_texture_update();
SDL_assert_release(_text_texture != nullptr);
}
core::Size size_dst {
(int)((float)_text_texture->attributes().w
@ -112,14 +120,12 @@ void widget::Caption::_handle_rendering()
case AlignmentV::TOP:
texture_dst.y = margins.h + _widget_area.y;
}
_renderer->copy(*_text_texture, NULL, texture_dst);
_renderer->copy(_text_texture, NULL, texture_dst);
}
void widget::Caption::_handle_texture_update()
{
SDL_assert_release(_renderer != nullptr);
core::OpaqueStruct<core::Texture>::discard(_text_texture);
auto txt_surface = _font->render(core::Font::RenderMode::SHADED,
_text, _color_fg, _color_bg);
_text_texture = new core::Texture(_renderer, txt_surface);