diff --git a/unshell-gui/src/app/app.rs b/unshell-gui/src/app/app.rs index fe744de..8234d68 100644 --- a/unshell-gui/src/app/app.rs +++ b/unshell-gui/src/app/app.rs @@ -1,7 +1,10 @@ use egui::Frame; use egui_tiles::Tree; -use crate::app::{AppState, windows::WindowWrapper}; +use crate::{ + FORCE_REDRAW_DELAY, + app::{AppState, windows::WindowWrapper}, +}; /// We derive Deserialize/Serialize so we can persist app state on shutdown. #[derive(serde::Deserialize, serde::Serialize)] @@ -83,5 +86,7 @@ impl eframe::App for TemplateApp { .frame(Frame::central_panel(&ctx.style()).inner_margin(0)) .show(ctx, |ui| self.tree.ui(&mut self.state, ui)); } + + ctx.request_repaint_after(FORCE_REDRAW_DELAY); } } diff --git a/unshell-gui/src/app/mod.rs b/unshell-gui/src/app/mod.rs index 7ce0408..b79f696 100644 --- a/unshell-gui/src/app/mod.rs +++ b/unshell-gui/src/app/mod.rs @@ -19,7 +19,7 @@ pub struct AppState { impl AppState { pub fn labels(&mut self, tree: &mut Tree, ui: &mut egui::Ui) { - for (i, (key, name)) in (vec![ + for (_, (key, name)) in (vec![ (AppWindow::Flowchart, "Flowchart"), (AppWindow::Config, "Config"), ]) @@ -38,7 +38,7 @@ impl AppState { // if self.open_windows.is_empty() } else { let tid = tree.tiles.insert_pane(WindowWrapper { - nr: i + 1, + name: name.to_string(), window: *key, }); @@ -78,4 +78,17 @@ impl AppWindow { AppWindow::Config => state.config.update(&mut state.auth, ui), } } + + fn render_title_buttons(&self, state: &mut AppState, ui: &mut egui::Ui) { + match self { + AppWindow::Flowchart => { + if ui.button("Arrange").clicked() { + state.flowchart.arrange(); + } + } + _ => { + ui.label(""); + } + } + } } diff --git a/unshell-gui/src/app/windows.rs b/unshell-gui/src/app/windows.rs index d42663b..a40ece5 100644 --- a/unshell-gui/src/app/windows.rs +++ b/unshell-gui/src/app/windows.rs @@ -1,14 +1,16 @@ +use egui::Rect; + use crate::app::{AppState, AppWindow}; #[derive(serde::Deserialize, serde::Serialize)] pub struct WindowWrapper { - pub nr: usize, + pub name: String, pub window: AppWindow, } impl egui_tiles::Behavior for AppState { fn tab_title_for_pane(&mut self, pane: &WindowWrapper) -> egui::WidgetText { - format!("Pane {}", pane.nr).into() + format!("{}", pane.name).into() } fn pane_ui( @@ -19,28 +21,49 @@ impl egui_tiles::Behavior for AppState { ) -> egui_tiles::UiResponse { let mut ret = egui_tiles::UiResponse::None; + let mut rect = Rect::NOTHING; + ui.horizontal(|ui| { - let titlebar = ui.interact( - ui.max_rect(), - ui.id().with(&format!("Pane_{}_sense", pane.nr)), - egui::Sense::drag(), - ); + rect = ui.max_rect(); - if titlebar.drag_started() { - ret = egui_tiles::UiResponse::DragStarted; - } - if titlebar.hovered() { - ui.ctx().set_cursor_icon(egui::CursorIcon::Grab); - } + let bg_color = ui.style().visuals.extreme_bg_color; - let color = egui::epaint::Hsva::new(0.103 * pane.nr as f32, 0.5, 0.5, 1.0); - ui.painter().rect_filled(ui.max_rect(), 0.0, color); + ui.painter().rect_filled(rect, 0.0, bg_color); - ui.label("Test"); + ui.vertical_centered(|ui| { + ui.label(&pane.name); + }); }); + let mut open_space = Rect::NOTHING; + + #[allow(deprecated)] + ui.allocate_ui_at_rect(rect, |ui| { + ui.horizontal(|ui| { + pane.window.render_title_buttons(self, ui); + open_space = ui.available_rect_before_wrap(); + }) + }); + + let drag_sense = ui.interact( + open_space, + ui.id().with(&format!("Pane_{}_sense", pane.name)), + egui::Sense::drag(), + ); + + if drag_sense.drag_started() { + ret = egui_tiles::UiResponse::DragStarted; + } + if drag_sense.hovered() { + ui.ctx().set_cursor_icon(egui::CursorIcon::Grab); + } + pane.window.update(self, ui); ret } + + fn tab_bar_color(&self, visuals: &egui::Visuals) -> egui::Color32 { + visuals.panel_fill // same as the tab contents + } } diff --git a/unshell-gui/src/auth/mod.rs b/unshell-gui/src/auth/mod.rs index f87e3f7..1137229 100644 --- a/unshell-gui/src/auth/mod.rs +++ b/unshell-gui/src/auth/mod.rs @@ -1,8 +1,6 @@ -use serde_json::json; -use std::{collections::HashMap, sync::Arc, time::Duration}; - -use chrono::Utc; use egui::{Align2, Area, Frame, Order, Sense, UiKind, Vec2, mutex::Mutex}; +use serde_json::json; +use std::sync::Arc; use wasm_bindgen::prelude::Closure; #[derive(serde::Deserialize, serde::Serialize)] diff --git a/unshell-gui/src/config/mod.rs b/unshell-gui/src/config/mod.rs index fc72820..19cd7d9 100644 --- a/unshell-gui/src/config/mod.rs +++ b/unshell-gui/src/config/mod.rs @@ -1,7 +1,9 @@ use crate::auth::Auth; #[derive(Default, serde::Deserialize, serde::Serialize)] -pub struct Config {} +pub struct Config { + response_text: String, +} impl Config { pub fn update(&mut self, auth: &mut Auth, ui: &mut egui::Ui) { diff --git a/unshell-gui/src/flowchart/flowchart.rs b/unshell-gui/src/flowchart/flowchart.rs index 2fb03f5..27d975a 100644 --- a/unshell-gui/src/flowchart/flowchart.rs +++ b/unshell-gui/src/flowchart/flowchart.rs @@ -2,6 +2,8 @@ use egui::{Color32, Painter, Pos2, Rect, Scene, Shape, Ui}; use crate::flowchart::CONNECTION_STROKE; use crate::flowchart::GROUP_BORDER_MARGIN; +use crate::flowchart::ITERATIONS; +use crate::flowchart::RESOLUTION; use crate::flowchart::container::DraggableContainer; use crate::flowchart::group::convex_hull; use crate::flowchart::{BG_STROKE, TARGET_LINE_GAP}; @@ -34,12 +36,19 @@ impl Default for FlowChart { }; this.arrange_circle(); + this.arrange(); this } } impl FlowChart { + pub fn arrange(&mut self) { + for _ in 0..ITERATIONS { + self.force(RESOLUTION); + } + } + fn paint_bg(rect: &Rect, painter: &Painter) { let h_start = (rect.min.x / TARGET_LINE_GAP).round() as i32; let h_end = ((rect.min.x + rect.width()) / TARGET_LINE_GAP).round() as i32 + 1; @@ -93,12 +102,6 @@ impl FlowChart { } pub fn paint(&mut self, ui: &mut Ui) { - if ui.button("Arrange").clicked() { - for _ in 0..1_000 { - self.force(0.1); - } - } - let scene = Scene::new() // .max_inner_size([350.0, 1000.0]) .zoom_range(0.1..=2.0); diff --git a/unshell-gui/src/flowchart/mod.rs b/unshell-gui/src/flowchart/mod.rs index b465c11..3881bbf 100644 --- a/unshell-gui/src/flowchart/mod.rs +++ b/unshell-gui/src/flowchart/mod.rs @@ -6,6 +6,9 @@ mod group; use egui::{Color32, Stroke}; pub use flowchart::FlowChart; +const ITERATIONS: usize = 1_000; +const RESOLUTION: f32 = 0.6; + const TARGET_LINE_GAP: f32 = 80.; const BG_STROKE: Stroke = Stroke { diff --git a/unshell-gui/src/lib.rs b/unshell-gui/src/lib.rs index eb3cd98..98b1660 100644 --- a/unshell-gui/src/lib.rs +++ b/unshell-gui/src/lib.rs @@ -8,6 +8,9 @@ mod auth; mod config; mod flowchart; +use std::time::Duration; +const FORCE_REDRAW_DELAY: Duration = Duration::from_millis(300); + // mod JsFunc { // use wasm_bindgen::JsValue; use wasm_bindgen::prelude::*;