VIP inspection tooling #4

Merged
SonicSwordcane merged 34 commits from vram into main 2025-02-24 04:01:18 +00:00
2 changed files with 67 additions and 18 deletions
Showing only changes of commit b5e1711a56 - Show all commits

View File

@ -1,10 +1,15 @@
use std::ops::{Bound, RangeBounds};
use std::{
fmt::Display,
ops::{Bound, RangeBounds},
str::FromStr,
};
use egui::{
ecolor::HexColor, Align, Color32, CursorIcon, Event, Frame, Key, Layout, Margin, Rect,
Response, RichText, Rounding, Sense, Shape, Stroke, TextEdit, Ui, UiBuilder, Vec2, Widget,
WidgetText,
};
use num_traits::PrimInt;
pub trait UiExt {
fn section(&mut self, title: impl Into<String>, add_contents: impl FnOnce(&mut Ui));
@ -86,37 +91,47 @@ impl UiExt for Ui {
}
}
pub struct NumberEdit<'a> {
value: &'a mut usize,
min: Option<usize>,
max: Option<usize>,
enum Direction {
Up,
Down,
}
impl<'a> NumberEdit<'a> {
pub fn new(value: &'a mut usize) -> Self {
pub trait Number: PrimInt + Display + FromStr + Send + Sync + 'static {}
impl<T: PrimInt + Display + FromStr + Send + Sync + 'static> Number for T {}
pub struct NumberEdit<'a, T: Number> {
value: &'a mut T,
increment: T,
min: Option<T>,
max: Option<T>,
}
impl<'a, T: Number> NumberEdit<'a, T> {
pub fn new(value: &'a mut T) -> Self {
Self {
value,
increment: T::one(),
min: None,
max: None,
}
}
pub fn range(self, range: impl RangeBounds<usize>) -> Self {
pub fn range(self, range: impl RangeBounds<T>) -> Self {
let min = match range.start_bound() {
Bound::Unbounded => None,
Bound::Included(t) => Some(*t),
Bound::Excluded(t) => t.checked_add(1),
Bound::Excluded(t) => t.checked_add(&self.increment),
};
let max = match range.end_bound() {
Bound::Unbounded => None,
Bound::Included(t) => Some(*t),
Bound::Excluded(t) => t.checked_sub(1),
Bound::Excluded(t) => t.checked_sub(&self.increment),
};
Self { min, max, ..self }
}
}
impl Widget for NumberEdit<'_> {
impl<T: Number> Widget for NumberEdit<'_, T> {
fn ui(self, ui: &mut Ui) -> Response {
let (last_value, mut str, focus) = ui.memory(|m| {
let (lv, s) = m
@ -131,7 +146,7 @@ impl Widget for NumberEdit<'_> {
str = self.value.to_string();
stale = true;
}
let valid = str.parse().is_ok_and(|v: usize| v == *self.value);
let valid = str.parse().is_ok_and(|v: T| v == *self.value);
let mut up_pressed = false;
let mut down_pressed = false;
if focus {
@ -192,26 +207,30 @@ impl Widget for NumberEdit<'_> {
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 = 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 = 1;
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 = -1;
delta = Some(Direction::Down);
}
let in_range =
|&val: &usize| self.min.is_none_or(|m| m <= val) && self.max.is_none_or(|m| m >= val);
if delta != 0 {
if let Some(new_value) = self.value.checked_add_signed(delta).filter(in_range) {
|val: &T| self.min.is_none_or(|m| &m <= val) && self.max.is_none_or(|m| &m >= val);
if let Some(dir) = delta {
let value = match dir {
Direction::Up => self.value.checked_add(&self.increment),
Direction::Down => self.value.checked_sub(&self.increment),
};
if let Some(new_value) = value.filter(in_range) {
*self.value = new_value;
}
str = self.value.to_string();

View File

@ -62,6 +62,9 @@ impl ObjectWindow {
});
ui.section("Properties", |ui| {
let object = self.objects.borrow().read::<[u16; 4]>(self.index);
let mut x = ((object[0] & 0x3ff) << 6 >> 6) as i16;
let mut parallax = ((object[1] & 0x3ff) << 6 >> 6) as i16;
let mut y = ((object[2] & 0x0ff) << 8 >> 8) as i16;
let (mut char_index, mut vflip, mut hflip, palette_index) =
utils::parse_cell(object[3]);
TableBuilder::new(ui)
@ -91,6 +94,33 @@ impl ObjectWindow {
);
});
});
body.row(row_height, |mut row| {
row.col(|ui| {
ui.label("X");
});
row.col(|ui| {
ui.add_enabled(false, NumberEdit::new(&mut x).range(-512..512));
});
});
body.row(row_height, |mut row| {
row.col(|ui| {
ui.label("Y");
});
row.col(|ui| {
ui.add_enabled(false, NumberEdit::new(&mut y).range(-8..=224));
});
});
body.row(row_height, |mut row| {
row.col(|ui| {
ui.label("Parallax");
});
row.col(|ui| {
ui.add_enabled(
false,
NumberEdit::new(&mut parallax).range(-512..512),
);
});
});
body.row(row_height, |mut row| {
row.col(|ui| {
let checkbox = Checkbox::new(&mut hflip, "H-flip");