1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
use crate::{ hash, types::{Rect, Vector2}, widgets::Editbox, Id, Layout, Ui, }; use std::ops::Range; pub struct Slider<'a> { id: Id, label: &'a str, range: Range<f32>, } impl<'a> Slider<'a> { pub fn new(id: Id, range: Range<f32>) -> Slider<'a> { Slider { id, range, label: "", } } pub fn label<'b>(self, label: &'b str) -> Slider<'b> { Slider { id: self.id, range: self.range, label, } } pub fn ui(self, ui: &mut Ui, data: &mut f32) { let context = ui.get_active_window_context(); let size = Vector2::new( context.window.cursor.area.w - context.global_style.margin * 3. - context.window.cursor.ident, 19., ); let pos = context.window.cursor.fit(size, Layout::Vertical); let editbox_width = 50.; let label_width = 100.; let slider_width = size.x - editbox_width - label_width; let margin = 5.; let mut temp_string = context .storage_any .get_or_insert_with::<String, _>(self.id, || format!("{:.2}", *data)) .clone(); let editbox_id = hash!(self.id, "editbox"); if context.window.input_focused(editbox_id) == false { use std::fmt::Write; temp_string.clear(); let _ = write!(&mut temp_string, "{:.2}", *data); } Editbox::new(editbox_id, Vector2::new(50., size.y)) .position(pos) .multiline(false) .filter(&|character| character.is_digit(10) || character == '.' || character == '-') .ui(ui, &mut temp_string); let context = ui.get_active_window_context(); let old_string = context.storage_any.get_or_default::<String>(self.id); if *old_string != temp_string { if let Ok(num) = temp_string.parse::<f32>() { if num > self.range.end { *data = self.range.end; } else if num < self.range.start { *data = self.range.start; } else { *data = num; } } } let dragging = context .storage_u32 .entry(hash!(self.id, "dragging")) .or_insert(0); let slider_start_x = editbox_width + pos.x + margin; let data_pos = (*data - self.range.start) / (self.range.end - self.range.start) * slider_width + slider_start_x; let bar_rect = Rect::new(data_pos - 4., pos.y, 8., 20.); let hovered = bar_rect.contains(context.input.mouse_position); if hovered && context.input.is_mouse_down() { *dragging = 1; context.window.input_focus = Some(self.id); context.input.cursor_grabbed = true; } if *dragging == 1 && context.input.is_mouse_down == false { context.input.cursor_grabbed = false; *dragging = 0; context.window.input_focus = None; } if *dragging == 1 { let mouse_position = ((context.input.mouse_position.x - slider_start_x) / slider_width) .min(1.) .max(0.); let old_data = *data; *data = self.range.start + (self.range.end - self.range.start) * mouse_position; if old_data != *data { use std::fmt::Write; temp_string.clear(); let _ = write!(&mut temp_string, "{:.2}", *data); } } context.window.draw_commands.draw_line( Vector2::new(pos.x + editbox_width + margin, pos.y + size.y / 2.), Vector2::new( pos.x + editbox_width + slider_width + margin, pos.y + size.y / 2., ), context.global_style.text(context.focused), ); context.window.draw_commands.draw_rect( bar_rect, None, context.global_style.slider_bar(context.focused, hovered), ); context.window.draw_commands.draw_label( self.label, Vector2::new( pos.x + editbox_width + slider_width + margin * 2., pos.y + 2., ), context.global_style.text(context.focused), ); *old_string = temp_string; } } impl Ui { pub fn slider(&mut self, id: Id, label: &str, range: Range<f32>, data: &mut f32) { Slider::new(id, range).label(label).ui(self, data) } }