pub struct AppShell { /* private fields */ }Expand description
All width/height fields are stored as multiples of line_height
so they are portable across TUI (cells) and GUI (pixels) backends.
compute_layout() resolves them: dimension_native = field * lh.
Implementations§
Source§impl AppShell
impl AppShell
pub fn new(panels: Vec<PanelDefinition>, default_sidebar_width: f32) -> Self
pub fn with_bottom_items(self, items: Vec<PanelDefinition>) -> Self
Sourcepub fn with_panel_icon(self, id: WidgetId, icon: Icon) -> Self
pub fn with_panel_icon(self, id: WidgetId, icon: Icon) -> Self
Attach a distinct Nerd-Font glyph + ASCII fallback pair to one
activity-bar row, overriding the single-string
PanelDefinition::icon that panel was registered with.
id may name a top panel or a bottom item; unknown ids are stored
but never consulted, so registration order relative to
Self::with_bottom_items / [Self::register_panel] does not
matter. Calling this twice for the same id keeps the last pair.
Which half actually paints is the backend’s decision, driven by its
nerd_fonts_enabled flag — glyph when the icon font is available,
fallback otherwise. Panels that never call this get
glyph == fallback == PanelDefinition::icon.
let shell = AppShell::new(
vec![PanelDefinition {
id: WidgetId::new("panel:explorer"),
icon: "E".to_string(),
tooltip: "Explorer".to_string(),
title: "EXPLORER".to_string(),
}],
20.0,
)
.with_panel_icon(WidgetId::new("panel:explorer"), Icon::new("\u{f07c}", "E"));
assert_eq!(shell.build_activity_bar().top_items[0].icon.glyph, "\u{f07c}");pub fn with_min_width(self, min: f32) -> Self
pub fn with_max_width(self, max: f32) -> Self
pub fn with_activity_bar_width(self, width: f32) -> Self
Sourcepub fn with_activity_bar_width_px(self, width_px: f32) -> Self
pub fn with_activity_bar_width_px(self, width_px: f32) -> Self
Pin the activity bar to a fixed pixel width, overriding the
line-height-derived width from Self::with_activity_bar_width.
The row height GTK/macOS paint each activity item at
(ACTIVITY_ROW_PX = 48.0) is already a fixed pixel constant, not a
line_height multiple — so a with_activity_bar_width(2.4)-style
call only produces a square 48×48 bar at whatever line_height
happens to make 2.4 * lh == 48.0. Passing 48.0 here keeps the
bar square regardless of the app’s editor font size.
None (the default) leaves the existing line_height-derived
width in place — this call is additive, not a replacement.
Sourcepub fn with_active_accent(self, color: Color) -> Self
pub fn with_active_accent(self, color: Color) -> Self
Colour painted on the active top panel’s row in the built
ActivityBar (its active_accent field) — e.g. a theme’s accent
colour, so the activity bar shows an active-panel indicator line.
AppShell has no Theme in scope itself; a host app sources the
colour from its own theme and passes it here before the first
Self::render. Unset (the default) paints no accent, matching the
pre-existing behaviour.
Sourcepub fn with_selection_bg(self, color: Color) -> Self
pub fn with_selection_bg(self, color: Color) -> Self
Colour painted behind the keyboard-selected row in the built
ActivityBar (its selection_bg field) when
Self::activity_keyboard_focused. Unset (the default) leaves each
backend’s own reversed/brightened fallback fill in charge.
pub fn with_position(self, position: ShellPosition) -> Self
Sourcepub fn with_title_bar(self, height_lh: f32) -> Self
pub fn with_title_bar(self, height_lh: f32) -> Self
Reserve a title-bar row at construction time. See
Self::set_title_bar_visible to show/hide the row at runtime
(e.g. a toggleable menu bar) without rebuilding the AppShell.
Sourcepub fn with_title_bar_min_px(self, min_px: f32) -> Self
pub fn with_title_bar_min_px(self, min_px: f32) -> Self
Pin a fixed-pixel floor under the title bar’s line-height-derived
height, overriding it only when the multiple would otherwise
resolve smaller — mirroring Self::with_activity_bar_width_px’s
pattern, but as a floor rather than a hard override, since
unlike the activity bar’s fixed-size icons, title-bar chrome (menu
labels, inline window controls) is expected to keep scaling with
the editor font above the floor.
None (the default) leaves title_bar_height_lh * line_height in
sole charge, unchanged from before this method existed. Set this
when a host needs the band to never shrink under some real
platform constraint it can’t otherwise express in line-height
units — e.g. staying clear of macOS’s native traffic-light cluster
even after a user shrinks settings.font_size at runtime
pub fn with_bottom_panel(self, height_lh: f32) -> Self
pub fn with_bottom_panel_limits(self, min: f32, max: f32) -> Self
Sourcepub fn with_bottom_bands(self, bands: Vec<BottomBand>) -> Self
pub fn with_bottom_bands(self, bands: Vec<BottomBand>) -> Self
Register the ordered list of independently-gated bottom bands.
See BottomBand for the stacking order and how this interacts
with Self::with_bottom_panel.
Replaces any previously-registered list. Vec::new() (the
default) restores a single-drawer layout.
pub fn with_command_line(self) -> Self
pub fn with_status_bar(self) -> Self
Sourcepub fn with_status_bar_height_px(self, height_px: f32) -> Self
pub fn with_status_bar_height_px(self, height_px: f32) -> Self
Fix the status bar to height_px native units, overriding the
line_height-derived height regardless of font size — VS Code’s
status bar is a constant 22px. Call alongside Self::with_status_bar;
has no visible effect unless that is also set.
Sourcepub fn with_status_bar_under_main_column(self) -> Self
pub fn with_status_bar_under_main_column(self) -> Self
Opt into the activity bar and sidebar running the full height of the area below the title bar, with the status bar and command line carved from the main column only (main column’s x/width) rather than the full window width.
Off by default: the status bar and command line span the full window, and the activity bar/sidebar stop above them — unchanged from before this method existed. Turn this on when a host wants the activity bar’s bottom-pinned items to sit in the window’s bottom-left corner rather than above a full-width status bar.
Sourcepub fn active_panel(&self) -> Option<&PanelDefinition>
pub fn active_panel(&self) -> Option<&PanelDefinition>
The PanelDefinition that currently owns the sidebar: the active
top panel, or a bottom item that was made the owner
via Self::show_panel. This is the same definition
Self::render titles the sidebar header from.
Sourcepub fn active_panel_id(&self) -> Option<&WidgetId>
pub fn active_panel_id(&self) -> Option<&WidgetId>
The id of Self::active_panel — a top panel’s id, or a bottom
item’s id when that bottom item owns the sidebar.
pub fn position(&self) -> ShellPosition
Sourcepub fn title_bar_visible(&self) -> bool
pub fn title_bar_visible(&self) -> bool
Whether the title-bar row is currently reserved. See
Self::set_title_bar_visible for the runtime toggle and
Self::with_title_bar for the construction-time builder.
pub fn hovered_activity_idx(&self) -> Option<usize>
Sourcepub fn activity_keyboard_focused(&self) -> bool
pub fn activity_keyboard_focused(&self) -> bool
Returns true when the activity bar currently holds keyboard focus.
When true, build_activity_bar() sets is_keyboard_focused = true
on the emitted ActivityBar, causing both the TUI and GTK backends
to deliver key presses as
UiEvent::ActivityBar(id, ActivityBarEvent::KeyPressed { … }) rather
than raw UiEvent::KeyPressed. The consumer maps those key strings to
the navigation methods below.
Sourcepub fn set_activity_keyboard_focused(&mut self, focused: bool)
pub fn set_activity_keyboard_focused(&mut self, focused: bool)
Focus or unfocus the activity bar. Pair with
Self::activity_keyboard_focused and the navigation methods to
implement keyboard nav in a ShellApp consumer.
Calling this does not reset the cursor — the cursor stays where
it was so repeated focus/blur round-trips feel natural. To reset to
the top item on focus, call
set_activity_keyboard_focused(true) then activity_set_cursor(0).
Sourcepub fn set_activity_cursor_visible(&mut self, visible: bool)
pub fn set_activity_cursor_visible(&mut self, visible: bool)
Show (or hide) the keyboard cursor highlight on the activity bar
without enabling the key-event redirect that
Self::set_activity_keyboard_focused triggers.
A ShellApp consumer that routes toolbar keys itself — through its
own chord / key-action handlers inside ShellApp::handle, receiving
plain UiEvent::KeyPressed events — calls this instead of
set_activity_keyboard_focused(true) so the cursor paints but the
TUI / GTK backends leave key events as KeyPressed rather than
rewriting them to UiEvent::ActivityBar(…).
Sourcepub fn set_active_accent(&mut self, color: Option<Color>)
pub fn set_active_accent(&mut self, color: Option<Color>)
Set (or clear, with None) the active-panel accent colour
Self::build_activity_bar passes through as
ActivityBar::active_accent. Runtime counterpart to
Self::with_active_accent — call this after a theme switch
instead of rebuilding the AppShell.
Sourcepub fn set_selection_bg(&mut self, color: Option<Color>)
pub fn set_selection_bg(&mut self, color: Option<Color>)
Set (or clear, with None) the keyboard-selection highlight colour
Self::build_activity_bar passes through as
ActivityBar::selection_bg. Runtime counterpart to
Self::with_selection_bg.
Sourcepub fn activity_select_next(&mut self)
pub fn activity_select_next(&mut self)
Move the keyboard cursor to the next item in the logical sequence (top panels first, then bottom items). Saturates at the last item — does not wrap to the top.
Sourcepub fn activity_select_prev(&mut self)
pub fn activity_select_prev(&mut self)
Move the keyboard cursor to the previous item. Saturates at index 0 — does not wrap to the bottom.
Sourcepub fn activity_set_cursor(&mut self, idx: usize)
pub fn activity_set_cursor(&mut self, idx: usize)
Set the keyboard cursor to an explicit index in the logical sequence.
Out-of-range values are clamped to the valid range [0, total-1].
Has no effect when the panel + bottom-item lists are both empty.
Sourcepub fn activity_selected_id(&self) -> Option<&WidgetId>
pub fn activity_selected_id(&self) -> Option<&WidgetId>
Returns the WidgetId of the item currently under the keyboard
cursor, or None if there are no items at all.
The logical sequence is top panels (0..panels.len()) followed by
bottom items (panels.len()..).
Sourcepub fn activity_activate_selected(&mut self) -> Option<AppShellEvent>
pub fn activity_activate_selected(&mut self) -> Option<AppShellEvent>
Activate the item currently under the keyboard cursor and return
the resulting AppShellEvent, or None if there are no items.
Equivalent to clicking the cursor item: top-panel items trigger the
same toggle / switch logic as a mouse click, bottom items emit
AppShellEvent::BottomItemClicked. Does not clear keyboard
focus — the consumer decides whether to do that.
Sourcepub fn show_panel(&mut self, panel_id: &WidgetId)
pub fn show_panel(&mut self, panel_id: &WidgetId)
Make panel_id the sidebar’s owner and reveal the sidebar.
Accepts either a top panel’s id or a bottom item’s id (one
registered via Self::with_bottom_items / Self::add_bottom_item).
In the latter case the bottom item becomes the sidebar header’s title
source (see Self::active_panel/Self::active_panel_id) until
show_panel is called again with a different id. A bottom item’s own
click (Self::handle_activity_click’s BottomItemClicked branch)
never calls this itself, so an app opts in explicitly from its
BottomItemClicked handler.
A no-op if panel_id matches neither a top panel nor a bottom item.
Sourcepub fn set_title_bar_visible(&mut self, visible: bool)
pub fn set_title_bar_visible(&mut self, visible: bool)
Runtime toggle for whether the title-bar row is reserved.
Unlike Self::with_title_bar — a construction-time builder that
permanently commits to reserving the row for the lifetime of the
AppShell — this can be flipped at any point after construction
without rebuilding the shell. compute_layout re-derives every
downstream bound (activity bar, sidebar, main content, bottom
panel, …) from area and current state on every
render/layout/handle call, so toggling this and calling any
of those next is sufficient — no other field needs to change in
lockstep, and no fixed offset is cached anywhere that would go stale.
A menu bar painted into the title-bar row that the user can show/hide at runtime requires this: always reserving the row costs a row even while the menu is hidden; never reserving it makes a shown menu overwrite the activity bar’s first row. Toggling this from the app’s own visibility state avoids both.
If Self::with_title_bar was never called, toggling visible for
the first time reserves the default height (title_bar_height_lh,
1.5 line-heights). The configured height is otherwise preserved
across visible → hidden → visible round-trips — hiding does not
forget it.
pub fn bottom_panel_visible(&self) -> bool
pub fn bottom_panel_height(&self) -> f32
pub fn show_bottom_panel(&mut self)
pub fn hide_bottom_panel(&mut self)
pub fn toggle_bottom_panel(&mut self)
pub fn set_bottom_panel_height(&mut self, height: f32)
Sourcepub fn bottom_bands(&self) -> &[BottomBand]
pub fn bottom_bands(&self) -> &[BottomBand]
The currently-registered bottom bands, in bottom-up stacking order
(see BottomBand). Includes bands with visible == false — use
Self::bottom_band_bounds to see which ones actually occupied
space in the last computed layout.
Sourcepub fn bottom_band_bounds(&self) -> Vec<(WidgetId, Rect)>
pub fn bottom_band_bounds(&self) -> Vec<(WidgetId, Rect)>
Resolved bounds for every currently-visible BottomBand, from
the most recent Self::layout or Self::render call, in the
same bottom-up order bottom_bands was given (index 0 = flush
against the bottom edge of the main content column). Bands with
visible == false have no entry — they occupy no space that
frame. Empty if layout/render was never called, or if
Self::with_bottom_bands was never used.
Not a field on AppShellLayout — see that struct’s doc for why.
Sourcepub fn bottom_band(&self, id: &WidgetId) -> Option<&BottomBand>
pub fn bottom_band(&self, id: &WidgetId) -> Option<&BottomBand>
Look up one registered band by id.
Sourcepub fn set_bottom_band_visible(&mut self, id: &WidgetId, visible: bool) -> bool
pub fn set_bottom_band_visible(&mut self, id: &WidgetId, visible: bool) -> bool
Flip one band’s presence at runtime (e.g. a quickfix list that
opens/closes independently of every other bottom band). Returns
false if no band with id was registered via
Self::with_bottom_bands.
Sourcepub fn set_bottom_band_height(&mut self, id: &WidgetId, height_lh: f32) -> bool
pub fn set_bottom_band_height(&mut self, id: &WidgetId, height_lh: f32) -> bool
Resize one band at runtime. Returns false if no band with id
was registered via Self::with_bottom_bands. Unlike the legacy
single bottom panel, bands have no configurable min/max — callers
own their own clamping (the toolbars/lists vimcode stacks here
generally have a fixed content-driven height, not a user drag).
pub fn panels(&self) -> &[PanelDefinition]
pub fn bottom_items(&self) -> &[PanelDefinition]
Sourcepub fn add_panel(&mut self, def: PanelDefinition) -> bool
pub fn add_panel(&mut self, def: PanelDefinition) -> bool
Register a panel at runtime. Returns false if a panel with the
same ID already exists (no-op in that case). If this is the first
panel, it becomes the active panel.
Sourcepub fn remove_panel(&mut self, id: &WidgetId) -> bool
pub fn remove_panel(&mut self, id: &WidgetId) -> bool
Unregister a panel by ID. Returns true if found and removed.
Adjusts active_panel to keep the same panel selected (or clears
it if the active panel was the one removed).
Also adjusts activity_cursor analogously so keyboard navigation
remains consistent after a dynamic removal.
Sourcepub fn add_bottom_item(&mut self, def: PanelDefinition) -> bool
pub fn add_bottom_item(&mut self, def: PanelDefinition) -> bool
Register a bottom-pinned activity bar item at runtime.
Sourcepub fn remove_bottom_item(&mut self, id: &WidgetId) -> bool
pub fn remove_bottom_item(&mut self, id: &WidgetId) -> bool
Unregister a bottom item by ID.
Adjusts activity_cursor so keyboard navigation remains consistent
after a dynamic removal (mirrors remove_panel’s treatment of
active_panel). Also adjusts sidebar_bottom_owner
the same way remove_panel adjusts active_panel: shifted down if
it pointed past the removed item, cleared (falling back to whatever
active_panel names) if it pointed at the removed item itself.
Sourcepub fn layout(&self, area: Rect, line_height: f32) -> AppShellLayout
pub fn layout(&self, area: Rect, line_height: f32) -> AppShellLayout
Compute layout bounds without drawing. Use when only hit-testing
is needed (e.g. in handle).
Takes line_height rather than a &dyn Backend so callers that
only know the line height (external consumers, tests) can still
call it. It mirrors Backend::snap_height’s own threshold —
identity above one line height (a real pixel metric), .round()
at or below it (TUI’s cell grid, whose chrome_line_height is
architecturally always exactly 1.0) — so this path always agrees
with Self::render/Self::handle, which pass backend.snap_height
directly, for the same area/line_height on the same backend.
Sourcepub fn build_activity_bar(&self) -> ActivityBar
pub fn build_activity_bar(&self) -> ActivityBar
Build the ActivityBar primitive from current panel state.
When Self::activity_keyboard_focused is true:
ActivityBar::is_keyboard_focusedis set totrue, causing both the TUI and GTK backends to route key events asUiEvent::ActivityBar(id, ActivityBarEvent::KeyPressed { … }).- The item at
Self::activity_cursor(in the top-then-bottom logical sequence) hasis_keyboard_selected = true, painting the selection ring on that icon.
ActivityBar::active_accent/selection_bg carry whatever colours
were last set via Self::with_active_accent/Self::set_active_accent
and Self::with_selection_bg/Self::set_selection_bg — None
(no accent/highlight painted) until a host app opts in.
Sourcepub fn render(&self, backend: &mut dyn Backend, area: Rect) -> AppShellLayout
pub fn render(&self, backend: &mut dyn Backend, area: Rect) -> AppShellLayout
Render shell chrome and return layout bounds for consumer content.
Draws: activity bar, sidebar header, resize divider. Consumer draws: sidebar panel content, main content area.
Sourcepub fn handle(
&mut self,
event: &UiEvent,
backend: &dyn Backend,
area: Rect,
) -> AppShellEvent
pub fn handle( &mut self, event: &UiEvent, backend: &dyn Backend, area: Rect, ) -> AppShellEvent
Process a UiEvent and return a semantic AppShellEvent.
Call this before the consumer’s own event handling. If the result
is not AppShellEvent::Ignored, the consumer should redraw.
Auto Trait Implementations§
impl !Freeze for AppShell
impl !RefUnwindSafe for AppShell
impl !Sync for AppShell
impl Send for AppShell
impl Unpin for AppShell
impl UnsafeUnpin for AppShell
impl UnwindSafe for AppShell
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more