Add colors to register view
This commit is contained in:
+104
-31
@@ -1,9 +1,10 @@
|
||||
use std::{
|
||||
fmt::Display,
|
||||
fmt::{Display, UpperHex},
|
||||
ops::{Bound, RangeBounds},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use atoi::FromRadix16;
|
||||
use egui::{
|
||||
ecolor::HexColor, Align, Color32, CursorIcon, Event, Frame, Key, Layout, Margin, Rect,
|
||||
Response, RichText, Rounding, Sense, Shape, Stroke, TextEdit, Ui, UiBuilder, Vec2, Widget,
|
||||
@@ -38,7 +39,12 @@ impl UiExt for Ui {
|
||||
let mut frame = Frame::group(self.style());
|
||||
frame.outer_margin.top += 10.0;
|
||||
frame.inner_margin.top += 2.0;
|
||||
let res = self.push_id(&title, |ui| frame.show(ui, add_contents));
|
||||
let res = self.push_id(&title, |ui| {
|
||||
frame.show(ui, |ui| {
|
||||
ui.set_min_width(ui.available_width());
|
||||
add_contents(ui);
|
||||
})
|
||||
});
|
||||
let text = RichText::new(title).background_color(self.style().visuals.panel_fill);
|
||||
let old_rect = res.response.rect;
|
||||
let mut text_rect = old_rect;
|
||||
@@ -98,11 +104,35 @@ enum Direction {
|
||||
}
|
||||
|
||||
pub trait Number:
|
||||
Copy + One + CheckedAdd + CheckedSub + Eq + Ord + Display + FromStr + Send + Sync + 'static
|
||||
Copy
|
||||
+ One
|
||||
+ CheckedAdd
|
||||
+ CheckedSub
|
||||
+ Eq
|
||||
+ Ord
|
||||
+ Display
|
||||
+ FromStr
|
||||
+ FromRadix16
|
||||
+ UpperHex
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static
|
||||
{
|
||||
}
|
||||
impl<
|
||||
T: Copy + One + CheckedAdd + CheckedSub + Eq + Ord + Display + FromStr + Send + Sync + 'static,
|
||||
T: Copy
|
||||
+ One
|
||||
+ CheckedAdd
|
||||
+ CheckedSub
|
||||
+ Eq
|
||||
+ Ord
|
||||
+ Display
|
||||
+ FromStr
|
||||
+ FromRadix16
|
||||
+ UpperHex
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
> Number for T
|
||||
{
|
||||
}
|
||||
@@ -113,6 +143,8 @@ pub struct NumberEdit<'a, T: Number> {
|
||||
precision: usize,
|
||||
min: Option<T>,
|
||||
max: Option<T>,
|
||||
arrows: bool,
|
||||
hex: bool,
|
||||
}
|
||||
|
||||
impl<'a, T: Number> NumberEdit<'a, T> {
|
||||
@@ -123,6 +155,8 @@ impl<'a, T: Number> NumberEdit<'a, T> {
|
||||
precision: 3,
|
||||
min: None,
|
||||
max: None,
|
||||
arrows: true,
|
||||
hex: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,12 +177,35 @@ impl<'a, T: Number> NumberEdit<'a, T> {
|
||||
};
|
||||
Self { min, max, ..self }
|
||||
}
|
||||
|
||||
pub fn arrows(self, arrows: bool) -> Self {
|
||||
Self { arrows, ..self }
|
||||
}
|
||||
|
||||
pub fn hex(self, hex: bool) -> Self {
|
||||
Self { hex, ..self }
|
||||
}
|
||||
}
|
||||
|
||||
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 to_string = |val: &T| {
|
||||
if self.hex {
|
||||
format!("{val:.0$X}", self.precision)
|
||||
} else {
|
||||
format!("{val:.0$}", self.precision)
|
||||
}
|
||||
};
|
||||
let from_string = |val: &str| {
|
||||
if self.hex {
|
||||
let bytes = val.as_bytes();
|
||||
let (result, consumed) = T::from_radix_16(bytes);
|
||||
(consumed == bytes.len()).then_some(result)
|
||||
} else {
|
||||
val.parse::<T>().ok()
|
||||
}
|
||||
};
|
||||
|
||||
let (last_value, mut str, focus) = ui.memory(|m| {
|
||||
let (lv, s) = m
|
||||
@@ -163,7 +220,7 @@ impl<T: Number> Widget for NumberEdit<'_, T> {
|
||||
str = to_string(self.value);
|
||||
stale = true;
|
||||
}
|
||||
let valid = str.parse().is_ok_and(|v: T| v == *self.value);
|
||||
let valid = from_string(&str).is_some_and(|v: T| v == *self.value);
|
||||
let mut up_pressed = false;
|
||||
let mut down_pressed = false;
|
||||
if focus {
|
||||
@@ -194,17 +251,25 @@ impl<T: Number> Widget for NumberEdit<'_, T> {
|
||||
.id(id)
|
||||
.margin(Margin {
|
||||
left: 4.0,
|
||||
right: 20.0,
|
||||
right: if self.arrows { 20.0 } else { 4.0 },
|
||||
top: 2.0,
|
||||
bottom: 2.0,
|
||||
});
|
||||
let res = if valid {
|
||||
let mut res = if valid {
|
||||
ui.add(text)
|
||||
} else {
|
||||
let message = match (self.min, self.max) {
|
||||
(Some(min), Some(max)) => format!("Please enter a number between {min} and {max}."),
|
||||
(Some(min), None) => format!("Please enter a number greater than {min}."),
|
||||
(None, Some(max)) => format!("Please enter a number less than {max}."),
|
||||
(Some(min), Some(max)) => format!(
|
||||
"Please enter a number between {} and {}.",
|
||||
to_string(&min),
|
||||
to_string(&max)
|
||||
),
|
||||
(Some(min), None) => {
|
||||
format!("Please enter a number greater than {}.", to_string(&min))
|
||||
}
|
||||
(None, Some(max)) => {
|
||||
format!("Please enter a number less than {}.", to_string(&max))
|
||||
}
|
||||
(None, None) => "Please enter a number.".to_string(),
|
||||
};
|
||||
ui.scope(|ui| {
|
||||
@@ -218,26 +283,28 @@ impl<T: Number> Widget for NumberEdit<'_, T> {
|
||||
.on_hover_text(message)
|
||||
};
|
||||
|
||||
let arrow_left = res.rect.max.x + 4.0;
|
||||
let arrow_right = res.rect.max.x + 20.0;
|
||||
let arrow_top = res.rect.min.y - 2.0;
|
||||
let arrow_middle = (res.rect.min.y + res.rect.max.y) / 2.0;
|
||||
let arrow_bottom = res.rect.max.y + 2.0;
|
||||
|
||||
let mut delta = None;
|
||||
let top_arrow_rect = Rect {
|
||||
min: (arrow_left, arrow_top).into(),
|
||||
max: (arrow_right, arrow_middle).into(),
|
||||
};
|
||||
if draw_arrow(ui, top_arrow_rect, true).clicked_or_dragged() || up_pressed {
|
||||
delta = Some(Direction::Up);
|
||||
}
|
||||
let bottom_arrow_rect = Rect {
|
||||
min: (arrow_left, arrow_middle).into(),
|
||||
max: (arrow_right, arrow_bottom).into(),
|
||||
};
|
||||
if draw_arrow(ui, bottom_arrow_rect, false).clicked_or_dragged() || down_pressed {
|
||||
delta = Some(Direction::Down);
|
||||
if self.arrows {
|
||||
let arrow_left = res.rect.max.x + 4.0;
|
||||
let arrow_right = res.rect.max.x + 20.0;
|
||||
let arrow_top = res.rect.min.y - 2.0;
|
||||
let arrow_middle = (res.rect.min.y + res.rect.max.y) / 2.0;
|
||||
let arrow_bottom = res.rect.max.y + 2.0;
|
||||
|
||||
let top_arrow_rect = Rect {
|
||||
min: (arrow_left, arrow_top).into(),
|
||||
max: (arrow_right, arrow_middle).into(),
|
||||
};
|
||||
if draw_arrow(ui, top_arrow_rect, true).clicked_or_dragged() || up_pressed {
|
||||
delta = Some(Direction::Up);
|
||||
}
|
||||
let bottom_arrow_rect = Rect {
|
||||
min: (arrow_left, arrow_middle).into(),
|
||||
max: (arrow_right, arrow_bottom).into(),
|
||||
};
|
||||
if draw_arrow(ui, bottom_arrow_rect, false).clicked_or_dragged() || down_pressed {
|
||||
delta = Some(Direction::Down);
|
||||
}
|
||||
}
|
||||
|
||||
let in_range =
|
||||
@@ -248,12 +315,18 @@ impl<T: Number> Widget for NumberEdit<'_, T> {
|
||||
Direction::Down => self.value.checked_sub(&self.increment),
|
||||
};
|
||||
if let Some(new_value) = value.filter(in_range) {
|
||||
if *self.value != new_value {
|
||||
res.mark_changed();
|
||||
}
|
||||
*self.value = new_value;
|
||||
}
|
||||
str = to_string(self.value);
|
||||
stale = true;
|
||||
} else if res.changed {
|
||||
if let Some(new_value) = str.parse().ok().filter(in_range) {
|
||||
if let Some(new_value) = from_string(&str).filter(in_range) {
|
||||
if *self.value != new_value {
|
||||
res.mark_changed();
|
||||
}
|
||||
*self.value = new_value;
|
||||
}
|
||||
stale = true;
|
||||
|
||||
Reference in New Issue
Block a user