#include #include #include #include using namespace bwidgets; ButtonImpl::ButtonImpl(Widget* parent) noexcept : WidgetImpl {parent}, _caption {create_caption(this)} { enable_mouse_handler(_widget_area, _viewport); _caption->alignment = Caption::Alignment::CENTER; _caption->render_mode(Font::RenderMode::BLENDED); border_gradient = [this](const int len, const int pos, const float divider) -> Color { const auto& end_color = hovered() ? color_bg_hover : color_bg; return lerp(end_color / divider, end_color, linear(pos, 0, len)); }; } auto ButtonImpl::size() const noexcept -> Size { return _caption->size() + border_size * 2; } auto ButtonImpl::text() const noexcept -> std::string_view { return _caption->text(); } void ButtonImpl::text(std::string txt) { _caption->text(std::move(txt)); _handle_geometry_change(_viewport); } void ButtonImpl::_handle_font_change(const std::shared_ptr& f) { _caption->font(f); _handle_geometry_change(_viewport); } void ButtonImpl::_handle_font_color_change(const Color fg, Color) { _caption->font_color_fg(fg); } void ButtonImpl::_handle_geometry_change(const SDL_Rect& vp) { const auto h = _caption->size().h + 2 * border_size.h; _widget_area = {0, center_line(vp.h, _caption->size().h) - border_size.h, vp.w, h}; const auto txt_size = _caption->size(); _caption_area = {center_line(vp.w, txt_size.w), center_line(vp.h, txt_size.h), txt_size.w, txt_size.h}; _caption->viewport(rect_offset(_caption_area, vp)); } void ButtonImpl::_handle_renderer_change(const std::shared_ptr& r) { _caption->renderer(r); } void ButtonImpl::_handle_rendering() { const Color& c = hovered() ? color_bg_hover : color_bg; const auto divider = pushed() ? 1.5F : 2.F; auto x = 0; auto y = 0; const auto biggest_dimension = border_size.w > border_size.h ? border_size.w : border_size.h; const auto& max_xy = border_size.w > border_size.h ? x : y; // Render button borders. while (x < border_size.w || y < border_size.h) { _renderer->draw_color(border_gradient(biggest_dimension, max_xy, divider)) ->draw_rect(rect_margin(_widget_area, {x, y})); if (x < border_size.w) x++; if (y < border_size.h) y++; } _renderer->draw_color(c)->fill_rect(rect_margin(_widget_area, border_size)); _caption->font_color_bg(c); _caption->render(); } void ButtonImpl::_on_push(const bool state) { // Move slightly the caption position to give a push effect. const auto offset = [state, this]() -> SDL_Point { if (state) { return {_viewport.x + 1, _viewport.y + 1}; } return {_viewport.x, _viewport.y}; }(); _caption->viewport(rect_offset(_caption_area, offset)); }