use nalgebra_glm::{Vec2, Vec4};
use crate::ecs::text::components::{TextAlignment, VerticalAlignment};
use crate::ecs::ui::builder::UiTreeBuilder;
use crate::ecs::ui::components::*;
use crate::ecs::ui::layout_types::FlowDirection;
use crate::ecs::ui::state::{UiBase, UiFocused, UiHover};
use crate::ecs::ui::types::Anchor;
use crate::ecs::ui::units::{Ab, Rl};
impl<'a> UiTreeBuilder<'a> {
pub fn add_drag_value(&mut self, min: f32, max: f32, initial: f32) -> freecs::Entity {
self.add_drag_value_configured(DragValueConfig::new(min, max, initial))
}
pub fn add_drag_value_configured(&mut self, config: DragValueConfig<'_>) -> freecs::Entity {
let initial = config.initial;
let min = config.min;
let max = config.max;
let speed = config.speed;
let precision = config.precision;
let prefix = config.prefix;
let suffix = config.suffix;
let show_arrows = config.show_arrows;
let theme = self
.world_mut()
.resources
.retained_ui
.theme_state
.active_theme();
let font_size = theme.font_size;
let accent_color = theme.accent_color;
let corner_radius = theme.corner_radius;
let border_color = theme.border_color;
let input_height = theme.button_height;
let display_text = format!("{prefix}{initial:.prec$}{suffix}", prec = precision);
let text_slot = self
.world_mut()
.resources
.text_cache
.add_text(&display_text);
let mut cursor_entity = freecs::Entity::default();
let mut selection_entity = freecs::Entity::default();
let wrapper_entity = self
.add_node()
.flow_child(Rl(Vec2::new(100.0, 0.0)) + Ab(Vec2::new(0.0, input_height)))
.flow(FlowDirection::Horizontal, 0.0, 0.0)
.without_pointer_events()
.entity();
self.push_parent(wrapper_entity);
let root_entity = self
.add_node()
.flow_child(Rl(Vec2::new(0.0, 100.0)) + Ab(Vec2::new(0.0, 0.0)))
.flex_grow(1.0)
.with_rect(corner_radius, 1.0, border_color)
.with_theme_border_color(ThemeColor::Border)
.with_theme_color::<UiBase>(ThemeColor::InputBackground)
.with_theme_color::<UiFocused>(ThemeColor::InputBackgroundFocused)
.with_interaction()
.with_transition::<UiFocused>(8.0, 6.0)
.with_cursor_icon(winit::window::CursorIcon::EwResize)
.with_clip()
.with_children(|tree| {
selection_entity = tree
.add_node()
.window(
Ab(Vec2::new(8.0, 4.0)),
Ab(Vec2::new(0.0, input_height - 8.0)),
Anchor::TopLeft,
)
.with_rect(2.0, 0.0, Vec4::new(0.0, 0.0, 0.0, 0.0))
.with_color::<UiBase>(Vec4::new(
accent_color.x,
accent_color.y,
accent_color.z,
0.3,
))
.with_visible(false)
.without_pointer_events()
.done();
tree.add_node()
.window(
Ab(Vec2::new(8.0, 0.0)),
Ab(Vec2::new(0.0, input_height)) + Rl(Vec2::new(100.0, 0.0)),
Anchor::TopLeft,
)
.with_text_slot(text_slot, font_size)
.with_text_alignment(TextAlignment::Left, VerticalAlignment::Middle)
.with_theme_color::<UiBase>(ThemeColor::Text)
.without_pointer_events()
.done();
cursor_entity = tree
.add_node()
.window(
Ab(Vec2::new(8.0, 4.0)),
Ab(Vec2::new(2.0, input_height - 8.0)),
Anchor::TopLeft,
)
.with_rect(1.0, 0.0, Vec4::new(0.0, 0.0, 0.0, 0.0))
.with_theme_color::<UiBase>(ThemeColor::Text)
.with_visible(false)
.without_pointer_events()
.done();
})
.done();
let mut up_entity = None;
let mut down_entity = None;
if show_arrows {
let arrow_width = 18.0;
let half_height = input_height / 2.0;
let arrow_col = self
.add_node()
.flow_child(Ab(Vec2::new(arrow_width, input_height)))
.flow(FlowDirection::Vertical, 0.0, 0.0)
.without_pointer_events()
.entity();
self.push_parent(arrow_col);
let up_slot = self.world_mut().resources.text_cache.add_text("\u{25B2}");
up_entity = Some(
self.add_node()
.flow_child(Ab(Vec2::new(arrow_width, half_height)))
.with_rect(corner_radius, 1.0, border_color)
.with_theme_border_color(ThemeColor::Border)
.with_theme_color::<UiBase>(ThemeColor::InputBackground)
.with_theme_color::<UiHover>(ThemeColor::BackgroundHover)
.with_interaction()
.with_transition::<UiHover>(8.0, 6.0)
.with_cursor_icon(winit::window::CursorIcon::Pointer)
.with_children(|tree| {
tree.add_node()
.boundary(Ab(Vec2::zeros()), Rl(Vec2::new(100.0, 100.0)))
.with_text_slot(up_slot, font_size * 0.5)
.with_text_alignment(TextAlignment::Center, VerticalAlignment::Middle)
.with_theme_color::<UiBase>(ThemeColor::Text)
.without_pointer_events()
.done();
})
.done(),
);
let down_slot = self.world_mut().resources.text_cache.add_text("\u{25BC}");
down_entity = Some(
self.add_node()
.flow_child(Ab(Vec2::new(arrow_width, half_height)))
.with_rect(corner_radius, 1.0, border_color)
.with_theme_border_color(ThemeColor::Border)
.with_theme_color::<UiBase>(ThemeColor::InputBackground)
.with_theme_color::<UiHover>(ThemeColor::BackgroundHover)
.with_interaction()
.with_transition::<UiHover>(8.0, 6.0)
.with_cursor_icon(winit::window::CursorIcon::Pointer)
.with_children(|tree| {
tree.add_node()
.boundary(Ab(Vec2::zeros()), Rl(Vec2::new(100.0, 100.0)))
.with_text_slot(down_slot, font_size * 0.5)
.with_text_alignment(TextAlignment::Center, VerticalAlignment::Middle)
.with_theme_color::<UiBase>(ThemeColor::Text)
.without_pointer_events()
.done();
})
.done(),
);
self.pop_parent();
}
self.pop_parent();
let step_val = speed * 10.0;
self.world_mut().ui.set_ui_widget_state(
root_entity,
UiWidgetState::DragValue(UiDragValueData {
value: initial,
min,
max,
speed,
precision,
prefix: prefix.to_string(),
suffix: suffix.to_string(),
changed: false,
text_slot,
editing: false,
cursor_entity,
selection_entity,
edit_text: String::new(),
cursor_position: 0,
selection_start: None,
cursor_blink_timer: 0.0,
scroll_offset: 0.0,
drag_start_value: initial,
undo_stack: UndoStack::new(100),
up_entity,
down_entity,
step: step_val,
}),
);
if let Some(interaction) = self.world_mut().ui.get_ui_node_interaction_mut(root_entity) {
interaction.accessible_role = Some(AccessibleRole::Slider);
}
self.assign_tab_index(root_entity);
root_entity
}
}