This commit is contained in:
Simon Gardling
2022-11-13 14:14:44 -05:00
parent b0a98b197b
commit 9a8f8a6539
11 changed files with 91 additions and 221 deletions

View File

@@ -1,43 +1,6 @@
#[derive(PartialEq, serde::Serialize, serde::Deserialize)]
pub struct TextData {
pub help_expr: egui::RichText,
pub help_vars: egui::RichText,
pub help_panel: egui::RichText,
pub help_function: egui::RichText,
pub help_other: egui::RichText,
pub welcome: egui::RichText,
}
#[derive(PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct TextDataRaw {
pub help_expr: String,
pub help_vars: String,
pub help_panel: String,
pub help_function: String,
pub help_other: String,
pub welcome: String,
}
pub const FONT_SIZE: f32 = 14.0;
// ui.fonts().crate::data::FONT_SIZE(&egui::FontSelection::default().resolve(ui.style()));
impl TextDataRaw {
#[allow(dead_code)]
fn into_rich(self) -> TextData {
use egui::RichText;
TextData {
help_expr: RichText::from(self.help_expr),
help_vars: RichText::from(self.help_vars),
help_panel: RichText::from(self.help_panel),
help_function: RichText::from(self.help_function),
help_other: RichText::from(self.help_other),
welcome: RichText::from(self.welcome).size(FONT_SIZE + 1.0),
}
}
}
#[derive(serde::Serialize, serde::Deserialize, PartialEq)]
pub struct TotalData {
pub text: TextData,
pub fonts: epaint::text::FontDefinitions,
}

View File

