psemek/libs/ui/source/slider.cpp

129 lines
2.5 KiB
C++

#include <psemek/ui/slider.hpp>
namespace psemek::ui
{
bool slider::on_event(mouse_move const & e)
{
bool const over = shape().contains(geom::cast<float>(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(geom::cast<float>(*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(geom::interval<int> 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 = geom::imod(v - value_range_.min, value_range_.length()) + value_range_.min;
else
v = geom::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();
}
geom::interval<float> 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, geom::interval<float> const & range) const
{
return std::round(geom::unlerp(range, x * 1.f) * value_range_.length()) + value_range_.min;
}
}