diff --git a/src/gui/core/event/distributor.cpp b/src/gui/core/event/distributor.cpp index d8fd5591c12e..3957f05f064c 100644 --- a/src/gui/core/event/distributor.cpp +++ b/src/gui/core/event/distributor.cpp @@ -125,6 +125,15 @@ mouse_motion::mouse_motion(widget& owner, _5), queue_position); + owner.connect_signal( + std::bind(&mouse_motion::signal_handler_sdl_touch_motion, + this, + _2, + _3, + _5, + _6), + queue_position); + owner_.connect_signal(std::bind( &mouse_motion::signal_handler_sdl_wheel, this, _2, _3, _5)); owner_.connect_signal(std::bind( @@ -199,6 +208,25 @@ void mouse_motion::signal_handler_sdl_mouse_motion(const event::ui_event event, handled = true; } +void mouse_motion::signal_handler_sdl_touch_motion(const event::ui_event event, + bool& handled, + const point& coordinate, + const point& distance) +{ + DBG_GUI_E << LOG_HEADER << event << ".\n"; + + if(mouse_captured_) { + assert(mouse_focus_); + owner_.fire(event, *mouse_focus_, coordinate, distance); + } else { + widget* mouse_over = owner_.find_at(coordinate, true); + if(mouse_over) { + owner_.fire(event, *mouse_over, coordinate, distance); + } + } + handled = true; +} + void mouse_motion::signal_handler_sdl_wheel(const event::ui_event event, bool& handled, const point& coordinate) diff --git a/src/gui/core/event/distributor.hpp b/src/gui/core/event/distributor.hpp index c94ece1c71af..55d0e791cf3b 100644 --- a/src/gui/core/event/distributor.hpp +++ b/src/gui/core/event/distributor.hpp @@ -138,6 +138,11 @@ class mouse_motion bool& handled, const point& coordinate); + void signal_handler_sdl_touch_motion(const event::ui_event event, + bool& handled, + const point& coordinate, + const point& distance); + void signal_handler_sdl_wheel(const event::ui_event event, bool& handled, const point& coordinate); diff --git a/src/gui/widgets/scrollbar.cpp b/src/gui/widgets/scrollbar.cpp index 55e2e8f711d5..dfe974b22690 100644 --- a/src/gui/widgets/scrollbar.cpp +++ b/src/gui/widgets/scrollbar.cpp @@ -43,6 +43,8 @@ scrollbar_base::scrollbar_base(const implementation::builder_styled_widget& buil &scrollbar_base::signal_handler_mouse_enter, this, _2, _3, _4)); connect_signal(std::bind( &scrollbar_base::signal_handler_mouse_motion, this, _2, _3, _4, _5)); + connect_signal(std::bind( + &scrollbar_base::signal_handler_mouse_motion, this, _2, _3, _4, _5)); connect_signal(std::bind( &scrollbar_base::signal_handler_mouse_leave, this, _2, _3)); connect_signal(std::bind( @@ -60,6 +62,11 @@ void scrollbar_base::finalize_setup() } } +void scrollbar_base::scroll_by(const int pixels) +{ + move_positioner(static_cast(pixels_per_step_ * pixels)); +} + void scrollbar_base::scroll(const scroll_mode scroll) { switch(scroll) { diff --git a/src/gui/widgets/scrollbar.hpp b/src/gui/widgets/scrollbar.hpp index 34940a0daad1..dad4d541ac1b 100644 --- a/src/gui/widgets/scrollbar.hpp +++ b/src/gui/widgets/scrollbar.hpp @@ -71,6 +71,8 @@ class scrollbar_base : public styled_widget * @param scroll 'step size' to scroll. */ void scroll(const scroll_mode scroll); + + void scroll_by(const int pixels); /** Is the positioner at the beginning of the scrollbar? */ bool at_begin() const diff --git a/src/gui/widgets/scrollbar_container.cpp b/src/gui/widgets/scrollbar_container.cpp index a401b29226e5..45dd9400747b 100644 --- a/src/gui/widgets/scrollbar_container.cpp +++ b/src/gui/widgets/scrollbar_container.cpp @@ -98,6 +98,15 @@ scrollbar_container::scrollbar_container( connect_signal( std::bind(&scrollbar_container::signal_handler_sdl_wheel_right, this, _2, _3), event::dispatcher::back_post_child); + + connect_signal( + std::bind(&scrollbar_container::signal_handler_sdl_touch_motion, + this, + _2, + _3, + _5, + _6), + event::dispatcher::back_post_child); } void scrollbar_container::layout_initialize(const bool full_initialization) @@ -1178,4 +1187,39 @@ void scrollbar_container::signal_handler_sdl_wheel_right(const event::ui_event e } } +void +scrollbar_container::signal_handler_sdl_touch_motion(const event::ui_event event, + bool& handled, + const point& position, + const point& distance) +{ + (void) position; + DBG_GUI_E << LOG_HEADER << event << ".\n"; + + bool is_scrollbar_moved = false; + + if (horizontal_scrollbar_grid_ && horizontal_scrollbar_) { + + if(horizontal_scrollbar_grid_->get_visible() == widget::visibility::visible) { + horizontal_scrollbar_->scroll_by(-distance.x); + is_scrollbar_moved = true; + } + } + + if (vertical_scrollbar_grid_ && vertical_scrollbar_) { + + if(vertical_scrollbar_grid_->get_visible() == widget::visibility::visible) { + vertical_scrollbar_->scroll_by(-distance.y); + is_scrollbar_moved = true; + } + } + + if (is_scrollbar_moved) { + scrollbar_moved(); + handled = true; + } +} + + + } // namespace gui2 diff --git a/src/gui/widgets/scrollbar_container.hpp b/src/gui/widgets/scrollbar_container.hpp index 5f74ad44033e..6312ff338281 100644 --- a/src/gui/widgets/scrollbar_container.hpp +++ b/src/gui/widgets/scrollbar_container.hpp @@ -540,6 +540,8 @@ class scrollbar_container : public container_base void signal_handler_sdl_wheel_down(const event::ui_event event, bool& handled); void signal_handler_sdl_wheel_left(const event::ui_event event, bool& handled); void signal_handler_sdl_wheel_right(const event::ui_event event, bool& handled); + void signal_handler_sdl_touch_motion(const event::ui_event event, bool& handled, + const point& position, const point& distance); public: scrollbar_base* horizontal_scrollbar() diff --git a/src/widgets/scrollarea.cpp b/src/widgets/scrollarea.cpp index 5f77aa9fe72e..4abca7b38d37 100644 --- a/src/widgets/scrollarea.cpp +++ b/src/widgets/scrollarea.cpp @@ -18,6 +18,7 @@ #include "widgets/scrollarea.hpp" #include "sdl/rect.hpp" +#include "video.hpp" namespace gui { @@ -25,7 +26,7 @@ namespace gui { scrollarea::scrollarea(CVideo &video, const bool auto_join) : widget(video, auto_join), scrollbar_(video), old_position_(0), recursive_(false), shown_scrollbar_(false), - shown_size_(0), full_size_(0) + shown_size_(0), full_size_(0), swipe_dy_(0) { scrollbar_.hide(true); } @@ -153,19 +154,59 @@ void scrollarea::handle_event(const SDL_Event& event) if (mouse_locked() || hidden()) return; - if (event.type != SDL_MOUSEWHEEL) - return; + if (event.type == SDL_MOUSEWHEEL) { + const SDL_MouseWheelEvent &ev = event.wheel; + int x, y; + SDL_GetMouseState(&x, &y); + if (sdl::point_in_rect(x, y, inner_location())) { + if (ev.y > 0) { + scrollbar_.scroll_up(); + } else if (ev.y < 0) { + scrollbar_.scroll_down(); + } + } + } + + if (event.type == SDL_FINGERUP) { + swipe_dy_ = 0; + } + + if (event.type == SDL_FINGERDOWN || event.type == SDL_FINGERMOTION) { + SDL_Rect r = video().screen_area(); + auto tx = static_cast(event.tfinger.x * r.w); + auto ty = static_cast(event.tfinger.y * r.h); + auto dy = static_cast(event.tfinger.dy * r.h); + + if (event.type == SDL_FINGERDOWN) { + swipe_dy_ = 0; + swipe_origin_.x = tx; + swipe_origin_.y = ty; + } - const SDL_MouseWheelEvent &ev = event.wheel; - int x, y; - SDL_GetMouseState(&x, &y); - if (sdl::point_in_rect(x, y, inner_location())) { - if (ev.y > 0) { - scrollbar_.scroll_up(); - } else if (ev.y < 0) { - scrollbar_.scroll_down(); + if (event.type == SDL_FINGERMOTION) { + + swipe_dy_ += dy; + if (scrollbar_.get_max_position() == 0) { + return; + } + + int scrollbar_step = scrollbar_.height() / scrollbar_.get_max_position(); + if (scrollbar_step <= 0) { + return; + } + + if (sdl::point_in_rect(swipe_origin_.x, swipe_origin_.y, inner_location()) + && abs(swipe_dy_) >= scrollbar_step) + { + unsigned int pos = std::max( + static_cast(scrollbar_.get_position() - swipe_dy_ / scrollbar_step), + 0); + scrollbar_.set_position(pos); + swipe_dy_ %= scrollbar_step; + } } } + } } // end namespace gui diff --git a/src/widgets/scrollarea.hpp b/src/widgets/scrollarea.hpp index 0f87681d8e2a..3be4ea26b3a7 100644 --- a/src/widgets/scrollarea.hpp +++ b/src/widgets/scrollarea.hpp @@ -60,6 +60,11 @@ class scrollarea : public widget bool recursive_, shown_scrollbar_; unsigned shown_size_; unsigned full_size_; + int swipe_dy_; + struct { + int x; + int y; + } swipe_origin_; void test_scrollbar(); };