breadhelp: capture the troubleshoot wizard modal
One more view: "troubleshoot-wizard" opens ui::troubleshoot_wizard directly (normally only reachable via Home's "Something's wrong?" button), using the same on_build-hook pattern as breadbar/breadman's add-dialogs — open() now takes a callback run before .present(), the only point connect_map can still catch the map. The real call site (ui::home) passes a no-op. Deliberately not covered: the onboarding tour (ui::tour) — it's a live, multi-step walkthrough that overlays callouts on the real desktop as the user does real things, which has no meaningful single-screenshot representation in an isolated environment with no real desktop for it to point at. guide_view and keybind_viewer aren't separate views either — both render embedded inside the Learn/Home tabs already captured.
This commit is contained in:
parent
5359a8b76d
commit
4efc5eafd1
3 changed files with 53 additions and 9 deletions
|
|
@ -7,6 +7,19 @@
|
||||||
//! see `ui::tabs`. The window is a plain top-level (not layer-shell), so a
|
//! see `ui::tabs`. The window is a plain top-level (not layer-shell), so a
|
||||||
//! full known-size canvas capture is enough, same reasoning as breadpad's
|
//! full known-size canvas capture is enough, same reasoning as breadpad's
|
||||||
//! popup view.
|
//! popup view.
|
||||||
|
//!
|
||||||
|
//! One more view isn't a tab: "troubleshoot-wizard" opens the modal wizard
|
||||||
|
//! window (`ui::troubleshoot_wizard`, normally reachable via Home's
|
||||||
|
//! "Something's wrong?" button) directly.
|
||||||
|
//!
|
||||||
|
//! Deliberately NOT covered here: the onboarding tour (`ui::tour`). It's a
|
||||||
|
//! live, multi-step walkthrough that overlays callouts on the *real*
|
||||||
|
//! desktop as the user does real things (opens real apps, switches real
|
||||||
|
//! workspaces) — there's no meaningful "screenshot" of a single step in an
|
||||||
|
//! isolated environment with no real desktop for it to point at.
|
||||||
|
//! `ui::guide_view` and `ui::keybind_viewer` also aren't separate views:
|
||||||
|
//! both render embedded *inside* the Learn/Home tabs respectively, so
|
||||||
|
//! they're already covered by those tabs' own captures.
|
||||||
|
|
||||||
use gtk4::prelude::*;
|
use gtk4::prelude::*;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
@ -17,7 +30,12 @@ use std::time::Duration;
|
||||||
/// anything has been drawn into it.
|
/// anything has been drawn into it.
|
||||||
const SETTLE_DELAY: Duration = Duration::from_millis(300);
|
const SETTLE_DELAY: Duration = Duration::from_millis(300);
|
||||||
|
|
||||||
const KNOWN_VIEWS: &[&str] = &["home", "learn", "ask"];
|
/// Delay before opening the wizard modal — same reasoning as every other
|
||||||
|
/// app's PRE_POPUP_DELAY: the parent window's own layout needs a beat to
|
||||||
|
/// settle first.
|
||||||
|
const PRE_POPUP_DELAY: Duration = Duration::from_millis(300);
|
||||||
|
|
||||||
|
const KNOWN_VIEWS: &[&str] = &["home", "learn", "ask", "troubleshoot-wizard"];
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ScreenshotRequest {
|
pub struct ScreenshotRequest {
|
||||||
|
|
@ -39,20 +57,41 @@ pub fn dispatch(window: >k4::ApplicationWindow, stack: >k4::Stack, req: Scre
|
||||||
);
|
);
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
stack.set_visible_child_name(&req.view);
|
|
||||||
|
|
||||||
let output = req.output;
|
let output = req.output;
|
||||||
let (width, height) = (req.width as i32, req.height as i32);
|
let (width, height) = (req.width as i32, req.height as i32);
|
||||||
|
|
||||||
|
if req.view == "troubleshoot-wizard" {
|
||||||
|
window.connect_map(move |win| {
|
||||||
|
let output = output.clone();
|
||||||
|
let win = win.clone();
|
||||||
|
gtk4::glib::timeout_add_local_once(PRE_POPUP_DELAY, move || {
|
||||||
|
crate::ui::troubleshoot_wizard::open(&win, move |dialog| {
|
||||||
|
let output = output.clone();
|
||||||
|
dialog.connect_map(move |_| {
|
||||||
|
let output = output.clone();
|
||||||
|
gtk4::glib::timeout_add_local_once(SETTLE_DELAY, move || {
|
||||||
|
finish(bread_screenshots::capture_region(0, 0, width, height, &output));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// The caller (`ui::window::present`) returns immediately after this
|
||||||
|
// for the screenshot path, skipping its own normal `window.present()`
|
||||||
|
// call — trigger it here instead, so `connect_map` above actually has
|
||||||
|
// something to fire for.
|
||||||
|
window.present();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stack.set_visible_child_name(&req.view);
|
||||||
|
|
||||||
window.connect_map(move |_| {
|
window.connect_map(move |_| {
|
||||||
let output = output.clone();
|
let output = output.clone();
|
||||||
gtk4::glib::timeout_add_local_once(SETTLE_DELAY, move || {
|
gtk4::glib::timeout_add_local_once(SETTLE_DELAY, move || {
|
||||||
finish(bread_screenshots::capture_region(0, 0, width, height, &output));
|
finish(bread_screenshots::capture_region(0, 0, width, height, &output));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// The caller (`ui::window::present`) returns immediately after this for
|
|
||||||
// the screenshot path, skipping its own normal `window.present()` call
|
|
||||||
// — trigger it here instead, so `connect_map` above actually has
|
|
||||||
// something to fire for.
|
|
||||||
window.present();
|
window.present();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ pub fn build(
|
||||||
troubleshoot_btn.set_halign(Align::Start);
|
troubleshoot_btn.set_halign(Align::Start);
|
||||||
{
|
{
|
||||||
let parent = parent_window.clone();
|
let parent = parent_window.clone();
|
||||||
troubleshoot_btn.connect_clicked(move |_| troubleshoot_wizard::open(&parent));
|
troubleshoot_btn.connect_clicked(move |_| troubleshoot_wizard::open(&parent, |_| {}));
|
||||||
}
|
}
|
||||||
vbox.append(&troubleshoot_btn);
|
vbox.append(&troubleshoot_btn);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,11 @@ struct Wizard {
|
||||||
trees: HashMap<String, Vec<SymptomNode>>,
|
trees: HashMap<String, Vec<SymptomNode>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open(parent: &impl IsA<gtk4::Window>) {
|
/// `on_build` runs on the freshly built window *before* it's presented —
|
||||||
|
/// screenshot mode's only hook point, since `connect_map` registered any
|
||||||
|
/// later would miss a map that already happened. The real call site
|
||||||
|
/// (`ui::home`) passes a no-op.
|
||||||
|
pub fn open(parent: &impl IsA<gtk4::Window>, on_build: impl FnOnce(&Window)) {
|
||||||
let window = Window::builder()
|
let window = Window::builder()
|
||||||
.transient_for(parent)
|
.transient_for(parent)
|
||||||
.modal(true)
|
.modal(true)
|
||||||
|
|
@ -41,6 +45,7 @@ pub fn open(parent: &impl IsA<gtk4::Window>) {
|
||||||
wizard.render_picker();
|
wizard.render_picker();
|
||||||
|
|
||||||
window.set_child(Some(&content));
|
window.set_child(Some(&content));
|
||||||
|
on_build(&window);
|
||||||
window.present();
|
window.present();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue