This commit is contained in:
Snorre Ettrup Altschul 2025-02-13 01:29:33 +01:00
parent ead504a483
commit bc9ade91fe
13 changed files with 464 additions and 3050 deletions

3187
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -4,8 +4,11 @@ version = "0.1.0"
edition = "2024"
[dependencies]
clay-layout = "0.2.0"
enum_dispatch = "0.3.13"
iced = "0.13.1"
font-kit = "0.14.2"
minifb = "0.28.0"
raqote = "0.8.5"
test-case = "3.3.1"
[lib]

View file

@ -39,13 +39,17 @@
xorg.libXrandr
wayland
libxkbcommon
rust-cbindgen
];
LD_LIBRARY_PATH =
builtins.foldl' (a: b: "${a}:${b}/lib") "${pkgs.vulkan-loader}/lib" buildInputs;
shell = ''
echo "Hello from nix dev shell"
# NIX_LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath buildInputs;
shellHook = ''
# export LD_LIBRARY_PATH=$NIX_LD_LIBRARY_PATH
# export LIBCLANG_PATH="${pkgs.llvmPackages.libclang.lib}/lib";
'';
};
};

View file

@ -1,7 +1,140 @@
use std::{any::Any, cell::RefCell, rc::Rc};
use clay_layout::{
Clay,
bindings::Clay_TextElementConfig,
elements::{
CornerRadius,
rectangle::Rectangle,
text::{Text, TextElementConfig},
},
fixed,
id::Id,
layout::Layout,
math::Dimensions,
};
use font_kit::{family_name::FamilyName, properties::Properties, source::SystemSource};
use gui::GUI;
use minifb::{Window, WindowOptions};
use raqote::{DrawOptions, DrawTarget, SolidSource};
mod gui;
fn main() -> Result<(), iced::Error> {
GUI::run("Openbirch GUI")
fn main() {
let clay = Clay::new((800., 600.).into());
let mut window = Window::new("Raqote", 800, 40, WindowOptions {
borderless: true,
scale_mode: minifb::ScaleMode::Center,
resize: true,
..Default::default()
})
.unwrap();
let font = SystemSource::new()
.select_best_match(&[FamilyName::Monospace], &Properties::new())
.unwrap()
.load()
.unwrap();
window.set_target_fps(60);
let mut size = window.get_size();
let mut dt = DrawTarget::new(size.0 as i32, size.1 as i32);
clay.measure_text_function(|text, config| {
let config: Clay_TextElementConfig = unsafe {
*std::mem::transmute::<TextElementConfig, *mut Clay_TextElementConfig>(config)
};
Dimensions {
width: config.fontSize as f32,
height: config.fontSize as f32 * text.len() as f32,
}
});
loop {
dt.clear(SolidSource::from_unpremultiplied_argb(
0xff, 0xff, 0xff, 0xff,
));
clay.begin();
// Adds a red rectangle with a corner radius of 5.
// The Layout makes the rectangle have a width and height of 50.
clay.with(
[
Id::new("red_rectangle"),
Layout::new().width(fixed!(50.)).height(fixed!(50.)).end(),
Rectangle::new()
.color((0xFF, 0x00, 0x00).into())
.corner_radius(CornerRadius::All(5.))
.end(),
],
|c| {
c.with(
[
Id::new("test_text"),
Layout::new().end(),
Rectangle::new().color((0xFF, 0xFF, 0xFF).into()).end(),
// Text::new().color((0xFF, 0xFF, 0xFF).into()).end()
],
|_| {},
);
},
);
// Return the list of render commands of your layout
let render_commands = clay.end();
for command in render_commands {
// println!("Id of the element: {}", command.id); // Note: Ids are in fact numbers generated by Clay
// println!("Bounding box: {:?}", command.bounding_box);
// println!("Type and config: {:?}", command.config);
match command.config {
clay_layout::render_commands::RenderCommandConfig::Rectangle(rectangle) => {
dt.fill_rect(
command.bounding_box.x,
command.bounding_box.y,
command.bounding_box.width,
command.bounding_box.height,
&raqote::Source::Solid(SolidSource {
r: (rectangle.color.r * 255.0) as u8,
g: (rectangle.color.g * 255.0) as u8,
b: (rectangle.color.b * 255.0) as u8,
a: (rectangle.color.a * 255.0) as u8,
}),
&DrawOptions::new(),
);
}
clay_layout::render_commands::RenderCommandConfig::Border(border_container) => {
todo!()
}
clay_layout::render_commands::RenderCommandConfig::Text(_, text) => todo!(),
clay_layout::render_commands::RenderCommandConfig::Image(image) => todo!(),
clay_layout::render_commands::RenderCommandConfig::ScissorStart() => todo!(),
clay_layout::render_commands::RenderCommandConfig::ScissorEnd() => todo!(),
clay_layout::render_commands::RenderCommandConfig::Custom(custom) => todo!(),
clay_layout::render_commands::RenderCommandConfig::None() => {}
}
}
if window.is_key_down(minifb::Key::Escape) {
break;
}
let (width, height) = window.get_size();
if width as i32 != dt.width() || height as i32 != dt.height() {
dt = DrawTarget::new(width as i32, height as i32);
clay.layout_dimensions((width as f32, height as f32).into());
size = (width, height);
// window.update();
} else {
window
.update_with_buffer(dt.get_data(), size.0, size.1)
.unwrap();
}
}
}

View file

@ -1,4 +0,0 @@
#[derive(Debug, Clone)]
pub enum Line {
Text(String)
}

View file

@ -0,0 +1,8 @@
use enum_dispatch::enum_dispatch;
use libopenbirch::node::{Node, NodeEnum};
pub trait MathSegment {
}
impl MathSegment for NodeEnum {
}

View file

@ -1,96 +1,27 @@
use iced::{Element, Length, Task, widget::text};
use std::rc::Rc;
#[derive(Debug, Clone)]
enum Message {
CreateLine(Option<usize>, Line, bool),
ChangeLine(usize, Line),
}
use libopenbirch::node::{
NodeEnum, add::Add, constant::Constant, divide::Divide, multiply::Multiply, symbol::Symbol,
};
use math_segments::MathSegment;
mod line;
use line::Line;
mod math_segments;
#[derive(Default)]
pub struct GUI {
lines: Vec<Line>,
current_line: usize,
meth: Vec<Rc<dyn MathSegment>>,
}
impl GUI {
pub fn run(title: &'static str) -> Result<(), iced::Error> {
iced::application(title, Self::update, Self::view)
.settings(iced::Settings {
default_font: iced::font::Font::MONOSPACE,
antialiasing: true,
..Default::default()
})
.theme(|_| iced::Theme::Nord)
.centered()
.run_with(move || Self::new())
}
pub fn new() -> Self {
let a = Constant::new(69.0).into();
let b = Constant::new(420.0).into();
let c: NodeEnum = Add::new(a, b).into();
let d = Symbol::new_from_str("x").into();
let e = Divide::new(c.clone(), d).into();
let f = Multiply::new(e, c);
fn new() -> (Self, Task<Message>) {
let s = Self {
..Default::default()
};
(
s,
Task::done(Message::CreateLine(
None,
Line::Text("Testline".to_owned()),
true,
)),
)
}
fn update(&mut self, message: Message) -> Task<Message> {
match message {
Message::CreateLine(idx, line, focus) => {
let idx = if let Some(idx) = idx {
idx
} else {
self.lines.len()
};
self.lines.insert(idx, line);
if focus {
self.current_line = idx;
}
}
Message::ChangeLine(idx, text) => {
let r = self.lines.get_mut(idx);
if let Some(r) = r {
std::mem::replace(r, text);
} else {
// TODO: Error message to user
}
}
Self {
meth: vec![Rc::new(NodeEnum::Multiply(f))],
}
Task::none()
}
fn view(&self) -> Element<Message> {
iced::widget::Column::from_vec(
self.lines
.iter()
.enumerate()
.map(move |(i, line)| {
match line {
Line::Text(text) => iced::widget::text_input("", text)
.width(Length::Fill)
.on_input(move |s| Message::ChangeLine(i, Line::Text(s)))
.on_submit(Message::CreateLine(
Some(i + 1),
Line::Text("".to_owned()),
true,
)),
}
.into()
})
.collect::<Vec<Element<Message>>>(),
)
.width(Length::Fill)
.height(Length::Fill)
.into()
}
}

View file

@ -1,6 +1,6 @@
use std::rc::Rc;
use super::{constant::Constant, Environment, Node, NodeEnum, Precedence};
use super::{Environment, Node, NodeEnum, Precedence, constant::Constant};
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct Add {
@ -47,4 +47,12 @@ impl Add {
right: Rc::new(right),
}
}
pub fn get_left(&self) -> Rc<NodeEnum> {
self.left.clone()
}
pub fn get_right(&self) -> Rc<NodeEnum> {
self.right.clone()
}
}

View file

@ -1,17 +1,24 @@
use std::rc::Rc;
use super::{empty::Empty, symbol::Symbol, Environment, Node, NodeEnum, Precedence};
use super::{Environment, Node, NodeEnum, Precedence, empty::Empty, symbol::Symbol};
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Assign {
left: Symbol,
left: Rc<NodeEnum>,
right: Rc<NodeEnum>,
}
impl Node for Assign {
fn evaluate(&self, env: &mut Environment) -> Result<Rc<NodeEnum>, String> {
env.insert(self.left.get_value(), self.right.clone());
Ok(Empty::EMPTY.clone())
if let NodeEnum::Symbol(symbol) = self.left.as_ref() {
env.insert(symbol.get_value(), self.right.clone());
Ok(Empty::EMPTY.clone())
} else {
Err(format!(
"Cannot assign to a {}",
self.left.as_string(Some(env))
))
}
}
fn as_string(&self, env: Option<&Environment>) -> String {
@ -26,3 +33,13 @@ impl Node for Assign {
Precedence::Assign
}
}
impl Assign {
pub fn get_left(&self) -> Rc<NodeEnum> {
self.left.clone()
}
pub fn get_right(&self) -> Rc<NodeEnum> {
self.left.clone()
}
}

View file

@ -47,4 +47,12 @@ impl Divide {
right: Rc::new(right),
}
}
pub fn get_left(&self) -> Rc<NodeEnum> {
self.left.clone()
}
pub fn get_right(&self) -> Rc<NodeEnum> {
self.right.clone()
}
}

View file

@ -47,4 +47,12 @@ impl Multiply {
right: Rc::new(right),
}
}
pub fn get_left(&self) -> Rc<NodeEnum> {
self.left.clone()
}
pub fn get_right(&self) -> Rc<NodeEnum> {
self.right.clone()
}
}

View file

@ -1,6 +1,6 @@
use std::rc::Rc;
use super::{constant::Constant, Environment, Node, NodeEnum, Precedence};
use super::{Environment, Node, NodeEnum, Precedence, constant::Constant};
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct Subtract {
@ -47,4 +47,12 @@ impl Subtract {
right: Rc::new(right),
}
}
pub fn get_left(&self) -> Rc<NodeEnum> {
self.left.clone()
}
pub fn get_right(&self) -> Rc<NodeEnum> {
self.right.clone()
}
}

View file

@ -60,7 +60,8 @@ impl Symbol {
Self { value }
}
pub fn new_from_str(str: String) -> Self {
pub fn new_from_str(str: impl Into<String>) -> Self {
let str = str.into();
if let Some(value) = Symbol::STR_TO_ID_MAP.lock().unwrap().get(str.as_str()) {
Self::new(value.clone())
} else {