#pragma once #include #include namespace psemek::ui { struct scroller : single_container { enum class direction { horizontal, vertical, }; virtual direction preferred_direction() const { return preferred_direction_; } virtual void set_preferred_direction(direction d); virtual bool set_horizontal_scroll(bool enabled); virtual bool set_vertical_scroll(bool enabled); virtual bool horizontal_scroll() const { return horizontal_; } virtual bool vertical_scroll() const { return vertical_; } virtual geom::box events_bbox() const override; virtual bool on_event(mouse_move const & e) override; virtual bool on_event(mouse_click const & e) override; virtual bool on_event(mouse_wheel const & e) override; struct shape const & shape() const override { return shape_; } void reshape(geom::box const & bbox) override; geom::box size_constraints() const override; geom::interval width_constraints(float height) const override; geom::interval height_constraints(float width) const override; virtual float position(direction dir) const; virtual void set_position(direction dir, float position, bool animate); void update(float dt) override; void draw(painter & p) const override; void post_draw(painter & p) const override; protected: virtual void on_scroll(geom::vector const & delta); virtual float width() const; virtual geom::box visible_range() const; virtual geom::box horizontal_box() const; virtual geom::box vertical_box() const; enum state_t { normal, mouseover, mousedown, }; state_t vertical_state_ = state_t::normal; state_t horizontal_state_ = state_t::normal; private: box_shape shape_; std::optional> mouse_; direction preferred_direction_ = direction::vertical; bool horizontal_ = false; bool vertical_ = true; geom::vector shift_{0.f, 0.f}; geom::vector shift_tgt_{0.f, 0.f}; void clamp_shift(); }; }