mod eval; mod lexer; mod op; mod parser; use gdk4::{Key, ModifierType}; use gtk4::glib::{clone, ExitCode}; use gtk4::prelude::{ ApplicationExt, ApplicationExtManual, EditableExt, GridExt, GtkWindowExt, WidgetExt, }; use gtk4::{glib, Application, ApplicationWindow, Entry, EventControllerKey, Grid}; use std::sync::{Arc, Mutex}; fn main() -> ExitCode { let app = Application::builder() .application_id("com.github.rhogenson.qc") .build(); app.connect_activate(|app| { let window = ApplicationWindow::builder() .application(app) .decorated(false) .resizable(false) .build(); let grid = Grid::new(); window.set_child(Some(&grid)); let input = Entry::builder().width_request(300).build(); grid.attach(&input, 0, 0, 1, 1); let output = Entry::builder().editable(false).build(); grid.attach(&output, 0, 1, 1, 1); let mailbox = Arc::new(Mutex::new(String::from(""))); let (flag_send, flag_recv) = async_channel::bounded(1); glib::spawn_future_local({ let mailbox = mailbox.clone(); async move { while let Ok(()) = flag_recv.recv().await { let input = std::mem::take(&mut *mailbox.lock().unwrap()); let (result_send, result_recv) = async_channel::bounded(1); gio::spawn_blocking(move || { let Some(bytecode) = parser::parse(&input) else { return; }; result_send .send_blocking(format!("{}", op::eval(bytecode.into_iter()))) .unwrap(); }) .await .unwrap(); if let Ok(result) = result_recv.try_recv() { output.set_text(&result); } } } }); let key_controller = EventControllerKey::new(); key_controller.connect_key_released(clone!( #[weak] window, #[weak] input, move |_, k, _, modifiers| { if k == Key::Escape || k == Key::Return || k == Key::bracketleft && modifiers.contains(ModifierType::CONTROL_MASK) { window.destroy(); } *mailbox.lock().unwrap() = input.text().to_string(); let _ = flag_send.try_send(()); } )); window.add_controller(key_controller); window.present(); }); app.run() }