refactor(gui): split app.rs into models and panel modules

Extract types (models.rs), font settings, session controls, and send
panel into separate modules. Reduces app.rs from 1488 to 848 lines.
Zero behavior change.

- models.rs: ConnectionStatus, View, SendMode, LineEnding,
  DisplayOptions, SearchState, SessionTab
- panels/font_settings.rs: font selector and settings window
- panels/session_controls.rs: session connect/disconnect UI
- panels/send_panel.rs: send input and payload building
This commit is contained in:
2026-06-22 15:33:25 +08:00
parent cd3f778502
commit 5923ad0143
7 changed files with 691 additions and 669 deletions

View File

@@ -0,0 +1,147 @@
use crate::models::{ConnectionStatus, SessionTab, View};
use egui::TextEdit;
use pipeview_client::SessionManager;
use pipeview_core::transport::TransportConfig;
pub fn render_search_bar(ui: &mut egui::Ui, tab: &mut SessionTab) {
if !tab.search.active {
return;
}
ui.horizontal(|ui| {
let response = ui.add(
TextEdit::singleline(&mut tab.search.query)
.hint_text("Search...")
.desired_width(200.0),
);
if tab.search.just_opened {
response.request_focus();
tab.search.just_opened = false;
}
if response.changed() {
let matches = match tab.view {
View::Text => tab.console.search(&tab.search.query, tab.search.case_sensitive),
View::Hex => tab.hex.search(&tab.search.query, tab.search.case_sensitive),
View::Plot => Vec::new(),
};
tab.search.matches = matches;
tab.search.current_match = 0;
}
if response.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)) {
tab.search.next();
}
ui.label(format!(
"{}/{}",
tab.search.current_display(),
tab.search.match_count()
));
if ui.button("").clicked() {
tab.search.prev();
}
if ui.button("").clicked() {
tab.search.next();
}
if ui.checkbox(&mut tab.search.case_sensitive, "Aa").changed() {
let matches = match tab.view {
View::Text => tab.console.search(&tab.search.query, tab.search.case_sensitive),
View::Hex => tab.hex.search(&tab.search.query, tab.search.case_sensitive),
View::Plot => Vec::new(),
};
tab.search.matches = matches;
tab.search.current_match = 0;
}
if ui.button("").clicked() {
tab.search.clear();
}
});
}
pub fn render_session_controls(
ui: &mut egui::Ui,
manager: &SessionManager,
tab: &mut SessionTab,
) -> bool {
let mut auto_reconnect_changed = false;
ui.horizontal_wrapped(|ui| {
let connected = matches!(
tab.status,
ConnectionStatus::Connected | ConnectionStatus::Connecting
);
let connect_label = if connected { "Disconnect" } else { "Connect" };
if ui.button(connect_label).clicked() {
if let Some(handle) = manager.get(tab.id) {
if connected {
tab.status = ConnectionStatus::Disconnected;
tokio::spawn(async move {
let _ = handle.disconnect().await;
});
} else {
tab.status = ConnectionStatus::Connecting;
tokio::spawn(async move {
let _ = handle.connect().await;
});
}
} else {
tab.status = ConnectionStatus::Error(String::from("session not found"));
}
}
// if ui.button("Reconnect").clicked() {
// if let Some(handle) = manager.get(tab.id) {
// tab.status = ConnectionStatus::Connecting;
// tokio::spawn(async move {
// let _ = handle.reconnect().await;
// });
// } else {
// tab.status = ConnectionStatus::Error(String::from("session not found"));
// }
// }
if ui.button("Clear").clicked() {
tab.console.clear();
tab.hex.clear();
tab.plot.clear();
tab.send_status = Some(String::from("Cleared"));
}
let response = ui.checkbox(&mut tab.auto_reconnect, "Auto reconnect");
if response.changed() {
tab.session_config.auto_reconnect = tab.auto_reconnect;
auto_reconnect_changed = true;
if let Some(handle) = manager.get(tab.id) {
let enabled = tab.auto_reconnect;
tokio::spawn(async move {
let _ = handle.set_auto_reconnect(enabled).await;
});
} else {
tab.status = ConnectionStatus::Error(String::from("session not found"));
}
}
if matches!(tab.status, ConnectionStatus::Connected)
&& matches!(tab.session_config.transport, TransportConfig::Serial { .. })
{
let dtr_changed = ui.checkbox(&mut tab.dtr, "DTR").changed();
let rts_changed = ui.checkbox(&mut tab.rts, "RTS").changed();
if dtr_changed || rts_changed {
if let Some(handle) = manager.get(tab.id) {
let dtr = tab.dtr;
let rts = tab.rts;
tokio::spawn(async move {
if dtr_changed {
let _ = handle.set_dtr(dtr).await;
}
if rts_changed {
let _ = handle.set_rts(rts).await;
}
});
} else {
tab.status = ConnectionStatus::Error(String::from("session not found"));
}
}
}
});
auto_reconnect_changed
}