From 8cb8d510ca0a7d83102f4da32ed95c1e884bd79e Mon Sep 17 00:00:00 2001 From: Snorre Date: Mon, 17 Feb 2025 17:01:44 +0100 Subject: [PATCH] U-U-I --- src/app/bin.rs | 56 ++++++--- src/app/gui/document/line.rs | 190 +++++++++++++++++++++++++++++- src/app/gui/document/mod.rs | 220 +++++++---------------------------- src/app/gui/mod.rs | 13 +-- src/lib/node/mod.rs | 10 +- 5 files changed, 284 insertions(+), 205 deletions(-) diff --git a/src/app/bin.rs b/src/app/bin.rs index 901413d..72bf3fe 100644 --- a/src/app/bin.rs +++ b/src/app/bin.rs @@ -1,13 +1,18 @@ use std::{ - cell::RefCell, - collections::{HashMap, HashSet}, - rc::Rc, + cell::RefCell, collections::{HashMap, HashSet}, rc::Rc }; -mod gui; +pub mod gui; use clay_layout::render_commands::RenderCommandConfig; -use gui::GUI; +use gui::{ + GUI, + document::{ + State, + line::{Line, LineSegment, Theme}, + }, +}; +use libopenbirch::node::{add::Add, constant::Constant, divide::Divide, multiply::Multiply}; use raylib::{ RaylibHandle, RaylibThread, color::Color, @@ -23,6 +28,8 @@ struct FontStore { fonts_to_be_loaded: HashSet, } +static CHAR_SET: &'static str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWYZ1234567890(){}[]./,?><|\\=+-_*&^%$#@!~`·×≤≥±∞≈∝≠∅∈∉∩∪⊂⊃⊆⊇¬∧∨∃∀⇒⇔→↔↑↓ℵ"; + impl FontStore { // const SIZE_PARAGRAPH: f32 = 20.; // const SIZE_HEADER: f32 = 30.; @@ -64,7 +71,7 @@ impl FontStore { for size in self.fonts_to_be_loaded.clone() { assert!(size != 0, "HOW IS THIS ZERO?"); println!("Loading {} in {size}px", self.font); - let font = Rc::new(handle.load_font_ex(&thread, &self.font, size, None)?); + let font = Rc::new(handle.load_font_ex(&thread, &self.font, size, Some(CHAR_SET))?); self.fonts.insert(size, font.clone()); } self.fonts_to_be_loaded.clear(); @@ -122,6 +129,18 @@ fn main() -> Result<(), String> { let mut gui = GUI::new(); + gui.document.add_line("This is a test line".to_string()); + + let a = Constant::new(69.); + let b = Constant::new(420.); + let meth = Divide::new(a.clone().into(), b.into()); + let meth2 = Add::new(a.into(), meth.clone().into()); + let meth3 = Multiply::new(meth2.into(), meth.into()); + + gui.document.add_line(Line { + segments: vec![LineSegment::Math(Rc::new(meth3.into()), 16)], + }); + let mut previous_left_button = false; let mut previous_right_button = false; @@ -188,6 +207,13 @@ fn main() -> Result<(), String> { let mut debug = false; + let theme = Theme { + text_color: (236, 239, 244).into(), + text_font: 0, + math_color: (129, 161, 193).into(), + math_font: 1, + }; + while !rl.window_should_close() { if rl.is_window_resized() { let size = (rl.get_screen_width() as f32, rl.get_screen_height() as f32); @@ -228,13 +254,17 @@ fn main() -> Result<(), String> { left_button, ); - let render_commands = gui.render( - &clay, - (left_button, left_button && !previous_left_button), - (right_button, right_button && !previous_right_button), - (rl.get_char_pressed(), rl.get_key_pressed_number()), - rl.get_time(), - ); + let state = State { + mouse_left_held: left_button, + mouse_left_pressed: left_button && !previous_left_button, + mouse_right_held: right_button, + mouse_right_pressed: right_button && !previous_right_button, + latest_char: rl.get_char_pressed(), + latest_key: rl.get_key_pressed_number(), + time: rl.get_time(), + }; + + let render_commands = gui.render(&clay, &state, &theme); let mut d = rl.begin_drawing(&thread); diff --git a/src/app/gui/document/line.rs b/src/app/gui/document/line.rs index a2fd272..1e852ce 100644 --- a/src/app/gui/document/line.rs +++ b/src/app/gui/document/line.rs @@ -1,19 +1,199 @@ use std::rc::Rc; +use clay_layout::{ + Declaration, fit, grow, + layout::{ + Alignment, LayoutAlignmentX, LayoutAlignmentY, + LayoutDirection::{self, TopToBottom}, + Padding, + }, + text::{TextConfig, TextElementConfig}, +}; use libopenbirch::node::NodeEnum; +use super::{Document, State}; + pub struct Line { - segments: Vec, + pub segments: Vec, +} + +impl From for Line { + fn from(value: String) -> Self { + Line { + segments: vec![LineSegment::Text(value, 20)], + } + } +} + +impl Line { + pub fn draw<'a>(&'a mut self, clay: &'a clay_layout::Clay, theme: &Theme, state: &'a State) { + for segment in self.segments.iter_mut() { + segment.draw(clay, theme, state); + } + } +} + +pub struct Theme { + pub text_color: clay_layout::color::Color, + pub text_font: u16, + pub math_color: clay_layout::color::Color, + pub math_font: u16, } pub enum LineSegment { - Text(String), + Text(String, u16), // Link(String, Link), - Math(Rc), + Math(Rc, u16), } impl LineSegment { - pub fn draw<'a>(&'a self, clay: &'a clay_layout::Clay) { - + pub fn draw<'a>(&'a mut self, clay: &'a clay_layout::Clay, theme: &'a Theme, state: &'a State) { + match self { + LineSegment::Text(text, font_size) => clay.text( + text.as_str(), + TextConfig::new() + .font_id(theme.text_font) + .font_size(*font_size) + .color(theme.text_color) + .end(), + ), + LineSegment::Math(node_enum, font_size) => { + draw_math_enum(node_enum.clone(), clay, theme, *font_size, state); + } + } + } +} +fn draw_binary( + symbol: &'static str, + left: Rc, + right: Rc, + font_size: u16, + clay: &clay_layout::Clay, + theme: &Theme, + state: &State, +) { + clay.with( + &Declaration::new() + .layout() + .direction(LayoutDirection::LeftToRight) + .width(fit!(0.)) + .height(fit!(0.)) + .child_alignment(Alignment::new( + LayoutAlignmentX::Center, + LayoutAlignmentY::Center, + )) + .padding(Padding::new(2, 2, 3, 3)) + .end(), + |clay| { + // Left side + draw_math_enum(left, clay, theme, font_size, state); + // add symbol + clay.text( + symbol, + TextConfig::new() + .color(theme.math_color) + .font_size(font_size) + .font_id(theme.math_font) + .end(), + ); + // Right side + draw_math_enum(right, clay, theme, font_size, state); + }, + ) +} + +fn draw_math_enum<'a>( + node: Rc, + clay: &'a clay_layout::Clay, + theme: &'a Theme, + font_size: u16, + state: &'a State, +) { + match node.as_ref() { + NodeEnum::Constant(constant) => { + let str = std::mem::ManuallyDrop::new(constant.get_value().to_string()); + clay.text( + str.as_str(), + TextConfig::new() + .color(theme.math_color) + .font_size(font_size) + .font_id(theme.math_font) + .end(), + ) + } + NodeEnum::Add(add) => draw_binary( + " + ", + add.get_left(), + add.get_right(), + font_size, + clay, + theme, + state, + ), + + NodeEnum::Subtract(sub) => draw_binary( + " - ", + sub.get_left(), + sub.get_right(), + font_size, + clay, + theme, + state, + ), + + NodeEnum::Multiply(mul) => draw_binary( + "× ", + mul.get_left(), + mul.get_right(), + font_size, + clay, + theme, + state, + ), + + NodeEnum::Assign(assign) => draw_binary( + " := ", + assign.get_left(), + assign.get_right(), + font_size, + clay, + theme, + state, + ), + + NodeEnum::Divide(divide) => clay.with( + &Declaration::new() + .layout() + .direction(TopToBottom) + .width(fit!(0.)) + .height(fit!(0.)) + .child_alignment(Alignment::new( + LayoutAlignmentX::Center, + LayoutAlignmentY::Center, + )) + .padding(Padding::new(4, 4, 2, 2)) + .end(), + |clay| { + // Left side + draw_math_enum(divide.get_left(), clay, theme, font_size, state); + // Seperator bar + clay.with( + &Declaration::new() + .layout() + .width(grow!(0.)) + .height(fit!(1.)) + .end() + .background_color(theme.math_color), + |_| {}, + ); + // Right side + draw_math_enum(divide.get_right(), clay, theme, font_size, state); + }, + ), + NodeEnum::Symbol(symbol) => todo!(), + NodeEnum::Function(function) => todo!(), + NodeEnum::Call(call) => todo!(), + + NodeEnum::Empty(empty) => {} } } diff --git a/src/app/gui/document/mod.rs b/src/app/gui/document/mod.rs index 575a128..d6e95f3 100644 --- a/src/app/gui/document/mod.rs +++ b/src/app/gui/document/mod.rs @@ -5,107 +5,51 @@ use clay_layout::{ layout::{LayoutDirection, Padding}, text::TextConfig, }; +use line::{Line, Theme}; use raylib::ffi::KeyboardKey; -pub type LineType = String; +pub mod line; -mod line; +pub struct State { + pub mouse_left_held: bool, + pub mouse_left_pressed: bool, + pub mouse_right_held: bool, + pub mouse_right_pressed: bool, + + pub latest_char: Option, + pub latest_key: Option, + + pub time: f64, +} pub struct Document { - lines: Vec<(String, LineType)>, + lines: Vec<(String, Line)>, total_lines: usize, - current_line: Option, - current_char: usize, - lines_to_delete: Vec, - lines_to_add: Vec<(usize, LineType)>, - last_type_time: f64, } impl Document { pub fn new() -> Self { Self { - lines: vec![("0".to_owned(), "".to_string())], - total_lines: 1, - current_line: Some(0), - current_char: 0, - lines_to_delete: vec![], - lines_to_add: vec![], - last_type_time: -100., + lines: vec![], + total_lines: 0, } } - pub fn add_line(&mut self, content: impl Into) { + pub fn add_line(&mut self, content: impl Into) { self.add_line_at(self.lines.len(), content); } - pub fn add_line_at(&mut self, idx: usize, content: impl Into) { - self.lines - .insert(idx, (self.total_lines.to_string(), content.into())); + pub fn add_line_at(&mut self, idx: usize, content: impl Into) { + self.lines.insert(idx, (self.total_lines.to_string(), content.into())); self.total_lines += 1; } pub fn render<'a>( &'a mut self, clay: &'a Clay, - (left_held, left_pressed): (bool, bool), - (righ_held, right_pressed): (bool, bool), - (latest_char, latest_key): (Option, Option), - time: f64, + state: &'a State, + theme: &'a Theme ) { - // if !self.lines_to_delete.is_empty() { - // self.lines_to_delete.sort(); - // - // for line in self.lines_to_delete.iter().rev() { - // let contents = &self.lines.remove(*line).1; - // self.lines[*line - 1].1 += contents; - // } - // - // self.lines_to_delete.clear(); - // - // self.current_line = if let Some(i) = self.current_line { - // if self.lines.len() == 0 { - // self.add_line("".to_string()); - // } - // Some( - // (TryInto::::try_into(i).unwrap() - 1) - // .max(0) - // .min(TryInto::::try_into(self.lines.len()).unwrap() - 1) - // .try_into() - // .unwrap(), - // ) - // } else { - // None - // }; - // } - // - // if !self.lines_to_add.is_empty() { - // // i am NOT cloning this shit - // let lines_to_add: ManuallyDrop> = unsafe { - // let len = self.lines_to_add.len(); - // let cap = self.lines_to_add.capacity(); - // let fuck = self.lines_to_add.as_mut_ptr(); - // std::mem::ManuallyDrop::new(Vec::from_raw_parts(fuck, len, cap)) - // }; - // - // for (idx, line) in lines_to_add.iter() { - // self.add_line_at(*idx, line); - // } - // - // self.lines_to_add.clear(); - // self.current_line = if let Some(i) = self.current_line { - // Some(i + 1) - // } else { - // None - // }; - // } - // - // if left_pressed && clay.pointer_over(clay.id("document")) { - // self.current_line = None; - // } - // - // let len = self.lines.len(); - // let mut can_go_down = true; - clay.with( &Declaration::new() .id(clay.id("document")) @@ -122,107 +66,27 @@ impl Document { .background_color((67, 76, 94).into()) .scroll(false, true), |clay| { - // for (i, line) in self.lines.iter_mut().enumerate() { - // let current_selected = - // if left_pressed && clay.pointer_over(clay.id(line.0.as_str())) { - // self.current_line = Some(i); - // true - // } else { - // Some(i) == self.current_line - // }; - // - // if current_selected { - // if let Some(char) = latest_char { - // line.1 += char.to_string().as_str(); - // self.last_type_time = time; - // } - // - // match latest_key { - // Some(val) if val == KeyboardKey::KEY_BACKSPACE as u32 => { - // if line.1.len() == 0 { - // self.lines_to_delete.push(i); - // } else { - // // let _ = line.1.pop(); - // line.1.remove(self.current_char); - // } - // } - // Some(val) if val == KeyboardKey::KEY_ENTER as u32 => { - // self.lines_to_add.push((i + 1, "".to_string())); - // } - // Some(val) if val == KeyboardKey::KEY_UP as u32 => { - // self.current_line = Some( - // (TryInto::::try_into(self.current_line.unwrap()).unwrap() - // - 1) - // .max(0) - // .try_into() - // .unwrap(), - // ); - // } - // Some(val) if val == KeyboardKey::KEY_DOWN as u32 && can_go_down => { - // self.current_line = Some( - // (TryInto::::try_into(self.current_line.unwrap()).unwrap() - // + 1) - // .min(TryInto::::try_into(len).unwrap() - 1) - // .try_into() - // .unwrap(), - // ); - // can_go_down = false; - // } - // _ => {} - // } - // } - // - // clay.with( - // &Declaration::new() - // .id(clay.id(line.0.as_str())) - // .layout() - // .width(grow!(0.)) - // .height(fit!(21.)) - // .direction(LayoutDirection::LeftToRight) - // .padding(Padding::new(4, 4, 0, 1)) - // .child_alignment(clay_layout::layout::Alignment { - // x: clay_layout::layout::LayoutAlignmentX::Left, - // y: clay_layout::layout::LayoutAlignmentY::Center, - // }) - // // .child_gap(2) - // // .end() - // // .border() - // // .color((67, 76, 94).into()) - // // .bottom(2) - // // .end() - // // .corner_radius() - // // .all(4.) - // .end(), - // |clay| { - // clay.text( - // line.1.as_str(), - // TextConfig::new() - // .color((229, 233, 240).into()) - // .font_size(20) - // .font_id(0) - // .letter_spacing(2) - // .end(), - // ); - // if current_selected - // && can_go_down - // && ((time - self.last_type_time) < 0.5 || time % 1.2 < 0.6) - // { - // clay.with( - // &Declaration::new() - // .id(clay.id("text_cursor")) - // .layout() - // .height(grow!(0.)) - // .width(fixed!(8.)) - // .end() - // .background_color((229, 233, 240, 100).into()), // .corner_radius() - // // .all(2.) - // // .end(), - // |_| {}, - // ); - // } - // }, - // ); - // } + for (id,line) in self.lines.iter_mut() { + clay.with( + &Declaration::new() + .id(clay.id(id)) + .layout() + .width(grow!(0.)) + .height(fit!(0.)) + .direction(LayoutDirection::TopToBottom) + .padding(Padding::all(8)) + .child_gap(0) + .end() + .corner_radius() + .all(8.) + .end() + .background_color((67, 76, 94).into()) + .scroll(false, true), + |clay| { + line.draw(clay, theme, state); + }, + ); + } }, ); } diff --git a/src/app/gui/mod.rs b/src/app/gui/mod.rs index 380fd97..1cc9529 100644 --- a/src/app/gui/mod.rs +++ b/src/app/gui/mod.rs @@ -3,9 +3,9 @@ use clay_layout::{ layout::{LayoutDirection, Padding}, render_commands::RenderCommand, }; -use document::Document; +use document::{Document, State, line::Theme}; -mod document; +pub mod document; pub struct GUI { pub document: Document, @@ -21,15 +21,12 @@ impl GUI { pub fn render<'a>( &'a mut self, clay: &'a Clay, - left_mouse: (bool, bool), - right_mouse: (bool, bool), - latest_char: (Option, Option), - time: f64, + state: &'a State, + theme: &'a Theme, ) -> impl Iterator { clay.begin(); - self.document - .render(clay, left_mouse, right_mouse, latest_char, time); + self.document.render(clay, state, theme); clay.end() } diff --git a/src/lib/node/mod.rs b/src/lib/node/mod.rs index 5df0df3..8e94f39 100644 --- a/src/lib/node/mod.rs +++ b/src/lib/node/mod.rs @@ -32,16 +32,24 @@ mod call; #[derive(Debug, Clone, PartialEq, PartialOrd)] pub enum NodeEnum { Constant, + + // Operators Add, Subtract, Multiply, Divide, + Symbol, // NodeRef, // DEPRECATED, use Symbol Assign, Empty, Function, - Call + Call, + + // Logical + // In, + // Or, + // Not, } #[derive(PartialEq, Eq, PartialOrd, Ord)]