diff --git a/src/app/view.rs b/src/app/view.rs index 867b787..672bd53 100644 --- a/src/app/view.rs +++ b/src/app/view.rs @@ -62,6 +62,15 @@ impl App { } } + /// Whether a dialog covers the window. Focus moves through the whole widget + /// tree, so the layers below have to stay out of the dialog's field order. + pub(super) fn modal_open(&self) -> bool { + self.preferences_open + || self.pending_project_path.is_some() + || self.session_rename.is_some() + || self.menu_session().is_some() + } + fn main_view(&self) -> Element<'_, Message> { let mut body = row![].width(Length::Fill).height(Length::Fill); if !self.config.interface.sidebar_collapsed { diff --git a/src/app/view/chat.rs b/src/app/view/chat.rs index 7bd83fa..d2d83b0 100644 --- a/src/app/view/chat.rs +++ b/src/app/view/chat.rs @@ -131,12 +131,32 @@ impl App { ); } } - let composer = text_input("Ask DS4Server anything…", &self.composer) - .id(composer_id()) - .on_input(Message::ComposerChanged) - .on_submit(Message::SubmitPrompt) + // Tab walks every focusable widget of every window, so a composer + // left behind an open dialog would take a turn in that dialog's + // field order. Behind a modal it becomes a plain look-alike that + // cannot be focused; the modal dims it either way. + let composer: Element<'_, Message> = if self.modal_open() { + container( + text(if self.composer.is_empty() { + "Ask DS4Server anything…" + } else { + &self.composer + }) + .size(14) + .color(muted_text()), + ) .padding(12) - .size(14); + .width(Length::Fill) + .into() + } else { + text_input("Ask DS4Server anything…", &self.composer) + .id(composer_id()) + .on_input(Message::ComposerChanged) + .on_submit(Message::SubmitPrompt) + .padding(12) + .size(14) + .into() + }; let action = if self.generating { action_button(text("Stop").size(12)).on_press(Message::StopGeneration) } else if self.composer.trim().is_empty() {