slider events and value setting
This commit is contained in:
@@ -20,7 +20,7 @@ use vulkano::{
|
||||
};
|
||||
use wgui::{
|
||||
event::{
|
||||
EventListenerCollection, MouseButton, MouseDownEvent, MouseMotionEvent, MouseUpEvent,
|
||||
EventListenerCollection, MouseButtonIndex, MouseDownEvent, MouseMotionEvent, MouseUpEvent,
|
||||
MouseWheelEvent,
|
||||
},
|
||||
gfx::WGfx,
|
||||
@@ -160,7 +160,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
&mut listeners,
|
||||
&wgui::event::Event::MouseDown(MouseDownEvent {
|
||||
pos: mouse / scale,
|
||||
button: MouseButton::Left,
|
||||
index: MouseButtonIndex::Left,
|
||||
device: 0,
|
||||
}),
|
||||
(&mut (), &mut ()),
|
||||
@@ -173,7 +173,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
&mut listeners,
|
||||
&wgui::event::Event::MouseUp(MouseUpEvent {
|
||||
pos: mouse / scale,
|
||||
button: MouseButton::Left,
|
||||
index: MouseButtonIndex::Left,
|
||||
device: 0,
|
||||
}),
|
||||
(&mut (), &mut ()),
|
||||
@@ -280,7 +280,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
return;
|
||||
}
|
||||
|
||||
log::trace!("drawing frame {}", frame_index);
|
||||
log::trace!("drawing frame {frame_index}");
|
||||
frame_index += 1;
|
||||
|
||||
profiler.start();
|
||||
|
||||
@@ -22,30 +22,33 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
pub struct Params {
|
||||
pub style: taffy::Style,
|
||||
pub initial_value: f32,
|
||||
#[derive(Default)]
|
||||
pub struct ValuesMinMax {
|
||||
pub value: f32,
|
||||
pub min_value: f32,
|
||||
pub max_value: f32,
|
||||
}
|
||||
|
||||
impl Default for Params {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
style: Default::default(),
|
||||
initial_value: 0.5,
|
||||
min_value: 0.0,
|
||||
max_value: 1.0,
|
||||
impl ValuesMinMax {
|
||||
fn to_normalized(&self) -> f32 {
|
||||
(self.value - self.min_value) / (self.max_value - self.min_value)
|
||||
}
|
||||
|
||||
fn get_from_normalized(&self, normalized: f32) -> f32 {
|
||||
normalized * (self.max_value - self.min_value) + self.min_value
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Params {
|
||||
pub style: taffy::Style,
|
||||
pub values: ValuesMinMax,
|
||||
}
|
||||
|
||||
pub struct SliderState {
|
||||
dragging: bool,
|
||||
hovered: bool,
|
||||
value: f32,
|
||||
min_value: f32,
|
||||
max_value: f32,
|
||||
values: ValuesMinMax,
|
||||
}
|
||||
|
||||
struct Data {
|
||||
@@ -53,6 +56,7 @@ struct Data {
|
||||
slider_handle_id: WidgetID, // Div
|
||||
slider_handle_rect_id: WidgetID, // Rectangle
|
||||
slider_handle_node: taffy::NodeId,
|
||||
slider_body_node: taffy::NodeId,
|
||||
}
|
||||
|
||||
pub struct Slider {
|
||||
@@ -63,12 +67,58 @@ pub struct Slider {
|
||||
|
||||
impl Component for Slider {}
|
||||
|
||||
// NOTICE: this can be re-used in the future
|
||||
fn map_mouse_x_to_normalized(mouse_x_rel: f32, widget_width: f32) -> f32 {
|
||||
(mouse_x_rel / widget_width).clamp(0.0, 1.0)
|
||||
}
|
||||
|
||||
fn get_width(slider_body_node: taffy::NodeId, tree: &taffy::tree::TaffyTree<WidgetID>) -> f32 {
|
||||
let layout = tree.layout(slider_body_node).unwrap(); /* shouldn't fail */
|
||||
layout.size.width
|
||||
}
|
||||
|
||||
fn conf_handle_style(
|
||||
values: &ValuesMinMax,
|
||||
slider_body_node: taffy::NodeId,
|
||||
slider_handle_style: &mut taffy::Style,
|
||||
tree: &taffy::tree::TaffyTree<WidgetID>,
|
||||
) {
|
||||
let norm = values.to_normalized();
|
||||
|
||||
// convert normalized value to taffy percentage margin in percent
|
||||
let width = get_width(slider_body_node, tree);
|
||||
let percent_margin = (HANDLE_WIDTH / width) / 2.0;
|
||||
slider_handle_style.margin.left = percent(percent_margin + norm * (1.0 - percent_margin * 2.0));
|
||||
}
|
||||
|
||||
const PAD_PERCENT: f32 = 0.75;
|
||||
const HANDLE_WIDTH: f32 = 32.0;
|
||||
const HANDLE_HEIGHT: f32 = 24.0;
|
||||
|
||||
impl SliderState {
|
||||
fn update_value_to_mouse(
|
||||
&mut self,
|
||||
event_data: &event::CallbackData<'_>,
|
||||
data: &Data,
|
||||
common: &mut CallbackDataCommon,
|
||||
) {
|
||||
let mouse_pos = event_data
|
||||
.metadata
|
||||
.get_mouse_pos_relative(&common.alterables.transform_stack)
|
||||
.unwrap(); // safe
|
||||
|
||||
let norm = map_mouse_x_to_normalized(
|
||||
mouse_pos.x - HANDLE_WIDTH / 2.0,
|
||||
get_width(data.slider_body_node, common.get_tree()) - HANDLE_WIDTH,
|
||||
);
|
||||
let target_value = self.values.get_from_normalized(norm);
|
||||
let val = target_value;
|
||||
self.set_value(data, common, val);
|
||||
}
|
||||
|
||||
fn set_value(&mut self, data: &Data, common: &mut CallbackDataCommon, value: f32) {
|
||||
self.value = value;
|
||||
common.mark_dirty(data.slider_handle_node);
|
||||
common.call_on_widget(data.slider_handle_id, |div: &mut Div| {});
|
||||
common.mark_redraw();
|
||||
//common.call_on_widget(data.slider_handle_id, |_div: &mut Div| {});
|
||||
self.values.value = value;
|
||||
|
||||
let mut style = common
|
||||
.refs
|
||||
@@ -77,9 +127,15 @@ impl SliderState {
|
||||
.unwrap()
|
||||
.clone();
|
||||
|
||||
// todo
|
||||
style.margin.left = percent(1.0);
|
||||
conf_handle_style(
|
||||
&self.values,
|
||||
data.slider_body_node,
|
||||
&mut style,
|
||||
common.get_tree(),
|
||||
);
|
||||
|
||||
common.mark_dirty(data.slider_handle_node);
|
||||
common.mark_redraw();
|
||||
common.set_style(data.slider_handle_node, style);
|
||||
}
|
||||
}
|
||||
@@ -133,11 +189,6 @@ fn on_leave_anim(common: &mut event::CallbackDataCommon, handle_id: WidgetID) {
|
||||
));
|
||||
}
|
||||
|
||||
const PAD_PERCENT: f32 = 0.75;
|
||||
|
||||
const HANDLE_WIDTH: f32 = 32.0;
|
||||
const HANDLE_HEIGHT: f32 = 24.0;
|
||||
|
||||
fn register_event_mouse_enter<U1, U2>(
|
||||
data: Rc<Data>,
|
||||
state: Rc<RefCell<SliderState>>,
|
||||
@@ -176,7 +227,7 @@ fn register_event_mouse_leave<U1, U2>(
|
||||
|
||||
fn register_event_mouse_motion<U1, U2>(
|
||||
data: Rc<Data>,
|
||||
_state: Rc<RefCell<SliderState>>,
|
||||
state: Rc<RefCell<SliderState>>,
|
||||
listeners: &mut EventListenerCollection<U1, U2>,
|
||||
listener_handles: &mut ListenerHandleVec,
|
||||
) {
|
||||
@@ -184,7 +235,13 @@ fn register_event_mouse_motion<U1, U2>(
|
||||
listener_handles,
|
||||
data.body,
|
||||
EventListenerKind::MouseMotion,
|
||||
Box::new(move |_common, _data, _, _| {}),
|
||||
Box::new(move |common, event_data, _, _| {
|
||||
let mut state = state.borrow_mut();
|
||||
|
||||
if state.dragging {
|
||||
state.update_value_to_mouse(event_data, &data, common);
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -198,15 +255,13 @@ fn register_event_mouse_press<U1, U2>(
|
||||
listener_handles,
|
||||
data.body,
|
||||
EventListenerKind::MousePress,
|
||||
Box::new(move |common, _data, _, _| {
|
||||
Box::new(move |common, event_data, _, _| {
|
||||
common.trigger_haptics();
|
||||
|
||||
let mut state = state.borrow_mut();
|
||||
|
||||
if state.hovered {
|
||||
state.dragging = true;
|
||||
let val = 1.0;
|
||||
state.set_value(&data, common, val);
|
||||
state.update_value_to_mouse(event_data, &data, common)
|
||||
}
|
||||
}),
|
||||
);
|
||||
@@ -244,7 +299,7 @@ pub fn construct<U1, U2>(
|
||||
style.min_size = style.size;
|
||||
style.max_size = style.size;
|
||||
|
||||
let (body_id, _) = layout.add_child(parent, Div::create()?, style)?;
|
||||
let (body_id, slider_body_node) = layout.add_child(parent, Div::create()?, style)?;
|
||||
|
||||
let (_background_id, _) = layout.add_child(
|
||||
body_id,
|
||||
@@ -267,11 +322,7 @@ pub fn construct<U1, U2>(
|
||||
},
|
||||
)?;
|
||||
|
||||
// invisible outer handle body
|
||||
let (slider_handle_id, slider_handle_node) = layout.add_child(
|
||||
body_id,
|
||||
Div::create()?,
|
||||
taffy::Style {
|
||||
let slider_handle_style = taffy::Style {
|
||||
size: taffy::Size {
|
||||
width: length(0.0),
|
||||
height: percent(1.0),
|
||||
@@ -279,9 +330,27 @@ pub fn construct<U1, U2>(
|
||||
position: taffy::Position::Absolute,
|
||||
align_items: Some(taffy::AlignItems::Center),
|
||||
justify_content: Some(taffy::JustifyContent::Center),
|
||||
..Default::default()
|
||||
margin: taffy::Rect {
|
||||
// FIXME: temporary just for testing
|
||||
left: percent(0.5),
|
||||
bottom: length(0.0),
|
||||
right: length(0.0),
|
||||
top: length(0.0),
|
||||
},
|
||||
)?;
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// TODO: dispatch style config after this taffy tree did a re-layout
|
||||
/*conf_handle_style(
|
||||
¶ms.values,
|
||||
slider_body_node,
|
||||
&mut slider_handle_style,
|
||||
&layout.tree,
|
||||
);*/
|
||||
|
||||
// invisible outer handle body
|
||||
let (slider_handle_id, slider_handle_node) =
|
||||
layout.add_child(body_id, Div::create()?, slider_handle_style)?;
|
||||
|
||||
let (slider_handle_rect_id, _) = layout.add_child(
|
||||
slider_handle_id,
|
||||
@@ -307,14 +376,13 @@ pub fn construct<U1, U2>(
|
||||
slider_handle_node,
|
||||
slider_handle_rect_id,
|
||||
slider_handle_id,
|
||||
slider_body_node,
|
||||
});
|
||||
|
||||
let state = Rc::new(RefCell::new(SliderState {
|
||||
dragging: false,
|
||||
hovered: false,
|
||||
max_value: params.max_value,
|
||||
value: params.initial_value,
|
||||
min_value: params.min_value,
|
||||
values: params.values,
|
||||
}));
|
||||
|
||||
let mut lhandles = ListenerHandleVec::default();
|
||||
|
||||
@@ -11,15 +11,26 @@ use crate::{
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum MouseButton {
|
||||
pub enum MouseButtonIndex {
|
||||
Left,
|
||||
Right,
|
||||
Middle,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct MouseButton {
|
||||
pub index: MouseButtonIndex,
|
||||
pub pos: Vec2,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct MousePosition {
|
||||
pub pos: Vec2,
|
||||
}
|
||||
|
||||
pub struct MouseDownEvent {
|
||||
pub pos: Vec2,
|
||||
pub button: MouseButton,
|
||||
pub index: MouseButtonIndex,
|
||||
pub device: usize,
|
||||
}
|
||||
|
||||
@@ -34,7 +45,7 @@ pub struct MouseMotionEvent {
|
||||
|
||||
pub struct MouseUpEvent {
|
||||
pub pos: Vec2,
|
||||
pub button: MouseButton,
|
||||
pub index: MouseButtonIndex,
|
||||
pub device: usize,
|
||||
}
|
||||
|
||||
@@ -150,9 +161,27 @@ pub struct CallbackData<'a> {
|
||||
pub enum CallbackMetadata {
|
||||
None,
|
||||
MouseButton(MouseButton),
|
||||
MousePosition(MousePosition),
|
||||
Custom(usize),
|
||||
}
|
||||
|
||||
impl CallbackMetadata {
|
||||
// helper function
|
||||
pub fn get_mouse_pos_absolute(&self) -> Option<Vec2> {
|
||||
match *self {
|
||||
CallbackMetadata::None => None,
|
||||
CallbackMetadata::MouseButton(b) => Some(b.pos),
|
||||
CallbackMetadata::MousePosition(b) => Some(b.pos),
|
||||
CallbackMetadata::Custom(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_mouse_pos_relative(&self, transform_stack: &TransformStack) -> Option<Vec2> {
|
||||
let mouse_pos_abs = self.get_mouse_pos_absolute()?;
|
||||
Some(mouse_pos_abs - transform_stack.get_pos())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub enum EventListenerKind {
|
||||
MousePress,
|
||||
|
||||
@@ -37,10 +37,12 @@ pub fn parse_component_slider<'a, U1, U2>(
|
||||
ctx.listeners,
|
||||
parent_id,
|
||||
slider::Params {
|
||||
style,
|
||||
values: slider::ValuesMinMax {
|
||||
min_value,
|
||||
max_value,
|
||||
initial_value,
|
||||
style,
|
||||
value: initial_value,
|
||||
},
|
||||
},
|
||||
)?);
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
use glam::Vec2;
|
||||
|
||||
use super::drawing::RenderPrimitive;
|
||||
|
||||
use crate::{
|
||||
any::AnyTrait,
|
||||
drawing,
|
||||
event::{
|
||||
CallbackData, CallbackDataCommon, CallbackMetadata, Event, EventAlterables, EventListener,
|
||||
EventListenerCollection, EventListenerKind, EventListenerVec, EventRefs, MouseWheelEvent,
|
||||
self, CallbackData, CallbackDataCommon, CallbackMetadata, Event, EventAlterables,
|
||||
EventListenerKind, EventListenerVec, EventRefs, MouseWheelEvent,
|
||||
},
|
||||
layout::{Layout, WidgetID},
|
||||
transform_stack::TransformStack,
|
||||
@@ -338,7 +339,10 @@ impl WidgetState {
|
||||
params,
|
||||
MousePress,
|
||||
user_data,
|
||||
CallbackMetadata::MouseButton(e.button)
|
||||
CallbackMetadata::MouseButton(event::MouseButton {
|
||||
index: e.index,
|
||||
pos: e.pos
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -352,15 +356,13 @@ impl WidgetState {
|
||||
params,
|
||||
MouseRelease,
|
||||
user_data,
|
||||
CallbackMetadata::MouseButton(e.button)
|
||||
CallbackMetadata::MouseButton(event::MouseButton {
|
||||
index: e.index,
|
||||
pos: e.pos,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
Event::MouseWheel(e) => {
|
||||
if hovered && self.process_wheel(params, e) {
|
||||
return EventResult::Consumed;
|
||||
}
|
||||
}
|
||||
Event::MouseMotion(e) => {
|
||||
if self.data.set_device_hovered(e.device, hovered) {
|
||||
if self.data.is_hovered() {
|
||||
@@ -396,9 +398,14 @@ impl WidgetState {
|
||||
params,
|
||||
MouseMotion,
|
||||
user_data,
|
||||
CallbackMetadata::None
|
||||
CallbackMetadata::MousePosition(event::MousePosition { pos: e.pos })
|
||||
);
|
||||
}
|
||||
Event::MouseWheel(e) => {
|
||||
if hovered && self.process_wheel(params, e) {
|
||||
return EventResult::Consumed;
|
||||
}
|
||||
}
|
||||
Event::MouseLeave(e) => {
|
||||
if self.data.set_device_hovered(e.device, false) {
|
||||
call_event!(
|
||||
|
||||
@@ -5,8 +5,8 @@ use vulkano::{command_buffer::CommandBufferUsage, image::view::ImageView};
|
||||
use wgui::{
|
||||
event::{
|
||||
Event as WguiEvent, EventListenerCollection, InternalStateChangeEvent, ListenerHandleVec,
|
||||
MouseButton, MouseDownEvent, MouseLeaveEvent, MouseMotionEvent, MouseUpEvent,
|
||||
MouseWheelEvent,
|
||||
MouseButton, MouseButtonIndex, MouseDownEvent, MouseLeaveEvent, MouseMotionEvent,
|
||||
MouseUpEvent, MouseWheelEvent,
|
||||
},
|
||||
layout::Layout,
|
||||
parser::ParserState,
|
||||
@@ -223,10 +223,10 @@ impl<S> OverlayBackend for GuiPanel<S> {
|
||||
}
|
||||
|
||||
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) {
|
||||
let button = match hit.mode {
|
||||
PointerMode::Left => MouseButton::Left,
|
||||
PointerMode::Right => MouseButton::Right,
|
||||
PointerMode::Middle => MouseButton::Middle,
|
||||
let index = match hit.mode {
|
||||
PointerMode::Left => MouseButtonIndex::Left,
|
||||
PointerMode::Right => MouseButtonIndex::Right,
|
||||
PointerMode::Middle => MouseButtonIndex::Middle,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
@@ -235,7 +235,7 @@ impl<S> OverlayBackend for GuiPanel<S> {
|
||||
app,
|
||||
&WguiEvent::MouseDown(MouseDownEvent {
|
||||
pos: hit.uv * self.layout.content_size,
|
||||
button,
|
||||
index,
|
||||
device: hit.pointer,
|
||||
}),
|
||||
);
|
||||
@@ -244,7 +244,7 @@ impl<S> OverlayBackend for GuiPanel<S> {
|
||||
app,
|
||||
&WguiEvent::MouseUp(MouseUpEvent {
|
||||
pos: hit.uv * self.layout.content_size,
|
||||
button,
|
||||
index,
|
||||
device: hit.pointer,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -7,7 +7,7 @@ use std::{
|
||||
use vulkano::image::view::ImageView;
|
||||
use wgui::{
|
||||
drawing,
|
||||
event::{InternalStateChangeEvent, MouseButton},
|
||||
event::{InternalStateChangeEvent, MouseButton, MouseButtonIndex},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@@ -134,9 +134,9 @@ fn handle_press(
|
||||
) {
|
||||
match &key.button_state {
|
||||
KeyButtonData::Key { vk, pressed } => {
|
||||
keyboard.modifiers |= match button {
|
||||
MouseButton::Right => SHIFT,
|
||||
MouseButton::Middle => keyboard.alt_modifier,
|
||||
keyboard.modifiers |= match button.index {
|
||||
MouseButtonIndex::Right => SHIFT,
|
||||
MouseButtonIndex::Middle => keyboard.alt_modifier,
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user