wip big rewrite
This commit is contained in:
parent
5a427ec4c2
commit
deb11ed9fd
|
@ -1,17 +1,22 @@
|
|||
#include <iostream>
|
||||
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
|
||||
#include <basic_widgets/button.hpp>
|
||||
#include <basic_widgets/horizontal_layout.hpp>
|
||||
#include <basic_widgets/utils/font.hpp>
|
||||
#include <basic_widgets/vertical_layout.hpp>
|
||||
|
||||
using namespace bwidgets::widget;
|
||||
using namespace bwidgets::utils;
|
||||
|
||||
int main()
|
||||
{
|
||||
int width = 640;
|
||||
int height = 480;
|
||||
|
||||
TTF_Init();
|
||||
TTF_Font* font = TTF_OpenFont(find_font("Monospace").c_str(), 20);
|
||||
TTF_Font* font = TTF_OpenFont(font::find("Monospace").c_str(), 20);
|
||||
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
SDL_Window* win = SDL_CreateWindow(
|
||||
|
@ -26,13 +31,13 @@ int main()
|
|||
SDL_SetRenderDrawBlendMode(rend, SDL_BLENDMODE_BLEND);
|
||||
|
||||
SDL_Rect layout_vp = {0, 0, width, height};
|
||||
auto layout = new Horizontal_Layout(rend);
|
||||
auto layout = new Horizontal_Layout();
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
auto column = new Vertical_Layout(rend);
|
||||
auto column = new Vertical_Layout();
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
auto widget = new Button(rend);
|
||||
auto widget = new Button();
|
||||
widget->text("hello");
|
||||
widget->click_handler = [i, j](const SDL_MouseButtonEvent&) {
|
||||
std::cerr << "click@" << j << ":" << i << std::endl;
|
||||
|
@ -72,7 +77,7 @@ int main()
|
|||
SDL_SetRenderDrawColor(rend, 75, 75, 75, SDL_ALPHA_OPAQUE);
|
||||
SDL_RenderClear(rend);
|
||||
|
||||
layout->render();
|
||||
layout->render(rend);
|
||||
SDL_RenderPresent(rend);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,13 +5,16 @@
|
|||
#include <basic_widgets/utils/font.hpp>
|
||||
#include <basic_widgets/vertical_layout.hpp>
|
||||
|
||||
using namespace bwidgets::utils;
|
||||
using namespace bwidgets::widget;
|
||||
|
||||
int main()
|
||||
{
|
||||
int width = 640;
|
||||
int height = 480;
|
||||
|
||||
TTF_Init();
|
||||
TTF_Font* font = TTF_OpenFont(find_font("Monospace").c_str(), 20);
|
||||
TTF_Font* font = TTF_OpenFont(font::find("Monospace").c_str(), 20);
|
||||
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
SDL_Window* win = SDL_CreateWindow(
|
||||
|
@ -26,13 +29,13 @@ int main()
|
|||
SDL_SetRenderDrawBlendMode(rend, SDL_BLENDMODE_BLEND);
|
||||
|
||||
SDL_Rect layout_vp = {0, 0, width, height};
|
||||
auto layout = new Horizontal_Layout(rend);
|
||||
auto layout = new Horizontal_Layout();
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
auto column = new Vertical_Layout(rend);
|
||||
auto column = new Vertical_Layout();
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
auto widget = new Numeric_Input<float>(rend);
|
||||
auto widget = new Numeric_Input<float>();
|
||||
widget->button_step = 0.5;
|
||||
widget->font(font);
|
||||
widget->value_range(-2.5, 2.5);
|
||||
|
@ -70,7 +73,7 @@ int main()
|
|||
SDL_SetRenderDrawColor(rend, 75, 75, 75, SDL_ALPHA_OPAQUE);
|
||||
SDL_RenderClear(rend);
|
||||
|
||||
layout->render();
|
||||
layout->render(rend);
|
||||
SDL_RenderPresent(rend);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef FOCUS_HANDLER_HPP
|
||||
#define FOCUS_HANDLER_HPP
|
||||
|
||||
struct SDL_Rect;
|
||||
|
||||
namespace bwidgets::abstract
|
||||
{
|
||||
class FocusHandler
|
||||
{
|
||||
protected:
|
||||
const SDL_Rect* _focus_area = nullptr;
|
||||
bool _has_focus = false;
|
||||
|
||||
virtual void _handle_focus_change();
|
||||
|
||||
public:
|
||||
virtual ~FocusHandler();
|
||||
|
||||
inline virtual void focus(bool focus)
|
||||
{
|
||||
_has_focus = focus;
|
||||
_handle_focus_change();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef FONT_HANDLER_HPP
|
||||
#define FONT_HANDLER_HPP
|
||||
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
|
||||
namespace bwidgets::abstract
|
||||
{
|
||||
class FontHandler
|
||||
{
|
||||
protected:
|
||||
TTF_Font* _font {nullptr};
|
||||
|
||||
virtual void _handle_font_change() = 0;
|
||||
|
||||
public:
|
||||
virtual ~FontHandler();
|
||||
virtual void font(TTF_Font*);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -7,255 +7,245 @@
|
|||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include <SDL2/SDL_events.h>
|
||||
#include <SDL2/SDL_keyboard.h>
|
||||
#include <SDL2/SDL_render.h>
|
||||
|
||||
#include <basic_widgets/abstract/keyboard_handler.hpp>
|
||||
#include <basic_widgets/abstract/mouse_handler.hpp>
|
||||
#include <basic_widgets/caption.hpp>
|
||||
#include <basic_widgets/utils/math.hpp>
|
||||
|
||||
template<typename T>
|
||||
concept CanToString = requires(T value) { std::to_string(value); };
|
||||
|
||||
template<typename T>
|
||||
concept Printable = requires(T value) { std::declval<std::ostream&>() << value; };
|
||||
|
||||
template<typename T> class Input : public Widget
|
||||
namespace bwidgets::abstract
|
||||
{
|
||||
protected:
|
||||
SDL_Rect _input_area {};
|
||||
SDL_Rect _input_field_area {};
|
||||
Caption _input_text;
|
||||
T _value {};
|
||||
SDL_Rect _input_text_area {};
|
||||
template<typename T>
|
||||
concept CanToString = requires(T value) { std::to_string(value); };
|
||||
|
||||
Input(SDL_Renderer* r)
|
||||
: Widget(r), _input_text(r)
|
||||
{
|
||||
input_text(value_to_string(_value));
|
||||
}
|
||||
template<typename T>
|
||||
concept Printable = requires(T value) { std::declval<std::ostream&>() << value; };
|
||||
|
||||
virtual void _on_focus()
|
||||
template<typename T> class Input : public Widget,
|
||||
public FontHandler,
|
||||
public KeyboardHandler,
|
||||
public MouseHandler
|
||||
{
|
||||
SDL_StartTextInput();
|
||||
}
|
||||
protected:
|
||||
const int _border_width {3};
|
||||
SDL_Rect _input_area {};
|
||||
widget::Caption _input_caption;
|
||||
SDL_Rect _input_caption_area {};
|
||||
T _value {};
|
||||
|
||||
virtual void _on_focus_loss()
|
||||
{
|
||||
input_text(value_to_string(_value));
|
||||
SDL_StopTextInput();
|
||||
}
|
||||
|
||||
virtual void _on_key(const SDL_KeyboardEvent& key)
|
||||
{
|
||||
if (key.type == SDL_KEYDOWN)
|
||||
{
|
||||
switch (key.keysym.sym)
|
||||
Input(Widget* parent=nullptr)
|
||||
: Widget(parent)
|
||||
{
|
||||
case SDLK_BACKSPACE:
|
||||
MouseHandler::_focus_area = &_input_area;
|
||||
MouseHandler::_button_area = &_input_area;
|
||||
_input_caption.text(value_to_string(_value));
|
||||
}
|
||||
|
||||
virtual void _handle_focus_change()
|
||||
{
|
||||
if (MouseHandler::_has_focus)
|
||||
SDL_StartTextInput();
|
||||
else
|
||||
{
|
||||
std::string txt = input_text();
|
||||
if (txt.length() > 0)
|
||||
{
|
||||
txt.pop_back();
|
||||
input_text(txt);
|
||||
value(value_from_string(txt));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SDLK_RETURN:
|
||||
case SDLK_RETURN2: // what is return2 btw?
|
||||
case SDLK_KP_ENTER:
|
||||
input_text(value_to_string(_value));
|
||||
break;
|
||||
SDL_StopTextInput();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void _on_text_input(const SDL_TextInputEvent& input)
|
||||
{
|
||||
Widget::_on_text_input(input);
|
||||
if (is_valid_input(input.text))
|
||||
{
|
||||
std::string new_txt_value = input_text() + input.text;
|
||||
input_text(new_txt_value);
|
||||
value(value_from_string(new_txt_value));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void _render_value()
|
||||
{
|
||||
_update_drawing_areas();
|
||||
}
|
||||
|
||||
virtual void _update_drawing_areas()
|
||||
{
|
||||
_update_widget_area();
|
||||
_input_area = {
|
||||
_input_field_area.x + 3,
|
||||
_input_field_area.y + 3,
|
||||
_input_field_area.w - 6,
|
||||
_input_field_area.h - 6
|
||||
};
|
||||
auto text_render_size = _input_text.rendered_text_size();
|
||||
int text_area_width = _input_area.h / (float)text_render_size.h * text_render_size.w;
|
||||
SDL_Rect value_text_vp = {
|
||||
_viewport.x + _input_area.x + Widget::center(_input_area.w, text_area_width),
|
||||
_viewport.y + _input_area.y,
|
||||
text_area_width,
|
||||
_input_area.h
|
||||
};
|
||||
_input_text.viewport(value_text_vp);
|
||||
//SDL_SetTextInputRect(&_input_area);
|
||||
}
|
||||
|
||||
virtual void _update_widget_area()
|
||||
{
|
||||
_widget_area = _input_field_area;
|
||||
}
|
||||
|
||||
public:
|
||||
SDL_Color border_color {160, 160, 160, SDL_ALPHA_OPAQUE};
|
||||
SDL_Color background_color {200, 200, 200, SDL_ALPHA_OPAQUE};
|
||||
int float_precision {2};
|
||||
SDL_Color focused_background_color {255, 255, 255, SDL_ALPHA_OPAQUE};
|
||||
|
||||
virtual const std::string& input_text() const
|
||||
{
|
||||
return _input_text.text();
|
||||
}
|
||||
|
||||
virtual void input_text(std::string txt)
|
||||
{
|
||||
_input_text.text(txt);
|
||||
_update_drawing_areas();
|
||||
}
|
||||
|
||||
virtual bool is_valid_input(const std::string) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void font(TTF_Font* f)
|
||||
{
|
||||
_input_text.font(f);
|
||||
_update_drawing_areas();
|
||||
}
|
||||
|
||||
virtual T process_value(T x) const
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
virtual void render()
|
||||
{
|
||||
Widget::render();
|
||||
|
||||
SDL_Rect old_vp;
|
||||
|
||||
SDL_RenderGetViewport(_renderer, &old_vp);
|
||||
SDL_RenderSetViewport(_renderer, &_viewport);
|
||||
|
||||
for (int i = 3; i > 0; i--)
|
||||
{
|
||||
SDL_SetRenderDrawColor(
|
||||
_renderer,
|
||||
border_color.r / i,
|
||||
border_color.g / i,
|
||||
border_color.b / i,
|
||||
border_color.a
|
||||
);
|
||||
SDL_Rect border_area = {
|
||||
_input_field_area.x + 3 - i,
|
||||
_input_field_area.y + 3 - i,
|
||||
_input_field_area.w - 2 * (3 - i),
|
||||
_input_field_area.h - 2 * (3 - i)
|
||||
};
|
||||
SDL_RenderDrawRect(_renderer, &border_area);
|
||||
}
|
||||
|
||||
SDL_Color* bg_color = &background_color;
|
||||
if (_focused)
|
||||
bg_color = &focused_background_color;
|
||||
|
||||
SDL_SetRenderDrawColor(
|
||||
_renderer,
|
||||
bg_color->r,
|
||||
bg_color->g,
|
||||
bg_color->b,
|
||||
bg_color->a
|
||||
);
|
||||
SDL_RenderFillRect(_renderer, &_input_area);
|
||||
|
||||
_input_text.render();
|
||||
|
||||
SDL_RenderSetViewport(_renderer, &old_vp);
|
||||
}
|
||||
|
||||
T value() const
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
void value(T new_value)
|
||||
{
|
||||
_value = new_value;
|
||||
_render_value();
|
||||
}
|
||||
|
||||
T value_from_string(std::string s)
|
||||
{
|
||||
T v;
|
||||
|
||||
if constexpr(std::is_arithmetic_v<T>)
|
||||
{
|
||||
s = s.length() > 0 ? s : "0";
|
||||
try
|
||||
virtual void _handle_font_change()
|
||||
{
|
||||
if constexpr(std::is_floating_point_v<T>)
|
||||
v = (T)std::stold(s);
|
||||
else if constexpr(std::is_integral_v<T>)
|
||||
v = (T)std::stoll(s);
|
||||
_input_caption.font(_font);
|
||||
}
|
||||
catch(std::exception&)
|
||||
|
||||
virtual void _handle_key(const SDL_KeyboardEvent& key)
|
||||
{
|
||||
v = value();
|
||||
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);
|
||||
value(value_from_string(txt));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SDLK_RETURN:
|
||||
case SDLK_RETURN2: // what is return2 btw?
|
||||
case SDLK_KP_ENTER:
|
||||
input_text(value_to_string(_value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if constexpr(std::is_same_v<T, std::string> || std::convertible_to<std::string, T>)
|
||||
v = s;
|
||||
else
|
||||
static_assert(sizeof(T) && false, "string cannot be converted to v type T.");
|
||||
|
||||
return process_value(v);
|
||||
}
|
||||
virtual void _handle_text_input(const SDL_TextInputEvent& input)
|
||||
{
|
||||
if (is_valid_input(input.text))
|
||||
{
|
||||
std::string new_txt_value = input_text() + input.text;
|
||||
input_text(new_txt_value);
|
||||
value(value_from_string(new_txt_value));
|
||||
}
|
||||
}
|
||||
|
||||
std::string value_to_string(T value)
|
||||
{
|
||||
std::string s;
|
||||
virtual void _update_widget_area()
|
||||
{
|
||||
_widget_area = {
|
||||
_viewport.x,
|
||||
utils::math::center_rect(_viewport.h, _input_caption.height()),
|
||||
_viewport.w,
|
||||
_input_caption.height()
|
||||
};
|
||||
_input_area = {
|
||||
_widget_area.x + _border_width,
|
||||
_widget_area.y + _border_width,
|
||||
_widget_area.w - 2 * _border_width,
|
||||
_widget_area.h - 2 * _border_width
|
||||
};
|
||||
|
||||
if constexpr(std::is_same_v<std::string, T> || std::convertible_to<T, std::string>)
|
||||
s = std::move(value);
|
||||
else if constexpr(CanToString<T>)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::fixed
|
||||
<< std::setprecision(float_precision)
|
||||
<< value;
|
||||
s = std::move(ss).str();
|
||||
}
|
||||
else if constexpr(Printable<T>)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << value;
|
||||
s = std::move(ss).str();
|
||||
}
|
||||
else
|
||||
static_assert(sizeof(T) && false, "_value cannot be converted to string.");
|
||||
_input_caption.viewport(
|
||||
utils::math::rect_offset(_input_area, _viewport)
|
||||
);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
public:
|
||||
SDL_Color color_border {160, 160, 160, SDL_ALPHA_OPAQUE};
|
||||
SDL_Color color_bg {200, 200, 200, SDL_ALPHA_OPAQUE};
|
||||
int float_precision {2};
|
||||
SDL_Color focused_bg_color {255, 255, 255, SDL_ALPHA_OPAQUE};
|
||||
|
||||
virtual void viewport(SDL_Rect vp)
|
||||
{
|
||||
Widget::viewport(vp);
|
||||
_update_drawing_areas();
|
||||
}
|
||||
};
|
||||
virtual void color_fg(const SDL_Color& c)
|
||||
{
|
||||
_input_caption.color_fg(c);
|
||||
}
|
||||
|
||||
virtual const std::string& input_text() const
|
||||
{
|
||||
return _input_caption.text();
|
||||
}
|
||||
|
||||
virtual void input_text(std::string txt)
|
||||
{
|
||||
_input_caption.text(txt);
|
||||
}
|
||||
|
||||
virtual bool is_valid_input(const std::string) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual T process_value(T x) const
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
virtual void render(SDL_Renderer* r)
|
||||
{
|
||||
Widget::render(r);
|
||||
|
||||
SDL_RenderSetViewport(r, &_viewport);
|
||||
|
||||
for (int i = 3; i > 0; i--)
|
||||
{
|
||||
SDL_SetRenderDrawColor(
|
||||
r,
|
||||
color_border.r / i,
|
||||
color_border.g / i,
|
||||
color_border.b / i,
|
||||
color_border.a
|
||||
);
|
||||
SDL_Rect border_area = {
|
||||
_widget_area.x + 3 - i,
|
||||
_widget_area.y + 3 - i,
|
||||
_widget_area.w - 2 * (3 - i),
|
||||
_widget_area.h - 2 * (3 - i)
|
||||
};
|
||||
SDL_RenderDrawRect(r, &border_area);
|
||||
}
|
||||
|
||||
SDL_Color* c = &color_bg;
|
||||
if (MouseHandler::_has_focus)
|
||||
c = &focused_bg_color;
|
||||
|
||||
SDL_SetRenderDrawColor(r, c->r, c->g, c->b, c->a);
|
||||
SDL_RenderFillRect(r, &_input_area);
|
||||
|
||||
_input_caption.render(r);
|
||||
}
|
||||
|
||||
T value() const
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
void value(T new_value)
|
||||
{
|
||||
_value = new_value;
|
||||
_input_caption.text(value_to_string(_value));
|
||||
_update_widget_area();
|
||||
}
|
||||
|
||||
T value_from_string(std::string s)
|
||||
{
|
||||
T v;
|
||||
|
||||
if constexpr(std::is_arithmetic_v<T>)
|
||||
{
|
||||
s = s.length() > 0 ? s : "0";
|
||||
try
|
||||
{
|
||||
if constexpr(std::is_floating_point_v<T>)
|
||||
v = (T)std::stold(s);
|
||||
else if constexpr(std::is_integral_v<T>)
|
||||
v = (T)std::stoll(s);
|
||||
}
|
||||
catch(std::exception&)
|
||||
{
|
||||
v = value();
|
||||
}
|
||||
}
|
||||
else if constexpr(std::is_same_v<T, std::string> || std::convertible_to<std::string, T>)
|
||||
v = s;
|
||||
else
|
||||
static_assert(sizeof(T) && false, "string cannot be converted to v type T.");
|
||||
|
||||
return process_value(v);
|
||||
}
|
||||
|
||||
std::string value_to_string(T value)
|
||||
{
|
||||
std::string s;
|
||||
|
||||
if constexpr(std::is_same_v<std::string, T> || std::convertible_to<T, std::string>)
|
||||
s = std::move(value);
|
||||
else if constexpr(CanToString<T>)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::fixed
|
||||
<< std::setprecision(float_precision)
|
||||
<< value;
|
||||
s = std::move(ss).str();
|
||||
}
|
||||
else if constexpr(Printable<T>)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << value;
|
||||
s = std::move(ss).str();
|
||||
}
|
||||
else
|
||||
static_assert(sizeof(T) && false, "_value cannot be converted to string.");
|
||||
|
||||
return s;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,33 @@
|
|||
#ifndef KEYBOARD_HANDLER
|
||||
#define KEYBOARD_HANDLER
|
||||
|
||||
#include <basic_widgets/abstract/focus_handler.hpp>
|
||||
|
||||
struct SDL_KeyboardEvent;
|
||||
struct SDL_TextInputEvent;
|
||||
|
||||
namespace bwidgets::abstract
|
||||
{
|
||||
class KeyboardHandler : public FocusHandler
|
||||
{
|
||||
protected:
|
||||
|
||||
virtual void _handle_key(const SDL_KeyboardEvent&);
|
||||
virtual void _handle_text_input(const SDL_TextInputEvent&);
|
||||
|
||||
public:
|
||||
inline virtual void handle_keyboard(const SDL_KeyboardEvent& ev)
|
||||
{
|
||||
if (_has_focus)
|
||||
_handle_key(ev);
|
||||
}
|
||||
|
||||
inline virtual void handle_keyboard(const SDL_TextInputEvent& ev)
|
||||
{
|
||||
if (_has_focus)
|
||||
_handle_text_input(ev);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -5,21 +5,23 @@
|
|||
|
||||
#include <basic_widgets/abstract/widget.hpp>
|
||||
|
||||
class Layout : public Widget
|
||||
namespace bwidgets::abstract
|
||||
{
|
||||
protected:
|
||||
float _interspace = 16;
|
||||
std::vector<Widget*> _widgets;
|
||||
class Layout : public abstract::Widget
|
||||
{
|
||||
protected:
|
||||
int _interspace = 16;
|
||||
std::vector<Widget*> _widgets;
|
||||
|
||||
virtual void _update_layout() = 0;
|
||||
virtual void _update_layout() = 0;
|
||||
|
||||
public:
|
||||
Layout(SDL_Renderer*);
|
||||
virtual ~Layout();
|
||||
virtual void add_widget(Widget*);
|
||||
virtual void handle_event(const SDL_Event&);
|
||||
virtual void render();
|
||||
virtual void viewport(SDL_Rect);
|
||||
};
|
||||
public:
|
||||
virtual ~Layout();
|
||||
virtual void add_widget(Widget*);
|
||||
virtual void handle_event(const SDL_Event&);
|
||||
virtual void render(SDL_Renderer*);
|
||||
virtual void viewport(SDL_Rect);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef MOUSE_HANDLER_HPP
|
||||
#define MOUSE_HANDLER_HPP
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <basic_widgets/abstract/focus_handler.hpp>
|
||||
|
||||
struct SDL_MouseButtonEvent;
|
||||
struct SDL_MouseMotionEvent;
|
||||
struct SDL_Rect;
|
||||
|
||||
namespace bwidgets::abstract
|
||||
{
|
||||
class MouseHandler : public FocusHandler
|
||||
{
|
||||
protected:
|
||||
const SDL_Rect* _button_area = nullptr;
|
||||
bool _is_hovered = false;
|
||||
bool _is_pushed = false;
|
||||
|
||||
virtual void _handle_focus_change();
|
||||
virtual void _handle_mouse_button(const SDL_MouseButtonEvent&,
|
||||
const SDL_Rect&);
|
||||
virtual void _handle_mouse_motion(const SDL_MouseMotionEvent&,
|
||||
const SDL_Rect&);
|
||||
|
||||
public:
|
||||
std::function<void (const SDL_MouseButtonEvent&)> click_handler;
|
||||
|
||||
virtual void handle_mouse(const SDL_MouseButtonEvent&,
|
||||
const SDL_Rect&);
|
||||
virtual void handle_mouse(const SDL_MouseMotionEvent&,
|
||||
const SDL_Rect&);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -3,41 +3,38 @@
|
|||
|
||||
#include <functional>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_events.h>
|
||||
#include <SDL2/SDL_rect.h>
|
||||
|
||||
class Widget
|
||||
struct SDL_Renderer;
|
||||
|
||||
namespace bwidgets::abstract
|
||||
{
|
||||
protected:
|
||||
bool _focused = false;
|
||||
bool _hovered = false;
|
||||
bool _pushed = false;
|
||||
SDL_Renderer* _renderer;
|
||||
SDL_Rect _viewport {0, 0, 0, 0};
|
||||
SDL_Rect _widget_area {0, 0, 0, 0};
|
||||
|
||||
virtual void _on_focus();
|
||||
virtual void _on_focus_loss();
|
||||
virtual void _on_key(const SDL_KeyboardEvent&);
|
||||
virtual void _on_push(const SDL_MouseButtonEvent&);
|
||||
virtual void _on_release(const SDL_MouseButtonEvent&);
|
||||
virtual void _on_text_input(const SDL_TextInputEvent&);
|
||||
virtual void _update_hover_state(const SDL_MouseMotionEvent&);
|
||||
virtual void _update_widget_area();
|
||||
|
||||
public:
|
||||
std::function<void (const SDL_MouseButtonEvent&)> click_handler = NULL;
|
||||
|
||||
Widget(SDL_Renderer*);
|
||||
virtual ~Widget();
|
||||
static inline int center(int available_size, int used_size)
|
||||
class Widget
|
||||
{
|
||||
return (available_size - used_size) / 2;
|
||||
}
|
||||
virtual void handle_event(const SDL_Event&);
|
||||
virtual int height() const;
|
||||
virtual void render();
|
||||
virtual void viewport(SDL_Rect);
|
||||
virtual int width() const;
|
||||
};
|
||||
protected:
|
||||
SDL_Rect _viewport {0, 0, 0, 0};
|
||||
SDL_Rect _widget_area {0, 0, 0, 0};
|
||||
|
||||
virtual void _update_widget_area();
|
||||
|
||||
public:
|
||||
struct Size {
|
||||
int w;
|
||||
int h;
|
||||
};
|
||||
|
||||
Widget* parent;
|
||||
|
||||
Widget(Widget* parent=nullptr);
|
||||
virtual ~Widget();
|
||||
|
||||
virtual void handle_event(const SDL_Event&);
|
||||
virtual int height() const;
|
||||
virtual void render(SDL_Renderer*);
|
||||
virtual void viewport(SDL_Rect);
|
||||
virtual int width() const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,35 +3,38 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
|
||||
#include <basic_widgets/abstract/mouse_handler.hpp>
|
||||
#include <basic_widgets/caption.hpp>
|
||||
|
||||
class Button : public Widget
|
||||
namespace bwidgets::widget
|
||||
{
|
||||
protected:
|
||||
int _border_width = 3;
|
||||
Caption _caption;
|
||||
SDL_Rect _caption_area;
|
||||
float _caption_height_multiplicator = 1.2;
|
||||
SDL_Color _color_background = {150, 150, 150, SDL_ALPHA_OPAQUE};
|
||||
SDL_Color _color_background_hover = {175, 175, 175, SDL_ALPHA_OPAQUE};
|
||||
SDL_Color _color_foreground = {0, 0, 0, SDL_ALPHA_OPAQUE};
|
||||
class Button : public abstract::Widget,
|
||||
public abstract::FontHandler,
|
||||
public abstract::MouseHandler
|
||||
{
|
||||
protected:
|
||||
widget::Caption _caption;
|
||||
SDL_Rect _caption_area;
|
||||
float _caption_height_multiplicator = 1.2;
|
||||
SDL_Color _color_foreground = {0, 0, 0, SDL_ALPHA_OPAQUE};
|
||||
|
||||
void _update_caption_area();
|
||||
void _update_widget_area();
|
||||
void _handle_font_change();
|
||||
|
||||
public:
|
||||
Button(SDL_Renderer*);
|
||||
int border_width() const;
|
||||
void border_width(int);
|
||||
void font(TTF_Font*);
|
||||
int height() const;
|
||||
void render();
|
||||
const std::string& text() const;
|
||||
void text(std::string);
|
||||
void viewport(SDL_Rect);
|
||||
int width() const;
|
||||
};
|
||||
void _update_caption_area();
|
||||
void _update_widget_area();
|
||||
|
||||
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};
|
||||
|
||||
int height() const;
|
||||
void render(SDL_Renderer*);
|
||||
const std::string& text() const;
|
||||
void text(std::string);
|
||||
void viewport(SDL_Rect);
|
||||
int width() const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,32 +3,47 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
|
||||
#include <basic_widgets/abstract/font_handler.hpp>
|
||||
#include <basic_widgets/abstract/widget.hpp>
|
||||
|
||||
class Caption : public Widget
|
||||
struct SDL_Surface;
|
||||
struct SDL_Texture;
|
||||
|
||||
namespace bwidgets::widget
|
||||
{
|
||||
SDL_Color _color = {0, 0, 0, SDL_ALPHA_OPAQUE};
|
||||
TTF_Font* _font = NULL;
|
||||
std::string _text;
|
||||
SDL_Texture* _rendered_text = NULL;
|
||||
class Caption : public abstract::Widget, public abstract::FontHandler
|
||||
{
|
||||
public:
|
||||
enum struct Alignment {
|
||||
CENTER,
|
||||
LEFT,
|
||||
RIGHT
|
||||
};
|
||||
|
||||
void _render_text();
|
||||
void _update_widget_area();
|
||||
private:
|
||||
Alignment _alignment {Alignment::RIGHT};
|
||||
SDL_Color _color_fg {0, 0, 0, SDL_ALPHA_OPAQUE};
|
||||
std::string _text;
|
||||
SDL_Surface* _rendered_text {nullptr};
|
||||
SDL_Texture* _text_texture {nullptr};
|
||||
SDL_Renderer* _renderer {nullptr};
|
||||
|
||||
public:
|
||||
Caption(SDL_Renderer*);
|
||||
~Caption();
|
||||
void color(SDL_Color);
|
||||
void font(TTF_Font*);
|
||||
int height() const;
|
||||
void render();
|
||||
const std::string& text() const;
|
||||
void text(std::string);
|
||||
SDL_Rect rendered_text_size() const;
|
||||
void viewport(SDL_Rect);
|
||||
int width() const;
|
||||
};
|
||||
void _handle_font_change();
|
||||
void _render_text();
|
||||
void _update_widget_area();
|
||||
|
||||
public:
|
||||
SDL_Color color_bg {0, 0, 0, SDL_ALPHA_TRANSPARENT};
|
||||
|
||||
~Caption();
|
||||
|
||||
void align(Alignment);
|
||||
void color_fg(const SDL_Color&);
|
||||
void render(SDL_Renderer*);
|
||||
abstract::Widget::Size text_size() const;
|
||||
const std::string& text() const;
|
||||
void text(const std::string&);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
|
||||
#include <basic_widgets/abstract/layout.hpp>
|
||||
|
||||
class Horizontal_Layout : public Layout
|
||||
namespace bwidgets::widget
|
||||
{
|
||||
protected:
|
||||
void _update_layout();
|
||||
|
||||
public:
|
||||
Horizontal_Layout(SDL_Renderer*);
|
||||
};
|
||||
class Horizontal_Layout : public abstract::Layout
|
||||
{
|
||||
private:
|
||||
void _update_layout();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,185 +5,188 @@
|
|||
#include <regex>
|
||||
#include <type_traits>
|
||||
|
||||
#include <basic_widgets/button.hpp>
|
||||
#include <basic_widgets/abstract/input.hpp>
|
||||
#include <basic_widgets/button.hpp>
|
||||
#include <basic_widgets/utils/math.hpp>
|
||||
|
||||
template<typename T>
|
||||
concept Numeric = std::is_arithmetic_v<T>;
|
||||
|
||||
template<typename T>
|
||||
requires Numeric<T>
|
||||
class Numeric_Input : public Input<T>
|
||||
namespace bwidgets::widget
|
||||
{
|
||||
private:
|
||||
Button _increment_button;
|
||||
SDL_Rect _increment_button_area;
|
||||
Button _decrement_button;
|
||||
SDL_Rect _decrement_button_area;
|
||||
std::pair<T, T> _value_range {
|
||||
std::numeric_limits<T>::lowest(),
|
||||
std::numeric_limits<T>::max()
|
||||
};
|
||||
template<typename T>
|
||||
concept Numeric = std::is_arithmetic_v<T>;
|
||||
|
||||
void handle_event(const SDL_Event& ev)
|
||||
{
|
||||
Widget::handle_event(ev);
|
||||
_increment_button.handle_event(ev);
|
||||
_decrement_button.handle_event(ev);
|
||||
}
|
||||
|
||||
void _update_drawing_areas()
|
||||
{
|
||||
const int widest_button =
|
||||
_increment_button.width() > _decrement_button.width()
|
||||
? _increment_button.width()
|
||||
: _decrement_button.width();
|
||||
const int heighest_button =
|
||||
_increment_button.height() > _decrement_button.height()
|
||||
? _increment_button.height()
|
||||
: _decrement_button.height();
|
||||
const int button_area_width = 2 * widest_button;
|
||||
const int spacing = Widget::center(button_area_width, widest_button);
|
||||
const int field_width = Widget::_viewport.w - 2 * button_area_width;
|
||||
const int field_height = heighest_button;
|
||||
Input<T>::_input_field_area = {
|
||||
(int)button_area_width,
|
||||
Widget::center(Widget::_viewport.h, field_height),
|
||||
field_width,
|
||||
field_height
|
||||
};
|
||||
|
||||
_increment_button_area = {
|
||||
spacing,
|
||||
Widget::center(Widget::_viewport.h, _increment_button.height()),
|
||||
_increment_button.width(),
|
||||
_increment_button.height()
|
||||
};
|
||||
|
||||
_decrement_button_area = {
|
||||
Widget::_viewport.w - spacing - _decrement_button.width(),
|
||||
Widget::center(Widget::_viewport.h, _decrement_button.height()),
|
||||
_decrement_button.width(),
|
||||
_decrement_button.height()
|
||||
};
|
||||
|
||||
Widget::_widget_area = {
|
||||
button_area_width,
|
||||
Widget::center(Widget::_viewport.h, heighest_button),
|
||||
Widget::_viewport.w
|
||||
- 2 * button_area_width,
|
||||
heighest_button
|
||||
};
|
||||
|
||||
Input<T>::_update_drawing_areas();
|
||||
}
|
||||
|
||||
public:
|
||||
T button_step = 1;
|
||||
|
||||
Numeric_Input(SDL_Renderer* r)
|
||||
: Input<T>(r),
|
||||
_increment_button(r),
|
||||
_decrement_button(r)
|
||||
{
|
||||
_increment_button.text("+");
|
||||
_increment_button.click_handler = [this](const SDL_MouseButtonEvent&) {
|
||||
T new_value = this->value() + button_step;
|
||||
if (_value_range.second - this->value() < button_step)
|
||||
new_value = _value_range.second;
|
||||
|
||||
this->value(new_value);
|
||||
this->input_text(this->value_to_string(new_value));
|
||||
};
|
||||
_decrement_button.text("-");
|
||||
_decrement_button.click_handler = [this](const SDL_MouseButtonEvent&) {
|
||||
T new_value = this->value() - button_step;
|
||||
if (this->value() - _value_range.first < button_step)
|
||||
new_value = _value_range.first;
|
||||
|
||||
this->value(new_value);
|
||||
this->input_text(this->value_to_string(new_value));
|
||||
};
|
||||
}
|
||||
|
||||
void font(TTF_Font* f)
|
||||
{
|
||||
_decrement_button.font(f);
|
||||
_increment_button.font(f);
|
||||
Input<T>::font(f);
|
||||
}
|
||||
|
||||
bool is_valid_input(const std::string input) const
|
||||
{
|
||||
bool valid = false;
|
||||
|
||||
if (input.at(0) >= '0' && input.at(0) <= '9')
|
||||
valid = true;
|
||||
if constexpr(std::is_floating_point_v<T>)
|
||||
if (input.at(0) == '.'
|
||||
&& Input<T>::input_text().find('.') == std::string::npos)
|
||||
valid = true;
|
||||
if constexpr(std::is_signed_v<T>)
|
||||
template<typename T>
|
||||
requires Numeric<T>
|
||||
class Numeric_Input : public abstract::Input<T>
|
||||
{
|
||||
std::string displayed_value = Input<T>::input_text();
|
||||
if (input.at(0) == '-'
|
||||
&& !std::regex_search(
|
||||
displayed_value,
|
||||
std::regex("[^\\s]")
|
||||
))
|
||||
valid = true;
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
private:
|
||||
Button _increment_button;
|
||||
SDL_Rect _increment_button_area;
|
||||
Button _decrement_button;
|
||||
SDL_Rect _decrement_button_area;
|
||||
std::pair<T, T> _value_range {
|
||||
std::numeric_limits<T>::lowest(),
|
||||
std::numeric_limits<T>::max()
|
||||
};
|
||||
|
||||
T process_value(T x) const
|
||||
{
|
||||
T value = x;
|
||||
if (x < _value_range.first)
|
||||
value = _value_range.first;
|
||||
else if (x > _value_range.second)
|
||||
value = _value_range.second;
|
||||
void handle_event(const SDL_Event& ev)
|
||||
{
|
||||
abstract::Widget::handle_event(ev);
|
||||
_increment_button.handle_event(ev);
|
||||
_decrement_button.handle_event(ev);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
void _update_drawing_areas()
|
||||
{
|
||||
const int widest_button =
|
||||
_increment_button.width() > _decrement_button.width()
|
||||
? _increment_button.width()
|
||||
: _decrement_button.width();
|
||||
const int heighest_button =
|
||||
_increment_button.height() > _decrement_button.height()
|
||||
? _increment_button.height()
|
||||
: _decrement_button.height();
|
||||
const int button_area_width = 2 * widest_button;
|
||||
const int spacing = utils::math::center_rect(button_area_width, widest_button);
|
||||
const int field_width = abstract::Widget::_viewport.w - 2 * button_area_width;
|
||||
const int field_height = heighest_button;
|
||||
abstract::Input<T>::_input_field_area = {
|
||||
(int)button_area_width,
|
||||
utils::math::center_rect(abstract::Widget::_viewport.h, field_height),
|
||||
field_width,
|
||||
field_height
|
||||
};
|
||||
|
||||
void render()
|
||||
{
|
||||
Input<T>::render();
|
||||
_increment_button.render();
|
||||
_decrement_button.render();
|
||||
}
|
||||
_increment_button_area = {
|
||||
spacing,
|
||||
utils::math::center_rect(abstract::Widget::_viewport.h, _increment_button.height()),
|
||||
_increment_button.width(),
|
||||
_increment_button.height()
|
||||
};
|
||||
|
||||
std::pair<T, T> value_range() const
|
||||
{
|
||||
return _value_range;
|
||||
}
|
||||
_decrement_button_area = {
|
||||
abstract::Widget::_viewport.w - spacing - _decrement_button.width(),
|
||||
utils::math::center_rect(abstract::Widget::_viewport.h, _decrement_button.height()),
|
||||
_decrement_button.width(),
|
||||
_decrement_button.height()
|
||||
};
|
||||
|
||||
void value_range(T min, T max)
|
||||
{
|
||||
abstract::Widget::_widget_area = {
|
||||
button_area_width,
|
||||
utils::math::center_rect(abstract::Widget::_viewport.h, heighest_button),
|
||||
abstract::Widget::_viewport.w
|
||||
- 2 * button_area_width,
|
||||
heighest_button
|
||||
};
|
||||
|
||||
if (min > max)
|
||||
throw std::invalid_argument("min cannot be greater than max");
|
||||
_value_range = {min, max};
|
||||
}
|
||||
abstract::Input<T>::_update_drawing_areas();
|
||||
}
|
||||
|
||||
void viewport(SDL_Rect vp)
|
||||
{
|
||||
Input<T>::viewport(vp);
|
||||
public:
|
||||
T button_step = 1;
|
||||
|
||||
_increment_button.viewport({
|
||||
Widget::_viewport.x + _increment_button_area.x,
|
||||
Widget::_viewport.y + _increment_button_area.y,
|
||||
_increment_button_area.w,
|
||||
_increment_button_area.h
|
||||
});
|
||||
_decrement_button.viewport({
|
||||
Widget::_viewport.x + _decrement_button_area.x,
|
||||
Widget::_viewport.y + _decrement_button_area.y,
|
||||
_decrement_button_area.w,
|
||||
_decrement_button_area.h
|
||||
});
|
||||
}
|
||||
};
|
||||
Numeric_Input(abstract::Widget* parent=nullptr)
|
||||
: abstract::Input<T>(parent),
|
||||
_increment_button(), // FIXME: parenthood
|
||||
_decrement_button()
|
||||
{
|
||||
_increment_button.text("+");
|
||||
_increment_button.click_handler = [this](const SDL_MouseButtonEvent&) {
|
||||
T new_value = this->value() + button_step;
|
||||
if (_value_range.second - this->value() < button_step)
|
||||
new_value = _value_range.second;
|
||||
|
||||
this->value(new_value);
|
||||
this->input_text(this->value_to_string(new_value));
|
||||
};
|
||||
_decrement_button.text("-");
|
||||
_decrement_button.click_handler = [this](const SDL_MouseButtonEvent&) {
|
||||
T new_value = this->value() - button_step;
|
||||
if (this->value() - _value_range.first < button_step)
|
||||
new_value = _value_range.first;
|
||||
|
||||
this->value(new_value);
|
||||
this->input_text(this->value_to_string(new_value));
|
||||
};
|
||||
}
|
||||
|
||||
void handle_font_chage()
|
||||
{
|
||||
_decrement_button.font(abstract::FontHandler::_font);
|
||||
_increment_button.font(abstract::FontHandler::_font);
|
||||
}
|
||||
|
||||
bool is_valid_input(const std::string input) const
|
||||
{
|
||||
bool valid = false;
|
||||
|
||||
if (input.at(0) >= '0' && input.at(0) <= '9')
|
||||
valid = true;
|
||||
if constexpr(std::is_floating_point_v<T>)
|
||||
if (input.at(0) == '.'
|
||||
&& abstract::Input<T>::input_text().find('.') == std::string::npos)
|
||||
valid = true;
|
||||
if constexpr(std::is_signed_v<T>)
|
||||
{
|
||||
std::string displayed_value = abstract::Input<T>::input_text();
|
||||
if (input.at(0) == '-'
|
||||
&& !std::regex_search(
|
||||
displayed_value,
|
||||
std::regex("[^\\s]")
|
||||
))
|
||||
valid = true;
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
T process_value(T x) const
|
||||
{
|
||||
T value = x;
|
||||
if (x < _value_range.first)
|
||||
value = _value_range.first;
|
||||
else if (x > _value_range.second)
|
||||
value = _value_range.second;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void render(SDL_Renderer* r)
|
||||
{
|
||||
abstract::Input<T>::render(r);
|
||||
_increment_button.render(r);
|
||||
_decrement_button.render(r);
|
||||
}
|
||||
|
||||
std::pair<T, T> value_range() const
|
||||
{
|
||||
return _value_range;
|
||||
}
|
||||
|
||||
void value_range(T min, T max)
|
||||
{
|
||||
|
||||
if (min > max)
|
||||
throw std::invalid_argument("min cannot be greater than max");
|
||||
_value_range = {min, max};
|
||||
}
|
||||
|
||||
void viewport(SDL_Rect vp)
|
||||
{
|
||||
abstract::Input<T>::viewport(vp);
|
||||
|
||||
_increment_button.viewport({
|
||||
abstract::Widget::_viewport.x + _increment_button_area.x,
|
||||
abstract::Widget::_viewport.y + _increment_button_area.y,
|
||||
_increment_button_area.w,
|
||||
_increment_button_area.h
|
||||
});
|
||||
_decrement_button.viewport({
|
||||
abstract::Widget::_viewport.x + _decrement_button_area.x,
|
||||
abstract::Widget::_viewport.y + _decrement_button_area.y,
|
||||
_decrement_button_area.w,
|
||||
_decrement_button_area.h
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,8 +4,14 @@
|
|||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
struct NotFound : std::exception {};
|
||||
namespace bwidgets::exception
|
||||
{
|
||||
struct NotFound : std::exception {};
|
||||
}
|
||||
|
||||
std::string find_font(const std::string&);
|
||||
namespace bwidgets::utils::font
|
||||
{
|
||||
std::string find(const std::string&);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef MATH_HPP
|
||||
#define MATH_HPP
|
||||
|
||||
#include <exception>
|
||||
|
||||
#include <SDL2/SDL_rect.h>
|
||||
|
||||
namespace bwidgets::utils::math
|
||||
{
|
||||
struct RectOverflow : std::exception {};
|
||||
|
||||
static inline int center_rect(int container_size, int rect_size)
|
||||
{
|
||||
return (container_size - rect_size) / 2;
|
||||
}
|
||||
|
||||
static inline float distance_sqrd(const SDL_Point& a, const SDL_Point& b)
|
||||
{
|
||||
return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
|
||||
}
|
||||
|
||||
static inline float distance(const SDL_Point& a, const SDL_Point& b)
|
||||
{
|
||||
return std::sqrt(distance_sqrd(a, b));
|
||||
}
|
||||
|
||||
static inline bool rect_in_rect(const SDL_Rect outer, const SDL_Rect inner)
|
||||
{
|
||||
SDL_Point top_left {inner.x, inner.y};
|
||||
SDL_Point bottom_right {inner.x + inner.w, inner.y + inner.h};
|
||||
|
||||
return
|
||||
SDL_PointInRect(&top_left, &outer) &&
|
||||
SDL_PointInRect(&bottom_right, &outer);
|
||||
}
|
||||
|
||||
static inline SDL_Rect rect_offset(const SDL_Rect& r, const SDL_Rect& offset)
|
||||
{
|
||||
return {
|
||||
r.x + offset.x,
|
||||
r.y + offset.y,
|
||||
r.w, r.h
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -9,20 +9,26 @@
|
|||
|
||||
struct SDL_Texture;
|
||||
|
||||
SDL_Texture* filled_circle(const SDL_Color&,
|
||||
int resolution,
|
||||
SDL_Renderer*,
|
||||
int aa_pixels = 5);
|
||||
void set_pixels_color(SDL_Texture*, std::function<Uint32 (const SDL_Point&,
|
||||
const SDL_PixelFormat*)>);
|
||||
namespace bwidgets::utils::render
|
||||
{
|
||||
SDL_Color aa(const SDL_Color&&, const int, const float);
|
||||
|
||||
static inline int render_copy(SDL_Renderer* r, SDL_Texture* t, SDL_Rect dst)
|
||||
{
|
||||
return SDL_RenderCopy(r, t, NULL, &dst);
|
||||
}
|
||||
static inline int render_copy(SDL_Renderer* r, SDL_Texture* t, SDL_Rect src, SDL_Rect dst)
|
||||
{
|
||||
return SDL_RenderCopy(r, t, &src, &dst);
|
||||
SDL_Texture* filled_circle(const SDL_Color&,
|
||||
int resolution,
|
||||
SDL_Renderer*,
|
||||
int aa_pixels = 5);
|
||||
void set_pixels_color(SDL_Texture*, std::function<Uint32 (const SDL_Point&,
|
||||
const SDL_PixelFormat*)>);
|
||||
|
||||
static inline int render_copy(SDL_Renderer* r, SDL_Texture* t, SDL_Rect dst)
|
||||
{
|
||||
return SDL_RenderCopy(r, t, NULL, &dst);
|
||||
}
|
||||
|
||||
static inline int render_copy(SDL_Renderer* r, SDL_Texture* t, SDL_Rect src, SDL_Rect dst)
|
||||
{
|
||||
return SDL_RenderCopy(r, t, &src, &dst);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
|
||||
#include <basic_widgets/abstract/layout.hpp>
|
||||
|
||||
class Vertical_Layout : public Layout
|
||||
namespace bwidgets::widget
|
||||
{
|
||||
protected:
|
||||
void _update_layout();
|
||||
|
||||
public:
|
||||
Vertical_Layout(SDL_Renderer*);
|
||||
};
|
||||
class Vertical_Layout : public abstract::Layout
|
||||
{
|
||||
protected:
|
||||
void _update_layout();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,11 +14,14 @@ pub_api = include_directories('inc')
|
|||
libbasic_widgets = static_library('basic_widgets',
|
||||
'src/button.cpp',
|
||||
'src/caption.cpp',
|
||||
'src/focus_handler.cpp',
|
||||
'src/font_handler.cpp',
|
||||
'src/horizontal_layout.cpp',
|
||||
'src/keyboard_handler.cpp',
|
||||
'src/layout.cpp',
|
||||
'src/mouse_handler.cpp',
|
||||
'src/vertical_layout.cpp',
|
||||
'src/widget.cpp',
|
||||
'src/with_font.cpp',
|
||||
'src/utils/render.cpp',
|
||||
'src/utils/font.cpp',
|
||||
dependencies : [sdl, fontconfig],
|
||||
|
|
111
src/button.cpp
111
src/button.cpp
|
@ -1,51 +1,38 @@
|
|||
#include <SDL2/SDL_render.h>
|
||||
|
||||
#include <basic_widgets/button.hpp>
|
||||
#include <basic_widgets/utils/math.hpp>
|
||||
|
||||
Button::Button(SDL_Renderer* r)
|
||||
: Widget(r), _caption(r)
|
||||
{
|
||||
}
|
||||
using namespace bwidgets;
|
||||
using namespace bwidgets::utils;
|
||||
|
||||
int Button::border_width() const
|
||||
{
|
||||
return _border_width;
|
||||
}
|
||||
|
||||
void Button::border_width(int w)
|
||||
{
|
||||
_border_width = w;
|
||||
_update_widget_area();
|
||||
}
|
||||
|
||||
int Button::height() const
|
||||
int widget::Button::height() const
|
||||
{
|
||||
return _caption.height() * _caption_height_multiplicator
|
||||
+ 2 * _border_width;
|
||||
+ 2 * border_width;
|
||||
}
|
||||
|
||||
void Button::render()
|
||||
void widget::Button::render(SDL_Renderer* r)
|
||||
{
|
||||
Widget::render();
|
||||
Widget::render(r);
|
||||
|
||||
SDL_Rect old_vp;
|
||||
|
||||
SDL_RenderGetViewport(_renderer, &old_vp);
|
||||
SDL_RenderSetViewport(_renderer, &_viewport);
|
||||
SDL_RenderSetViewport(r, &_viewport);
|
||||
|
||||
auto color_shade = [](int base, int step, int total_steps) -> int {
|
||||
int steps_to_max = 255 - base;
|
||||
return base + step * steps_to_max / total_steps;
|
||||
};
|
||||
|
||||
SDL_Color bg_color = _hovered ? _color_background_hover : _color_background;
|
||||
if (_pushed)
|
||||
SDL_Color bg_color = _is_hovered ? color_bg_hover : color_bg;
|
||||
if (_is_pushed)
|
||||
{
|
||||
for (int i = 0; i < _border_width; i++)
|
||||
for (int i = 0; i < border_width; i++)
|
||||
{
|
||||
SDL_SetRenderDrawColor(
|
||||
_renderer,
|
||||
color_shade(bg_color.r, i, _border_width),
|
||||
color_shade(bg_color.g, i, _border_width),
|
||||
color_shade(bg_color.b, i, _border_width),
|
||||
r,
|
||||
color_shade(bg_color.r, i, border_width),
|
||||
color_shade(bg_color.g, i, border_width),
|
||||
color_shade(bg_color.b, i, border_width),
|
||||
bg_color.a
|
||||
);
|
||||
SDL_Rect rect = {
|
||||
|
@ -54,74 +41,72 @@ void Button::render()
|
|||
_widget_area.w - i * 2,
|
||||
_widget_area.h - i * 2
|
||||
};
|
||||
SDL_RenderFillRect(_renderer, &rect);
|
||||
SDL_RenderFillRect(r, &rect);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = _border_width; i >= 0; i--)
|
||||
for (int i = border_width; i >= 0; i--)
|
||||
{
|
||||
SDL_SetRenderDrawColor(
|
||||
_renderer,
|
||||
color_shade(bg_color.r, i, _border_width),
|
||||
color_shade(bg_color.g, i, _border_width),
|
||||
color_shade(bg_color.b, i, _border_width),
|
||||
r,
|
||||
color_shade(bg_color.r, i, border_width),
|
||||
color_shade(bg_color.g, i, border_width),
|
||||
color_shade(bg_color.b, i, border_width),
|
||||
bg_color.a
|
||||
);
|
||||
int margin = _border_width - i;
|
||||
int margin = border_width - i;
|
||||
SDL_Rect rect = {
|
||||
_widget_area.x + margin,
|
||||
_widget_area.y + margin,
|
||||
_widget_area.w - margin * 2,
|
||||
_widget_area.h - margin * 2
|
||||
};
|
||||
SDL_RenderFillRect(_renderer, &rect);
|
||||
SDL_RenderFillRect(r, &rect);
|
||||
}
|
||||
}
|
||||
|
||||
_caption.render();
|
||||
|
||||
SDL_RenderSetViewport(_renderer, &old_vp);
|
||||
_caption.render(r);
|
||||
}
|
||||
|
||||
const std::string& Button::text() const
|
||||
const std::string& widget::Button::text() const
|
||||
{
|
||||
return _caption.text();
|
||||
}
|
||||
|
||||
void Button::text(std::string txt)
|
||||
void widget::Button::text(std::string txt)
|
||||
{
|
||||
_caption.text(txt);
|
||||
_update_widget_area();
|
||||
_update_caption_area();
|
||||
}
|
||||
|
||||
void Button::font(TTF_Font* f)
|
||||
{
|
||||
_caption.font(f);
|
||||
_update_widget_area();
|
||||
_update_caption_area();
|
||||
}
|
||||
|
||||
void Button::viewport(SDL_Rect vp)
|
||||
void widget::Button::viewport(SDL_Rect vp)
|
||||
{
|
||||
Widget::viewport(vp);
|
||||
_update_caption_area();
|
||||
}
|
||||
|
||||
int Button::width() const
|
||||
int widget::Button::width() const
|
||||
{
|
||||
return _caption.width() * _caption_height_multiplicator
|
||||
+ 2 * _border_width;
|
||||
+ 2 * border_width;
|
||||
}
|
||||
|
||||
void Button::_update_caption_area()
|
||||
void widget::Button::_handle_font_change()
|
||||
{
|
||||
SDL_Rect txt_size = _caption.rendered_text_size();
|
||||
_caption.font(_font);
|
||||
_update_widget_area();
|
||||
_update_caption_area();
|
||||
}
|
||||
|
||||
void widget::Button::_update_caption_area()
|
||||
{
|
||||
auto txt_size = _caption.text_size();
|
||||
|
||||
_caption_area = {
|
||||
center(_viewport.w, txt_size.w),
|
||||
center(_viewport.h, txt_size.h),
|
||||
math::center_rect(_viewport.w, txt_size.w),
|
||||
math::center_rect(_viewport.h, txt_size.h),
|
||||
txt_size.w,
|
||||
txt_size.h
|
||||
};
|
||||
|
@ -133,17 +118,17 @@ void Button::_update_caption_area()
|
|||
});
|
||||
}
|
||||
|
||||
void Button::_update_widget_area()
|
||||
void widget::Button::_update_widget_area()
|
||||
{
|
||||
int h = _caption.rendered_text_size().h * _caption_height_multiplicator
|
||||
+ 2 * _border_width;
|
||||
int h = _caption.text_size().h * _caption_height_multiplicator
|
||||
+ 2 * border_width;
|
||||
|
||||
_widget_area = {
|
||||
0,
|
||||
center(
|
||||
math::center_rect(
|
||||
_viewport.h,
|
||||
_caption.rendered_text_size().h * _caption_height_multiplicator
|
||||
) - _border_width,
|
||||
_caption.text_size().h * _caption_height_multiplicator
|
||||
) - border_width,
|
||||
_viewport.w,
|
||||
h
|
||||
};
|
||||
|
|
132
src/caption.cpp
132
src/caption.cpp
|
@ -1,128 +1,122 @@
|
|||
#include <SDL2/SDL_render.h>
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
|
||||
#include <basic_widgets/caption.hpp>
|
||||
#include <basic_widgets/utils/math.hpp>
|
||||
|
||||
Caption::Caption(SDL_Renderer* r)
|
||||
: Widget(r)
|
||||
using namespace bwidgets;
|
||||
using namespace bwidgets::utils;
|
||||
|
||||
widget::Caption::~Caption()
|
||||
{
|
||||
SDL_FreeSurface(_rendered_text);
|
||||
SDL_DestroyTexture(_text_texture);
|
||||
}
|
||||
|
||||
Caption::~Caption()
|
||||
void widget::Caption::color_fg(const SDL_Color& c)
|
||||
{
|
||||
SDL_DestroyTexture(_rendered_text);
|
||||
}
|
||||
|
||||
void Caption::color(SDL_Color c)
|
||||
{
|
||||
_color = c;
|
||||
_color_fg = c;
|
||||
_render_text();
|
||||
}
|
||||
|
||||
void Caption::font(TTF_Font* f)
|
||||
void widget::Caption::_handle_font_change()
|
||||
{
|
||||
_font = f;
|
||||
_render_text();
|
||||
}
|
||||
|
||||
int Caption::height() const
|
||||
void widget::Caption::render(SDL_Renderer* r)
|
||||
{
|
||||
return _widget_area.h;
|
||||
Widget::render(r);
|
||||
|
||||
_renderer = r;
|
||||
|
||||
if (_font == nullptr)
|
||||
return;
|
||||
|
||||
SDL_RenderSetViewport(r, &_viewport);
|
||||
if (_text_texture == nullptr || _renderer != r)
|
||||
{
|
||||
_renderer = r;
|
||||
_text_texture = SDL_CreateTextureFromSurface(r, _rendered_text);
|
||||
}
|
||||
SDL_RenderCopy(
|
||||
r,
|
||||
_text_texture,
|
||||
NULL,
|
||||
&_widget_area
|
||||
);
|
||||
}
|
||||
|
||||
void Caption::render()
|
||||
void widget::Caption::_render_text()
|
||||
{
|
||||
if (_font == nullptr)
|
||||
return;
|
||||
|
||||
Widget::render();
|
||||
|
||||
SDL_Rect old_vp;
|
||||
|
||||
SDL_RenderGetViewport(_renderer, &old_vp);
|
||||
SDL_RenderSetViewport(_renderer, &_viewport);
|
||||
SDL_SetRenderDrawColor(_renderer, 255, 255, 0, 50);
|
||||
SDL_RenderFillRect(_renderer, &_widget_area);
|
||||
SDL_RenderCopy(
|
||||
_renderer,
|
||||
_rendered_text,
|
||||
NULL,
|
||||
&_widget_area
|
||||
SDL_FreeSurface(_rendered_text);
|
||||
_rendered_text = TTF_RenderUTF8_Blended(
|
||||
_font,
|
||||
_text.c_str(),
|
||||
_color_fg
|
||||
);
|
||||
|
||||
SDL_RenderSetViewport(_renderer, &old_vp);
|
||||
_update_widget_area();
|
||||
}
|
||||
|
||||
const std::string& Caption::text() const
|
||||
|
||||
const std::string& widget::Caption::text() const
|
||||
{
|
||||
return _text;
|
||||
}
|
||||
|
||||
void Caption::text(std::string t)
|
||||
void widget::Caption::text(const std::string& t)
|
||||
{
|
||||
_text = t;
|
||||
_render_text();
|
||||
}
|
||||
|
||||
SDL_Rect Caption::rendered_text_size() const
|
||||
abstract::Widget::Size widget::Caption::text_size() const
|
||||
{
|
||||
if (_font == nullptr)
|
||||
return {0, 0, 0, 0};
|
||||
return {0, 0};
|
||||
|
||||
int w, h;
|
||||
TTF_SizeUTF8(_font, _text.c_str(), &w, &h);
|
||||
abstract::Widget::Size size;
|
||||
TTF_SizeUTF8(_font, _text.c_str(), &size.w, &size.h);
|
||||
|
||||
return {0, 0, w, h};
|
||||
return size;
|
||||
}
|
||||
|
||||
void Caption::viewport(SDL_Rect vp)
|
||||
{
|
||||
Widget::viewport(vp);
|
||||
_update_widget_area();
|
||||
}
|
||||
|
||||
int Caption::width() const
|
||||
{
|
||||
return _widget_area.w;
|
||||
}
|
||||
|
||||
void Caption::_render_text()
|
||||
{
|
||||
if (_font == nullptr)
|
||||
return;
|
||||
|
||||
SDL_Surface* surface = TTF_RenderUTF8_Blended(
|
||||
_font,
|
||||
_text.c_str(),
|
||||
_color
|
||||
);
|
||||
SDL_DestroyTexture(_rendered_text);
|
||||
_rendered_text = SDL_CreateTextureFromSurface(_renderer, surface);
|
||||
SDL_FreeSurface(surface);
|
||||
|
||||
_update_widget_area();
|
||||
}
|
||||
|
||||
void Caption::_update_widget_area()
|
||||
void widget::Caption::_update_widget_area()
|
||||
{
|
||||
Widget::_update_widget_area();
|
||||
|
||||
if (_font == nullptr)
|
||||
return;
|
||||
|
||||
auto txt_size = rendered_text_size();
|
||||
auto txt_size = text_size();
|
||||
|
||||
SDL_Rect resized_txt = {};
|
||||
if (_widget_area.w > _widget_area.h)
|
||||
{
|
||||
resized_txt.h = _widget_area.h;
|
||||
resized_txt.w = resized_txt.h / (float)txt_size.h * txt_size.w;
|
||||
_widget_area.x = Widget::center(_widget_area.w, resized_txt.w);
|
||||
resized_txt.w = resized_txt.h / (txt_size.h * txt_size.w);
|
||||
switch (_alignment)
|
||||
{
|
||||
case Alignment::CENTER:
|
||||
_widget_area.x = math::center_rect(_widget_area.w, resized_txt.w);
|
||||
break;
|
||||
case Alignment::LEFT:
|
||||
break;
|
||||
case Alignment::RIGHT:
|
||||
_widget_area.x = _widget_area.w - resized_txt.w;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
resized_txt.w = _widget_area.w;
|
||||
if (txt_size.w > 0)
|
||||
resized_txt.h = resized_txt.w / (float)txt_size.w * txt_size.h;
|
||||
resized_txt.h = resized_txt.w / (txt_size.w * txt_size.h);
|
||||
else
|
||||
resized_txt.h = txt_size.w;
|
||||
_widget_area.y = Widget::center(_widget_area.h, resized_txt.h);
|
||||
_widget_area.y = math::center_rect(_widget_area.h, resized_txt.h);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
#include <basic_widgets/abstract/focus_handler.hpp>
|
||||
|
||||
using namespace bwidgets;
|
||||
|
||||
abstract::FocusHandler::~FocusHandler()
|
||||
{
|
||||
}
|
||||
|
||||
void abstract::FocusHandler::_handle_focus_change()
|
||||
{
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#include <basic_widgets/abstract/font_handler.hpp>
|
||||
|
||||
using namespace bwidgets;
|
||||
|
||||
abstract::FontHandler::~FontHandler()
|
||||
{
|
||||
}
|
||||
|
||||
void abstract::FontHandler::font(TTF_Font* f)
|
||||
{
|
||||
_font = f;
|
||||
_handle_font_change();
|
||||
}
|
|
@ -1,22 +1,19 @@
|
|||
#include <basic_widgets/horizontal_layout.hpp>
|
||||
|
||||
Horizontal_Layout::Horizontal_Layout(SDL_Renderer* r)
|
||||
: Layout::Layout(r)
|
||||
{
|
||||
}
|
||||
using namespace bwidgets;
|
||||
|
||||
void Horizontal_Layout::_update_layout()
|
||||
void widget::Horizontal_Layout::_update_layout()
|
||||
{
|
||||
float widget_size = (float)_viewport.w / _widgets.size();
|
||||
int widget_size = _viewport.w / _widgets.size();
|
||||
|
||||
for (std::vector<Widget*>::size_type i = 0; i < _widgets.size(); i++)
|
||||
{
|
||||
SDL_Rect widget_vp = {
|
||||
_viewport.x + (int)(_interspace / 2 + i * (widget_size + _interspace / 2)),
|
||||
_widgets.at(i)->viewport({
|
||||
_viewport.x + (int)(_interspace / 2.0 +
|
||||
i * (widget_size + _interspace / 2.0)),
|
||||
_viewport.y,
|
||||
(int)(widget_size - _interspace),
|
||||
widget_size - _interspace,
|
||||
_viewport.h
|
||||
};
|
||||
_widgets.at(i)->viewport(widget_vp);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#include <SDL2/SDL_events.h>
|
||||
|
||||
#include <basic_widgets/abstract/keyboard_handler.hpp>
|
||||
|
||||
using namespace bwidgets;
|
||||
|
||||
void abstract::KeyboardHandler::_handle_key(const SDL_KeyboardEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void abstract::KeyboardHandler::_handle_text_input(const SDL_TextInputEvent&)
|
||||
{
|
||||
}
|
|
@ -1,44 +1,38 @@
|
|||
#include <SDL2/SDL_render.h>
|
||||
|
||||
#include <basic_widgets/abstract/layout.hpp>
|
||||
|
||||
Layout::Layout(SDL_Renderer* r)
|
||||
: Widget(r)
|
||||
{
|
||||
}
|
||||
using namespace bwidgets;
|
||||
|
||||
Layout::~Layout()
|
||||
abstract::Layout::~Layout()
|
||||
{
|
||||
for (Widget* widget_ptr : _widgets)
|
||||
delete widget_ptr;
|
||||
}
|
||||
|
||||
void Layout::add_widget(Widget *widget_ptr)
|
||||
void abstract::Layout::add_widget(Widget *widget_ptr)
|
||||
{
|
||||
_widgets.push_back(widget_ptr);
|
||||
}
|
||||
|
||||
void Layout::handle_event(const SDL_Event& ev)
|
||||
void abstract::Layout::handle_event(const SDL_Event& ev)
|
||||
{
|
||||
for (Widget* widget_ptr : _widgets)
|
||||
widget_ptr->handle_event(ev);
|
||||
}
|
||||
|
||||
void Layout::render()
|
||||
void abstract::Layout::render(SDL_Renderer* r)
|
||||
{
|
||||
SDL_Rect old_vp;
|
||||
SDL_RenderSetViewport(r, &_viewport);
|
||||
|
||||
SDL_RenderGetViewport(_renderer, &old_vp);
|
||||
SDL_RenderSetViewport(_renderer, &_viewport);
|
||||
|
||||
SDL_SetRenderDrawColor(_renderer, 255, 0, 0, SDL_ALPHA_OPAQUE);
|
||||
SDL_RenderDrawRect(_renderer, NULL);
|
||||
SDL_SetRenderDrawColor(r, 255, 0, 0, SDL_ALPHA_OPAQUE);
|
||||
SDL_RenderDrawRect(r, NULL);
|
||||
|
||||
for (Widget* widget_ptr : _widgets)
|
||||
widget_ptr->render();
|
||||
|
||||
SDL_RenderSetViewport(_renderer, &old_vp);
|
||||
widget_ptr->render(r);
|
||||
}
|
||||
|
||||
void Layout::viewport(SDL_Rect vp)
|
||||
void abstract::Layout::viewport(SDL_Rect vp)
|
||||
{
|
||||
Widget::viewport(vp);
|
||||
_update_layout();
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
#include <SDL2/SDL_rect.h>
|
||||
#include <SDL2/SDL_events.h>
|
||||
|
||||
#include <basic_widgets/abstract/mouse_handler.hpp>
|
||||
#include <basic_widgets/utils/math.hpp>
|
||||
|
||||
using namespace bwidgets;
|
||||
using namespace bwidgets::utils;
|
||||
|
||||
void abstract::MouseHandler::handle_mouse(const SDL_MouseButtonEvent& ev,
|
||||
const SDL_Rect& orig)
|
||||
{
|
||||
if (_button_area == nullptr)
|
||||
return;
|
||||
|
||||
SDL_Point p {ev.x, ev.y};
|
||||
SDL_Rect vp = math::rect_offset(*_button_area, orig);
|
||||
if (ev.type == SDL_MOUSEBUTTONDOWN)
|
||||
{
|
||||
if (SDL_PointInRect(&p, &vp))
|
||||
{
|
||||
_is_pushed = true;
|
||||
_handle_mouse_button(ev, vp);
|
||||
}
|
||||
else
|
||||
focus(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_is_pushed)
|
||||
{
|
||||
if (SDL_PointInRect(&p, &vp))
|
||||
{
|
||||
focus(true);
|
||||
}
|
||||
_is_pushed = false;
|
||||
_handle_mouse_button(ev, vp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void abstract::MouseHandler::handle_mouse(const SDL_MouseMotionEvent& ev,
|
||||
const SDL_Rect& orig)
|
||||
{
|
||||
if (_focus_area == nullptr)
|
||||
return;
|
||||
|
||||
SDL_Point p {ev.x, ev.y};
|
||||
SDL_Rect vp {math::rect_offset(*_button_area, orig)};
|
||||
if (SDL_PointInRect(&p, &vp))
|
||||
_is_hovered = true;
|
||||
else
|
||||
_is_hovered = false;
|
||||
|
||||
if (_has_focus)
|
||||
_handle_mouse_motion(ev, orig);
|
||||
}
|
||||
|
||||
void abstract::MouseHandler::_handle_focus_change()
|
||||
{
|
||||
}
|
||||
|
||||
void abstract::MouseHandler::_handle_mouse_button(const SDL_MouseButtonEvent&,
|
||||
const SDL_Rect&)
|
||||
{
|
||||
}
|
||||
|
||||
void abstract::MouseHandler::_handle_mouse_motion(const SDL_MouseMotionEvent&,
|
||||
const SDL_Rect&)
|
||||
{
|
||||
}
|
|
@ -3,35 +3,36 @@
|
|||
|
||||
#include <basic_widgets/utils/font.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
string find_font(const string& pat)
|
||||
namespace bwidgets::utils::font
|
||||
{
|
||||
FcConfig* conf = FcInitLoadConfigAndFonts();
|
||||
|
||||
FcPattern* pattern = FcNameParse((FcChar8*)pat.c_str());
|
||||
FcConfigSubstitute(conf, pattern, FcMatchPattern);
|
||||
FcDefaultSubstitute(pattern);
|
||||
|
||||
bool found = false;
|
||||
string file_path;
|
||||
FcResult res;
|
||||
FcPattern* font = FcFontMatch(conf, pattern, &res);
|
||||
if (font != nullptr)
|
||||
std::string find(const std::string& pat)
|
||||
{
|
||||
FcChar8* file = nullptr;
|
||||
if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch)
|
||||
FcConfig* conf = FcInitLoadConfigAndFonts();
|
||||
|
||||
FcPattern* pattern = FcNameParse((FcChar8*)pat.c_str());
|
||||
FcConfigSubstitute(conf, pattern, FcMatchPattern);
|
||||
FcDefaultSubstitute(pattern);
|
||||
|
||||
bool found = false;
|
||||
std::string file_path;
|
||||
FcResult res;
|
||||
FcPattern* font = FcFontMatch(conf, pattern, &res);
|
||||
if (font != nullptr)
|
||||
{
|
||||
file_path = (char*)file;
|
||||
found = true;
|
||||
FcChar8* file = nullptr;
|
||||
if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch)
|
||||
{
|
||||
file_path = (char*)file;
|
||||
found = true;
|
||||
}
|
||||
FcPatternDestroy(font);
|
||||
}
|
||||
FcPatternDestroy(font);
|
||||
FcConfigDestroy(conf);
|
||||
FcFini();
|
||||
|
||||
if (!found)
|
||||
throw exception::NotFound();
|
||||
|
||||
return file_path;
|
||||
}
|
||||
FcConfigDestroy(conf);
|
||||
FcFini();
|
||||
|
||||
if (!found)
|
||||
throw NotFound();
|
||||
|
||||
return file_path;
|
||||
}
|
||||
|
|
|
@ -1,80 +1,84 @@
|
|||
#include <vector>
|
||||
|
||||
#include "render_priv.hpp"
|
||||
#include <basic_widgets/utils/math.hpp>
|
||||
#include <basic_widgets/utils/render.hpp>
|
||||
|
||||
SDL_Color aa(
|
||||
const SDL_Color& base_color,
|
||||
const int aa_pixels,
|
||||
const float d
|
||||
)
|
||||
namespace bwidgets::utils::render
|
||||
{
|
||||
const auto d_clamp {std::abs(std::clamp<float>(d, -aa_pixels, 0))};
|
||||
const auto d_norm {d_clamp / aa_pixels};
|
||||
const auto factor {3 * d_norm * d_norm - 2 * d_norm * d_norm * d_norm};
|
||||
|
||||
return {
|
||||
base_color.r, base_color.g, base_color.b,
|
||||
static_cast<Uint8>(base_color.a * factor)
|
||||
};
|
||||
}
|
||||
|
||||
SDL_Texture* filled_circle(
|
||||
const SDL_Color& c,
|
||||
const int resolution,
|
||||
SDL_Renderer* r,
|
||||
const int aa_pixels
|
||||
)
|
||||
{
|
||||
auto texture {SDL_CreateTexture(
|
||||
r,
|
||||
SDL_PIXELFORMAT_RGBA32,
|
||||
SDL_TEXTUREACCESS_STATIC,
|
||||
resolution, resolution)};
|
||||
const auto radius {resolution / 2};
|
||||
const SDL_Point center {radius, radius};
|
||||
|
||||
set_pixels_color(
|
||||
texture,
|
||||
[aa_pixels, c, center, radius]
|
||||
(const SDL_Point& p, const SDL_PixelFormat* format) -> Uint32 {
|
||||
const auto d_delta = distance(center, p) - radius;
|
||||
const auto aa_color = aa(c, aa_pixels, d_delta);
|
||||
|
||||
return SDL_MapRGBA(format,
|
||||
aa_color.r, aa_color.g, aa_color.b,
|
||||
aa_color.a);
|
||||
}
|
||||
);
|
||||
|
||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetTextureScaleMode(texture, SDL_ScaleModeNearest);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
void set_pixels_color(
|
||||
SDL_Texture* t,
|
||||
std::function<Uint32 (const SDL_Point&, const SDL_PixelFormat*)> pixel_color
|
||||
)
|
||||
{
|
||||
int w, h;
|
||||
Uint32 format_enum;
|
||||
SDL_QueryTexture(t, &format_enum, NULL, &w, &h);
|
||||
|
||||
auto format = SDL_AllocFormat(format_enum);
|
||||
auto pitch = w * format->BytesPerPixel;
|
||||
|
||||
std::vector<Uint32> pixels;
|
||||
pixels.reserve(h * pitch);
|
||||
for (auto y = 0; y < h; y++)
|
||||
SDL_Color aa(
|
||||
const SDL_Color& base_color,
|
||||
const int aa_pixels,
|
||||
const float d
|
||||
)
|
||||
{
|
||||
for (auto x = 0; x < w; x++)
|
||||
{
|
||||
pixels.push_back(pixel_color({x, y}, format));
|
||||
}
|
||||
const auto d_clamp {std::abs(std::clamp<float>(d, -aa_pixels, 0))};
|
||||
const auto d_norm {d_clamp / aa_pixels};
|
||||
const auto factor {3 * d_norm * d_norm - 2 * d_norm * d_norm * d_norm};
|
||||
|
||||
return {
|
||||
base_color.r, base_color.g, base_color.b,
|
||||
static_cast<Uint8>(base_color.a * factor)
|
||||
};
|
||||
}
|
||||
|
||||
SDL_UpdateTexture(t, NULL, (const void*)pixels.data(), pitch);
|
||||
SDL_Texture* filled_circle(
|
||||
const SDL_Color& c,
|
||||
const int resolution,
|
||||
SDL_Renderer* r,
|
||||
const int aa_pixels
|
||||
)
|
||||
{
|
||||
auto texture {SDL_CreateTexture(
|
||||
r,
|
||||
SDL_PIXELFORMAT_RGBA32,
|
||||
SDL_TEXTUREACCESS_STATIC,
|
||||
resolution, resolution)};
|
||||
const auto radius {resolution / 2};
|
||||
const SDL_Point center {radius, radius};
|
||||
|
||||
SDL_FreeFormat(format);
|
||||
bwidgets::utils::render::set_pixels_color(
|
||||
texture,
|
||||
[aa_pixels, c, center, radius]
|
||||
(const SDL_Point& p, const SDL_PixelFormat* format) -> Uint32 {
|
||||
const auto d_delta = math::distance(center, p) - radius;
|
||||
const auto aa_color = aa(c, aa_pixels, d_delta);
|
||||
|
||||
return SDL_MapRGBA(format,
|
||||
aa_color.r, aa_color.g, aa_color.b,
|
||||
aa_color.a);
|
||||
}
|
||||
);
|
||||
|
||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetTextureScaleMode(texture, SDL_ScaleModeNearest);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
void set_pixels_color(
|
||||
SDL_Texture* t,
|
||||
std::function<Uint32 (const SDL_Point&, const SDL_PixelFormat*)> pixel_color
|
||||
)
|
||||
{
|
||||
int w, h;
|
||||
Uint32 format_enum;
|
||||
SDL_QueryTexture(t, &format_enum, NULL, &w, &h);
|
||||
|
||||
auto format = SDL_AllocFormat(format_enum);
|
||||
auto pitch = w * format->BytesPerPixel;
|
||||
|
||||
std::vector<Uint32> pixels;
|
||||
pixels.reserve(h * pitch);
|
||||
for (auto y = 0; y < h; y++)
|
||||
{
|
||||
for (auto x = 0; x < w; x++)
|
||||
{
|
||||
pixels.push_back(pixel_color({x, y}, format));
|
||||
}
|
||||
}
|
||||
|
||||
SDL_UpdateTexture(t, NULL, (const void*)pixels.data(), pitch);
|
||||
|
||||
SDL_FreeFormat(format);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
#ifndef DRAWING_PRIMITIVE_PRIVATE
|
||||
#define DRAWING_PRIMITIVE_PRIVATE
|
||||
|
||||
#include <basic_widgets/utils/render.hpp>
|
||||
|
||||
SDL_Color aa(const SDL_Color&&, const int, const float);
|
||||
|
||||
static inline float distance_sqrd(const SDL_Point& a, const SDL_Point& b)
|
||||
{
|
||||
return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
|
||||
}
|
||||
static inline float distance(const SDL_Point& a, const SDL_Point& b)
|
||||
{
|
||||
return std::sqrt(distance_sqrd(a, b));
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,21 +1,18 @@
|
|||
#include <basic_widgets/vertical_layout.hpp>
|
||||
|
||||
Vertical_Layout::Vertical_Layout(SDL_Renderer* r)
|
||||
: Layout(r)
|
||||
{
|
||||
}
|
||||
using namespace bwidgets;
|
||||
|
||||
void Vertical_Layout::_update_layout()
|
||||
void widget::Vertical_Layout::_update_layout()
|
||||
{
|
||||
float widget_size = (float)_viewport.h / _widgets.size();
|
||||
int widget_size = _viewport.h / _widgets.size();
|
||||
|
||||
for (std::vector<Widget*>::size_type i = 0; i < _widgets.size(); i++)
|
||||
for (int i = 0; i < _widgets.size(); i++)
|
||||
{
|
||||
SDL_Rect widget_vp = {
|
||||
_viewport.x,
|
||||
_viewport.y + (int)(_interspace / 2 + i * (widget_size + _interspace / 2)),
|
||||
_viewport.y + _interspace / 2 + i * (widget_size + _interspace / 2),
|
||||
_viewport.w,
|
||||
(int)(widget_size - _interspace),
|
||||
widget_size - _interspace,
|
||||
};
|
||||
_widgets.at(i)->viewport(widget_vp);
|
||||
}
|
||||
|
|
135
src/widget.cpp
135
src/widget.cpp
|
@ -1,117 +1,82 @@
|
|||
#include <SDL2/SDL_events.h>
|
||||
#include <SDL2/SDL_render.h>
|
||||
|
||||
#include <basic_widgets/abstract/keyboard_handler.hpp>
|
||||
#include <basic_widgets/abstract/mouse_handler.hpp>
|
||||
#include <basic_widgets/abstract/widget.hpp>
|
||||
|
||||
Widget::Widget(SDL_Renderer* r)
|
||||
: _renderer(r)
|
||||
using namespace bwidgets;
|
||||
|
||||
abstract::Widget::Widget(Widget* p)
|
||||
: parent(p)
|
||||
{
|
||||
}
|
||||
|
||||
Widget::~Widget()
|
||||
abstract::Widget::~Widget()
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::handle_event(const SDL_Event &ev)
|
||||
void abstract::Widget::handle_event(const SDL_Event &ev)
|
||||
{
|
||||
switch (ev.type)
|
||||
if (auto handler = dynamic_cast<KeyboardHandler*>(this);
|
||||
handler != nullptr)
|
||||
{
|
||||
case SDL_MOUSEMOTION:
|
||||
_update_hover_state(ev.motion);
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
_on_push(ev.button);
|
||||
break;
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
_on_release(ev.button);
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
if (_focused)
|
||||
_on_key(ev.key);
|
||||
break;
|
||||
case SDL_TEXTINPUT:
|
||||
if (_focused)
|
||||
_on_text_input(ev.text);
|
||||
break;
|
||||
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 != nullptr)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Widget::height() const
|
||||
int abstract::Widget::height() const
|
||||
{
|
||||
return _widget_area.h;
|
||||
}
|
||||
|
||||
void Widget::render()
|
||||
void abstract::Widget::render(SDL_Renderer* r)
|
||||
{
|
||||
SDL_Rect old_vp;
|
||||
|
||||
SDL_RenderGetViewport(_renderer, &old_vp);
|
||||
SDL_RenderSetViewport(_renderer, &_viewport);
|
||||
|
||||
SDL_SetRenderDrawColor(_renderer, 0, 255, 0, SDL_ALPHA_OPAQUE);
|
||||
SDL_RenderDrawRect(_renderer, NULL);
|
||||
|
||||
SDL_RenderSetViewport(_renderer, &old_vp);
|
||||
SDL_RenderSetViewport(r, NULL);
|
||||
SDL_Rect dbg_outline = {
|
||||
_viewport.x - 1, _viewport.y - 1,
|
||||
_viewport.w + 2, _viewport.h + 2
|
||||
};
|
||||
SDL_SetRenderDrawColor(r, 0, 255, 0, SDL_ALPHA_OPAQUE / 2);
|
||||
SDL_RenderDrawRect(r, &dbg_outline);
|
||||
}
|
||||
|
||||
void Widget::viewport(SDL_Rect vp)
|
||||
void abstract::Widget::viewport(SDL_Rect vp)
|
||||
{
|
||||
_viewport = vp;
|
||||
_update_widget_area();
|
||||
}
|
||||
|
||||
int Widget::width() const
|
||||
int abstract::Widget::width() const
|
||||
{
|
||||
return _widget_area.w;
|
||||
}
|
||||
|
||||
void Widget::_on_focus()
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::_on_focus_loss()
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::_on_key(const SDL_KeyboardEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::_on_push(const SDL_MouseButtonEvent& button)
|
||||
{
|
||||
SDL_Point position = {button.x - _viewport.x, button.y - _viewport.y};
|
||||
if (SDL_PointInRect(&position, &_widget_area) == SDL_TRUE)
|
||||
{
|
||||
_pushed = true;
|
||||
}
|
||||
else if (_focused)
|
||||
{
|
||||
_focused = false;
|
||||
_on_focus_loss();
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::_on_release(const SDL_MouseButtonEvent& button)
|
||||
{
|
||||
if (_pushed)
|
||||
{
|
||||
_focused = true;
|
||||
_on_focus();
|
||||
if (click_handler != NULL)
|
||||
click_handler(button);
|
||||
}
|
||||
_pushed = false;
|
||||
}
|
||||
|
||||
void Widget::_on_text_input(const SDL_TextInputEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void Widget::_update_hover_state(const SDL_MouseMotionEvent& mouse)
|
||||
{
|
||||
SDL_Point position = {mouse.x - _viewport.x, mouse.y - _viewport.y};
|
||||
_hovered = SDL_PointInRect(&position, &_widget_area) == SDL_TRUE;
|
||||
}
|
||||
|
||||
void Widget::_update_widget_area()
|
||||
void abstract::Widget::_update_widget_area()
|
||||
{
|
||||
_widget_area = {
|
||||
0,
|
||||
|
|
Loading…
Reference in New Issue