Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
564 changes: 313 additions & 251 deletions Cargo.lock

Large diffs are not rendered by default.

19 changes: 7 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -122,19 +122,19 @@ wit-bindgen = "0.42"
clap = { version = "4.5", features = ["derive"] }
walkdir = "2.5"

egui = "0.34"
eframe = { version = "0.34", default-features = false }
egui = "0.36"
eframe = { version = "0.36", default-features = false }
rfd = "0.17"
egui_extras = { version = "0.34", default-features = false }
egui_extras = { version = "0.36", default-features = false }
image = { version = "0.25", default-features = false }
egui_table = "0.8"
egui_plot = "0.35"
egui_table = "0.10"
egui_plot = "0.37"
# We don't have direct dependency to winit but we need to specify it here to activate
# its default features which won't be activated otherwise without activating egui default
# features.
winit = { version = "0.30" }
egui-phosphor = "0.12"
egui_commonmark = "0.23"
egui-phosphor = "0.14"
egui_commonmark = "0.25"

## Development Dependencies ##
# Support for `html_reports` needs running the benchmarks via `cargo-criterion` tool.
Expand All @@ -146,11 +146,6 @@ trybuild = "1.0"

[patch.crates-io]
# Dependencies patches before they are released can be defined here.
# These batches are used until PR is included in egui main stream `https://github.com/emilk/egui/pull/8033`
eframe = { git = "https://github.com/AmmarAbouZor/egui", rev = "a9f3a3e4ce95e014d46bae8ab49021b3e77213c8" }
egui = { git = "https://github.com/AmmarAbouZor/egui", rev = "a9f3a3e4ce95e014d46bae8ab49021b3e77213c8" }
egui_extras = { git = "https://github.com/AmmarAbouZor/egui", rev = "a9f3a3e4ce95e014d46bae8ab49021b3e77213c8" }
emath = { git = "https://github.com/AmmarAbouZor/egui", rev = "a9f3a3e4ce95e014d46bae8ab49021b3e77213c8" }

[workspace.lints.clippy]
undocumented_unsafe_blocks = "deny"
Expand Down
1 change: 1 addition & 0 deletions crates/app/src/common/ui/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod buttons;
pub mod modal;
pub mod panel;
pub mod search_picker;
pub mod tab_strip;
pub mod visibility_tracker;
Expand Down
22 changes: 22 additions & 0 deletions crates/app/src/common/ui/panel.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//! Shared helpers for application panels.

use egui::{Panel, Ui};

