scrollable (texture) area works

This commit is contained in:
Andrea Blankenstijn 2022-01-26 22:49:41 +01:00
parent af7b9803d2
commit 3f15d1d857
11 changed files with 99 additions and 45 deletions

View file

@ -8,7 +8,7 @@ auto main() -> int
{
run_example<bwidgets::Button>(
[]() { return bwidgets::create_button(); },
[](auto w, auto f, auto x, auto y) {
[](auto w, auto f, auto x, auto y, auto) {
w->click_handler([x, y](const SDL_MouseButtonEvent&) {
std::cout << "button(" << x << ',' << y << "):click!" << std::endl;
});

View file

@ -5,7 +5,7 @@
auto main() -> int
{
run_example<bwidgets::Caption>([]() { return bwidgets::create_caption(); },
[](auto w, auto f, auto, auto) {
[](auto w, auto f, auto, auto, auto) {
w->alignment(
bwidgets::Caption::Alignment::CENTER);
w->text("¡jello!");

View file

@ -5,7 +5,7 @@ auto main() -> int
{
run_example<Example>(
[]() { return std::make_unique<Example>(); },
[](auto w, auto, auto x, auto y) {
[](auto w, auto, auto x, auto y, auto) {
w->cycle_r = (x + 1) * 3000; // NOLINT(readability-magic-numbers)
w->cycle_b = (y + 1) * 3000; // NOLINT(readability-magic-numbers)
w->cycle_b = (1 + x + y) * (y + 1) * 400; // NOLINT(readability-magic-numbers)

View file

@ -6,7 +6,7 @@ auto main() -> int
{
run_example<bwidgets::NumericInput<float>>(
[]() { return bwidgets::create_input_float(); },
[](auto w, auto f, auto, auto) {
[](auto w, auto f, auto, auto, auto) {
w->font(f);
w->button_step = 0.5; // NOLINT(readability-magic-numbers)
w->value_range(-3.14, 8.5); // NOLINT(readability-magic-numbers)

View file

@ -11,10 +11,11 @@ template<typename T>
concept WidgetType = std::derived_from<T, bwidgets::Widget>;
template<WidgetType W>
void run_example(
std::function<std::unique_ptr<W>()> factory,
std::function<void(W*, const std::shared_ptr<bwidgets::Font>, int, int)> setup,
int w = 3, int h = 3)
void run_example(std::function<std::unique_ptr<W>()> factory,
std::function<void(W*, const std::shared_ptr<bwidgets::Font>&, int, int,
const std::shared_ptr<bwidgets::Renderer>)>
setup,
int w = 3, int h = 3)
{
std::atexit([]() {
TTF_Quit();
@ -43,7 +44,7 @@ void run_example(
auto col = bwidgets::create_vertical_layout();
for (auto y = 0; y < h; y++) {
auto widget = factory();
setup(widget.get(), font, x, y);
setup(widget.get(), font, x, y, renderer);
col->add_widget(std::move(widget));
}
layout->add_widget(std::move(col));

View file

@ -1,3 +1,4 @@
#include <basic_widgets/core/draw.hpp>
#include <basic_widgets/w/widget_factory.hpp>
#include "run.hpp"
@ -6,6 +7,9 @@ auto main() -> int
{
run_example<bwidgets::ScrollableArea>(
[]() { return bwidgets::create_scrollable_area(); },
[](auto w, auto f, auto x, auto y) { w->font(f); });
[](auto w, auto f, auto x, auto y, auto r) {
w->font(f);
w->texture(bwidgets::filled_circle({255, 0, 0, 255}, 300, *r));
});
return 0;
}

View file

@ -1,11 +1,19 @@
#include <iostream>
#include <basic_widgets/w/widget_factory.hpp>
#include "run.hpp"
auto main() -> int
{
run_example<bwidgets::ScrollableArea>(
[]() { return bwidgets::create_scrollable_area(); },
[](auto w, auto f, auto x, auto y) {});
run_example<bwidgets::ScrollBar>([]() { return bwidgets::create_scrollbar(); },
[](auto w, auto f, auto x, auto y, auto) {
w->font(f);
w->on_scroll([x, y](const float v) {
std::cout << "Scroll(" << x << "," << y
<< "): " << v * 100 << "%"
<< std::endl;
});
});
return 0;
}

View file

@ -20,11 +20,13 @@ namespace bwidgets
VERTICAL
};
virtual void on_scroll(std::function<void(int)>) = 0;
[[nodiscard]] virtual auto orientation() const -> Orientation = 0;
virtual void orientation(Orientation) = 0;
[[nodiscard]] virtual auto value() const -> int = 0;
virtual void value(int) = 0;
virtual void on_scroll(std::function<void(float)>) = 0;
[[nodiscard]] virtual auto orientation() const -> Orientation = 0;
virtual void orientation(Orientation) = 0;
[[nodiscard]] virtual auto step() const -> float = 0;
virtual void step(float) = 0;
[[nodiscard]] virtual auto value() const -> float = 0;
virtual void value(float) = 0;
};
}

View file

@ -22,22 +22,25 @@ namespace bwidgets
auto cursor_area() const -> SDL_Rect;
void handle_event(const SDL_Event&) override;
void on_scroll(std::function<void(int)>) override;
void on_scroll(std::function<void(float)>) override;
[[nodiscard]] auto orientation() const -> Orientation override;
void orientation(Orientation) override;
[[nodiscard]] auto size() const noexcept -> Size override;
[[nodiscard]] auto value() const -> int override;
void value(int) override;
[[nodiscard]] auto step() const -> float override;
void step(float) override;
[[nodiscard]] auto value() const -> float override;
void value(float) override;
protected:
SDL_Rect _bar_area;
std::unique_ptr<Button> _button_minus;
std::unique_ptr<Button> _button_plus;
const Size _cursor_size {16, 16};
SDL_Rect _bar_area;
std::unique_ptr<Button> _button_minus;
std::unique_ptr<Button> _button_plus;
const Size _cursor_size {16, 16};
// TODO: cursor_area
std::function<void(int)> _on_scroll;
Orientation _orientation;
int _value {0};
std::function<void(float)> _on_scroll;
Orientation _orientation;
float _step;
float _value {0};
void _handle_font_change(const std::shared_ptr<Font>&) override;
void _handle_font_color_change(Color, Color) override;

View file

@ -1,6 +1,7 @@
#include <utility>
#include <basic_widgets/core/draw.hpp>
#include <basic_widgets/core/math.hpp>
#include <basic_widgets/w/scrollable_area_impl.hpp>
#include <basic_widgets/w/widget_factory.hpp>
@ -68,6 +69,30 @@ void ScrollableAreaImpl::_handle_rendering()
{
fill_rect_gradient(*renderer(), _texture_area, theme()->color_widget_border(),
theme()->color_widget_bg(), theme()->size_widget_border());
const auto texture_attr = _texture->attributes();
const auto copy_dst = [this, &texture_attr]() {
auto dst = rect_margin(
_texture_area, {theme()->size_widget_border(), theme()->size_widget_border()});
if (dst.w > texture_attr.w) {
dst.x += center_line(dst.w, texture_attr.w);
dst.w = texture_attr.w;
}
if (dst.h > texture_attr.h) {
dst.y += center_line(dst.h, texture_attr.h);
dst.h = texture_attr.h;
}
return dst;
}();
renderer()->copy(
*_texture,
{static_cast<int>(_scrollbar_h->value()
* std::clamp(texture_attr.w - copy_dst.w, 0, texture_attr.w)),
static_cast<int>(_scrollbar_v->value()
* std::clamp(texture_attr.h - copy_dst.h, 0, texture_attr.h)),
copy_dst.w, copy_dst.h},
copy_dst);
_scrollbar_h->render();
_scrollbar_v->render();
}

View file

@ -30,21 +30,22 @@ ScrollBarImpl::ScrollBarImpl(Widget* parent)
: WidgetImpl {parent},
_button_minus {create_button(this)},
_button_plus {create_button(this)},
_orientation {Orientation::VERTICAL}
_orientation {Orientation::VERTICAL},
_step {.05F}
{
_button_minus->text("");
_button_plus->text("");
_button_minus->click_handler([this](auto) { value(value() - 5); });
_button_plus->click_handler([this](auto) { value(value() + 5); });
_button_minus->click_handler([this](auto) { value(value() - _step); });
_button_plus->click_handler([this](auto) { value(value() + _step); });
click_handler([this](const SDL_MouseButtonEvent ev) {
SDL_Point p {ev.x - viewport().x - _bar_area.x,
ev.y - viewport().y - _bar_area.y};
if (_orientation == Orientation::VERTICAL) {
value(p.y * 100 / _bar_area.h);
value(p.y / static_cast<float>(_bar_area.h));
}
else {
value(p.x * 100 / _bar_area.w);
value(p.x / static_cast<float>(_bar_area.w));
}
});
mouse_motion_handler([this](SDL_MouseMotionEvent ev) {
@ -52,20 +53,20 @@ ScrollBarImpl::ScrollBarImpl(Widget* parent)
SDL_Point p = {ev.x - viewport().x - _bar_area.x,
ev.y - viewport().y - _bar_area.y};
if (_orientation == Orientation::VERTICAL) {
value(clamp(p.y, 0, _bar_area.h) * 100 / _bar_area.h);
value(clamp(p.y, 0, _bar_area.h) / static_cast<float>(_bar_area.h));
}
else {
value(clamp(p.x, 0, _bar_area.w) * 100 / _bar_area.w);
value(clamp(p.x, 0, _bar_area.w) / static_cast<float>(_bar_area.w));
}
});
mouse_wheel_handler([this](SDL_MouseWheelEvent ev) {
if (orientation() == ScrollBar::Orientation::VERTICAL) {
if (ev.y < 0) value(value() + 5);
else if (ev.y > 0) value(value() - 5);
if (ev.y < 0) value(value() + _step);
else if (ev.y > 0) value(value() - _step);
}
else {
if (ev.x > 0) value(value() + 5);
else if (ev.x < 0) value(value() - 5);
if (ev.x > 0) value(value() + _step);
else if (ev.x < 0) value(value() - _step);
}
});
enable_mouse_handler(_bar_area, viewport());
@ -74,11 +75,11 @@ ScrollBarImpl::ScrollBarImpl(Widget* parent)
auto ScrollBarImpl::cursor_area() const -> SDL_Rect
{
if (_orientation == Orientation::VERTICAL) {
const auto offset = value() * _bar_area.h / 100;
const auto offset = static_cast<int>(value() * _bar_area.h);
return {_bar_area.x, _bar_area.y + offset - _cursor_size.h / 2, _bar_area.w,
_cursor_size.h};
}
const auto offset = value() * _bar_area.w / 100;
const auto offset = static_cast<int>(value() * _bar_area.w);
return {_bar_area.x + offset - _cursor_size.h / 2, _bar_area.y, _cursor_size.h,
_bar_area.h};
}
@ -90,7 +91,7 @@ void ScrollBarImpl::handle_event(const SDL_Event& ev)
_button_plus->handle_event(ev);
}
void ScrollBarImpl::on_scroll(function<void(int)> cb)
void ScrollBarImpl::on_scroll(function<void(float)> cb)
{
_on_scroll = move(cb);
}
@ -136,14 +137,24 @@ auto ScrollBarImpl::size() const noexcept -> Size
return {height, button_size + button_size + 3 * _cursor_size.h};
}
auto ScrollBarImpl::value() const -> int
auto ScrollBarImpl::step() const -> float
{
return _step;
}
void ScrollBarImpl::step(float s)
{
_step = s;
}
auto ScrollBarImpl::value() const -> float
{
return _value;
}
void ScrollBarImpl::value(const int v)
void ScrollBarImpl::value(const float v)
{
const auto new_value = clamp(v, 0, 100);
const auto new_value = clamp(v, 0.F, 1.F);
if (new_value != _value) {
_value = new_value;
if (_on_scroll) _on_scroll(new_value);