From db738371ac0af0b64ff61fe84a2bff7b486c1bd8 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 9 Jan 2024 10:16:32 -0700 Subject: [PATCH] Add menu --- Cargo.lock | 63 +++++++++++++---------------- i18n/en/cosmic_term.ftl | 20 +++++++++- src/config.rs | 2 +- src/main.rs | 88 ++++++++++++++++++++++++++--------------- src/menu.rs | 78 ++++++++++++++++++++++++++++++++++-- src/terminal.rs | 7 +++- 6 files changed, 184 insertions(+), 74 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c5acb8e..520698f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -518,9 +518,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.5" +version = "0.21.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "c79fed4cdb43e993fcdadc7e58a09fd0e3e649c4436fa11da71c9f1f3ee7feb9" [[package]] name = "bit-set" @@ -840,7 +840,7 @@ dependencies = [ [[package]] name = "cosmic-config" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#98d6d67ab9a895eef4fa2ab6103253f5fe9ac52b" +source = "git+https://github.com/pop-os/libcosmic.git#5b2ac941c36e1b7e2b4fa9a9162b64dc10afffef" dependencies = [ "atomicwrites", "cosmic-config-derive", @@ -855,7 +855,7 @@ dependencies = [ [[package]] name = "cosmic-config-derive" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#98d6d67ab9a895eef4fa2ab6103253f5fe9ac52b" +source = "git+https://github.com/pop-os/libcosmic.git#5b2ac941c36e1b7e2b4fa9a9162b64dc10afffef" dependencies = [ "quote", "syn 1.0.109", @@ -903,7 +903,7 @@ dependencies = [ [[package]] name = "cosmic-theme" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#98d6d67ab9a895eef4fa2ab6103253f5fe9ac52b" +source = "git+https://github.com/pop-os/libcosmic.git#5b2ac941c36e1b7e2b4fa9a9162b64dc10afffef" dependencies = [ "almost", "cosmic-config", @@ -934,44 +934,37 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a9b73a36529d9c47029b9fb3a6f0ea3cc916a261195352ba19e770fc1748b2" +checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.17" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.18" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crunchy" @@ -1785,9 +1778,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "js-sys", @@ -2086,7 +2079,7 @@ dependencies = [ [[package]] name = "iced" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#98d6d67ab9a895eef4fa2ab6103253f5fe9ac52b" +source = "git+https://github.com/pop-os/libcosmic.git#5b2ac941c36e1b7e2b4fa9a9162b64dc10afffef" dependencies = [ "iced_accessibility", "iced_core", @@ -2101,7 +2094,7 @@ dependencies = [ [[package]] name = "iced_accessibility" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#98d6d67ab9a895eef4fa2ab6103253f5fe9ac52b" +source = "git+https://github.com/pop-os/libcosmic.git#5b2ac941c36e1b7e2b4fa9a9162b64dc10afffef" dependencies = [ "accesskit", "accesskit_winit", @@ -2110,7 +2103,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#98d6d67ab9a895eef4fa2ab6103253f5fe9ac52b" +source = "git+https://github.com/pop-os/libcosmic.git#5b2ac941c36e1b7e2b4fa9a9162b64dc10afffef" dependencies = [ "bitflags 1.3.2", "instant", @@ -2126,7 +2119,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#98d6d67ab9a895eef4fa2ab6103253f5fe9ac52b" +source = "git+https://github.com/pop-os/libcosmic.git#5b2ac941c36e1b7e2b4fa9a9162b64dc10afffef" dependencies = [ "futures", "iced_core", @@ -2139,7 +2132,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#98d6d67ab9a895eef4fa2ab6103253f5fe9ac52b" +source = "git+https://github.com/pop-os/libcosmic.git#5b2ac941c36e1b7e2b4fa9a9162b64dc10afffef" dependencies = [ "bitflags 1.3.2", "bytemuck", @@ -2162,7 +2155,7 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#98d6d67ab9a895eef4fa2ab6103253f5fe9ac52b" +source = "git+https://github.com/pop-os/libcosmic.git#5b2ac941c36e1b7e2b4fa9a9162b64dc10afffef" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -2175,7 +2168,7 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#98d6d67ab9a895eef4fa2ab6103253f5fe9ac52b" +source = "git+https://github.com/pop-os/libcosmic.git#5b2ac941c36e1b7e2b4fa9a9162b64dc10afffef" dependencies = [ "iced_core", "iced_futures", @@ -2185,7 +2178,7 @@ dependencies = [ [[package]] name = "iced_style" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#98d6d67ab9a895eef4fa2ab6103253f5fe9ac52b" +source = "git+https://github.com/pop-os/libcosmic.git#5b2ac941c36e1b7e2b4fa9a9162b64dc10afffef" dependencies = [ "iced_core", "once_cell", @@ -2195,7 +2188,7 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#98d6d67ab9a895eef4fa2ab6103253f5fe9ac52b" +source = "git+https://github.com/pop-os/libcosmic.git#5b2ac941c36e1b7e2b4fa9a9162b64dc10afffef" dependencies = [ "bytemuck", "cosmic-text", @@ -2213,7 +2206,7 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#98d6d67ab9a895eef4fa2ab6103253f5fe9ac52b" +source = "git+https://github.com/pop-os/libcosmic.git#5b2ac941c36e1b7e2b4fa9a9162b64dc10afffef" dependencies = [ "bitflags 1.3.2", "bytemuck", @@ -2233,7 +2226,7 @@ dependencies = [ [[package]] name = "iced_widget" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#98d6d67ab9a895eef4fa2ab6103253f5fe9ac52b" +source = "git+https://github.com/pop-os/libcosmic.git#5b2ac941c36e1b7e2b4fa9a9162b64dc10afffef" dependencies = [ "iced_renderer", "iced_runtime", @@ -2247,7 +2240,7 @@ dependencies = [ [[package]] name = "iced_winit" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic.git#98d6d67ab9a895eef4fa2ab6103253f5fe9ac52b" +source = "git+https://github.com/pop-os/libcosmic.git#5b2ac941c36e1b7e2b4fa9a9162b64dc10afffef" dependencies = [ "iced_graphics", "iced_runtime", @@ -2499,7 +2492,7 @@ source = "git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox_0.2. [[package]] name = "libcosmic" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic.git#98d6d67ab9a895eef4fa2ab6103253f5fe9ac52b" +source = "git+https://github.com/pop-os/libcosmic.git#5b2ac941c36e1b7e2b4fa9a9162b64dc10afffef" dependencies = [ "apply", "ashpd", diff --git a/i18n/en/cosmic_term.ftl b/i18n/en/cosmic_term.ftl index a7e5787..775af8d 100644 --- a/i18n/en/cosmic_term.ftl +++ b/i18n/en/cosmic_term.ftl @@ -15,9 +15,25 @@ default-font = Default font default-font-size = Default font size default-zoom-step = Default zoom step -# Context menu +# Menu + +## File +file = File +new-tab = New tab +new-window = New window +close-tab = Close tab +quit = Quit + +## Edit +edit = Edit copy = Copy paste = Paste select-all = Select all -new-tab = New tab +find = Find + +## View +view = View +menu-settings = Settings... + +# Context menu show-headerbar = Show header bar diff --git a/src/config.rs b/src/config.rs index a6e3a0c..c0aec54 100644 --- a/src/config.rs +++ b/src/config.rs @@ -56,7 +56,7 @@ impl Config { let font_size = f32::from(self.font_size).max(1.0); let adj = f32::from(zoom_adj); let adj_step = f32::from(self.font_size_zoom_step_mul_100) / 100.0; - (font_size + adj*adj_step).max(1.0) + (font_size + adj * adj_step).max(1.0) } // Calculate metrics from font size diff --git a/src/main.rs b/src/main.rs index 892a806..fe60819 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,12 +30,13 @@ mod config; mod localize; +use menu::menu_bar; mod menu; -use self::terminal::{Terminal, TerminalScroll}; +use terminal::{Terminal, TerminalScroll}; mod terminal; -use self::terminal_box::terminal_box; +use terminal_box::terminal_box; mod terminal_box; mod terminal_theme; @@ -140,24 +141,27 @@ pub enum Message { Copy(Option), DefaultFont(usize), DefaultFontSize(usize), - ZoomIn, - ZoomOut, - ZoomReset, DefaultZoomStep(usize), Paste(Option), PasteValue(Option, String), SelectAll(Option), ShowHeaderBar(bool), - SystemThemeModeChange(cosmic_theme::ThemeMode), SyntaxTheme(usize, bool), + SystemThemeModeChange(cosmic_theme::ThemeMode), TabActivate(segmented_button::Entity), - TabClose(segmented_button::Entity), + TabClose(Option), TabContextAction(segmented_button::Entity, Action), TabContextMenu(segmented_button::Entity, Option), TabNew, TermEvent(segmented_button::Entity, TermEvent), TermEventTx(mpsc::Sender<(segmented_button::Entity, TermEvent)>), + Todo(&'static str), ToggleContextPage(ContextPage), + WindowClose, + WindowNew, + ZoomIn, + ZoomOut, + ZoomReset, } #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -473,17 +477,15 @@ impl Application for App { } } } - Message::ZoomIn => { - self.zoom_adj = self.zoom_adj.saturating_add(1); - return self.save_config(); - }, - Message::ZoomOut => { - self.zoom_adj = self.zoom_adj.saturating_sub(1); - return self.save_config(); - }, - Message::ZoomReset => { - self.zoom_adj = 0; - return self.save_config(); + Message::DefaultFontSize(index) => match self.font_sizes.get(index) { + Some(font_size) => { + self.config.font_size = *font_size; + self.zoom_adj = 0; // reset zoom + return self.save_config(); + } + None => { + log::warn!("failed to find font with index {}", index); + } }, Message::DefaultZoomStep(index) => match self.zoom_steps.get(index) { Some(zoom_step) => { @@ -495,16 +497,6 @@ impl Application for App { log::warn!("failed to find zoom step with index {}", index); } }, - Message::DefaultFontSize(index) => match self.font_sizes.get(index) { - Some(font_size) => { - self.config.font_size = *font_size; - self.zoom_adj = 0; // reset zoom - return self.save_config(); - } - None => { - log::warn!("failed to find font with index {}", index); - } - }, Message::Paste(entity_opt) => { return clipboard::read(move |value_opt| match value_opt { Some(value) => message::app(Message::PasteValue(entity_opt, value)), @@ -551,7 +543,9 @@ impl Application for App { self.tab_model.activate(entity); return self.update_title(); } - Message::TabClose(entity) => { + Message::TabClose(entity_opt) => { + let entity = entity_opt.unwrap_or_else(|| self.tab_model.active()); + // Activate closest item if let Some(position) = self.tab_model.position(entity) { if position > 0 { @@ -640,7 +634,7 @@ impl Application for App { } } TermEvent::Exit => { - return self.update(Message::TabClose(entity)); + return self.update(Message::TabClose(Some(entity))); } TermEvent::PtyWrite(text) => { if let Some(terminal) = self.tab_model.data::>(entity) { @@ -676,6 +670,9 @@ impl Application for App { Message::TermEventTx(term_event_tx) => { self.term_event_tx_opt = Some(term_event_tx); } + Message::Todo(todo) => { + log::warn!("TODO: {}", todo); + } Message::ToggleContextPage(context_page) => { if self.context_page == context_page { self.core.window.show_context = !self.core.window.show_context; @@ -685,6 +682,32 @@ impl Application for App { } self.set_context_title(context_page.title()); } + Message::WindowClose => { + return window::close(window::Id::MAIN); + } + Message::WindowNew => match env::current_exe() { + Ok(exe) => match process::Command::new(&exe).spawn() { + Ok(_child) => {} + Err(err) => { + log::error!("failed to execute {:?}: {}", exe, err); + } + }, + Err(err) => { + log::error!("failed to get current executable path: {}", err); + } + }, + Message::ZoomIn => { + self.zoom_adj = self.zoom_adj.saturating_add(1); + return self.save_config(); + } + Message::ZoomOut => { + self.zoom_adj = self.zoom_adj.saturating_sub(1); + return self.save_config(); + } + Message::ZoomReset => { + self.zoom_adj = 0; + return self.save_config(); + } } Command::none() @@ -707,7 +730,8 @@ impl Application for App { widget::button(widget::icon::from_name("list-add-symbolic").size(16).icon()) .on_press(Message::TabNew) .padding(space_xxs) - .style(style::Button::Icon) + .style(style::Button::Icon), + menu_bar(&self.config) ] .align_items(Alignment::Center) .into()] @@ -741,7 +765,7 @@ impl Application for App { .button_height(32) .button_spacing(space_xxs) .on_activate(Message::TabActivate) - .on_close(Message::TabClose), + .on_close(|entity| Message::TabClose(Some(entity))), ) .style(style::Container::Background) .width(Length::Fill), diff --git a/src/menu.rs b/src/menu.rs index 600d4c2..f3b5fdd 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -3,15 +3,19 @@ use cosmic::{ //TODO: export in cosmic::widget iced::{ - widget::{column, horizontal_rule}, + widget::{column, horizontal_rule, horizontal_space}, Alignment, Background, Length, }, theme, - widget::{self, segmented_button}, + widget::{ + self, + menu::{ItemHeight, ItemWidth, MenuBar, MenuTree}, + segmented_button, + }, Element, }; -use crate::{fl, Action, Config, Message}; +use crate::{fl, Action, Config, ContextPage, Message}; macro_rules! menu_button { ($($x:expr),+ $(,)?) => ( @@ -75,3 +79,71 @@ pub fn context_menu<'a>(config: &Config, entity: segmented_button::Entity) -> El .width(Length::Fixed(240.0)) .into() } + +pub fn menu_bar<'a>(config: &Config) -> Element<'a, Message> { + //TODO: port to libcosmic + let menu_root = |label| { + widget::button(widget::text(label)) + .padding([4, 12]) + .style(theme::Button::MenuRoot) + }; + + let find_key = |message: &Message| -> String { + //TODO: hotkey config + String::new() + }; + + let menu_item = |label, message| { + let key = find_key(&message); + MenuTree::new( + menu_button!( + widget::text(label), + horizontal_space(Length::Fill), + widget::text(key) + ) + .on_press(message), + ) + }; + + let menu_key = |label, key, message| { + MenuTree::new( + menu_button!(widget::text(label), horizontal_space(Length::Fill), key) + .on_press(message), + ) + }; + + MenuBar::new(vec![ + MenuTree::with_children( + menu_root(fl!("file")), + vec![ + menu_item(fl!("new-tab"), Message::TabNew), + menu_item(fl!("new-window"), Message::WindowNew), + MenuTree::new(horizontal_rule(1)), + menu_item(fl!("close-tab"), Message::TabClose(None)), + MenuTree::new(horizontal_rule(1)), + menu_item(fl!("quit"), Message::WindowClose), + ], + ), + MenuTree::with_children( + menu_root(fl!("edit")), + vec![ + menu_item(fl!("copy"), Message::Copy(None)), + menu_item(fl!("paste"), Message::Paste(None)), + menu_item(fl!("select-all"), Message::SelectAll(None)), + MenuTree::new(horizontal_rule(1)), + menu_key(fl!("find"), "Ctrl + F", Message::Todo("find")), + ], + ), + MenuTree::with_children( + menu_root(fl!("view")), + vec![menu_item( + fl!("menu-settings"), + Message::ToggleContextPage(ContextPage::Settings), + )], + ), + ]) + .item_height(ItemHeight::Dynamic(40)) + .item_width(ItemWidth::Uniform(240)) + .spacing(4.0) + .into() +} diff --git a/src/terminal.rs b/src/terminal.rs index df49a54..74ac22d 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -318,7 +318,12 @@ impl Terminal { self.update(); } - pub fn set_config(&mut self, config: &crate::Config, themes: &HashMap, zoom_adj: i8) { + pub fn set_config( + &mut self, + config: &crate::Config, + themes: &HashMap, + zoom_adj: i8, + ) { let mut update_cell_size = false; let mut update = false;