236 lines
10 KiB
Rust
236 lines
10 KiB
Rust
{
|
|
let (connection_panel, connection_body) = build_panel("Relay Controls");
|
|
let server_entry = gtk::Entry::new();
|
|
server_entry.add_css_class("server-entry");
|
|
server_entry.set_hexpand(true);
|
|
server_entry.set_width_chars(18);
|
|
server_entry.set_text(server_addr);
|
|
server_entry.set_tooltip_text(Some("Relay host address."));
|
|
let relay_row = gtk::Box::new(gtk::Orientation::Horizontal, 8);
|
|
relay_row.set_halign(gtk::Align::Fill);
|
|
relay_row.set_hexpand(true);
|
|
relay_row.append(&server_entry);
|
|
let start_button = gtk::Button::with_label("Connect");
|
|
start_button.add_css_class("suggested-action");
|
|
start_button.set_hexpand(false);
|
|
stabilize_button(&start_button, 108);
|
|
relay_row.append(&start_button);
|
|
connection_body.append(&relay_row);
|
|
|
|
let live_actions_row = gtk::Box::new(gtk::Orientation::Horizontal, 8);
|
|
live_actions_row.set_homogeneous(true);
|
|
let clipboard_button = gtk::Button::with_label("Send Clipboard");
|
|
clipboard_button.set_hexpand(true);
|
|
stabilize_button(&clipboard_button, 108);
|
|
clipboard_button.set_tooltip_text(Some("Type clipboard remotely."));
|
|
let probe_button = gtk::Button::with_label("Copy Gate Probe");
|
|
probe_button.set_hexpand(true);
|
|
stabilize_button(&probe_button, 108);
|
|
probe_button.set_tooltip_text(Some("Copy quality probe."));
|
|
let usb_recover_button = gtk::Button::with_label("Recover USB");
|
|
usb_recover_button.set_hexpand(true);
|
|
stabilize_button(&usb_recover_button, 108);
|
|
usb_recover_button.set_tooltip_text(Some("Re-enumerate remote USB."));
|
|
live_actions_row.append(&clipboard_button);
|
|
live_actions_row.append(&probe_button);
|
|
live_actions_row.append(&usb_recover_button);
|
|
connection_body.append(&live_actions_row);
|
|
|
|
connection_body.append(>k::Separator::new(gtk::Orientation::Horizontal));
|
|
let power_heading = gtk::Label::new(Some("GPIO Power"));
|
|
power_heading.add_css_class("subgroup-title");
|
|
power_heading.set_halign(gtk::Align::Start);
|
|
|
|
let power_shell = gtk::Box::new(gtk::Orientation::Vertical, 6);
|
|
power_shell.set_halign(gtk::Align::Fill);
|
|
let power_row = gtk::Box::new(gtk::Orientation::Horizontal, 8);
|
|
power_row.set_hexpand(true);
|
|
power_heading.set_width_chars(10);
|
|
power_row.append(&power_heading);
|
|
let power_buttons = gtk::Box::new(gtk::Orientation::Horizontal, 8);
|
|
power_buttons.set_hexpand(true);
|
|
power_buttons.set_homogeneous(true);
|
|
let power_on_button = gtk::Button::with_label("On");
|
|
power_on_button.set_hexpand(true);
|
|
stabilize_button(&power_on_button, 52);
|
|
power_on_button.add_css_class("pill-toggle");
|
|
let power_auto_button = gtk::Button::with_label("Auto");
|
|
power_auto_button.set_hexpand(true);
|
|
stabilize_button(&power_auto_button, 52);
|
|
power_auto_button.add_css_class("pill-toggle");
|
|
let power_off_button = gtk::Button::with_label("Off");
|
|
power_off_button.set_hexpand(true);
|
|
stabilize_button(&power_off_button, 52);
|
|
power_off_button.add_css_class("pill-toggle");
|
|
let power_detail = gtk::Label::new(Some("Capture power status is loading..."));
|
|
power_detail.add_css_class("dim-label");
|
|
power_detail.set_wrap(true);
|
|
power_detail.set_xalign(0.0);
|
|
power_buttons.append(&power_on_button);
|
|
power_buttons.append(&power_auto_button);
|
|
power_buttons.append(&power_off_button);
|
|
power_row.append(&power_buttons);
|
|
power_shell.append(&power_row);
|
|
connection_body.append(&power_shell);
|
|
let routing_heading = gtk::Label::new(Some("Inputs"));
|
|
routing_heading.add_css_class("subgroup-title");
|
|
routing_heading.set_halign(gtk::Align::Start);
|
|
connection_body.append(>k::Separator::new(gtk::Orientation::Horizontal));
|
|
|
|
let routing_row = gtk::Box::new(gtk::Orientation::Horizontal, 8);
|
|
routing_row.set_hexpand(true);
|
|
routing_heading.set_width_chars(10);
|
|
routing_row.append(&routing_heading);
|
|
let routing_buttons = gtk::Box::new(gtk::Orientation::Horizontal, 8);
|
|
routing_buttons.set_hexpand(true);
|
|
routing_buttons.set_homogeneous(true);
|
|
let input_toggle_button = gtk::Button::with_label("Route");
|
|
input_toggle_button.set_hexpand(true);
|
|
stabilize_button(&input_toggle_button, 106);
|
|
input_toggle_button.set_tooltip_text(Some("Swap input ownership."));
|
|
let swap_key_button = gtk::Button::with_label("Set Swap Key");
|
|
swap_key_button.set_hexpand(true);
|
|
stabilize_button(&swap_key_button, 106);
|
|
routing_buttons.append(&input_toggle_button);
|
|
routing_buttons.append(&swap_key_button);
|
|
routing_row.append(&routing_buttons);
|
|
connection_body.append(&routing_row);
|
|
operations.append(&connection_panel);
|
|
|
|
let (diagnostics_panel, diagnostics_body) = build_panel("Diagnostics");
|
|
diagnostics_panel.set_vexpand(true);
|
|
diagnostics_panel.set_valign(gtk::Align::Fill);
|
|
diagnostics_body.set_vexpand(true);
|
|
let diagnostics_toolbar = gtk::Box::new(gtk::Orientation::Horizontal, 8);
|
|
diagnostics_toolbar.set_homogeneous(true);
|
|
let diagnostics_copy_button = gtk::Button::with_label("Copy Report");
|
|
stabilize_button(&diagnostics_copy_button, 112);
|
|
let diagnostics_popout_button = gtk::Button::with_label("Break Out");
|
|
stabilize_button(&diagnostics_popout_button, 112);
|
|
diagnostics_toolbar.append(&diagnostics_copy_button);
|
|
diagnostics_toolbar.append(&diagnostics_popout_button);
|
|
let diagnostics_log = Rc::new(RefCell::new(DiagnosticsLog::new(16)));
|
|
let diagnostics_label = gtk::Label::new(None);
|
|
diagnostics_label.add_css_class("status-log");
|
|
diagnostics_label.set_selectable(true);
|
|
diagnostics_label.set_xalign(0.0);
|
|
diagnostics_label.set_yalign(0.0);
|
|
diagnostics_label.set_wrap(false);
|
|
diagnostics_label.set_halign(gtk::Align::Start);
|
|
diagnostics_label.set_valign(gtk::Align::Start);
|
|
diagnostics_label.set_hexpand(true);
|
|
let diagnostics_shell = gtk::Box::new(gtk::Orientation::Vertical, 0);
|
|
diagnostics_shell.set_hexpand(true);
|
|
diagnostics_shell.set_vexpand(false);
|
|
diagnostics_shell.append(&diagnostics_label);
|
|
let diagnostics_scroll = gtk::ScrolledWindow::builder()
|
|
.hexpand(true)
|
|
.vexpand(true)
|
|
.min_content_height(SIDE_LOG_MIN_HEIGHT)
|
|
.child(&diagnostics_shell)
|
|
.build();
|
|
diagnostics_body.append(&diagnostics_toolbar);
|
|
diagnostics_body.append(&diagnostics_scroll);
|
|
operations.append(&diagnostics_panel);
|
|
|
|
let (console_panel, console_body) = build_panel("Session Console");
|
|
console_panel.set_vexpand(true);
|
|
console_panel.set_valign(gtk::Align::Fill);
|
|
console_body.set_vexpand(true);
|
|
let console_toolbar = gtk::Box::new(gtk::Orientation::Horizontal, 8);
|
|
let session_log_level = Rc::new(RefCell::new(ConsoleLogLevel::default()));
|
|
let console_level_combo = gtk::ComboBoxText::new();
|
|
for level in ConsoleLogLevel::ALL {
|
|
console_level_combo.append(Some(level.id()), level.label());
|
|
}
|
|
console_level_combo.set_active_id(Some(ConsoleLogLevel::default().id()));
|
|
console_level_combo.set_size_request(78, 36);
|
|
console_level_combo.set_tooltip_text(Some("Show relay logs at this level or higher."));
|
|
let console_copy_button = gtk::Button::with_label("Copy");
|
|
console_copy_button.set_tooltip_text(Some("Copy visible log."));
|
|
let console_popout_button = gtk::Button::with_label("Pop Out");
|
|
console_popout_button.set_tooltip_text(Some("Open log window."));
|
|
let console_buttons = gtk::Box::new(gtk::Orientation::Horizontal, 8);
|
|
console_buttons.set_hexpand(true);
|
|
console_buttons.set_homogeneous(true);
|
|
console_copy_button.set_hexpand(true);
|
|
console_popout_button.set_hexpand(true);
|
|
console_buttons.append(&console_copy_button);
|
|
console_buttons.append(&console_popout_button);
|
|
console_toolbar.append(&console_level_combo);
|
|
console_toolbar.append(&console_buttons);
|
|
let status_label = gtk::Label::new(Some("Session log ready."));
|
|
status_label.add_css_class("status-line");
|
|
status_label.set_halign(gtk::Align::Start);
|
|
status_label.set_wrap(true);
|
|
status_label.set_xalign(0.0);
|
|
let session_log_buffer = gtk::TextBuffer::new(None);
|
|
session_log_buffer.create_tag(Some("log-launcher"), &[("foreground", &"#8bd5ca")]);
|
|
session_log_buffer.create_tag(Some("log-relay"), &[("foreground", &"#89b4fa")]);
|
|
session_log_buffer.create_tag(Some("log-preview"), &[("foreground", &"#cba6f7")]);
|
|
session_log_buffer.create_tag(Some("log-stderr"), &[("foreground", &"#f9e2af")]);
|
|
session_log_buffer.create_tag(Some("log-warn"), &[("foreground", &"#fab387")]);
|
|
session_log_buffer.create_tag(Some("log-error"), &[("foreground", &"#f38ba8")]);
|
|
super::ui_runtime::append_session_log(&session_log_buffer, "[launcher] Session log ready.");
|
|
let session_log_view = gtk::TextView::with_buffer(&session_log_buffer);
|
|
session_log_view.add_css_class("status-log");
|
|
session_log_view.set_editable(false);
|
|
session_log_view.set_cursor_visible(false);
|
|
session_log_view.set_monospace(true);
|
|
session_log_view.set_wrap_mode(gtk::WrapMode::WordChar);
|
|
let log_scroll = gtk::ScrolledWindow::builder()
|
|
.hexpand(true)
|
|
.vexpand(true)
|
|
.min_content_height(SIDE_LOG_MIN_HEIGHT)
|
|
.child(&session_log_view)
|
|
.build();
|
|
console_body.append(&console_toolbar);
|
|
console_body.append(&log_scroll);
|
|
operations.append(&console_panel);
|
|
|
|
{
|
|
let buffer = session_log_buffer.clone();
|
|
let view = session_log_view.clone();
|
|
status_label.connect_notify_local(Some("label"), move |label, _| {
|
|
super::ui_runtime::append_session_log(&buffer, &format!("[launcher] {}", label.text()));
|
|
let mut end = buffer.end_iter();
|
|
view.scroll_to_iter(&mut end, 0.0, false, 0.0, 1.0);
|
|
});
|
|
}
|
|
|
|
let preview = match LauncherPreview::new(server_addr.to_string()) {
|
|
Ok(preview) => Some(Rc::new(preview)),
|
|
Err(err) => {
|
|
status_label.set_text(&format!("Preview unavailable: {err}"));
|
|
None
|
|
}
|
|
};
|
|
|
|
OperationsRailContext {
|
|
server_entry,
|
|
start_button,
|
|
clipboard_button,
|
|
probe_button,
|
|
usb_recover_button,
|
|
power_auto_button,
|
|
power_on_button,
|
|
power_off_button,
|
|
power_detail,
|
|
input_toggle_button,
|
|
swap_key_button,
|
|
diagnostics_copy_button,
|
|
diagnostics_popout_button,
|
|
diagnostics_log,
|
|
diagnostics_label,
|
|
diagnostics_scroll,
|
|
console_copy_button,
|
|
console_popout_button,
|
|
console_level_combo,
|
|
session_log_level,
|
|
status_label,
|
|
session_log_buffer,
|
|
session_log_view,
|
|
preview,
|
|
}
|
|
}
|