don't do sketchy egui Id stuff

This commit is contained in:
Simon Gardling 2025-12-03 03:42:51 -05:00
parent 5e01e1762f
commit 75092e7d9f
Signed by: titaniumtown
GPG Key ID: 9AB28AC10ECE533D
2 changed files with 44 additions and 52 deletions

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
consts::COLORS, consts::COLORS,
function_entry::FunctionEntry, function_entry::FunctionEntry,
misc::{create_id, get_u64_id, random_u64}, misc::{random_u64},
widgets::widgets_ontop, widgets::widgets_ontop,
}; };
use egui::{Button, Id, Key, Modifiers, TextEdit, WidgetText}; use egui::{Button, Id, Key, Modifiers, TextEdit, WidgetText};
@ -22,50 +22,46 @@ impl Default for FunctionManager {
fn default() -> Self { fn default() -> Self {
let mut vec: Functions = Vec::with_capacity(COLORS.len()); let mut vec: Functions = Vec::with_capacity(COLORS.len());
vec.push(( vec.push((
create_id(11414819524356497634), // Random number here to avoid call to crate::misc::random_u64() Id::new(11414819524356497634 as u64), // Random number here to avoid call to crate::misc::random_u64()
FunctionEntry::default(), FunctionEntry::default(),
)); ));
Self { functions: vec } Self { functions: vec }
} }
} }
impl Serialize for FunctionManager { impl Serialize for FunctionManager {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
S: Serializer, S: Serializer,
{ {
let mut s = serializer.serialize_struct("FunctionManager", 1)?; let mut s = serializer.serialize_struct("FunctionManager", 1)?;
s.serialize_field( s.serialize_field(
"data", "data",
&self &self
.functions .functions
.iter() .iter()
.map(|(id, func)| (get_u64_id(*id), func.clone())) .map(|(id, func)| (*id, func.clone()))
.collect::<Vec<(u64, FunctionEntry)>>(), .collect::<Vec<(Id, FunctionEntry)>>(),
)?; )?;
s.end() s.end()
} }
} }
impl<'de> Deserialize<'de> for FunctionManager { impl<'de> Deserialize<'de> for FunctionManager {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
#[derive(Deserialize)] #[derive(Deserialize)]
struct Helper(Vec<(u64, FunctionEntry)>); struct Helper(Vec<(Id, FunctionEntry)>);
let helper = Helper::deserialize(deserializer)?; let helper = Helper::deserialize(deserializer)?;
Ok(FunctionManager { Ok(FunctionManager {
functions: helper functions: helper.0.to_vec(),
.0 })
.iter() }
.cloned()
.map(|(id, func)| (create_id(id), func))
.collect::<Vec<(Id, FunctionEntry)>>(),
})
}
} }
/// Function that creates button that's used with the `button_area` /// Function that creates button that's used with the `button_area`
@ -151,14 +147,11 @@ impl FunctionManager {
if movement != Movement::Complete if movement != Movement::Complete
&& let Some(hints) = function.autocomplete.hint.many() && let Some(hints) = function.autocomplete.hint.many()
{ {
// Doesn't need to have a number in id as there should only be 1 autocomplete popup in the entire gui
// hashed "autocomplete_popup"
const POPUP_ID: Id = create_id(7574801616484505465);
let mut clicked = false; let mut clicked = false;
egui::popup_below_widget(ui, POPUP_ID, &re, |ui| { let autocomplete_popup_id = Id::new("autocomplete popup");
egui::popup_below_widget(ui, autocomplete_popup_id.clone(), &re, |ui| {
hints.iter().enumerate().for_each(|(i, candidate)| { hints.iter().enumerate().for_each(|(i, candidate)| {
if ui if ui
.selectable_label(i == function.autocomplete.i, *candidate) .selectable_label(i == function.autocomplete.i, *candidate)
@ -175,12 +168,9 @@ impl FunctionManager {
.autocomplete .autocomplete
.apply_hint(hints[function.autocomplete.i]); .apply_hint(hints[function.autocomplete.i]);
// Don't need this here as it simply won't be display next frame
// ui.memory_mut().close_popup();
movement = Movement::Complete; movement = Movement::Complete;
} else { } else {
ui.memory_mut(|x| x.open_popup(POPUP_ID)); ui.memory_mut(|x| x.open_popup(autocomplete_popup_id.clone()));
} }
} }
@ -198,7 +188,7 @@ impl FunctionManager {
const BUTTONS_Y_OFFSET: f32 = 1.32; const BUTTONS_Y_OFFSET: f32 = 1.32;
const Y_OFFSET: f32 = crate::consts::FONT_SIZE * BUTTONS_Y_OFFSET; const Y_OFFSET: f32 = crate::consts::FONT_SIZE * BUTTONS_Y_OFFSET;
widgets_ontop(ui, create_id(i as u64), &re, Y_OFFSET, |ui| { widgets_ontop(ui, Id::new(i), &re, Y_OFFSET, |ui| {
ui.horizontal(|ui| { ui.horizontal(|ui| {
// There's more than 1 function! Functions can now be deleted // There's more than 1 function! Functions can now be deleted
if ui if ui
@ -260,7 +250,7 @@ impl FunctionManager {
/// Create and push new empty function entry /// Create and push new empty function entry
pub fn push_empty(&mut self) { pub fn push_empty(&mut self) {
self.functions.push(( self.functions.push((
create_id(random_u64().expect("unable to generate random id")), Id::new(random_u64().expect("unable to generate random id")),
FunctionEntry::default(), FunctionEntry::default(),
)); ));
} }
@ -273,6 +263,7 @@ impl FunctionManager {
#[inline] #[inline]
pub fn len(&self) -> usize { self.functions.len() } pub fn len(&self) -> usize { self.functions.len() }
#[inline] #[inline]
pub fn get_entries_mut(&mut self) -> &mut Functions { &mut self.functions } pub fn get_entries_mut(&mut self) -> &mut Functions { &mut self.functions }

View File

@ -1,4 +1,3 @@
use egui::Id;
use egui_plot::{Line, PlotPoint, PlotPoints, Points}; use egui_plot::{Line, PlotPoint, PlotPoints, Points};
use emath::Pos2; use emath::Pos2;
use getrandom::getrandom; use getrandom::getrandom;
@ -27,10 +26,14 @@ impl EguiHelper for Vec<PlotPoint> {
} }
#[inline(always)] #[inline(always)]
fn to_line(self) -> Line { Line::new(self.to_values()) } fn to_line(self) -> Line {
Line::new(self.to_values())
}
#[inline(always)] #[inline(always)]
fn to_points(self) -> Points { Points::new(self.to_values()) } fn to_points(self) -> Points {
Points::new(self.to_values())
}
#[inline(always)] #[inline(always)]
fn to_tuple(self) -> Vec<(f64, f64)> { fn to_tuple(self) -> Vec<(f64, f64)> {
@ -59,10 +62,6 @@ impl const Offset for Pos2 {
} }
} }
pub const fn create_id(x: u64) -> Id { unsafe { std::mem::transmute::<u64, Id>(x) } }
pub const fn get_u64_id(id: Id) -> u64 { unsafe { std::mem::transmute::<Id, u64>(id) } }
/* /*
/// Rounds f64 to `n` decimal places /// Rounds f64 to `n` decimal places
pub fn decimal_round(x: f64, n: usize) -> f64 { pub fn decimal_round(x: f64, n: usize) -> f64 {
@ -198,4 +197,6 @@ pub fn random_u64() -> Result<u64, getrandom::Error> {
include!(concat!(env!("OUT_DIR"), "/valid_chars.rs")); include!(concat!(env!("OUT_DIR"), "/valid_chars.rs"));
pub fn is_valid_char(c: char) -> bool { c.is_alphanumeric() | VALID_EXTRA_CHARS.contains(&c) } pub fn is_valid_char(c: char) -> bool {
c.is_alphanumeric() | VALID_EXTRA_CHARS.contains(&c)
}