Fit modal dialogs to the phone screen on mobile
Add mobile::dialog_width(ctx, desired) — a min()-clamp that's a no-op on wide desktop screens. Clamp the Export and Export Progress modals and the Sample Import window to it. Render Preferences as an egui::Modal (dim backdrop, centered, no title bar) with a screen-fit scroll height when mobile_active(); desktop keeps its window. Extracted the preferences body into render_body() shared by both paths.
This commit is contained in:
parent
a0ac4f2d35
commit
f13a127c9d
|
|
@ -208,7 +208,7 @@ impl ExportDialog {
|
|||
|
||||
let modal_response = egui::Modal::new(egui::Id::new("export_dialog_modal"))
|
||||
.show(ctx, |ui| {
|
||||
ui.set_width(500.0);
|
||||
ui.set_width(crate::mobile::dialog_width(ctx, 500.0));
|
||||
|
||||
ui.heading(window_title);
|
||||
ui.add_space(8.0);
|
||||
|
|
@ -801,7 +801,7 @@ impl ExportProgressDialog {
|
|||
|
||||
egui::Modal::new(egui::Id::new("export_progress_modal"))
|
||||
.show(ctx, |ui| {
|
||||
ui.set_width(400.0);
|
||||
ui.set_width(crate::mobile::dialog_width(ctx, 400.0));
|
||||
|
||||
ui.heading("Exporting...");
|
||||
ui.add_space(8.0);
|
||||
|
|
|
|||
|
|
@ -6329,7 +6329,8 @@ impl eframe::App for EditorApp {
|
|||
}
|
||||
|
||||
// Render preferences dialog
|
||||
if let Some(result) = self.preferences_dialog.render(ctx, &mut self.config, &mut self.theme) {
|
||||
let mobile = self.mobile_active();
|
||||
if let Some(result) = self.preferences_dialog.render(ctx, &mut self.config, &mut self.theme, mobile) {
|
||||
if result.buffer_size_changed {
|
||||
println!("⚠️ Audio buffer size will be applied on next app restart");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,13 @@ pub const MOBILE_NS: usize = usize::MAX;
|
|||
const TRANSPORT_H: f32 = 60.0;
|
||||
const TOPBAR_H: f32 = 40.0;
|
||||
|
||||
/// Clamp a desktop dialog width to fit the current screen (with side margins). A no-op on wide
|
||||
/// desktop screens (`min` keeps the desired width); on a phone-aspect window it shrinks to fit.
|
||||
pub fn dialog_width(ctx: &egui::Context, desired: f32) -> f32 {
|
||||
let avail = ctx.screen_rect().width() - 24.0;
|
||||
desired.min(avail.max(200.0))
|
||||
}
|
||||
|
||||
/// Returns true if the mobile UI is requested via the `LB_MOBILE_UI` env var.
|
||||
/// Any non-empty value other than "0" enables it.
|
||||
pub fn is_mobile_env() -> bool {
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ impl PreferencesDialog {
|
|||
ctx: &egui::Context,
|
||||
config: &mut AppConfig,
|
||||
theme: &mut Theme,
|
||||
mobile: bool,
|
||||
) -> Option<PreferencesSaveResult> {
|
||||
if !self.open {
|
||||
return None;
|
||||
|
|
@ -160,68 +161,32 @@ impl PreferencesDialog {
|
|||
let mut should_cancel = false;
|
||||
let mut open = self.open;
|
||||
|
||||
egui::Window::new("Preferences")
|
||||
.open(&mut open)
|
||||
.resizable(false)
|
||||
.collapsible(false)
|
||||
.anchor(egui::Align2::CENTER_CENTER, egui::Vec2::ZERO)
|
||||
.show(ctx, |ui| {
|
||||
ui.set_width(550.0);
|
||||
// On mobile, render as a screen-fitting modal sheet (dim backdrop, centered) like the other
|
||||
// mobile modals; on desktop, the familiar draggable window.
|
||||
let width = crate::mobile::dialog_width(ctx, 550.0);
|
||||
let scroll_h = if mobile {
|
||||
(ctx.screen_rect().height() - 220.0).clamp(160.0, 400.0)
|
||||
} else {
|
||||
400.0
|
||||
};
|
||||
|
||||
// Error message
|
||||
if let Some(error) = &self.error_message {
|
||||
ui.colored_label(egui::Color32::from_rgb(255, 100, 100), error);
|
||||
ui.add_space(8.0);
|
||||
}
|
||||
|
||||
// Tab bar
|
||||
ui.horizontal(|ui| {
|
||||
ui.selectable_value(&mut self.tab, PreferencesTab::General, "General");
|
||||
ui.selectable_value(&mut self.tab, PreferencesTab::Shortcuts, "Keyboard Shortcuts");
|
||||
});
|
||||
ui.separator();
|
||||
|
||||
// Tab content
|
||||
match self.tab {
|
||||
PreferencesTab::General => {
|
||||
egui::ScrollArea::vertical()
|
||||
.max_height(400.0)
|
||||
.show(ui, |ui| {
|
||||
self.render_general_section(ui);
|
||||
ui.add_space(8.0);
|
||||
self.render_audio_section(ui);
|
||||
ui.add_space(8.0);
|
||||
self.render_appearance_section(ui);
|
||||
ui.add_space(8.0);
|
||||
self.render_startup_section(ui);
|
||||
ui.add_space(8.0);
|
||||
self.render_advanced_section(ui);
|
||||
});
|
||||
}
|
||||
PreferencesTab::Shortcuts => {
|
||||
self.render_shortcuts_tab(ui);
|
||||
}
|
||||
}
|
||||
|
||||
ui.add_space(16.0);
|
||||
|
||||
// Buttons
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("Cancel").clicked() {
|
||||
should_cancel = true;
|
||||
}
|
||||
|
||||
if ui.button("Reset to Defaults").clicked() {
|
||||
self.reset_to_defaults();
|
||||
}
|
||||
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
if ui.button("Save").clicked() {
|
||||
should_save = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
if mobile {
|
||||
let resp = egui::Modal::new(egui::Id::new("preferences_modal")).show(ctx, |ui| {
|
||||
self.render_body(ui, width, scroll_h, &mut should_save, &mut should_cancel);
|
||||
});
|
||||
if resp.backdrop_response.clicked() {
|
||||
should_cancel = true;
|
||||
}
|
||||
} else {
|
||||
egui::Window::new("Preferences")
|
||||
.open(&mut open)
|
||||
.resizable(false)
|
||||
.collapsible(false)
|
||||
.anchor(egui::Align2::CENTER_CENTER, egui::Vec2::ZERO)
|
||||
.show(ctx, |ui| {
|
||||
self.render_body(ui, width, scroll_h, &mut should_save, &mut should_cancel);
|
||||
});
|
||||
}
|
||||
|
||||
// Update open state
|
||||
self.open = open;
|
||||
|
|
@ -238,6 +203,70 @@ impl PreferencesDialog {
|
|||
None
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn render_body(
|
||||
&mut self,
|
||||
ui: &mut egui::Ui,
|
||||
width: f32,
|
||||
scroll_h: f32,
|
||||
should_save: &mut bool,
|
||||
should_cancel: &mut bool,
|
||||
) {
|
||||
ui.set_width(width);
|
||||
|
||||
// Error message
|
||||
if let Some(error) = &self.error_message {
|
||||
ui.colored_label(egui::Color32::from_rgb(255, 100, 100), error);
|
||||
ui.add_space(8.0);
|
||||
}
|
||||
|
||||
// Tab bar
|
||||
ui.horizontal(|ui| {
|
||||
ui.selectable_value(&mut self.tab, PreferencesTab::General, "General");
|
||||
ui.selectable_value(&mut self.tab, PreferencesTab::Shortcuts, "Keyboard Shortcuts");
|
||||
});
|
||||
ui.separator();
|
||||
|
||||
// Tab content
|
||||
match self.tab {
|
||||
PreferencesTab::General => {
|
||||
egui::ScrollArea::vertical().max_height(scroll_h).show(ui, |ui| {
|
||||
self.render_general_section(ui);
|
||||
ui.add_space(8.0);
|
||||
self.render_audio_section(ui);
|
||||
ui.add_space(8.0);
|
||||
self.render_appearance_section(ui);
|
||||
ui.add_space(8.0);
|
||||
self.render_startup_section(ui);
|
||||
ui.add_space(8.0);
|
||||
self.render_advanced_section(ui);
|
||||
});
|
||||
}
|
||||
PreferencesTab::Shortcuts => {
|
||||
self.render_shortcuts_tab(ui);
|
||||
}
|
||||
}
|
||||
|
||||
ui.add_space(16.0);
|
||||
|
||||
// Buttons
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("Cancel").clicked() {
|
||||
*should_cancel = true;
|
||||
}
|
||||
|
||||
if ui.button("Reset to Defaults").clicked() {
|
||||
self.reset_to_defaults();
|
||||
}
|
||||
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
if ui.button("Save").clicked() {
|
||||
*should_save = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn render_shortcuts_tab(&mut self, ui: &mut egui::Ui) {
|
||||
// Capture key events for rebinding BEFORE rendering the rest
|
||||
if let Some(rebind_action) = self.rebinding {
|
||||
|
|
|
|||
|
|
@ -58,7 +58,8 @@ impl SampleImportDialog {
|
|||
.resizable(true)
|
||||
.collapsible(false)
|
||||
.anchor(egui::Align2::CENTER_CENTER, egui::Vec2::ZERO)
|
||||
.default_width(700.0)
|
||||
.default_width(crate::mobile::dialog_width(ctx, 700.0))
|
||||
.max_width(crate::mobile::dialog_width(ctx, 700.0))
|
||||
.default_height(500.0)
|
||||
.show(ctx, |ui| {
|
||||
// Folder info
|
||||
|
|
|
|||
Loading…
Reference in New Issue