@@ -149,7 +149,7 @@ impl FunctionEntry {
pub const fn is_some(&self) -> bool { !self.function.is_none() }
pub fn settings_window(&mut self, ctx: &mut Context) {
pub fn settings_window(&mut self, ctx: &Context) {
let mut invalidate_nth = false;
egui::Window::new(format!("Settings: {}", self.raw_func_str))
.open(&mut self.settings_opened)
@@ -382,8 +382,8 @@ impl FunctionEntry {
.cloned()
.collect::<Vec<Value>>()
.to_line()
.stroke(const { epaint::Stroke::none() })
.color(const { Color32::from_rgb(4, 4, 255) })
.stroke(epaint::Stroke::none())
.color(Color32::from_rgb(4, 4, 255))
.fill(0.0),
);
}

View File

@@ -19,7 +19,7 @@ impl Default for FunctionManager {
fn default() -> Self {
let mut vec: Functions = Vec::with_capacity(COLORS.len());
vec.push((
Id::new_from_u64(11414819524356497634), // Random number here to avoid call to crate::misc::random_u64()
Id(11414819524356497634), // Random number here to avoid call to crate::misc::random_u64()
FunctionEntry::EMPTY,
));
Self { functions: vec }
@@ -37,7 +37,7 @@ impl Serialize for FunctionManager {
&self
.functions
.iter()
.map(|(id, func)| (id.value(), func.clone()))
.map(|(id, func)| (id.0, func.clone()))
.collect::<Vec<(u64, FunctionEntry)>>(),
)?;
s.end()
@@ -59,16 +59,14 @@ impl<'de> Deserialize<'de> for FunctionManager {
.0
.iter()
.cloned()
.map(|(id, func)| (egui::Id::new_from_u64(id), func))
.map(|(id, func)| (Id(id), func))
.collect::<Vec<(Id, FunctionEntry)>>(),
})
}
}
/// Function that creates button that's used with the `button_area`
const fn button_area_button(text: impl Into<WidgetText>) -> Button {
Button::new(text).frame(false)
}
fn button_area_button(text: impl Into<WidgetText>) -> Button { Button::new(text).frame(false) }
impl FunctionManager {
#[inline]
@@ -94,8 +92,8 @@ impl FunctionManager {
let mut movement: Movement = Movement::default();
let size_multiplier = vec2(1.0, {
let had_focus = ui.ctx.memory().has_focus(*te_id);
(ui.ctx.animate_bool(*te_id, had_focus) * 1.5) + 1.0
let had_focus = ui.ctx().memory().has_focus(*te_id);
(ui.ctx().animate_bool(*te_id, had_focus) * 1.5) + 1.0
});
let re = ui.add_sized(
@@ -117,7 +115,7 @@ impl FunctionManager {
new_string.retain(|c| crate::misc::is_valid_char(&c));
// If not fully open, return here as buttons cannot yet be displayed, therefore the user is inable to mark it for deletion
let animate_bool = ui.ctx.animate_bool(*te_id, re.has_focus());
let animate_bool = ui.ctx().animate_bool(*te_id, re.has_focus());
if animate_bool == 1.0 {
function.autocomplete.update_string(&new_string);
@@ -145,7 +143,7 @@ impl FunctionManager {
// 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 = Id::new_from_u64(7574801616484505465);
const POPUP_ID: Id = Id(7574801616484505465);
let mut clicked = false;
@@ -166,17 +164,17 @@ impl FunctionManager {
movement = Movement::Complete;
} else {
ui.memory_mut().open_popup(POPUP_ID);
ui.memory().open_popup(POPUP_ID);
}
}
// Push cursor to end if needed
if movement == Movement::Complete {
let mut state =
unsafe { TextEdit::load_state(ui.ctx, *te_id).unwrap_unchecked() };
unsafe { TextEdit::load_state(ui.ctx(), *te_id).unwrap_unchecked() };
let ccursor = egui::text::CCursor::new(function.autocomplete.string.len());
state.set_ccursor_range(Some(egui::text::CCursorRange::one(ccursor)));
TextEdit::store_state(ui.ctx, *te_id, state);
TextEdit::store_state(ui.ctx(), *te_id, state);
}
}
@@ -189,7 +187,7 @@ impl FunctionManager {
// There's more than 1 function! Functions can now be deleted
if ui
.add_enabled(can_remove, button_area_button(""))
.on_hover_text(ui.ctx, "Delete Function")
.on_hover_text("Delete Function")
.clicked()
{
remove_i = Some(i);
@@ -199,39 +197,30 @@ impl FunctionManager {
// Toggle integral being enabled or not
function.integral.bitxor_assign(
ui.add(button_area_button(""))
.on_hover_text(
ui.ctx,
match function.integral {
true => "Don't integrate",
false => "Integrate",
},
)
.on_hover_text(match function.integral {
true => "Don't integrate",
false => "Integrate",
})
.clicked(),
);
// Toggle showing the derivative (even though it's already calculated this option just toggles if it's displayed or not)
function.derivative.bitxor_assign(
ui.add(button_area_button("d/dx"))
.on_hover_text(
ui.ctx,
match function.derivative {
true => "Don't Differentiate",
false => "Differentiate",
},
)
.on_hover_text(match function.derivative {
true => "Don't Differentiate",
false => "Differentiate",
})
.clicked(),
);
// Toggle showing the settings window
function.settings_opened.bitxor_assign(
ui.add(button_area_button(""))
.on_hover_text(
ui.ctx,
match function.settings_opened {
true => "Close Settings",
false => "Open Settings",
},
)
.on_hover_text(match function.settings_opened {
true => "Close Settings",
false => "Open Settings",
})
.clicked(),
);
});
@@ -239,7 +228,7 @@ impl FunctionManager {
});
}
function.settings_window(ui.ctx);
function.settings_window(ui.ctx());
}
// Remove function if the user requests it
@@ -255,7 +244,7 @@ impl FunctionManager {
/// Create and push new empty function entry
pub fn push_empty(&mut self) {
self.functions.push((
Id::new_from_u64(random_u64().expect("unable to generate random id")),
Id(random_u64().expect("unable to generate random id")),
FunctionEntry::EMPTY,
));
}

View File

@@ -1,6 +1,5 @@
use crate::{
consts::*, data::TextData, function_entry::Riemann, function_manager::FunctionManager,
misc::option_vec_printer,
consts::*, function_entry::Riemann, function_manager::FunctionManager, misc::option_vec_printer,
};
use eframe::App;
use egui::{
@@ -102,9 +101,6 @@ pub struct MathApp {
/// Stores opened windows/elements for later reference
opened: Opened,
/// Stores loaded text data from `test.json`
text: TextData,
/// Stores settings (pretty self-explanatory)
settings: AppSettings,
}
@@ -128,7 +124,7 @@ const FUNC_NAME: &str = "YTBN-FUNCTIONS";
impl MathApp {
#[allow(dead_code)] // This is used lol
/// Create new instance of [`MathApp`] and return it
pub fn new(cc: &mut eframe::CreationContext<'_, '_>) -> Self {
pub fn new(cc: &eframe::CreationContext<'_>) -> Self {
#[cfg(threading)]
tracing::info!("Threading: Enabled");
@@ -252,10 +248,10 @@ impl MathApp {
cc.egui_ctx.set_fonts(data.fonts);
// Set dark mode by default
cc.egui_ctx.set_visuals(crate::style::STYLE);
cc.egui_ctx.set_visuals(crate::style::style());
// Set spacing
cc.egui_ctx.set_spacing(crate::style::SPACING);
// cc.egui_ctx.set_spacing(crate::style::SPACING);
tracing::info!("Initialized! Took: {:?}", start.elapsed());
@@ -267,14 +263,13 @@ impl MathApp {
functions: FunctionManager::default(),
last_info: (None, None),
text: data.text,
opened: const { Opened::default() },
settings: const { AppSettings::default() },
}
}
/// Creates SidePanel which contains configuration options
fn side_panel(&mut self, ctx: &mut Context) {
fn side_panel(&mut self, ctx: &Context) {
// Side Panel which contains vital options to the operation of the application
// (such as adding functions and other options)
SidePanel::left("side_panel")
@@ -369,25 +364,19 @@ impl MathApp {
ui.horizontal(|ui| {
self.settings.do_extrema.bitxor_assign(
ui.add(Button::new("Extrema"))
.on_hover_text(
ui.ctx,
match self.settings.do_extrema {
true => "Disable Displaying Extrema",
false => "Display Extrema",
},
)
.on_hover_text(match self.settings.do_extrema {
true => "Disable Displaying Extrema",
false => "Display Extrema",
})
.clicked(),
);
self.settings.do_roots.bitxor_assign(
ui.add(Button::new("Roots"))
.on_hover_text(
ui.ctx,
match self.settings.do_roots {
true => "Disable Displaying Roots",
false => "Display Roots",
},
)
.on_hover_text(match self.settings.do_roots {
true => "Disable Displaying Roots",
false => "Display Roots",
})
.clicked(),
);
});
@@ -428,7 +417,7 @@ impl MathApp {
impl App for MathApp {
/// Called each time the UI needs repainting.
fn update(&mut self, ctx: &mut Context, _frame: &mut eframe::Frame) {
fn update(&mut self, ctx: &Context, _frame: &mut eframe::Frame) {
// start timer
let start = if self.opened.info {
Some(instant::Instant::now())
@@ -453,13 +442,10 @@ impl App for MathApp {
// Button in top bar to toggle showing the side panel
self.opened.side_panel.bitxor_assign(
ui.add(Button::new("Panel"))
.on_hover_text(
ui.ctx,
match self.opened.side_panel {
true => "Hide Side Panel",
false => "Show Side Panel",
},
)
.on_hover_text(match self.opened.side_panel {
true => "Hide Side Panel",
false => "Show Side Panel",
})
.clicked(),
);
@@ -469,7 +455,7 @@ impl App for MathApp {
COLORS.len() > self.functions.len(),
Button::new("Add Function"),
)
.on_hover_text(ui.ctx, "Create and graph new function")
.on_hover_text("Create and graph new function")
.clicked()
{
self.functions.push_empty();
@@ -478,26 +464,20 @@ impl App for MathApp {
// Toggles opening the Help window
self.opened.help.bitxor_assign(
ui.add(Button::new("Help"))
.on_hover_text(
ui.ctx,
match self.opened.help {
true => "Close Help Window",
false => "Open Help Window",
},
)
.on_hover_text(match self.opened.help {
true => "Close Help Window",
false => "Open Help Window",
})
.clicked(),
);
// Toggles opening the Info window
self.opened.info.bitxor_assign(
ui.add(Button::new("Info"))
.on_hover_text(
ui.ctx,
match self.opened.info {
true => "Close Info Window",
false => "Open Info Window",
},
)
.on_hover_text(match self.opened.info {
true => "Close Info Window",
false => "Open Info Window",
})
.clicked(),
);
@@ -516,23 +496,23 @@ impl App for MathApp {
.collapsible(false)
.show(ctx, |ui| {
ui.collapsing("Supported Expressions", |ui| {
ui.label(self.text.help_expr.clone());
ui.label("abs, signum, sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, floor, round, ceil, trunc, fract, exp, sqrt, cbrt, ln, log2, log10, log");
});
ui.collapsing("Supported Constants", |ui| {
ui.label(self.text.help_vars.clone());
ui.label("- Euler's number is supported via 'e' or 'E'\n- PI is available through 'pi' or 'π'");
});
ui.collapsing("Panel", |ui| {
ui.label(self.text.help_panel.clone());
ui.label("- The 'Panel' button toggles if the side bar should be shown or not. This can also be accomplished by pressing the 'h' key.\n- The 'Add Function' button adds a new function to be graphed. You can then configure that function in the side panel.\n- The 'Help' button opens and closes this window!\n- The 'Info' button provides information on the build currently running.");
});
ui.collapsing("Functions", |ui| {
ui.label(self.text.help_function.clone());
ui.label("(From Left to Right)\n`✖` allows you to delete the selected function. Deleting a function is prevented if only 1 function exists.\n`∫` toggles integration.\n`d/dx` toggles the calculation of derivatives.\n`⚙` opens a window to tweak function options.");
});
ui.collapsing("Other", |ui| {
ui.label(self.text.help_other.clone());
ui.label("- Extrema (local minimums and maximums) and Roots (intersections with the x-axis) are displayed though yellow and light blue points respectively located on the graph. These can be toggled in the side panel.");
});
});
@@ -544,7 +524,7 @@ impl App for MathApp {
.collapsible(false)
.title_bar(false)
.show(ctx, |ui| {
ui.label(self.text.welcome.clone());
ui.label("Welcome to the (Yet-to-be-named) Graphing Software!\n\nThis project aims to provide an intuitive experience graphing mathematical functions with features such as Integration, Differentiation, Extrema, Roots, and much more! (see the Help Window for more details)");
});
if let Some(response) = welcome_response {
@@ -576,16 +556,12 @@ impl App for MathApp {
// Central panel which contains the central plot (or an error created when parsing)
CentralPanel::default()
.frame(
const {
Frame {
inner_margin: Margin::symmetric(0.0, 0.0),
rounding: Rounding::none(),
fill: crate::style::STYLE.window_fill(),
..Frame::none()
}
},
)
.frame(Frame {
inner_margin: Margin::symmetric(0.0, 0.0),
rounding: Rounding::none(),
// fill: crate::style::STYLE.window_fill(),
..Frame::none()
})
.show(ctx, |ui| {
// Display an error if it exists
let errors_formatted: String = self
@@ -663,8 +639,4 @@ impl App for MathApp {
// Calculate and store the last time it took to draw the frame
self.last_info.1 = start.map(|a| format!("Took: {}ms", a.elapsed().as_micros()));
}
fn clear_color(&self, _visuals: &egui::Visuals) -> egui::Rgba {
crate::style::STYLE.window_fill().into()
}
}

View File

@@ -17,7 +17,7 @@ pub trait EguiHelper {
fn to_tuple(self) -> Vec<(f64, f64)>;
}
impl const EguiHelper for Vec<Value> {
impl EguiHelper for Vec<Value> {
#[inline(always)]
fn to_values(self) -> Values { Values::from_values(self) }

View File

@@ -5,7 +5,7 @@ use egui::{
use emath::vec2;
use epaint::{Color32, Rounding, Shadow, Stroke};
const fn widgets_dark() -> Widgets {
fn widgets_dark() -> Widgets {
Widgets {
noninteractive: WidgetVisuals {
bg_fill: Color32::from_gray(27), // window background
@@ -45,10 +45,7 @@ const fn widgets_dark() -> Widgets {
}
}
pub const STYLE: Visuals = dark();
pub const SPACING: Spacing = spacing();
const fn dark() -> Visuals {
pub fn style() -> Visuals {
Visuals {
dark_mode: true,
override_text_color: None,
@@ -70,7 +67,7 @@ const fn dark() -> Visuals {
}
}
const fn spacing() -> Spacing {
pub fn spacing() -> Spacing {
Spacing {
item_spacing: vec2(8.0, 3.0),
window_margin: Margin::same(6.0),

View File

@@ -7,8 +7,8 @@ pub fn widgets_ontop<R>(
add_contents: impl FnOnce(&mut egui::Ui) -> R,
) -> InnerResponse<R> {
let area = egui::Area::new(id)
.fixed_pos(re.rect().min.offset_y(y_offset))
.fixed_pos(re.rect.min.offset_y(y_offset))
.order(egui::Order::Foreground);
area.show(ui.ctx, |ui| add_contents(ui))
area.show(ui.ctx(), |ui| add_contents(ui))
}