diff --git a/src/ui.rs b/src/ui.rs index ea8dbb2fd3ac5a4c9c74de336cf88039d953c413..46926d541a2c15600212afe5fcb2dcb86bda982a 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -2,5 +2,6 @@ mod composable_view; mod layout_manager; mod panes; mod shortcuts; +mod utils; pub use composable_view::ComposableView; diff --git a/src/ui/composable_view.rs b/src/ui/composable_view.rs index b2a0c5d8ce5f398c43e0c27081f9e71d063ba49b..7351601b00ded36cf8511ebbc8b90b6fff031910 100644 --- a/src/ui/composable_view.rs +++ b/src/ui/composable_view.rs @@ -1,7 +1,8 @@ use super::{ layout_manager::LayoutManager, - panes::{Pane, PaneBehavior}, + panes::{Pane, PaneBehavior, PaneKind}, shortcuts, + utils::maximized_pane_ui, }; use std::{ fs, @@ -19,6 +20,7 @@ pub struct ComposableView { pub layout_manager: LayoutManager, behavior: ComposableBehavior, + maximized_pane: Option<TileId>, } // An app must implement the `App` trait to define how the ui is built @@ -44,6 +46,8 @@ impl eframe::App for ComposableView { ((Modifiers::NONE, Key::V), PaneAction::SplitV), ((Modifiers::NONE, Key::H), PaneAction::SplitH), ((Modifiers::NONE, Key::C), PaneAction::Close), + ((Modifiers::SHIFT, Key::Escape), PaneAction::Maximize), + ((Modifiers::NONE, Key::Escape), PaneAction::Exit), ]; pane_action = pane_action.or(shortcuts::map_to_action(ctx, &key_action_pairs[..]) .map(|action| (action, hovered_pane))); @@ -53,40 +57,70 @@ impl eframe::App for ComposableView { if let Some((action, hovered_tile)) = pane_action.take() { match action { PaneAction::SplitH => { - let hovered_tile_pane = panes_tree.tiles.remove(hovered_tile).unwrap(); - let left_pane = panes_tree.tiles.insert_new(hovered_tile_pane); - let right_pane = panes_tree.tiles.insert_pane(Pane::default()); - panes_tree.tiles.insert( - hovered_tile, - Tile::Container(Container::Linear(Linear::new_binary( - LinearDir::Horizontal, - [left_pane, right_pane], - 0.5, - ))), - ); + if self.maximized_pane.is_none() { + let hovered_tile_pane = panes_tree.tiles.remove(hovered_tile).unwrap(); + let left_pane = panes_tree.tiles.insert_new(hovered_tile_pane); + let right_pane = panes_tree.tiles.insert_pane(Pane::default()); + panes_tree.tiles.insert( + hovered_tile, + Tile::Container(Container::Linear(Linear::new_binary( + LinearDir::Horizontal, + [left_pane, right_pane], + 0.5, + ))), + ); + } } PaneAction::SplitV => { - let hovered_tile_pane = panes_tree.tiles.remove(hovered_tile).unwrap(); - let replaced = panes_tree.tiles.insert_new(hovered_tile_pane); - let lower_pane = panes_tree.tiles.insert_pane(Pane::default()); - panes_tree.tiles.insert( - hovered_tile, - Tile::Container(Container::Linear(Linear::new_binary( - LinearDir::Vertical, - [replaced, lower_pane], - 0.5, - ))), - ); + if self.maximized_pane.is_none() { + let hovered_tile_pane = panes_tree.tiles.remove(hovered_tile).unwrap(); + let replaced = panes_tree.tiles.insert_new(hovered_tile_pane); + let lower_pane = panes_tree.tiles.insert_pane(Pane::default()); + panes_tree.tiles.insert( + hovered_tile, + Tile::Container(Container::Linear(Linear::new_binary( + LinearDir::Vertical, + [replaced, lower_pane], + 0.5, + ))), + ); + } } PaneAction::Close => { // Ignore if the root pane is the only one - if panes_tree.tiles.len() != 1 { + if panes_tree.tiles.len() != 1 && self.maximized_pane.is_none() { panes_tree.remove_recursively(hovered_tile); } } PaneAction::Replace(new_pane) => { panes_tree.tiles.insert(hovered_tile, Tile::Pane(*new_pane)); } + PaneAction::Maximize => { + // This is a toggle: if there is not currently a maximized pane, + // maximize the hovered pane, otherwize remove the maximized pane. + if self.maximized_pane.is_some() { + self.maximized_pane = None; + } else { + let hovered_pane_is_default = panes_tree + .tiles + .get(hovered_tile) + .map(|hovered_pane| match hovered_pane { + Tile::Pane(Pane { + pane: PaneKind::Default(_), + }) => true, + _ => false, + }) + .unwrap_or(false); + if !hovered_pane_is_default { + self.maximized_pane = Some(hovered_tile); + } + } + } + PaneAction::Exit => { + if self.maximized_pane.is_some() { + self.maximized_pane = None; + } + } } } @@ -98,12 +132,25 @@ impl eframe::App for ComposableView { if ui.button("Layout Manager").clicked() { self.layout_manager.toggle_open_state(); } + + // If a pane is maximized show a visual clue + if self.maximized_pane.is_some() { + ui.label("Pane Maximized!"); + } }) }); // A central panel covers the remainder of the screen, i.e. whatever area is left after adding other panels. egui::CentralPanel::default().show(ctx, |ui| { - panes_tree.ui(&mut self.behavior, ui); + if let Some(maximized_pane) = self.maximized_pane { + if let Some(Tile::Pane(pane)) = panes_tree.tiles.get_mut(maximized_pane) { + maximized_pane_ui(ui, pane); + } else { + panic!("Maximized pane not found in tree!"); + } + } else { + panes_tree.ui(&mut self.behavior, ui); + } }); LayoutManager::show(self, ctx); @@ -246,4 +293,6 @@ pub enum PaneAction { SplitV, Close, Replace(Box<Pane>), + Maximize, + Exit, } diff --git a/src/ui/utils.rs b/src/ui/utils.rs new file mode 100644 index 0000000000000000000000000000000000000000..b9f510bda78fab7513f25defa33d1377ffdd6cd7 --- /dev/null +++ b/src/ui/utils.rs @@ -0,0 +1,14 @@ +use egui::containers::Frame; +use egui::{Shadow, Stroke, Style, Ui}; + +use super::panes::{Pane, PaneBehavior}; + +/// This function wraps a ui into a popup frame intended for the pane that needs +/// to be maximized on screen. +pub fn maximized_pane_ui(ui: &mut Ui, pane: &mut Pane) { + Frame::popup(&Style::default()) + .fill(egui::Color32::TRANSPARENT) + .shadow(Shadow::NONE) + .stroke(Stroke::NONE) + .show(ui, |ui| pane.ui(ui)); +}