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:
|
2021-06-17 20:45:06 +02:00
|
|
|
SDL_Rect _input_field_area {};
|
|
|
|
SDL_Rect _input_area {};
|
|
|
|
T _value {};
|
2021-06-16 18:09:14 +02:00
|
|
|
Caption _value_rendering;
|
2021-06-17 20:45:06 +02:00
|
|
|
SDL_Rect _value_rendering_area {};
|
2021-06-16 18:09:14 +02:00
|
|
|
|
|
|
|
Input(SDL_Renderer* r)
|
2021-06-17 20:45:06 +02:00
|
|
|
: 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 = {
|
2021-06-17 20:45:06 +02:00
|
|
|
_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
|
|
|
};
|
2021-06-17 20:45:06 +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:
|
2021-06-17 20:45:06 +02:00
|
|
|
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
|
|
|
{
|
2021-06-17 20:45:06 +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);
|
|
|
|
|
2021-06-17 20:45:06 +02:00
|
|
|
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 = {
|
2021-06-17 20:45:06 +02:00
|
|
|
_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
|
|
|
|
2021-06-17 20:45:06 +02:00
|
|
|
_value_rendering.render();
|
|
|
|
|
2021-06-11 13:30:33 +02:00
|
|
|
SDL_RenderSetViewport(_renderer, &old_vp);
|
|
|
|
}
|
2021-06-17 20:45:06 +02:00
|
|
|
|
|
|
|
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
|