Improve session controls and GUI views
This commit is contained in:
@@ -14,6 +14,7 @@ pub struct ConfigForm {
|
||||
pub udp_remote: String,
|
||||
pub pipelines: Vec<(String, FramerChoice, DecoderChoice)>,
|
||||
pub history: usize,
|
||||
pub auto_reconnect: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
@@ -47,11 +48,63 @@ impl Default for ConfigForm {
|
||||
udp_remote: String::new(),
|
||||
pipelines: vec![("text".into(), FramerChoice::Line, DecoderChoice::Text)],
|
||||
history: 10000,
|
||||
auto_reconnect: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigForm {
|
||||
pub fn from_session_config(config: &SessionConfig) -> Self {
|
||||
Self {
|
||||
transport: match &config.transport {
|
||||
TransportConfig::Serial { .. } => TransportChoice::Serial,
|
||||
TransportConfig::Tcp { .. } => TransportChoice::Tcp,
|
||||
TransportConfig::Udp { .. } => TransportChoice::Udp,
|
||||
},
|
||||
port: match &config.transport {
|
||||
TransportConfig::Serial { port, .. } => port.clone(),
|
||||
_ => String::from("/dev/ttyUSB0"),
|
||||
},
|
||||
baud: match &config.transport {
|
||||
TransportConfig::Serial { baud_rate, .. } => *baud_rate,
|
||||
_ => 115200,
|
||||
},
|
||||
addr: match &config.transport {
|
||||
TransportConfig::Tcp { addr } => addr.clone(),
|
||||
_ => String::from("127.0.0.1:8080"),
|
||||
},
|
||||
udp_bind: match &config.transport {
|
||||
TransportConfig::Udp { bind_addr, .. } => bind_addr.clone(),
|
||||
_ => String::from("0.0.0.0:9000"),
|
||||
},
|
||||
udp_remote: match &config.transport {
|
||||
TransportConfig::Udp { remote_addr, .. } => remote_addr.clone().unwrap_or_default(),
|
||||
_ => String::new(),
|
||||
},
|
||||
pipelines: config
|
||||
.pipelines
|
||||
.iter()
|
||||
.map(|pipeline| {
|
||||
let framer = match &pipeline.framer {
|
||||
FramerConfig::Line { .. } => FramerChoice::Line,
|
||||
FramerConfig::Fixed { frame_len } => FramerChoice::Fixed(*frame_len),
|
||||
FramerConfig::Length { .. } | FramerConfig::Cobs { .. } => {
|
||||
FramerChoice::Line
|
||||
}
|
||||
};
|
||||
let decoder = match &pipeline.decoder {
|
||||
DecoderConfig::Text { .. } => DecoderChoice::Text,
|
||||
DecoderConfig::Hex { .. } => DecoderChoice::Hex,
|
||||
DecoderConfig::Plot { .. } => DecoderChoice::Plot,
|
||||
};
|
||||
(pipeline.name.clone(), framer, decoder)
|
||||
})
|
||||
.collect(),
|
||||
history: config.history_limit,
|
||||
auto_reconnect: config.auto_reconnect,
|
||||
}
|
||||
}
|
||||
|
||||
// 把表单数据转换成 xserial-client 的 SessionConfig
|
||||
pub fn to_session_config(&self) -> SessionConfig {
|
||||
SessionConfig {
|
||||
@@ -104,14 +157,14 @@ impl ConfigForm {
|
||||
})
|
||||
.collect(),
|
||||
history_limit: self.history,
|
||||
auto_reconnect: false,
|
||||
auto_reconnect: self.auto_reconnect,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── 渲染函数 ──────────────────────────────────────────────────────
|
||||
|
||||
pub fn render(ui: &mut Ui, form: &mut ConfigForm) -> Option<SessionConfig> {
|
||||
pub fn render(ui: &mut Ui, form: &mut ConfigForm, submit_label: &str) -> Option<SessionConfig> {
|
||||
let mut result = None;
|
||||
|
||||
ScrollArea::vertical().show(ui, |ui| {
|
||||
@@ -234,9 +287,10 @@ pub fn render(ui: &mut Ui, form: &mut ConfigForm) -> Option<SessionConfig> {
|
||||
ui.label("History:");
|
||||
ui.add(DragValue::new(&mut form.history).range(100..=1_000_000));
|
||||
});
|
||||
ui.checkbox(&mut form.auto_reconnect, "Auto reconnect");
|
||||
|
||||
ui.separator();
|
||||
if ui.button("✓ Create Session").clicked() {
|
||||
if ui.button(submit_label).clicked() {
|
||||
result = Some(form.to_session_config());
|
||||
}
|
||||
});
|
||||
|
||||
36
crates/xserial-gui/src/panels/console.rs
Normal file
36
crates/xserial-gui/src/panels/console.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
use crate::app::DisplayOptions;
|
||||
use crate::buffers::{LineDirection, TextBuffer};
|
||||
use egui::{ScrollArea, Ui};
|
||||
|
||||
pub fn render(ui: &mut Ui, buf: &TextBuffer, display: DisplayOptions) {
|
||||
ScrollArea::vertical().stick_to_bottom(true).show(ui, |ui| {
|
||||
for line in buf.iter() {
|
||||
let mut prefix = Vec::new();
|
||||
if display.show_timestamp {
|
||||
let ts = line.elapsed.as_secs_f64();
|
||||
let time = if ts < 60.0 {
|
||||
format!("{:05.2}", ts)
|
||||
} else {
|
||||
format!("{:02}:{:02}", (ts / 60.0) as u64, (ts % 60.0) as u64)
|
||||
};
|
||||
prefix.push(format!("[{time}]"));
|
||||
}
|
||||
if display.show_direction {
|
||||
let dir = match line.direction {
|
||||
LineDirection::In => "IN",
|
||||
LineDirection::Out => "OUT",
|
||||
};
|
||||
prefix.push(format!("[{dir}]"));
|
||||
}
|
||||
if display.show_pipeline {
|
||||
prefix.push(format!("[{}]", line.pipeline));
|
||||
}
|
||||
let prefix = if prefix.is_empty() {
|
||||
String::new()
|
||||
} else {
|
||||
format!("{} ", prefix.join(" "))
|
||||
};
|
||||
ui.monospace(format!("{prefix}{}", line.text));
|
||||
}
|
||||
});
|
||||
}
|
||||
41
crates/xserial-gui/src/panels/hex_view.rs
Normal file
41
crates/xserial-gui/src/panels/hex_view.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
use crate::app::DisplayOptions;
|
||||
use crate::buffers::{HexBuffer, LineDirection};
|
||||
use egui::{ScrollArea, Ui};
|
||||
|
||||
pub fn render(ui: &mut Ui, buf: &HexBuffer, display: DisplayOptions) {
|
||||
let mut lines = buf.iter().peekable();
|
||||
if lines.peek().is_none() {
|
||||
ui.label("no hex data");
|
||||
return;
|
||||
}
|
||||
ScrollArea::vertical().stick_to_bottom(true).show(ui, |ui| {
|
||||
for line in lines {
|
||||
let mut prefix = Vec::new();
|
||||
if display.show_timestamp {
|
||||
let ts = line.elapsed.as_secs_f64();
|
||||
let time = if ts < 60.0 {
|
||||
format!("{:05.2}", ts)
|
||||
} else {
|
||||
format!("{:02}:{:02}", (ts / 60.0) as u64, (ts % 60.0) as u64)
|
||||
};
|
||||
prefix.push(format!("[{time}]"));
|
||||
}
|
||||
if display.show_direction {
|
||||
let dir = match line.direction {
|
||||
LineDirection::In => "IN",
|
||||
LineDirection::Out => "OUT",
|
||||
};
|
||||
prefix.push(format!("[{dir}]"));
|
||||
}
|
||||
if display.show_pipeline {
|
||||
prefix.push(format!("[{}]", line.pipeline));
|
||||
}
|
||||
let prefix = if prefix.is_empty() {
|
||||
String::new()
|
||||
} else {
|
||||
format!("{} ", prefix.join(" "))
|
||||
};
|
||||
ui.monospace(format!("{prefix}{} |{}|", line.hex, line.ascii));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,2 +1,4 @@
|
||||
pub mod config;
|
||||
pub mod console;
|
||||
pub mod hex_view;
|
||||
pub mod sidebar;
|
||||
|
||||
Reference in New Issue
Block a user