forked from 1b-agent/fieldcraft-upstream
Remove the SETUP card: the browser tree shows the progress
The setup checklist card (#265), its show_setup view setting, the View menu checkbox and the preferences file that only remembered it go; the tree's marks and ghost rows replace them. Session::progress and model.check's progress stay for agents. An old prefs.json is no longer read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
1 parent
f5a84f5f74
commit
012119e2c2
8 files changed
+3
-239
No files matched your search
@@ -188,7 +188,6 @@ fn services(inbox: Inbox, ctx: egui::Context) -> Services {
|
|||||||
pick_save: Some(Box::new(|name: &str, _: &[Filter]| Some(page_path(name)))),
|
pick_save: Some(Box::new(|name: &str, _: &[Filter]| Some(page_path(name)))),
|
||||||
// The recent list holds the page's files, which go with the page.
|
// The recent list holds the page's files, which go with the page.
|
||||||
recent_path: None,
|
recent_path: None,
|
||||||
prefs_path: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -95,7 +95,6 @@ fn services() -> Services {
|
|||||||
})),
|
})),
|
||||||
// Beside the recovery folder in the per-user data folder.
|
// Beside the recovery folder in the per-user data folder.
|
||||||
recent_path: fieldcraft_io::recovery::default_dir().and_then(|d| d.parent().map(|p| p.join("recent.json"))),
|
recent_path: fieldcraft_io::recovery::default_dir().and_then(|d| d.parent().map(|p| p.join("recent.json"))),
|
||||||
prefs_path: fieldcraft_io::recovery::default_dir().and_then(|d| d.parent().map(|p| p.join("prefs.json"))),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -525,7 +525,6 @@ pub fn browser(app: &mut ModelApp, ui: &mut egui::Ui) {
|
|||||||
.frame(egui::Frame::NONE.fill(t.panel).inner_margin(egui::Margin::symmetric(6, 6)))
|
.frame(egui::Frame::NONE.fill(t.panel).inner_margin(egui::Margin::symmetric(6, 6)))
|
||||||
.show(ui, |ui| {
|
.show(ui, |ui| {
|
||||||
app.place("browser", ui.max_rect());
|
app.place("browser", ui.max_rect());
|
||||||
crate::setup::card(app, ui);
|
|
||||||
ui.label(RichText::new("BROWSER").font(crate::theme::label_font(ui.ctx(), 10.5)).color(t.text_dim));
|
ui.label(RichText::new("BROWSER").font(crate::theme::label_font(ui.ctx(), 10.5)).color(t.text_dim));
|
||||||
ui.add_space(4.0);
|
ui.add_space(4.0);
|
||||||
egui::ScrollArea::vertical().id_salt("fc_browser_scroll").auto_shrink([false, false]).show(ui, |ui| {
|
egui::ScrollArea::vertical().id_salt("fc_browser_scroll").auto_shrink([false, false]).show(ui, |ui| {
|
||||||
|
|||||||
@@ -597,30 +597,6 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The setup checklist shows once there is something to set up, and a click on its next
|
|
||||||
/// stage opens that stage's form (#74).
|
|
||||||
#[test]
|
|
||||||
fn a_setup_stage_click_starts_its_command() {
|
|
||||||
let mut app = ModelApp::new(Session::default());
|
|
||||||
let ctx = egui::Context::default();
|
|
||||||
frame(&mut app, &ctx);
|
|
||||||
assert!(!app.layout.contains_key("setup"), "an empty model shows the Start card instead");
|
|
||||||
let cube = [[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0], [0, 0, 1], [1, 0, 1], [1, 1, 1], [0, 1, 1]];
|
|
||||||
app.run("mesh.block", json!({"body": "B", "kind": "hex8", "corners": cube, "divisions": [1, 1, 1]})).unwrap();
|
|
||||||
frame(&mut app, &ctx);
|
|
||||||
let at = app.layout[crate::setup::region(fieldcraft_engine::progress::Stage::Material)].center();
|
|
||||||
call_in(&mut app, &ctx, "ui.click", json!({"x": at.x, "y": at.y}));
|
|
||||||
for _ in 0..4 {
|
|
||||||
frame(&mut app, &ctx);
|
|
||||||
}
|
|
||||||
assert_eq!(app.dialog.as_ref().map(|d| d.command), Some("model.material.create"));
|
|
||||||
// Hidden from the View menu (or `ui.set`), it stays hidden.
|
|
||||||
assert_eq!(call_in(&mut app, &ctx, "ui.set", json!({"show_setup": false}))["ok"], true);
|
|
||||||
app.layout.clear();
|
|
||||||
frame(&mut app, &ctx);
|
|
||||||
assert!(!app.layout.contains_key("setup"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A meshed model's Materials node shows a highlighted ghost row; a click on it opens the
|
/// A meshed model's Materials node shows a highlighted ghost row; a click on it opens the
|
||||||
/// material form, and `ui.inspect` reports each node's state.
|
/// material form, and `ui.inspect` reports each node's state.
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -42,8 +42,6 @@ pub struct Services {
|
|||||||
pub pick_save: Option<PickSave>,
|
pub pick_save: Option<PickSave>,
|
||||||
/// The recent-files list's file (JSON); `None` keeps the list for this run only.
|
/// The recent-files list's file (JSON); `None` keeps the list for this run only.
|
||||||
pub recent_path: Option<PathBuf>,
|
pub recent_path: Option<PathBuf>,
|
||||||
/// The user's preferences file (JSON, [`Prefs`]); `None` keeps them for this run only.
|
|
||||||
pub prefs_path: Option<PathBuf>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const MODEL: Filter = Filter { name: "FieldCraft model", extensions: &["fieldcraft"] };
|
const MODEL: Filter = Filter { name: "FieldCraft model", extensions: &["fieldcraft"] };
|
||||||
@@ -166,47 +164,6 @@ impl Recent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Largest preferences file read.
|
|
||||||
const MAX_PREFS_BYTES: u64 = 64 * 1024;
|
|
||||||
|
|
||||||
/// What the window remembers for the user between runs.
|
|
||||||
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub struct Prefs {
|
|
||||||
/// The setup checklist at the top of the browser ([`crate::setup`]).
|
|
||||||
pub show_setup: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Prefs {
|
|
||||||
fn default() -> Self {
|
|
||||||
Prefs { show_setup: true }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Prefs {
|
|
||||||
/// The preferences kept in `file` (an unreadable or malformed file gives the defaults).
|
|
||||||
pub fn load(file: Option<&Path>) -> Prefs {
|
|
||||||
file.filter(|f| std::fs::metadata(f).is_ok_and(|m| m.is_file() && m.len() <= MAX_PREFS_BYTES))
|
|
||||||
.and_then(|f| std::fs::read(f).ok())
|
|
||||||
.and_then(|b| serde_json::from_slice(&b).ok())
|
|
||||||
.unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Write them to `file`; a failure is logged (the preferences stay for this run).
|
|
||||||
pub fn save(&self, file: Option<&Path>) {
|
|
||||||
let Some(file) = file else { return };
|
|
||||||
let write = || -> std::io::Result<()> {
|
|
||||||
if let Some(dir) = file.parent() {
|
|
||||||
std::fs::create_dir_all(dir)?;
|
|
||||||
}
|
|
||||||
std::fs::write(file, serde_json::to_vec_pretty(self).unwrap_or_default())
|
|
||||||
};
|
|
||||||
if let Err(e) = write() {
|
|
||||||
log::warn!("preferences {}: {e}", file.display());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A command running in the background on a copy of the session: a file opening, a solve, a
|
/// A command running in the background on a copy of the session: a file opening, a solve, a
|
||||||
/// mesher started from its form.
|
/// mesher started from its form.
|
||||||
pub struct Loading {
|
pub struct Loading {
|
||||||
@@ -1069,22 +1026,6 @@ mod tests {
|
|||||||
dir
|
dir
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Hiding the setup checklist is remembered in the preferences file; a missing or
|
|
||||||
/// malformed file gives the defaults.
|
|
||||||
#[test]
|
|
||||||
fn hiding_the_setup_checklist_is_remembered() {
|
|
||||||
let file = temp("prefs").join("prefs.json");
|
|
||||||
assert!(Prefs::load(Some(&file)).show_setup);
|
|
||||||
let services = || Services { prefs_path: Some(file.clone()), ..Default::default() };
|
|
||||||
let mut app = ModelApp::new(Session::default()).with_services(services());
|
|
||||||
app.ui.show_setup = false;
|
|
||||||
app.save_prefs();
|
|
||||||
let again = ModelApp::new(Session::default()).with_services(services());
|
|
||||||
assert!(!again.ui.show_setup);
|
|
||||||
std::fs::write(&file, b"{nope").unwrap();
|
|
||||||
assert_eq!(Prefs::load(Some(&file)), Prefs::default());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A picker that answers `path` and records the filters it was offered.
|
/// A picker that answers `path` and records the filters it was offered.
|
||||||
fn answering(path: Option<String>, offered: Rc<RefCell<Vec<Vec<Filter>>>>) -> PickOpen {
|
fn answering(path: Option<String>, offered: Rc<RefCell<Vec<Vec<Filter>>>>) -> PickOpen {
|
||||||
Box::new(move |f: &[Filter]| {
|
Box::new(move |f: &[Filter]| {
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ pub mod results;
|
|||||||
pub mod results_panel;
|
pub mod results_panel;
|
||||||
pub mod scene;
|
pub mod scene;
|
||||||
pub mod selection;
|
pub mod selection;
|
||||||
pub mod setup;
|
|
||||||
pub mod theme;
|
pub mod theme;
|
||||||
pub mod timeline;
|
pub mod timeline;
|
||||||
pub mod titlebar;
|
pub mod titlebar;
|
||||||
@@ -88,8 +87,6 @@ pub struct UiState {
|
|||||||
pub show_tree: bool,
|
pub show_tree: bool,
|
||||||
/// The journal timeline (bottom).
|
/// The journal timeline (bottom).
|
||||||
pub show_timeline: bool,
|
pub show_timeline: bool,
|
||||||
/// The setup checklist at the top of the browser (remembered per user).
|
|
||||||
pub show_setup: bool,
|
|
||||||
/// The workspace shown, and its toolbar tab.
|
/// The workspace shown, and its toolbar tab.
|
||||||
pub workspace: Workspace,
|
pub workspace: Workspace,
|
||||||
pub tab: Tab,
|
pub tab: Tab,
|
||||||
@@ -113,7 +110,6 @@ impl Default for UiState {
|
|||||||
dark: true,
|
dark: true,
|
||||||
show_tree: true,
|
show_tree: true,
|
||||||
show_timeline: true,
|
show_timeline: true,
|
||||||
show_setup: true,
|
|
||||||
workspace: Workspace::default(),
|
workspace: Workspace::default(),
|
||||||
tab: Tab::default(),
|
tab: Tab::default(),
|
||||||
palette: false,
|
palette: false,
|
||||||
@@ -356,8 +352,7 @@ pub struct ModelApp {
|
|||||||
/// Recently opened and saved files.
|
/// Recently opened and saved files.
|
||||||
pub recent: files::Recent,
|
pub recent: files::Recent,
|
||||||
/// The user's preferences as last saved.
|
/// The user's preferences as last saved.
|
||||||
prefs: files::Prefs,
|
/// The setup progress the browser marks, and what it was worked out for.
|
||||||
/// The setup checklist and what it was worked out for.
|
|
||||||
setup: (Option<(u64, u64, bool, bool)>, std::sync::Arc<Vec<fieldcraft_engine::progress::StageState>>),
|
setup: (Option<(u64, u64, bool, bool)>, std::sync::Arc<Vec<fieldcraft_engine::progress::StageState>>),
|
||||||
/// The file opening in the background, and files waiting to open after it.
|
/// The file opening in the background, and files waiting to open after it.
|
||||||
pub loading: Option<files::Loading>,
|
pub loading: Option<files::Loading>,
|
||||||
@@ -436,7 +431,6 @@ impl ModelApp {
|
|||||||
quit_requested: false,
|
quit_requested: false,
|
||||||
services: files::Services::default(),
|
services: files::Services::default(),
|
||||||
recent: files::Recent::default(),
|
recent: files::Recent::default(),
|
||||||
prefs: files::Prefs::default(),
|
|
||||||
setup: (None, std::sync::Arc::default()),
|
setup: (None, std::sync::Arc::default()),
|
||||||
loading: None,
|
loading: None,
|
||||||
queued: std::collections::VecDeque::new(),
|
queued: std::collections::VecDeque::new(),
|
||||||
@@ -469,8 +463,6 @@ impl ModelApp {
|
|||||||
/// Use the host's services (file pickers, the recent-files file) and load the recent list.
|
/// Use the host's services (file pickers, the recent-files file) and load the recent list.
|
||||||
pub fn with_services(mut self, services: files::Services) -> Self {
|
pub fn with_services(mut self, services: files::Services) -> Self {
|
||||||
self.recent = files::Recent::load(services.recent_path.clone());
|
self.recent = files::Recent::load(services.recent_path.clone());
|
||||||
self.prefs = files::Prefs::load(services.prefs_path.as_deref());
|
|
||||||
self.ui.show_setup = self.prefs.show_setup;
|
|
||||||
self.services = services;
|
self.services = services;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -1327,7 +1319,6 @@ impl ModelApp {
|
|||||||
browser::browser(self, ui);
|
browser::browser(self, ui);
|
||||||
}
|
}
|
||||||
context::panel(self, ui);
|
context::panel(self, ui);
|
||||||
self.save_prefs();
|
|
||||||
egui::CentralPanel::default().frame(egui::Frame::NONE).show(ui, |ui| viewport::show(self, ui));
|
egui::CentralPanel::default().frame(egui::Frame::NONE).show(ui, |ui| viewport::show(self, ui));
|
||||||
palette::popup(self, ui.ctx());
|
palette::popup(self, ui.ctx());
|
||||||
files::show(self, ui.ctx());
|
files::show(self, ui.ctx());
|
||||||
@@ -1336,8 +1327,8 @@ impl ModelApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The setup checklist ([`fieldcraft_engine::progress`]), worked out again only when the model
|
/// The setup progress ([`fieldcraft_engine::progress`]) the browser marks, worked out again
|
||||||
/// or its results change.
|
/// only when the model or its results change.
|
||||||
pub fn setup_stages(&mut self) -> std::sync::Arc<Vec<fieldcraft_engine::progress::StageState>> {
|
pub fn setup_stages(&mut self) -> std::sync::Arc<Vec<fieldcraft_engine::progress::StageState>> {
|
||||||
use fieldcraft_engine::requirement::Requirement;
|
use fieldcraft_engine::requirement::Requirement;
|
||||||
let key = (self.revision, self.session.revision(), Requirement::Result.met(&self.session), Requirement::ResultsShown.met(&self.session));
|
let key = (self.revision, self.session.revision(), Requirement::Result.met(&self.session), Requirement::ResultsShown.met(&self.session));
|
||||||
@@ -1347,14 +1338,6 @@ impl ModelApp {
|
|||||||
self.setup.1.clone()
|
self.setup.1.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Save the preferences the window changed (a View menu toggle, `ui.set`).
|
|
||||||
pub(crate) fn save_prefs(&mut self) {
|
|
||||||
if self.ui.show_setup != self.prefs.show_setup {
|
|
||||||
self.prefs.show_setup = self.ui.show_setup;
|
|
||||||
self.prefs.save(self.services.prefs_path.as_deref());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Remember where a region of the window was drawn (`ui.inspect`'s `layout`).
|
/// Remember where a region of the window was drawn (`ui.inspect`'s `layout`).
|
||||||
pub fn place(&mut self, region: &'static str, rect: egui::Rect) {
|
pub fn place(&mut self, region: &'static str, rect: egui::Rect) {
|
||||||
self.layout.insert(region, rect);
|
self.layout.insert(region, rect);
|
||||||
|
|||||||
@@ -1,132 +0,0 @@
|
|||||||
//! The setup checklist at the top of the browser: the analysis stages from geometry to results
|
|
||||||
//! ([`fieldcraft_engine::progress`]), each ticked when done, the next one highlighted, and
|
|
||||||
//! optional ones dashed. A click on a stage starts its command (as its toolbar button would);
|
|
||||||
//! a blocked stage's hover says what it waits for. It shows once the model has geometry or a
|
|
||||||
//! mesh (before that the viewport's Start card is the entry), and the × hides it until the
|
|
||||||
//! View menu shows it again; the choice is remembered per user.
|
|
||||||
|
|
||||||
use egui::{FontId, Pos2, Rect, Sense, Stroke, pos2, vec2};
|
|
||||||
use fieldcraft_engine::progress::{Stage, StageState, Status};
|
|
||||||
|
|
||||||
use crate::ModelApp;
|
|
||||||
use crate::theme::Tokens;
|
|
||||||
|
|
||||||
const ROW_H: f32 = 20.0;
|
|
||||||
|
|
||||||
/// Where a stage's row was drawn (`ui.inspect`'s `layout`).
|
|
||||||
pub fn region(stage: Stage) -> &'static str {
|
|
||||||
match stage {
|
|
||||||
Stage::Geometry => "setup/geometry",
|
|
||||||
Stage::Prepare => "setup/prepare",
|
|
||||||
Stage::Mesh => "setup/mesh",
|
|
||||||
Stage::Material => "setup/material",
|
|
||||||
Stage::Section => "setup/section",
|
|
||||||
Stage::Sets => "setup/sets",
|
|
||||||
Stage::BoundaryConditions => "setup/boundary_conditions",
|
|
||||||
Stage::Loads => "setup/loads",
|
|
||||||
Stage::Step => "setup/step",
|
|
||||||
Stage::Solve => "setup/solve",
|
|
||||||
Stage::Results => "setup/results",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn card(app: &mut ModelApp, ui: &mut egui::Ui) {
|
|
||||||
if !app.ui.show_setup {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let stages = app.setup_stages();
|
|
||||||
if stages.first().is_none_or(|g| g.status != Status::Done) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let t = Tokens::get(app.ui.dark);
|
|
||||||
let mut start = None;
|
|
||||||
let frame = egui::Frame::NONE.fill(t.dialog_bg).stroke(Stroke::new(1.0, t.border)).corner_radius(4.0).inner_margin(egui::Margin::same(6));
|
|
||||||
let r = frame.show(ui, |ui| {
|
|
||||||
ui.spacing_mut().item_spacing.y = 0.0;
|
|
||||||
ui.horizontal(|ui| {
|
|
||||||
ui.label(egui::RichText::new("SETUP").font(crate::theme::label_font(ui.ctx(), 10.5)).color(t.text_dim));
|
|
||||||
let done = stages.iter().filter(|s| matches!(s.status, Status::Done)).count();
|
|
||||||
ui.label(egui::RichText::new(format!("{done} of {}", stages.len())).size(10.5).color(t.text_dim));
|
|
||||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
|
||||||
let close = ui.add(egui::Button::new(egui::RichText::new("×").size(13.0).color(t.text_dim)).frame(false));
|
|
||||||
if close.on_hover_text("Hide the setup checklist (View › Setup checklist shows it again)").clicked() {
|
|
||||||
app.ui.show_setup = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
ui.add_space(2.0);
|
|
||||||
for s in stages.iter() {
|
|
||||||
if row(app, ui, &t, s) {
|
|
||||||
start = Some(s.command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
app.place("setup", r.response.rect);
|
|
||||||
ui.add_space(6.0);
|
|
||||||
if let Some(command) = start {
|
|
||||||
// A command that cannot run yet says why in the status bar.
|
|
||||||
let _ = app.start(command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// One stage; true when clicked.
|
|
||||||
fn row(app: &mut ModelApp, ui: &mut egui::Ui, t: &Tokens, s: &StageState) -> bool {
|
|
||||||
let (r, resp) = ui.allocate_exact_size(vec2(ui.available_width(), ROW_H), Sense::click());
|
|
||||||
app.place(region(s.stage), r);
|
|
||||||
let next = s.status == Status::Next;
|
|
||||||
if next {
|
|
||||||
ui.painter().rect_filled(r, 3.0, t.accent_soft);
|
|
||||||
} else if resp.hovered() {
|
|
||||||
ui.painter().rect_filled(r, 3.0, t.hover);
|
|
||||||
}
|
|
||||||
let mark = Rect::from_center_size(pos2(r.left() + 10.0, r.center().y), vec2(10.0, 10.0));
|
|
||||||
paint_mark(ui.painter(), mark, s.status, t);
|
|
||||||
let colour = match s.status {
|
|
||||||
Status::Done | Status::Next => t.text,
|
|
||||||
Status::Todo | Status::Blocked | Status::Optional => t.text_dim,
|
|
||||||
};
|
|
||||||
let x = r.left() + 22.0;
|
|
||||||
ui.painter().with_clip_rect(r).text(pos2(x, r.center().y), egui::Align2::LEFT_CENTER, s.label, FontId::proportional(12.5), colour);
|
|
||||||
let note = match s.status {
|
|
||||||
Status::Next => Some("next"),
|
|
||||||
Status::Optional => Some("optional"),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
if let Some(n) = note {
|
|
||||||
let c = if next { t.accent } else { t.text_dim };
|
|
||||||
ui.painter().text(pos2(r.right() - 4.0, r.center().y), egui::Align2::RIGHT_CENTER, n, FontId::proportional(11.0), c);
|
|
||||||
}
|
|
||||||
let tip = match &s.detail {
|
|
||||||
Some(why) => format!("{}\n\n{why}", s.place),
|
|
||||||
None => s.place.clone(),
|
|
||||||
};
|
|
||||||
let resp = resp.on_hover_text(tip);
|
|
||||||
resp.widget_info(|| egui::WidgetInfo::labeled(egui::WidgetType::Button, true, s.label));
|
|
||||||
resp.clicked()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ✓ done, → next, – optional, an open circle for the rest (struck through when blocked).
|
|
||||||
fn paint_mark(p: &egui::Painter, r: Rect, status: Status, t: &Tokens) {
|
|
||||||
let at = |x: f32, y: f32| Pos2::new(r.left() + x * r.width(), r.top() + y * r.height());
|
|
||||||
match status {
|
|
||||||
Status::Done => {
|
|
||||||
p.line_segment([at(0.05, 0.55), at(0.4, 0.88)], Stroke::new(1.8, t.ok));
|
|
||||||
p.line_segment([at(0.4, 0.88), at(0.95, 0.15)], Stroke::new(1.8, t.ok));
|
|
||||||
}
|
|
||||||
Status::Next => {
|
|
||||||
p.line_segment([at(0.0, 0.5), at(0.95, 0.5)], Stroke::new(1.6, t.accent));
|
|
||||||
p.line_segment([at(0.55, 0.15), at(0.95, 0.5)], Stroke::new(1.6, t.accent));
|
|
||||||
p.line_segment([at(0.55, 0.85), at(0.95, 0.5)], Stroke::new(1.6, t.accent));
|
|
||||||
}
|
|
||||||
Status::Optional => {
|
|
||||||
p.line_segment([at(0.15, 0.5), at(0.85, 0.5)], Stroke::new(1.4, t.text_dim));
|
|
||||||
}
|
|
||||||
Status::Todo => {
|
|
||||||
p.circle_stroke(r.center(), r.width() * 0.4, Stroke::new(1.2, t.text_dim));
|
|
||||||
}
|
|
||||||
Status::Blocked => {
|
|
||||||
p.circle_stroke(r.center(), r.width() * 0.4, Stroke::new(1.2, t.text_dim));
|
|
||||||
p.line_segment([at(0.2, 0.8), at(0.8, 0.2)], Stroke::new(1.2, t.text_dim));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -559,7 +559,6 @@ fn nav_bar(app: &mut ModelApp, ui: &mut egui::Ui, rect: Rect, t: &Tokens) {
|
|||||||
ui.checkbox(&mut app.ui.show_interactions, "Interactions");
|
ui.checkbox(&mut app.ui.show_interactions, "Interactions");
|
||||||
ui.separator();
|
ui.separator();
|
||||||
ui.checkbox(&mut app.ui.show_tree, "Browser");
|
ui.checkbox(&mut app.ui.show_tree, "Browser");
|
||||||
ui.checkbox(&mut app.ui.show_setup, "Setup checklist");
|
|
||||||
ui.checkbox(&mut app.ui.show_timeline, "Timeline");
|
ui.checkbox(&mut app.ui.show_timeline, "Timeline");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user