bwidgets/input.hpp

171 lines
4.4 KiB
C++
Raw Normal View History

2021-06-11 13:30:33 +02:00
#ifndef INPUT_HPP
#define INPUT_HPP
2021-06-16 13:50:34 +02:00
#include <sstream>
#include <string>
#include <type_traits>
2021-06-16 18:09:14 +02:00
#include "caption.hpp"
2021-06-11 13:30:33 +02:00
#include "widget.hpp"
2021-06-16 13:50:34 +02:00
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; };
2021-06-11 13:30:33 +02:00
template<typename T> class Input : public Widget
{
protected:
SDL_Rect _input_field_area {};
SDL_Rect _input_area {};
T _value {};
2021-06-16 18:09:14 +02:00
Caption _value_rendering;
SDL_Rect _value_rendering_area {};
2021-06-16 18:09:14 +02:00
Input(SDL_Renderer* r)
: Widget(r), _value_rendering(r)
{
}
virtual void _render_value()
{
_value_rendering.text(_value_to_string(_value));
_update_drawing_areas();
}
2021-06-11 13:30:33 +02:00
2021-06-16 13:50:34 +02:00
virtual void _update_drawing_areas()
{
2021-06-16 18:09:14 +02:00
_update_widget_area();
2021-06-16 13:50:34 +02:00
_input_area = {
_input_field_area.x + 3,
_input_field_area.y + 3,
_input_field_area.w - 6,
_input_field_area.h - 6
2021-06-16 13:50:34 +02:00
};
auto text_render_size = _value_rendering.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
};
_value_rendering.viewport(value_text_vp);
2021-06-16 13:50:34 +02:00
}
2021-06-16 18:09:14 +02:00
virtual void _update_widget_area()
{
_widget_area = _input_field_area;
}
static T _value_from_string(std::string s)
{
T value;
if constexpr(std::is_floating_point_v<T>)
value = (T)std::stold(s);
else if constexpr(std::is_integral_v<T>)
value = (T)std::stoll(s);
else if constexpr(std::is_same_v<T, std::string> || std::convertible_to<std::string, T>)
value = s;
else
static_assert(sizeof(T) && false, "string cannot be converted to value type T.");
}
static std::string _value_to_string(T value)
2021-06-16 13:50:34 +02:00
{
std::string s;
if constexpr(std::is_same_v<std::string, T> || std::convertible_to<T, std::string>)
2021-06-16 18:09:14 +02:00
s = value;
2021-06-16 13:50:34 +02:00
else if constexpr(CanToString<T>)
2021-06-16 18:09:14 +02:00
s = std::to_string(value);
2021-06-16 13:50:34 +02:00
else if constexpr(Printable<T>)
{
std::stringstream ss;
2021-06-16 18:09:14 +02:00
ss << value;
2021-06-16 13:50:34 +02:00
return std::move(ss).str();
}
else
static_assert(sizeof(T) && false, "_value cannot be converted to string.");
return s;
}
2021-06-11 13:30:33 +02:00
public:
SDL_Color border_color {160, 160, 160, SDL_ALPHA_OPAQUE};
SDL_Color background_color {200, 200, 200, SDL_ALPHA_OPAQUE};
SDL_Color focused_background_color {255, 255, 255, SDL_ALPHA_OPAQUE};
virtual void font(TTF_Font* f)
2021-06-11 13:30:33 +02:00
{
_value_rendering.font(f);
2021-06-11 13:30:33 +02:00
_update_drawing_areas();
}
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--)
2021-06-16 13:50:34 +02:00
{
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)
2021-06-16 13:50:34 +02:00
};
2021-06-16 18:09:14 +02:00
SDL_RenderDrawRect(_renderer, &border_area);
2021-06-16 13:50:34 +02:00
}
2021-06-16 18:09:14 +02:00
SDL_Color* bg_color = &background_color;
if (_focused)
bg_color = &focused_background_color;
2021-06-16 13:50:34 +02:00
SDL_SetRenderDrawColor(
_renderer,
2021-06-16 18:09:14 +02:00
bg_color->r,
bg_color->g,
bg_color->b,
bg_color->a
2021-06-16 13:50:34 +02:00
);
SDL_RenderFillRect(_renderer, &_input_area);
2021-06-11 13:30:33 +02:00
_value_rendering.render();
2021-06-11 13:30:33 +02:00
SDL_RenderSetViewport(_renderer, &old_vp);
}
T value() const
{
return _value;
}
void value(T new_value)
{
_value = new_value;
_render_value();
}
virtual void viewport(SDL_Rect vp)
{
Widget::viewport(vp);
_update_drawing_areas();
}
2021-06-11 13:30:33 +02:00
};
#endif