//! Eine Befehlsliste für Menü, Tastatur und Statusleiste. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Command { NewProject, OpenProject, SaveProject, NewForm, NewModule, AddFile, RemoveFile, SaveFile, SaveAs, LoadText, SaveText, Print, Shell, Exit, Undo, Cut, Copy, Paste, Clear, Procedures, PreviousCode, Diagnostics, NewSub, NewFunction, Events, Code, Form, NextStatement, OutputScreen, IncludedFile, IncludedLines, MenuBar, Grid, Find, SelectedText, FindNext, Replace, Start, Restart, Continue, Pause, CommandLine, MakeExe, MakeLibrary, Startup, AddWatch, InstantWatch, Watchpoint, DeleteWatch, DeleteWatches, Trace, History, Breakpoint, ClearBreakpoints, BreakErrors, SetStatement, RunToCursor, Step, ProcedureStep, HistoryBack, HistoryForward, Display, Paths, RightMouse, SaveOptions, SyntaxChecking, NewWindow, Arrange, Calls, Debug, HelpWindow, Immediate, Output, Project, Palette, MenuDesign, Toolbox, Tool(&'static str), HelpIndex, HelpContents, Keyboard, Topic, UsingHelp, Tutorial, About, NextWindow, PreviousWindow, CloseWindow, MoveWindow, SizeWindow, Minimize, Maximize, Restore, ControlMenu, FocusWindow(u64), } impl Command { pub fn feature_phase(self) -> Option { use Command::*; match self { NextStatement | AddWatch | InstantWatch | Watchpoint | DeleteWatch | DeleteWatches | Trace | History | Breakpoint | ClearBreakpoints | BreakErrors | SetStatement | RunToCursor | Step | ProcedureStep | HistoryBack | HistoryForward => Some(6), HelpIndex | HelpContents | Keyboard | Topic | UsingHelp | Tutorial => Some(7), _ => None, } } } #[derive(Debug, Clone)] pub struct Item { /// & markiert das sichtbare Mnemonic, … einen Dialog. pub label: String, pub command: Option, } impl Item { pub fn text(&self) -> String { self.label.replace('&', "") } pub fn mnemonic(&self) -> Option { self.label .split_once('&')? .1 .chars() .next() .map(|c| c.to_ascii_lowercase()) } } pub struct Menu { pub title: &'static str, pub mnemonic: char, pub items: Vec, } pub fn menus(designer: bool) -> Vec { use Command::*; let item = |label: &str, command| Item { label: label.into(), command: Some(command), }; let sep = || Item { label: "────────".into(), command: None, }; let menu = |title, mnemonic, items| Menu { title, mnemonic, items, }; let mut result = vec![ menu( "File", 'f', vec![ item("&New Project", NewProject), item("&Open Project…", OpenProject), item("Save &Project", SaveProject), sep(), item("New &Form", NewForm), item("New &Module…", NewModule), item("&Add File…", AddFile), item("&Remove File…", RemoveFile), item("&Save File", SaveFile), item("Sa&ve File As…", SaveAs), sep(), item("&Load Text…", LoadText), item("Save &Text…", SaveText), sep(), item("Pr&int…", Print), item("S&hell", Shell), sep(), item("E&xit", Exit), ], ), menu( "Edit", 'e', vec![ item("&Undo", Undo), sep(), item("Cu&t", Cut), item("&Copy", Copy), item("&Paste", Paste), item("C&lear", Clear), sep(), item("New &Sub…", NewSub), item("New &Function…", NewFunction), item("&Event Procedures…", Events), ], ), menu( "View", 'v', vec![ item("&Code…", Code), item("&Procedures…", Procedures), item("Diagno&stics…", Diagnostics), item("&Form…", Form), sep(), item("&Next Statement", NextStatement), item("&Output Screen", OutputScreen), sep(), item("&Included File", IncludedFile), item("Included &Lines", IncludedLines), ], ), ]; if designer { result[2] .items .extend([sep(), item("&Menu Bar", MenuBar), item("&Grid Lines", Grid)]); result.push(menu("Tools", 't', { let mut used = std::collections::BTreeSet::new(); crate::designer::tools() .into_iter() .map(|(name, _, _)| { let mut label = name.to_owned(); if let Some((at, c)) = name .char_indices() .find(|(_, c)| !used.contains(&c.to_ascii_lowercase())) { used.insert(c.to_ascii_lowercase()); label.insert(at, '&'); } else { let c = ('1'..='9').find(|c| !used.contains(c)).unwrap(); used.insert(c); label = format!("&{c} {label}"); } Item { label, command: Some(Tool(name)), } }) .collect() })); } else { result.extend([ menu( "Search", 's', vec![ item("&Find…", Find), item("&Selected Text", SelectedText), item("&Repeat Last Find", FindNext), item("&Change…", Replace), ], ), menu( "Run", 'r', vec![ item("&Start", Start), item("&Restart", Restart), item("&Continue", Continue), item("&Pause (Ctrl+Break)", Pause), item("Modify COMMAND&$…", CommandLine), sep(), item("Make &EXE File…", MakeExe), item("Make &Library…", MakeLibrary), sep(), item("Set Start-&up File…", Startup), ], ), menu( "Debug", 'd', vec![ item("&Add Watch…", AddWatch), item("&Instant Watch…", InstantWatch), item("&Watchpoint…", Watchpoint), item("&Delete Watch…", DeleteWatch), item("Delete A&ll Watch", DeleteWatches), sep(), item("&Trace On", Trace), item("&History On", History), sep(), item("Toggle &Breakpoint", Breakpoint), item("&Clear All Breakpoints", ClearBreakpoints), item("Break on &Errors", BreakErrors), item("Set &Next Statement", SetStatement), ], ), ]); } result.push(menu( "Options", 'o', vec![ item("&Display…", Display), item("Set &Paths…", Paths), item("&Right Mouse…", RightMouse), item("&Save…", SaveOptions), item("S&yntax Checking", SyntaxChecking), ], )); result.push(if designer { menu( "Window", 'w', vec![ item("&Color Palette", Palette), item("&Menu Design Window", MenuDesign), item("&Toolbox", Toolbox), item("&Help", HelpWindow), ], ) } else { menu( "Window", 'w', vec![ item("&New Window", NewWindow), item("&Arrange All", Arrange), sep(), item("&Calls", Calls), item("&Debug", Debug), item("&Help", HelpWindow), item("&Immediate", Immediate), item("&Output", Output), item("&Project", Project), sep(), ], ) }); result.push(menu( "Help", 'h', vec![ item("&Index", HelpIndex), item("&Contents", HelpContents), sep(), item("&Keyboard", Keyboard), sep(), item("&Topic", Topic), item("&Using Help", UsingHelp), item("Tuto&rial", Tutorial), sep(), item("&About…", About), ], )); result }