#include namespace psemek::ui { bool slider::on_event(mouse_move const & e) { bool const over = shape().contains(math::cast(e.position)); mouse_ = e.position; switch (state_) { case state_t::normal: if (over) { state_ = state_t::mouseover; on_state_changed(state_t::normal); } break; case state_t::mouseover: if (!over) { state_ = state_t::normal; on_state_changed(state_t::mouseover); } break; case state_t::mousedown: if (mouse_) set_value(compute_value((*mouse_)[0], *drag_range_)); break; } return false; } bool slider::on_event(mouse_click const & e) { if (e.button != mouse_button::left) return false; switch (state_) { case state_t::normal: break; case state_t::mouseover: if (e.down) { state_ = state_t::mousedown; if (mouse_) { drag_range_ = slider_range(); set_value(compute_value((*mouse_)[0], *drag_range_)); } on_state_changed(state_t::mouseover); return true; } break; case state_t::mousedown: if (!e.down) { if (mouse_ && shape().contains(math::cast(*mouse_))) state_ = state_t::mouseover; else state_ = state_t::normal; drag_range_ = std::nullopt; on_state_changed(state_t::mousedown); return true; } break; } return false; } bool slider::on_event(mouse_wheel const & e) { if (state_ == state_t::mouseover) { set_value(value_ + e.delta); return true; } return false; } void slider::set_value_range(math::interval i, bool notify) { if (i.empty()) throw std::runtime_error("Empty value range for ui::slider"); value_range_ = i; set_value(value_, notify); } void slider::set_value(int v, bool notify) { if (cyclic_) v = math::imod(v - value_range_.min, value_range_.length()) + value_range_.min; else v = math::clamp(v, value_range_); if (value_ != v) { value_ = v; if (notify) post_value_changed(); } } void slider::on_value_changed(on_value_changed_callback callback, bool notify) { callback_ = std::move(callback); if (notify) post_value_changed(); } math::interval slider::slider_range() const { return shape().bbox()[0]; } void slider::post_value_changed() { if (callback_) post([cb = callback_, value = value_]{ cb(value); }); } int slider::compute_value(int x, math::interval const & range) const { return std::round(math::unlerp(range, x * 1.f) * value_range_.length()) + value_range_.min; } }