Created
December 14, 2024 19:45
-
-
Save airstrike/1e9d5067b58937c6e5c2e5de2b842304 to your computer and use it in GitHub Desktop.
owned LLVM Context pattern for `iced`
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::collections::HashMap; | |
use components::sidebar; | |
use desmos_compiler::{ | |
expressions::{ExpressionId, Expressions}, | |
lang::backends::llvm::{codegen::compile_all_exprs, CompiledExprs}, | |
}; | |
use graph::GraphRenderer; | |
use iced::{ | |
alignment::Horizontal, | |
overlay, | |
widget::{ | |
self, | |
canvas::Cache, | |
container, mouse_area, opaque, | |
pane_grid::{self, Axis, Content, Pane, ResizeEvent}, | |
row, | |
text_input::{self, focus, Id}, | |
Canvas, Stack, TextInput, | |
}, | |
Application, Color, Length, Padding, Settings, Task, Vector, | |
}; | |
mod components; | |
mod graph; | |
static DCG_FONT: &[u8; 45324] = include_bytes!("./dcg-icons-2024-08-02.ttf"); | |
struct OwnedCompiledExprs { | |
context: inkwell::context::Context, | |
compiled_eqs: CompiledExprs<'static>, | |
} | |
impl OwnedCompiledExprs { | |
fn new() -> Self { | |
let context = inkwell::context::Context::create(); | |
Self { | |
context, | |
compiled_eqs: CompiledExprs::new(), | |
} | |
} | |
fn recompile(&mut self, exprs: &Expressions) { | |
// SAFETY: Safe because compiled_eqs cannot outlive context | |
// since they're in the same struct and context is dropped last | |
unsafe { | |
self.compiled_eqs = std::mem::transmute(compile_all_exprs(&self.context, exprs)); | |
} | |
} | |
fn get(&self) -> &CompiledExprs<'static> { | |
&self.compiled_eqs | |
} | |
} | |
#[derive(Debug, Clone)] | |
pub enum Message { | |
Moved(Vector), | |
Scaled(f32, Option<Vector>), | |
EquationChanged(ExpressionId, String), | |
EquationAdded(String), | |
ShowError(Option<ExpressionId>), | |
FocusExpr(usize), | |
Resized(pane_grid::ResizeEvent), | |
} | |
enum PaneType { | |
Graph, | |
Sidebar, | |
} | |
struct Somsed { | |
owned_exprs: OwnedCompiledExprs, | |
panes: pane_grid::State<PaneType>, | |
graph_caches: HashMap<ExpressionId, Cache>, | |
parsed_expressions: Expressions, | |
expressions: HashMap<ExpressionId, String>, | |
errors: HashMap<ExpressionId, String>, | |
shown_error: Option<ExpressionId>, | |
scale: f32, | |
mid: Vector, | |
resolution: u32, | |
} | |
impl Somsed { | |
fn new() -> Self { | |
let graph_caches = HashMap::new(); | |
let expressions = Expressions::new(); | |
let (mut panes, pane) = pane_grid::State::new(PaneType::Sidebar); | |
panes.split(Axis::Vertical, pane, PaneType::Graph); | |
Self { | |
owned_exprs: OwnedCompiledExprs::new(), | |
panes, | |
scale: 100.0, | |
mid: Vector { x: 0.0, y: 0.0 }, | |
resolution: 1000, | |
errors: HashMap::new(), | |
parsed_expressions: expressions, | |
expressions: HashMap::new(), | |
graph_caches, | |
shown_error: None, | |
} | |
} | |
fn view(&self) -> pane_grid::PaneGrid<'_, Message> { | |
pane_grid::PaneGrid::new(&self.panes, move |_, id, _| match id { | |
PaneType::Graph => Content::new( | |
Canvas::new(GraphRenderer::new( | |
self.owned_exprs.get(), | |
&self.graph_caches, | |
self.scale, | |
self.mid, | |
self.resolution, | |
)) | |
.width(Length::Fill) | |
.height(Length::Fill), | |
), | |
PaneType::Sidebar => pane_grid::Content::new(sidebar::view( | |
&self.expressions, | |
&self.errors, | |
&self.shown_error, | |
)), | |
}) | |
.on_resize(10, Message::Resized) | |
.width(Length::Fill) | |
.height(Length::Fill) | |
} | |
pub fn clear_caches(&mut self) { | |
for (_, v) in &mut self.graph_caches { | |
v.clear(); | |
} | |
} | |
fn update(&mut self, message: Message) -> Task<Message> { | |
match message { | |
Message::Moved(p) => { | |
self.mid = self.mid + p; | |
self.clear_caches(); | |
} | |
Message::EquationChanged(i, s) => { | |
self.parsed_expressions.set_expr(i, &s); | |
self.owned_exprs.recompile(&self.parsed_expressions); | |
self.graph_caches[&i].clear(); | |
} | |
Message::EquationAdded(s) => { | |
if let Some(expr_id) = self.parsed_expressions.max_id.checked_sub(1) { | |
self.parsed_expressions.add_expr(&s); | |
self.graph_caches | |
.insert(ExpressionId(expr_id), Cache::new()); | |
self.owned_exprs.recompile(&self.parsed_expressions); | |
return focus(Id::new(format!("equation_{}", expr_id))); | |
} | |
} | |
Message::Scaled(scale, mid) => { | |
self.scale = scale; | |
if let Some(mid) = mid { | |
self.mid = mid; | |
} | |
self.clear_caches(); | |
} | |
Message::ShowError(i) => { | |
self.shown_error = i; | |
} | |
Message::FocusExpr(i) => return focus(Id::new(format!("equation_{}", i))), | |
Message::Resized(ResizeEvent { split, ratio }) => { | |
self.panes.resize(split, ratio); | |
} | |
}; | |
Task::none() | |
} | |
} | |
fn main() -> iced::Result { | |
iced::application("Somsed", Somsed::update, Somsed::view) | |
.font(DCG_FONT) | |
.antialiasing(true) | |
.run_with(|| (Somsed::new(), Task::none())) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment