it works!!
This commit is contained in:
18
src/data.rs
Normal file
18
src/data.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(PartialEq, Debug, Serialize, Deserialize)]
|
||||
pub struct TextData {
|
||||
pub help_expr: String,
|
||||
pub help_vars: String,
|
||||
pub help_panel: String,
|
||||
pub help_function: String,
|
||||
pub help_other: String,
|
||||
pub license_info: String,
|
||||
pub welcome: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct TotalData {
|
||||
pub text: TextData,
|
||||
pub fonts: epaint::text::FontDefinitions,
|
||||
}
|
||||
@@ -32,7 +32,7 @@ impl FunctionManager {
|
||||
// ui.label("Functions:");
|
||||
let can_remove = self.functions.len() > 1;
|
||||
|
||||
// update if font settings are ever changed
|
||||
// Update if font settings are ever changed
|
||||
const ROW_HEIGHT: f32 = 14.0;
|
||||
// ui.fonts().row_height(&egui::FontSelection::default().resolve(ui.style()));
|
||||
|
||||
@@ -55,9 +55,9 @@ impl FunctionManager {
|
||||
egui::TextEdit::singleline(&mut new_string)
|
||||
.hint_forward(true) // Make the hint appear after the last text in the textbox
|
||||
.lock_focus(true)
|
||||
.id(*te_id) // set widget's id to `te_id`
|
||||
.id(*te_id) // Set widget's id to `te_id`
|
||||
.hint_text({
|
||||
// if there's a single hint, go ahead and apply the hint here, if not, set the hint to an empty string
|
||||
// If there's a single hint, go ahead and apply the hint here, if not, set the hint to an empty string
|
||||
if let Hint::Single(single_hint) = function.autocomplete.hint {
|
||||
*single_hint
|
||||
} else {
|
||||
@@ -66,7 +66,7 @@ impl FunctionManager {
|
||||
}),
|
||||
);
|
||||
|
||||
// if not fully open, return here as buttons cannot yet be displayed, therefore the user is inable to mark it for deletion
|
||||
// If not fully open, return here as buttons cannot yet be displayed, therefore the user is inable to mark it for deletion
|
||||
if ui.ctx().animate_bool(*te_id, re.has_focus()) >= 1.0 {
|
||||
function.autocomplete.update_string(&new_string);
|
||||
|
||||
@@ -110,7 +110,7 @@ impl FunctionManager {
|
||||
if clicked {
|
||||
function.autocomplete.apply_hint(hints[function.autocomplete.i]);
|
||||
|
||||
// don't need this here as it simply won't be display next frame
|
||||
// Don't need this here as it simply won't be display next frame
|
||||
// ui.memory().close_popup();
|
||||
|
||||
movement = Movement::Complete;
|
||||
@@ -190,11 +190,13 @@ impl FunctionManager {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create and push new empty function entry
|
||||
pub fn push_empty(&mut self) {
|
||||
self.functions
|
||||
.push((Id::new(Uuid::new_v4()), FunctionEntry::EMPTY));
|
||||
}
|
||||
|
||||
/// Detect if any functions are using integrals
|
||||
pub fn any_using_integral(&self) -> bool {
|
||||
self.functions.iter().any(|(_, func)| func.integral)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ extern crate static_assertions;
|
||||
extern crate uuid;
|
||||
|
||||
mod consts;
|
||||
mod data;
|
||||
mod function_entry;
|
||||
mod function_manager;
|
||||
mod math_app;
|
||||
|
||||
@@ -11,6 +11,7 @@ extern crate static_assertions;
|
||||
extern crate uuid;
|
||||
|
||||
mod consts;
|
||||
mod data;
|
||||
mod function_entry;
|
||||
mod function_manager;
|
||||
mod math_app;
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
use crate::consts::*;
|
||||
use crate::data::TextData;
|
||||
use crate::function_entry::Riemann;
|
||||
use crate::function_manager::FunctionManager;
|
||||
use crate::misc::{dyn_mut_iter, option_vec_printer, TextData};
|
||||
use crate::misc::{dyn_mut_iter, option_vec_printer};
|
||||
use eframe::App;
|
||||
use egui::{
|
||||
plot::Plot, style::Margin, vec2, Button, CentralPanel, Color32, ComboBox, Context,
|
||||
FontDefinitions, Frame, Key, Label, Layout, RichText, SidePanel, Slider, TopBottomPanel, Vec2,
|
||||
Visuals, Window,
|
||||
plot::Plot, style::Margin, vec2, Button, CentralPanel, Color32, ComboBox, Context, Frame, Key,
|
||||
Label, Layout, RichText, SidePanel, Slider, TopBottomPanel, Vec2, Visuals, Window,
|
||||
};
|
||||
use emath::{Align, Align2};
|
||||
use epaint::Rounding;
|
||||
use instant::Duration;
|
||||
use std::{io::Read, ops::BitXorAssign, str};
|
||||
use std::{io::Read, ops::BitXorAssign};
|
||||
|
||||
#[cfg(threading)]
|
||||
use rayon::iter::{IndexedParallelIterator, ParallelIterator};
|
||||
@@ -142,55 +142,24 @@ impl MathApp {
|
||||
tracing::info!("Initializing...");
|
||||
let start = instant::Instant::now();
|
||||
|
||||
let mut tar_file_data = Vec::new();
|
||||
let mut data = Vec::new();
|
||||
let _ = unsafe {
|
||||
ruzstd::StreamingDecoder::new(&mut include_bytes!("../assets.tar.zst").as_slice())
|
||||
ruzstd::StreamingDecoder::new(&mut include_bytes!("../assets/data").as_slice())
|
||||
.unwrap_unchecked()
|
||||
.read_to_end(&mut tar_file_data)
|
||||
.read_to_end(&mut data)
|
||||
.unwrap_unchecked()
|
||||
};
|
||||
|
||||
let data: crate::data::TotalData = bincode::deserialize(data.as_slice()).unwrap();
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
update_loading(&loading_element, 30);
|
||||
|
||||
// Stores fonts
|
||||
let mut font_data: Option<FontDefinitions> = None;
|
||||
|
||||
// Stores text
|
||||
let mut text_data: Option<TextData> = None;
|
||||
|
||||
tracing::info!("Reading assets...");
|
||||
|
||||
// Iterate through all entries in the tarball
|
||||
for file in unsafe {
|
||||
tar::Archive::new(&*tar_file_data)
|
||||
.entries()
|
||||
.unwrap_unchecked()
|
||||
} {
|
||||
let mut file = unsafe { file.unwrap_unchecked() };
|
||||
let mut data: Vec<u8> = Vec::new();
|
||||
unsafe { file.read_to_end(&mut data).unwrap_unchecked() };
|
||||
let path = unsafe { file.header().path().unwrap_unchecked() };
|
||||
let path_string = path.to_string_lossy();
|
||||
|
||||
// Match the file extention
|
||||
if path_string.ends_with("font_data") {
|
||||
font_data = Some(bincode::deserialize(&data).unwrap());
|
||||
} else if path_string.ends_with("text.json") {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
update_loading(&loading_element, 10);
|
||||
text_data = Some(TextData::from_json_str(unsafe {
|
||||
str::from_utf8(&data).unwrap_unchecked()
|
||||
}));
|
||||
} else {
|
||||
panic!("File {} not expected!", path_string);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize fonts
|
||||
// This used to be in the `update` method, but (after a ton of digging) this actually caused OOMs. that was a pain to debug
|
||||
cc.egui_ctx
|
||||
.set_fonts(font_data.expect("Failed to load font_data"));
|
||||
cc.egui_ctx.set_fonts(data.fonts);
|
||||
|
||||
// Set dark mode by default
|
||||
cc.egui_ctx.set_visuals(Visuals::dark());
|
||||
@@ -208,7 +177,7 @@ impl MathApp {
|
||||
functions: Default::default(),
|
||||
last_info: (vec![None], None),
|
||||
dark_mode: true, // dark mode is default and is previously set
|
||||
text: text_data.expect("Didn't find text.json"),
|
||||
text: data.text,
|
||||
opened: Opened::default(),
|
||||
settings: Default::default(),
|
||||
}
|
||||
|
||||
45
src/misc.rs
45
src/misc.rs
@@ -1,6 +1,5 @@
|
||||
use eframe::egui::plot::{Line, Points, Value as EguiValue, Values};
|
||||
use itertools::Itertools;
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
#[cfg(threading)]
|
||||
use rayon::prelude::*;
|
||||
@@ -185,50 +184,6 @@ impl EguiHelper for Vec<EguiValue> {
|
||||
fn to_tuple(&self) -> Vec<(f64, f64)> { self.iter().map(|ele| (ele.x, ele.y)).collect() }
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct TextData {
|
||||
pub help_expr: String,
|
||||
pub help_vars: String,
|
||||
pub help_panel: String,
|
||||
pub help_function: String,
|
||||
pub help_other: String,
|
||||
pub license_info: String,
|
||||
pub welcome: String,
|
||||
}
|
||||
|
||||
/// Parses an array of strings at `self.value[key]` as a multiline string
|
||||
fn parse_multiline(value: &JsonValue, key: &str) -> String {
|
||||
(value[key])
|
||||
.as_array()
|
||||
.expect("Cannot cast to array")
|
||||
.iter()
|
||||
.map(|ele| ele.as_str().unwrap())
|
||||
.fold(String::new(), |s, l| s + l + "\n")
|
||||
.trim_end()
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
/// Parses `self.value[key]` as a single line string
|
||||
fn parse_singleline(value: &JsonValue, key: &str) -> String {
|
||||
value[key].as_str().expect("cannot cast to str").to_owned()
|
||||
}
|
||||
|
||||
impl TextData {
|
||||
pub fn from_json_str(string: &str) -> Self {
|
||||
let value = serde_json::from_str(string).expect("Cannot parse json file");
|
||||
|
||||
Self {
|
||||
help_expr: parse_multiline(&value, "help_expr"),
|
||||
help_vars: parse_multiline(&value, "help_vars"),
|
||||
help_panel: parse_multiline(&value, "help_panel"),
|
||||
help_function: parse_multiline(&value, "help_func"),
|
||||
help_other: parse_multiline(&value, "help_other"),
|
||||
license_info: parse_singleline(&value, "agpl_info"),
|
||||
welcome: parse_multiline(&value, "welcome"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Rounds f64 to `n` decimal places
|
||||
pub fn decimal_round(x: f64, n: usize) -> f64 {
|
||||
let large_number: f64 = 10.0_f64.powf(n as f64); // 10^n
|
||||
|
||||
Reference in New Issue
Block a user