#include #include namespace psemek::ui { std::shared_ptr scroller::set_child(std::shared_ptr c) { auto old = std::move(child_); if (old) old->set_parent(nullptr); child_ = std::move(c); if (child_) child_->set_parent(this); children_[0] = child_.get(); return old; } bool scroller::set_horizontal_scroll(bool enabled) { std::swap(horizontal_, enabled); return enabled; } bool scroller::set_vertical_scroll(bool enabled) { std::swap(vertical_, enabled); return enabled; } bool scroller::on_event(mouse_move const & e) { mouse_ = e.position; return false; } bool scroller::on_event(mouse_wheel const & e) { if (mouse_ && geom::contains(shape_.box, geom::cast(*mouse_))) { if (vertical_scroll()) { shift_tgt_[1] += e.delta * 50.f; post_reshape(); return true; } else if (horizontal_scroll()) { shift_tgt_[0] += e.delta * 50.f; post_reshape(); return true; } } return false; } void scroller::reshape(geom::box const & bbox) { shape_.box = bbox; if (child_) { auto child_constraints = child_->size_constraints(); auto child_bbox = bbox; if (horizontal_scroll()) { child_bbox[0].min += shift_[0]; child_bbox[0].max = child_bbox[0].min + child_constraints[0].min; } if (vertical_scroll()) { child_bbox[1].min += shift_[1]; child_bbox[1].max = child_bbox[1].min + child_constraints[1].min; } child_->reshape(child_bbox); } } geom::box scroller::size_constraints() const { geom::box result; result[0] = {0.f, std::numeric_limits::infinity()}; result[1] = {0.f, std::numeric_limits::infinity()}; if (child_) { auto child_constraints = child_->size_constraints(); if (!horizontal_scroll()) result[0] = child_constraints[0]; if (!vertical_scroll()) result[1] = child_constraints[1]; } return result; } void scroller::update(float dt) { shift_ += (shift_tgt_ - shift_) * std::min(10.f * dt, 1.f); post_reshape(); } void scroller::draw(painter & p) const { p.begin_stencil(); p.draw_rect(shape_.box, {0, 0, 0, 255}); p.commit_stencil(); } void scroller::post_draw(painter & p) const { p.end_stencil(); } scroller::~scroller() { release_children(); } }