View affine worlds
This commit is contained in:
+20
-6
@@ -9,7 +9,7 @@ use egui::{
|
||||
Response, RichText, Rounding, Sense, Shape, Stroke, TextEdit, Ui, UiBuilder, Vec2, Widget,
|
||||
WidgetText,
|
||||
};
|
||||
use num_traits::PrimInt;
|
||||
use num_traits::{CheckedAdd, CheckedSub, One};
|
||||
|
||||
pub trait UiExt {
|
||||
fn section(&mut self, title: impl Into<String>, add_contents: impl FnOnce(&mut Ui));
|
||||
@@ -97,12 +97,20 @@ enum Direction {
|
||||
Down,
|
||||
}
|
||||
|
||||
pub trait Number: PrimInt + Display + FromStr + Send + Sync + 'static {}
|
||||
impl<T: PrimInt + Display + FromStr + Send + Sync + 'static> Number for T {}
|
||||
pub trait Number:
|
||||
Copy + One + CheckedAdd + CheckedSub + Eq + Ord + Display + FromStr + Send + Sync + 'static
|
||||
{
|
||||
}
|
||||
impl<
|
||||
T: Copy + One + CheckedAdd + CheckedSub + Eq + Ord + Display + FromStr + Send + Sync + 'static,
|
||||
> Number for T
|
||||
{
|
||||
}
|
||||
|
||||
pub struct NumberEdit<'a, T: Number> {
|
||||
value: &'a mut T,
|
||||
increment: T,
|
||||
precision: usize,
|
||||
min: Option<T>,
|
||||
max: Option<T>,
|
||||
}
|
||||
@@ -112,11 +120,16 @@ impl<'a, T: Number> NumberEdit<'a, T> {
|
||||
Self {
|
||||
value,
|
||||
increment: T::one(),
|
||||
precision: 3,
|
||||
min: None,
|
||||
max: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn precision(self, precision: usize) -> Self {
|
||||
Self { precision, ..self }
|
||||
}
|
||||
|
||||
pub fn range(self, range: impl RangeBounds<T>) -> Self {
|
||||
let min = match range.start_bound() {
|
||||
Bound::Unbounded => None,
|
||||
@@ -135,18 +148,19 @@ impl<'a, T: Number> NumberEdit<'a, T> {
|
||||
impl<T: Number> Widget for NumberEdit<'_, T> {
|
||||
fn ui(self, ui: &mut Ui) -> Response {
|
||||
let id = ui.id();
|
||||
let to_string = |val: &T| format!("{val:.0$}", self.precision);
|
||||
|
||||
let (last_value, mut str, focus) = ui.memory(|m| {
|
||||
let (lv, s) = m
|
||||
.data
|
||||
.get_temp(id)
|
||||
.unwrap_or((*self.value, self.value.to_string()));
|
||||
.unwrap_or((*self.value, to_string(self.value)));
|
||||
let focus = m.has_focus(id);
|
||||
(lv, s, focus)
|
||||
});
|
||||
let mut stale = false;
|
||||
if *self.value != last_value {
|
||||
str = self.value.to_string();
|
||||
str = to_string(self.value);
|
||||
stale = true;
|
||||
}
|
||||
let valid = str.parse().is_ok_and(|v: T| v == *self.value);
|
||||
@@ -236,7 +250,7 @@ impl<T: Number> Widget for NumberEdit<'_, T> {
|
||||
if let Some(new_value) = value.filter(in_range) {
|
||||
*self.value = new_value;
|
||||
}
|
||||
str = self.value.to_string();
|
||||
str = to_string(self.value);
|
||||
stale = true;
|
||||
} else if res.changed {
|
||||
if let Some(new_value) = str.parse().ok().filter(in_range) {
|
||||
|
||||
Reference in New Issue
Block a user