/// Shows `panel` with egui's slide animation, while only the application's own
/// toggles change its visibility.
///
/// egui's drag-to-close, drag-to-open and double-click toggle gestures are disabled.
pub fn show_toggled_panel(
panel: Panel,
ui: &mut Ui,
visible: bool,
add_contents: impl FnOnce(&mut Ui),
) {
// `show_collapsible` writes panel gestures back into `is_expanded`. Pass a
// per-frame copy so those writes are discarded, and disable drag-to-open so a
// closed panel leaves no grab handle behind.
let mut expanded = visible;
panel
.drag_to_open(false)
.show_collapsible(ui, &mut expanded, add_contents);
}
22 changes: 3 additions & 19 deletions crates/app/src/common/ui/tab_strip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,10 +266,8 @@ impl TabStrip {

if max_scroll_offset > 0.0 {
let current_scroll_offset = output.state.offset.x.clamp(0.0, max_scroll_offset);
let clip_rect_margin = ui.visuals().clip_rect_margin;
let left_rect = self.scroll_button_rect(control_rect, output.inner_rect, true, 0.0);
let right_rect =
self.scroll_button_rect(control_rect, output.inner_rect, false, clip_rect_margin);
let left_rect = self.scroll_button_rect(control_rect, output.inner_rect, true);
let right_rect = self.scroll_button_rect(control_rect, output.inner_rect, false);

let mut requested_scroll_delta = 0.0;
if self.can_scroll_left(current_scroll_offset)
Expand Down Expand Up @@ -339,14 +337,11 @@ impl TabStrip {
control_rect: Rect,
viewport_rect: Rect,
fade_from_left: bool,
clip_rect_margin: f32,
) -> Rect {
let button_min_x = if fade_from_left {
viewport_rect.min.x
} else {
// ScrollArea clips content with `clip_rect_margin`, so the rightmost tab can
// still paint slightly past the logical viewport edge.
control_rect.max.x - SCROLL_BUTTON_WIDTH + clip_rect_margin
control_rect.max.x - SCROLL_BUTTON_WIDTH
};

Rect::from_min_size(
Expand Down Expand Up @@ -660,17 +655,6 @@ mod tests {
);
}

#[test]
fn right_button_rect_uses_clip_margin() {
let control_rect = Rect::from_min_max(pos2(0.0, 0.0), pos2(120.0, 30.0));
let viewport_rect = Rect::from_min_max(pos2(0.0, 4.0), pos2(90.0, 30.0));

assert_eq!(
test_strip().scroll_button_rect(control_rect, viewport_rect, false, 3.0),
Rect::from_min_max(pos2(103.0, 0.0), pos2(123.0, 30.0))
);
}

#[test]
fn split_tab_rects_reserves_close_slot() {
let tab_rect = Rect::from_min_max(pos2(0.0, 0.0), pos2(180.0, 26.0));
Expand Down
28 changes: 17 additions & 11 deletions crates/app/src/common/ui/visibility_tracker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,35 +50,41 @@ mod tests {
let mut tracker = VisibilityTracker::default();
let ctx = egui::Context::default();

let _ = ctx.run_ui(Default::default(), |ui| {
ctx.run_ui(Default::default(), |ui| {
assert!(tracker.is_newly_visible(ui));
});
})
.drop_without_applying_deltas();
}

#[test]
fn returns_false_while_visibility_is_continuous() {
let mut tracker = VisibilityTracker::default();
let ctx = egui::Context::default();

let _ = ctx.run_ui(Default::default(), |ui| {
ctx.run_ui(Default::default(), |ui| {
assert!(tracker.is_newly_visible(ui));
});
let _ = ctx.run_ui(Default::default(), |ui| {
})
.drop_without_applying_deltas();
ctx.run_ui(Default::default(), |ui| {
assert!(!tracker.is_newly_visible(ui));
});
})
.drop_without_applying_deltas();
}

#[test]
fn returns_true_after_visibility_gap() {
let mut tracker = VisibilityTracker::default();
let ctx = egui::Context::default();

let _ = ctx.run_ui(Default::default(), |ui| {
ctx.run_ui(Default::default(), |ui| {
assert!(tracker.is_newly_visible(ui));
});
let _ = ctx.run_ui(Default::default(), |_| {});
let _ = ctx.run_ui(Default::default(), |ui| {
})
.drop_without_applying_deltas();
ctx.run_ui(Default::default(), |_| {})
.drop_without_applying_deltas();
ctx.run_ui(Default::default(), |ui| {
assert!(tracker.is_newly_visible(ui));
});
})
.drop_without_applying_deltas();
}
}
7 changes: 0 additions & 7 deletions crates/app/src/host/common/app_style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,6 @@ pub fn global_styles(style: &mut Style) {
}

apply_global_color_styles(&mut style.visuals);

//NOTE: Workaround until issue with egui_table is fixed.
// Issue Link: https://github.com/rerun-io/egui_table/issues/56
#[cfg(debug_assertions)]
{
style.debug.warn_if_rect_changes_id = false;
}
}

fn apply_global_color_styles(visuals: &mut Visuals) {
Expand Down
20 changes: 3 additions & 17 deletions crates/app/src/host/common/ui_utls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,29 +141,15 @@ pub fn truncate_path_to_width(
TruncatedPath { text, truncated }
}

/// Build a single-line [`TextEdit`] that approximates the provided outer size.
///
/// # Note:
///
/// This function is a workaround for the regression egui 0.34 regarding
/// `TextEdit::min_size().y` not being respected anymore.
/// Build a single-line [`TextEdit`] with the provided outer size and vertically centered text.
pub fn sized_singleline_text_edit<'t>(
ui: &mut Ui,
text: &'t mut dyn TextBuffer,
size: Vec2,
horizontal_margin: i8,
) -> TextEdit<'t> {
let font_id = TextStyle::Body.resolve(ui.style());
let row_height = ui.fonts_mut(|fonts| fonts.row_height(&font_id));
let vertical_margin = ((size.y - row_height) / 2.0)
.round()
.clamp(0.0, i8::MAX as f32) as i8;

// egui 0.34 no longer applies `TextEdit::min_size().y`, so use the inner margin to reach the
// requested row height instead.
// TODO: Keep track on issue: https://github.com/emilk/egui/issues/8071
TextEdit::singleline(text)
.desired_width(size.x)
.margin(Margin::symmetric(horizontal_margin, vertical_margin))
.min_size(size)
.margin(Margin::symmetric(horizontal_margin, 2))
.vertical_align(Align::Center)
}
4 changes: 2 additions & 2 deletions crates/app/src/host/ui/app_settings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ impl AppSettingsView {

Panel::top("app_settings_header")
.exact_size(40.0)
.show_inside(ui, |ui| {
.show(ui, |ui| {
ui.with_layout(Layout::left_to_right(Align::Center), |ui| {
ui.heading("App Settings");
});
});

CentralPanel::default().show_inside(ui, |ui| {
CentralPanel::default().show(ui, |ui| {
const ACTIONS_HEIGHT: f32 = 40.0;

let content_width = ui.available_width().min(CONTENT_MAX_WIDTH);
Expand Down
1 change: 0 additions & 1 deletion crates/app/src/host/ui/command_palette/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,6 @@ impl CommandPalette {

let search_id = ui.make_persistent_id("command_palette_search");
let query_response = sized_singleline_text_edit(
ui,
&mut self.query,
vec2(ui.available_width(), 25.0),
7,
Expand Down
2 changes: 1 addition & 1 deletion crates/app/src/host/ui/dnd_paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ fn handle_dropping_files(ui: &mut Ui, actions: &mut UiActions, cmd_tx: &Sender<H
for path in ui
.input_mut(|input| std::mem::take(&mut input.raw.dropped_files))
.into_iter()
.filter_map(|file| file.path)
.map(|file| file.path().to_path_buf())
{
if path.is_dir() {
dirs.push(path);
Expand Down
7 changes: 3 additions & 4 deletions crates/app/src/host/ui/home/file_explorer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
//! This module renders the home-screen file explorer, manages its transient UI
//! state, and bridges user actions to the host/storage layers.

use std::{hash::Hash, ops::Not, path::PathBuf, time::Duration};
use std::{ops::Not, path::PathBuf, time::Duration};

use egui::{Align, Layout, TextStyle};
use egui::{Align, AsIdSalt, Layout, TextStyle};
use egui::{
Button, Label, Response, RichText, Sense, Ui, UiBuilder, Widget,
collapsing_header::CollapsingState, vec2,
Expand Down Expand Up @@ -167,7 +167,6 @@ impl FileExplorerUi {
}

let search_response = sized_singleline_text_edit(
ui,
&mut self.search_query,
vec2(ui.available_width(), CONTROL_ROW_HEIGHT),
7,
Expand Down Expand Up @@ -500,7 +499,7 @@ impl FileExplorerUi {
/// * `render_label` - Renders the caller-specific label after the caret icon, using the provided text color.
fn render_folder_header(
ui: &mut Ui,
id_salt: impl Hash,
id_salt: impl AsIdSalt,
force_expanded: bool,
render_label: impl FnOnce(&mut Ui, egui::Color32),
) -> (Response, Option<CollapsingState>) {
Expand Down
19 changes: 11 additions & 8 deletions crates/app/src/host/ui/home/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ use self::{file_explorer::FileExplorerUi, recent::RecentSessionsUi};
use super::menu::render_connections_menu;
use crate::common::{
phosphor::icons,
ui::{RESIZABLE_PANEL_DEFAULT_SIZE, RESIZABLE_PANEL_MAX_SIZE, RESIZABLE_PANEL_MIN_SIZE},
ui::{
RESIZABLE_PANEL_DEFAULT_SIZE, RESIZABLE_PANEL_MAX_SIZE, RESIZABLE_PANEL_MIN_SIZE,
panel::show_toggled_panel,
},
};
use crate::host::{
command::HostCommand,
Expand Down Expand Up @@ -63,16 +66,16 @@ impl HomeView {
) {
self.handle_pending_file_dialog(actions);

Panel::right("favorite folders")
let panel = Panel::right("favorite folders")
.size_range(RESIZABLE_PANEL_MIN_SIZE..=RESIZABLE_PANEL_MAX_SIZE)
.default_size(RESIZABLE_PANEL_DEFAULT_SIZE)
.resizable(true)
.show_animated_inside(ui, preferences.panels_visibility.right, |ui| {
self.file_explorer
.render_content(actions, &mut storage.file_explorer, ui);
});
.resizable(true);
show_toggled_panel(panel, ui, preferences.panels_visibility.right, |ui| {
self.file_explorer
.render_content(actions, &mut storage.file_explorer, ui);
});

CentralPanel::default().show_inside(ui, |ui| {
CentralPanel::default().show(ui, |ui| {
// Layout rules:
// - Wide views show the horizontal quick actions and center them with recent sessions.
// - Smaller views switch to the narrow quick-actions rail, but the pair stays centered
Expand Down
2 changes: 1 addition & 1 deletion crates/app/src/host/ui/home/recent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ impl RecentSessionsUi {

let focus_filter = self.visibility_tracker.is_newly_visible(ui);
let query_response =
sized_singleline_text_edit(ui, &mut self.query, vec2(ui.available_width(), 27.0), 7)
sized_singleline_text_edit(&mut self.query, vec2(ui.available_width(), 27.0), 7)
.hint_text("Filter recent sessions")
.ui(ui);
if focus_filter {
Expand Down
6 changes: 3 additions & 3 deletions crates/app/src/host/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ impl Host {

Panel::top("menu_bar")
.frame(Frame::side_top_panel(ui.style()))
.show_inside(ui, |ui| {
.show(ui, |ui| {
self.render_menu(ui);
});

Expand All @@ -308,7 +308,7 @@ impl Host {
.fill(colors::main_accent_background(ui.visuals().dark_mode)),
)
.show_separator_line(false)
.show_inside(ui, |ui| {
.show(ui, |ui| {
self.render_tabs(ui);
});

Expand All @@ -326,7 +326,7 @@ impl Host {

CentralPanel::default()
.frame(Frame::central_panel(ui.style()).inner_margin(0))
.show_inside(ui, |ui| {
.show(ui, |ui| {
self.render_main(ui);

if self.state.app_info.show_update_banner {
Expand Down
5 changes: 3 additions & 2 deletions crates/app/src/host/ui/multi_setup/main_table/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use std::path::Path;

use egui::{
Align, Align2, Color32, Context, CursorIcon, Label, LayerId, Layout, Order, Rect, Response,
RichText, ScrollArea, Sense, Stroke, TextStyle, Ui, Widget, pos2, vec2,
RichText, ScrollArea, Sense, Stroke, TextStyle, Ui, Widget, pos2, scroll_area::DragScroll,
vec2,
};
use egui_extras::{Column, TableBuilder};
use enum_iterator::all;
Expand Down Expand Up @@ -79,7 +80,7 @@ impl MainTable {
let table = TableBuilder::new(ui)
.id_salt(state.id())
.auto_shrink(true)
.drag_to_scroll(false)
.drag_to_scroll(DragScroll::Never)
.striped(false)
.resizable(false)
.cell_layout(Layout::left_to_right(Align::Center))
Expand Down
Loading
Loading