Refine UI panels and render mode flow
This commit is contained in:
590
src/ui.rs
590
src/ui.rs
@@ -3,9 +3,9 @@ use eframe::egui;
|
||||
use crate::{
|
||||
connection::{ConnectionManager, ConnectionState},
|
||||
recording::Recorder,
|
||||
theme::{
|
||||
ACCENT_BLUE, ACCENT_GREEN, ACCENT_ORANGE, ACCENT_RED, ONE_DARK_PRO, accent_text, dim_text,
|
||||
group_frame, panel_frame, tag_button,
|
||||
style::{
|
||||
self, ACCENT_BLUE, ACCENT_GREEN, ACCENT_ORANGE, ACCENT_RED, METRICS, ONE_DARK_PRO,
|
||||
accent_text, dim_text, group_frame, layout, panel_frame, tag_button,
|
||||
},
|
||||
utils::serial_enum,
|
||||
};
|
||||
@@ -47,9 +47,8 @@ pub struct ConnectPanelState {
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SerialMode {
|
||||
SingleModule,
|
||||
Manual,
|
||||
Model,
|
||||
Finger,
|
||||
Hand,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
@@ -80,7 +79,7 @@ impl FloatingPanelState {
|
||||
impl Default for ConfigPanelState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
mode: SerialMode::SingleModule,
|
||||
mode: SerialMode::Finger,
|
||||
port: "COM3".to_owned(),
|
||||
baud_rate: 115_200,
|
||||
data_bits: 8,
|
||||
@@ -98,10 +97,10 @@ impl Default for ConfigPanelState {
|
||||
|
||||
impl Default for ConnectPanelState {
|
||||
fn default() -> Self {
|
||||
let port = serial_enum().unwrap();
|
||||
let port = serial_enum().unwrap_or_default();
|
||||
let selected_port = port.first().cloned().unwrap_or_default();
|
||||
Self {
|
||||
mode: SerialMode::SingleModule,
|
||||
mode: SerialMode::Finger,
|
||||
port,
|
||||
selected_port,
|
||||
duration: 10,
|
||||
@@ -143,165 +142,162 @@ pub fn draw_connect_panel(
|
||||
ConnectionState::Connected | ConnectionState::Streaming
|
||||
);
|
||||
|
||||
draw_center_floating_panel(ctx, panel, "connect_center_panel", 42.0, "连接", |ui| {
|
||||
ui.set_min_width(320.0);
|
||||
draw_center_floating_panel(
|
||||
ctx,
|
||||
panel,
|
||||
"connect_center_panel",
|
||||
layout::CENTER_PANEL_TOP,
|
||||
"连接",
|
||||
|ui| {
|
||||
ui.vertical(|ui| {
|
||||
// centered_mode_row(ui, &mut config.mode);
|
||||
ui.add_space(METRICS.row_gap);
|
||||
|
||||
ui.vertical(|ui| {
|
||||
let button_width = 96.0;
|
||||
let gap = 8.0;
|
||||
let total_width = button_width * 3.0 + gap * 2.0;
|
||||
let left_space = ((ui.available_width() - total_width) * 0.5).max(0.0);
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_space(left_space);
|
||||
|
||||
mode_button(ui, &mut config.mode, SerialMode::SingleModule, "单模块");
|
||||
ui.add_space(gap);
|
||||
mode_button(ui, &mut config.mode, SerialMode::Manual, "全手");
|
||||
ui.add_space(gap);
|
||||
mode_button(ui, &mut config.mode, SerialMode::Model, "模型");
|
||||
});
|
||||
|
||||
ui.add_space(6.0);
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_space(10.0);
|
||||
ui.add(
|
||||
egui::Image::new(egui::include_image!("../static/cpu.png"))
|
||||
.fit_to_exact_size(egui::vec2(72.0, 72.0)),
|
||||
);
|
||||
|
||||
ui.vertical(|ui| {
|
||||
group_frame().show(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.colored_label(ONE_DARK_PRO.text, "串口");
|
||||
egui::ComboBox::from_id_salt("connect_ports")
|
||||
.width(130.0)
|
||||
.selected_text(if config.selected_port.is_empty() {
|
||||
"无可用串口".to_owned()
|
||||
} else {
|
||||
config.selected_port.clone()
|
||||
})
|
||||
.show_ui(ui, |ui| {
|
||||
for port in &config.port {
|
||||
let label = port.clone();
|
||||
ui.selectable_value(
|
||||
&mut config.selected_port,
|
||||
port.clone(),
|
||||
label,
|
||||
);
|
||||
}
|
||||
});
|
||||
if ui
|
||||
.add(
|
||||
egui::Button::new("⟳")
|
||||
.fill(ONE_DARK_PRO.panel_strong)
|
||||
.stroke(egui::Stroke::new(1.0, ONE_DARK_PRO.border_soft))
|
||||
.min_size(egui::vec2(24.0, 20.0)),
|
||||
)
|
||||
.on_hover_text("刷新串口")
|
||||
.clicked()
|
||||
{
|
||||
if let Ok(ports) = serial_enum() {
|
||||
if !ports.contains(&config.selected_port) {
|
||||
config.selected_port =
|
||||
ports.first().cloned().unwrap_or_default();
|
||||
}
|
||||
config.port = ports;
|
||||
}
|
||||
}
|
||||
ui.add_space(10.0);
|
||||
|
||||
ui.label("频率");
|
||||
ui.add_sized(
|
||||
egui::vec2(72.0, 20.0),
|
||||
egui::DragValue::new(&mut config.duration).range(1..=120),
|
||||
ui.add(
|
||||
egui::Image::new(egui::include_image!("../static/cpu.png"))
|
||||
.fit_to_exact_size(egui::vec2(64.0, 64.0)),
|
||||
);
|
||||
});
|
||||
ui.add_space(METRICS.item_gap);
|
||||
|
||||
ui.add_space(10.0);
|
||||
ui.horizontal(|ui| {
|
||||
ui.checkbox(&mut config.manual, "手动");
|
||||
|
||||
ui.add_enabled_ui(config.manual, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.colored_label(ONE_DARK_PRO.text_dim, "行");
|
||||
ui.add_sized(
|
||||
egui::vec2(48.0, 20.0),
|
||||
egui::DragValue::new(&mut config.rows).range(1..=64),
|
||||
);
|
||||
ui.colored_label(ONE_DARK_PRO.text_dim, "列");
|
||||
ui.add_sized(
|
||||
egui::vec2(48.0, 20.0),
|
||||
egui::DragValue::new(&mut config.cols).range(1..=64),
|
||||
);
|
||||
});
|
||||
ui.vertical(|ui| {
|
||||
draw_connect_port_row(ui, config);
|
||||
ui.add_space(6.0);
|
||||
draw_connect_matrix_row(ui, config);
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
ui.add_space(METRICS.row_gap);
|
||||
draw_connect_action_row(ui, conn_state, is_connected, config, connection);
|
||||
|
||||
if is_connected {
|
||||
draw_recording_toolbar(ui, recorder, export_path);
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
ui.add_space(8.0);
|
||||
// fn centered_mode_row(ui: &mut egui::Ui, mode: &mut SerialMode) {
|
||||
// let button_width = 96.0;
|
||||
// let gap = METRICS.item_gap;
|
||||
// let total_width = button_width * 3.0 + gap * 2.0;
|
||||
// let left_space = ((ui.available_width() - total_width) * 0.5).max(0.0);
|
||||
|
||||
// Connection status and button row
|
||||
ui.horizontal(|ui| {
|
||||
let status_text = match conn_state {
|
||||
ConnectionState::Disconnected => "未连接",
|
||||
ConnectionState::Connecting => "连接中...",
|
||||
ConnectionState::Connected => "已连接",
|
||||
ConnectionState::Streaming => "采集中",
|
||||
ConnectionState::Error => "连接错误",
|
||||
};
|
||||
let status_color = match conn_state {
|
||||
ConnectionState::Disconnected => ONE_DARK_PRO.text_dim,
|
||||
ConnectionState::Connecting => egui::Color32::from_rgb(200, 180, 60),
|
||||
ConnectionState::Connected => egui::Color32::from_rgb(158, 184, 101),
|
||||
ConnectionState::Streaming => egui::Color32::from_rgb(100, 200, 255),
|
||||
ConnectionState::Error => egui::Color32::from_rgb(255, 98, 82),
|
||||
};
|
||||
ui.colored_label(status_color, status_text);
|
||||
// ui.horizontal(|ui| {
|
||||
// ui.add_space(left_space);
|
||||
// mode_button(ui, mode, SerialMode::Finger, "指尖模块");
|
||||
// ui.add_space(gap);
|
||||
// mode_button(ui, mode, SerialMode::Hand, "手掌模块");
|
||||
// // ui.add_space(gap);
|
||||
// // mode_button(ui, mode, SerialMode::Model, "模型");
|
||||
// });
|
||||
// }
|
||||
|
||||
let used = 100.0;
|
||||
let remaining = (ui.available_width() - used).max(0.0);
|
||||
ui.add_space(remaining);
|
||||
|
||||
let btn_label = if is_connected { "断开" } else { "连接" };
|
||||
let btn_fill = if is_connected {
|
||||
egui::Color32::from_rgb(180, 60, 60)
|
||||
} else {
|
||||
ONE_DARK_PRO.accent
|
||||
};
|
||||
let btn_stroke = if is_connected {
|
||||
egui::Stroke::new(1.0, egui::Color32::from_rgb(220, 80, 80))
|
||||
} else {
|
||||
egui::Stroke::new(1.0, ONE_DARK_PRO.accent_hot)
|
||||
};
|
||||
|
||||
if ui
|
||||
.add(
|
||||
egui::Button::new(
|
||||
egui::RichText::new(btn_label).color(egui::Color32::WHITE),
|
||||
)
|
||||
.fill(btn_fill)
|
||||
.stroke(btn_stroke)
|
||||
.min_size(egui::vec2(96.0, 28.0)),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
if is_connected {
|
||||
connection.disconnect();
|
||||
} else if !config.selected_port.is_empty() {
|
||||
connection.connect(
|
||||
&config.selected_port,
|
||||
config.rows as u32,
|
||||
config.cols as u32,
|
||||
);
|
||||
}
|
||||
fn draw_connect_port_row(ui: &mut egui::Ui, config: &mut ConnectPanelState) {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(style::field_label("串口"));
|
||||
egui::ComboBox::from_id_salt("connect_ports")
|
||||
.width(150.0)
|
||||
.selected_text(if config.selected_port.is_empty() {
|
||||
"无可用串口".to_owned()
|
||||
} else {
|
||||
config.selected_port.clone()
|
||||
})
|
||||
.show_ui(ui, |ui| {
|
||||
for port in &config.port {
|
||||
ui.selectable_value(&mut config.selected_port, port.clone(), port.as_str());
|
||||
}
|
||||
});
|
||||
|
||||
// Recording toolbar (visible when connected)
|
||||
if is_connected {
|
||||
draw_recording_toolbar(ui, recorder, export_path);
|
||||
if ui
|
||||
.add(style::icon_button(
|
||||
egui::RichText::new("⟳").color(ONE_DARK_PRO.text).size(16.0),
|
||||
METRICS.icon_button,
|
||||
))
|
||||
.on_hover_text("刷新串口")
|
||||
.clicked()
|
||||
{
|
||||
if let Ok(ports) = serial_enum() {
|
||||
if !ports.contains(&config.selected_port) {
|
||||
config.selected_port = ports.first().cloned().unwrap_or_default();
|
||||
}
|
||||
config.port = ports;
|
||||
}
|
||||
}
|
||||
|
||||
ui.add_space(METRICS.item_gap);
|
||||
ui.label(style::field_label("频率"));
|
||||
ui.add_sized(
|
||||
egui::vec2(72.0, METRICS.field_height),
|
||||
egui::DragValue::new(&mut config.duration).range(1..=120),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
fn draw_connect_matrix_row(ui: &mut egui::Ui, config: &mut ConnectPanelState) {
|
||||
ui.horizontal(|ui| {
|
||||
ui.checkbox(&mut config.manual, "手动矩阵");
|
||||
|
||||
ui.add_enabled_ui(config.manual, |ui| {
|
||||
ui.add_space(METRICS.item_gap);
|
||||
ui.label(style::field_label("行"));
|
||||
ui.add_sized(
|
||||
egui::vec2(56.0, METRICS.field_height),
|
||||
egui::DragValue::new(&mut config.rows).range(1..=64),
|
||||
);
|
||||
ui.label(style::field_label("列"));
|
||||
ui.add_sized(
|
||||
egui::vec2(56.0, METRICS.field_height),
|
||||
egui::DragValue::new(&mut config.cols).range(1..=64),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn draw_connect_action_row(
|
||||
ui: &mut egui::Ui,
|
||||
conn_state: ConnectionState,
|
||||
is_connected: bool,
|
||||
config: &ConnectPanelState,
|
||||
connection: &ConnectionManager,
|
||||
) {
|
||||
ui.horizontal(|ui| {
|
||||
let status_text = match conn_state {
|
||||
ConnectionState::Disconnected => "未连接",
|
||||
ConnectionState::Connecting => "连接中...",
|
||||
ConnectionState::Connected => "已连接",
|
||||
ConnectionState::Streaming => "采集中",
|
||||
ConnectionState::Error => "连接错误",
|
||||
};
|
||||
let status_color = match conn_state {
|
||||
ConnectionState::Disconnected => ONE_DARK_PRO.text_dim,
|
||||
ConnectionState::Connecting => style::status_color_warn(),
|
||||
ConnectionState::Connected => style::status_color_ok(),
|
||||
ConnectionState::Streaming => style::status_color_info(),
|
||||
ConnectionState::Error => style::status_color_error(),
|
||||
};
|
||||
|
||||
ui.colored_label(status_color, status_text);
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
let button = if is_connected {
|
||||
style::danger_button("断开")
|
||||
} else {
|
||||
style::primary_button("连接")
|
||||
};
|
||||
|
||||
if ui.add(button).clicked() {
|
||||
if is_connected {
|
||||
connection.disconnect();
|
||||
} else if !config.selected_port.is_empty() {
|
||||
connection.connect(
|
||||
&config.selected_port,
|
||||
config.rows as u32,
|
||||
config.cols as u32,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -311,11 +307,16 @@ pub fn draw_config_panel(
|
||||
ctx: &egui::Context,
|
||||
panel: &mut FloatingPanelState,
|
||||
config: &mut ConfigPanelState,
|
||||
) {
|
||||
) -> Option<SerialMode> {
|
||||
let mut changed_mode = None;
|
||||
draw_floating_panel(ctx, panel, "配置", "config_panel", |ui| {
|
||||
ui.set_min_width(560.0);
|
||||
|
||||
draw_mode_row(ui, config);
|
||||
if let Some(mode) = draw_mode_row(ui, config) {
|
||||
changed_mode = Some(mode);
|
||||
}
|
||||
|
||||
// draw_mode_row(ui, config);
|
||||
ui.separator();
|
||||
draw_connection_row(ui, config);
|
||||
ui.add_space(8.0);
|
||||
@@ -323,22 +324,30 @@ pub fn draw_config_panel(
|
||||
ui.add_space(8.0);
|
||||
draw_mode_body(ui, config);
|
||||
});
|
||||
changed_mode
|
||||
}
|
||||
|
||||
fn draw_mode_row(ui: &mut egui::Ui, config: &mut ConfigPanelState) {
|
||||
fn draw_mode_row(ui: &mut egui::Ui, config: &mut ConfigPanelState) -> Option<SerialMode> {
|
||||
let mut changed_to = None;
|
||||
ui.horizontal(|ui| {
|
||||
ui.colored_label(dim_text(), "模式");
|
||||
ui.add_space(12.0);
|
||||
|
||||
mode_button(ui, &mut config.mode, SerialMode::SingleModule, "单模块");
|
||||
mode_button(ui, &mut config.mode, SerialMode::Manual, "全手");
|
||||
mode_button(ui, &mut config.mode, SerialMode::Model, "模型");
|
||||
if mode_button(ui, &mut config.mode, SerialMode::Finger, "指尖模块") {
|
||||
changed_to = Some(SerialMode::Finger)
|
||||
}
|
||||
if mode_button(ui, &mut config.mode, SerialMode::Hand, "手掌模块") {
|
||||
changed_to = Some(SerialMode::Hand)
|
||||
}
|
||||
// mode_button(ui, &mut config.mode, SerialMode::Model, "模型");
|
||||
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
ui.checkbox(&mut config.auto_reconnect, "自动");
|
||||
ui.colored_label(dim_text(), "重连");
|
||||
});
|
||||
});
|
||||
|
||||
changed_to
|
||||
}
|
||||
|
||||
fn draw_connection_row(ui: &mut egui::Ui, config: &mut ConfigPanelState) {
|
||||
@@ -348,20 +357,20 @@ fn draw_connection_row(ui: &mut egui::Ui, config: &mut ConfigPanelState) {
|
||||
.fit_to_exact_size(egui::vec2(72.0, 72.0)),
|
||||
);
|
||||
|
||||
ui.add_space(10.0);
|
||||
ui.add_space(METRICS.item_gap);
|
||||
|
||||
ui.vertical(|ui| {
|
||||
ui.label(format!("端口 {}", config.port));
|
||||
ui.label(format!("波特率 {}", config.baud_rate));
|
||||
ui.label(style::value_text(format!("端口 {}", config.port)));
|
||||
ui.label(style::value_text(format!("波特率 {}", config.baud_rate)));
|
||||
let status = if config.connected {
|
||||
"已连接"
|
||||
} else {
|
||||
"未连接"
|
||||
};
|
||||
let status_color = if config.connected {
|
||||
egui::Color32::from_rgb(158, 184, 101)
|
||||
style::status_color_ok()
|
||||
} else {
|
||||
egui::Color32::from_rgb(255, 98, 82)
|
||||
style::status_color_error()
|
||||
};
|
||||
ui.colored_label(status_color, status);
|
||||
});
|
||||
@@ -370,12 +379,11 @@ fn draw_connection_row(ui: &mut egui::Ui, config: &mut ConfigPanelState) {
|
||||
|
||||
let button_text = if config.connected { "断开" } else { "连接" };
|
||||
if ui
|
||||
.add(
|
||||
egui::Button::new(button_text)
|
||||
.fill(ONE_DARK_PRO.accent)
|
||||
.stroke(egui::Stroke::new(1.0, ONE_DARK_PRO.accent_hot))
|
||||
.min_size(egui::vec2(120.0, 30.0)),
|
||||
)
|
||||
.add(if config.connected {
|
||||
style::danger_button(button_text)
|
||||
} else {
|
||||
style::primary_button(button_text)
|
||||
})
|
||||
.clicked()
|
||||
{
|
||||
config.connected = !config.connected;
|
||||
@@ -383,7 +391,11 @@ fn draw_connection_row(ui: &mut egui::Ui, config: &mut ConfigPanelState) {
|
||||
|
||||
ui.add_space(18.0);
|
||||
ui.colored_label(
|
||||
egui::Color32::from_rgb(158, 184, 101),
|
||||
if config.auto_reconnect {
|
||||
style::status_color_ok()
|
||||
} else {
|
||||
ONE_DARK_PRO.text_dim
|
||||
},
|
||||
if config.auto_reconnect {
|
||||
"链路保护 开"
|
||||
} else {
|
||||
@@ -397,39 +409,39 @@ fn draw_serial_grid(ui: &mut egui::Ui, config: &mut ConfigPanelState) {
|
||||
group_frame().show(ui, |ui| {
|
||||
egui::Grid::new("serial_config_grid")
|
||||
.num_columns(4)
|
||||
.spacing(egui::vec2(10.0, 5.0))
|
||||
.spacing(egui::vec2(14.0, 7.0))
|
||||
.striped(true)
|
||||
.show(ui, |ui| {
|
||||
ui.label("端口");
|
||||
ui.label(style::field_label("端口"));
|
||||
ui.add_sized(
|
||||
egui::vec2(110.0, 20.0),
|
||||
egui::vec2(110.0, METRICS.field_height),
|
||||
egui::TextEdit::singleline(&mut config.port),
|
||||
);
|
||||
|
||||
ui.label("波特率");
|
||||
ui.label(style::field_label("波特率"));
|
||||
baud_combo(ui, config);
|
||||
ui.end_row();
|
||||
|
||||
ui.label("数据位");
|
||||
ui.label(style::field_label("数据位"));
|
||||
ui.add_sized(
|
||||
egui::vec2(70.0, 20.0),
|
||||
egui::vec2(70.0, METRICS.field_height),
|
||||
egui::DragValue::new(&mut config.data_bits).range(5..=8),
|
||||
);
|
||||
|
||||
ui.label("校验");
|
||||
ui.label(style::field_label("校验"));
|
||||
parity_combo(ui, config);
|
||||
ui.end_row();
|
||||
|
||||
ui.label("停止位");
|
||||
ui.label(style::field_label("停止位"));
|
||||
ui.add_sized(
|
||||
egui::vec2(70.0, 20.0),
|
||||
egui::vec2(70.0, METRICS.field_height),
|
||||
egui::DragValue::new(&mut config.stop_bits).range(1..=2),
|
||||
);
|
||||
|
||||
ui.label("超时");
|
||||
ui.label(style::field_label("超时"));
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_sized(
|
||||
egui::vec2(84.0, 20.0),
|
||||
egui::vec2(84.0, METRICS.field_height),
|
||||
egui::DragValue::new(&mut config.timeout_ms)
|
||||
.range(50..=30_000)
|
||||
.speed(50),
|
||||
@@ -443,11 +455,11 @@ fn draw_serial_grid(ui: &mut egui::Ui, config: &mut ConfigPanelState) {
|
||||
|
||||
fn draw_mode_body(ui: &mut egui::Ui, config: &mut ConfigPanelState) {
|
||||
group_frame().show(ui, |ui| match config.mode {
|
||||
SerialMode::SingleModule => {
|
||||
SerialMode::Finger => {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("模块地址");
|
||||
ui.label(style::field_label("模块地址"));
|
||||
ui.add_sized(
|
||||
egui::vec2(80.0, 20.0),
|
||||
egui::vec2(80.0, METRICS.field_height),
|
||||
egui::DragValue::new(&mut config.module_addr).range(1..=247),
|
||||
);
|
||||
ui.add_space(16.0);
|
||||
@@ -464,11 +476,11 @@ fn draw_mode_body(ui: &mut egui::Ui, config: &mut ConfigPanelState) {
|
||||
ui.label("0 字节");
|
||||
});
|
||||
}
|
||||
SerialMode::Manual => {
|
||||
SerialMode::Hand => {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("发送");
|
||||
ui.label(style::field_label("发送"));
|
||||
ui.add_sized(
|
||||
egui::vec2(300.0, 20.0),
|
||||
egui::vec2(300.0, METRICS.field_height),
|
||||
egui::TextEdit::singleline(&mut config.manual_tx),
|
||||
);
|
||||
if ui.add(tag_button("发送")).clicked() {}
|
||||
@@ -476,18 +488,17 @@ fn draw_mode_body(ui: &mut egui::Ui, config: &mut ConfigPanelState) {
|
||||
config.manual_tx.clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
SerialMode::Model => {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("模型");
|
||||
ui.add_sized(
|
||||
egui::vec2(300.0, 20.0),
|
||||
egui::TextEdit::singleline(&mut config.model_path),
|
||||
);
|
||||
if ui.add(tag_button("加载")).clicked() {}
|
||||
if ui.add(tag_button("运行")).clicked() {}
|
||||
});
|
||||
}
|
||||
} // SerialMode::Model => {
|
||||
// ui.horizontal(|ui| {
|
||||
// ui.label(style::field_label("模型"));
|
||||
// ui.add_sized(
|
||||
// egui::vec2(300.0, METRICS.field_height),
|
||||
// egui::TextEdit::singleline(&mut config.model_path),
|
||||
// );
|
||||
// if ui.add(tag_button("加载")).clicked() {}
|
||||
// if ui.add(tag_button("运行")).clicked() {}
|
||||
// });
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
@@ -517,35 +528,25 @@ pub fn icon_button_sized<'a>(
|
||||
}
|
||||
.fill(ONE_DARK_PRO.panel_strong)
|
||||
.stroke(egui::Stroke::new(1.0, ONE_DARK_PRO.border))
|
||||
.corner_radius(egui::CornerRadius::same(2))
|
||||
.corner_radius(egui::CornerRadius::same(ONE_DARK_PRO.radius))
|
||||
.min_size(size);
|
||||
|
||||
ui.add(button).on_hover_text(tooltip)
|
||||
}
|
||||
|
||||
fn mode_button(ui: &mut egui::Ui, mode: &mut SerialMode, value: SerialMode, label: &'static str) {
|
||||
let selected = *mode == value;
|
||||
let fill = if selected {
|
||||
ONE_DARK_PRO.accent
|
||||
} else {
|
||||
ONE_DARK_PRO.panel_strong
|
||||
};
|
||||
let stroke = if selected {
|
||||
ONE_DARK_PRO.accent_hot
|
||||
} else {
|
||||
ONE_DARK_PRO.border_soft
|
||||
};
|
||||
fn mode_button(
|
||||
ui: &mut egui::Ui,
|
||||
mode: &mut SerialMode,
|
||||
value: SerialMode,
|
||||
label: &'static str,
|
||||
) -> bool {
|
||||
let clicked = ui.add(style::mode_button(label, *mode == value)).clicked();
|
||||
|
||||
if ui
|
||||
.add(
|
||||
egui::Button::new(egui::RichText::new(label).color(egui::Color32::WHITE))
|
||||
.fill(fill)
|
||||
.stroke(egui::Stroke::new(1.0, stroke))
|
||||
.min_size(egui::vec2(96.0, 24.0)),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
if clicked && *mode != value {
|
||||
*mode = value;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -581,13 +582,13 @@ pub fn draw_stats_panel(ctx: &egui::Context, panel: &mut FloatingPanelState) {
|
||||
draw_floating_panel(ctx, panel, "统计", "stats_panel", |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.colored_label(accent_text(), "0.030");
|
||||
ui.label("81m:51s");
|
||||
ui.label(style::subtle_text("81m:51s"));
|
||||
});
|
||||
ui.separator();
|
||||
group_frame().show(ui, |ui| {
|
||||
ui.label("帧率 / GPU 信息");
|
||||
ui.label("边界 589.0us");
|
||||
ui.label("簇 12.8ms");
|
||||
ui.label(style::field_label("帧率 / GPU 信息"));
|
||||
ui.label(style::value_text("边界 589.0us"));
|
||||
ui.label(style::value_text("簇 12.8ms"));
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -612,12 +613,13 @@ fn draw_floating_panel(
|
||||
.resizable(true)
|
||||
.frame(panel_frame(ctx))
|
||||
.show(ctx, |ui| {
|
||||
ui.spacing_mut().item_spacing = egui::vec2(METRICS.item_gap, 6.0);
|
||||
ui.horizontal(|ui| {
|
||||
if ui.add(tag_button("隐藏")).clicked() {
|
||||
hide_requested = true;
|
||||
}
|
||||
ui.add_space(6.0);
|
||||
ui.colored_label(dim_text(), title);
|
||||
ui.label(style::panel_title(title));
|
||||
});
|
||||
ui.separator();
|
||||
add_contents(ui);
|
||||
@@ -647,23 +649,24 @@ fn draw_floating_panel(
|
||||
}
|
||||
}
|
||||
panel.visible = open && !hide_requested;
|
||||
} else {
|
||||
let response = egui::Area::new(egui::Id::new(format!("{id}_tag")))
|
||||
.current_pos(panel.tag_pos)
|
||||
.movable(true)
|
||||
.order(egui::Order::Foreground)
|
||||
.show(ctx, |ui| {
|
||||
ui.set_min_width(86.0);
|
||||
if ui
|
||||
.add(tag_button(format!("▸ {title}")).min_size(egui::vec2(86.0, 22.0)))
|
||||
.clicked()
|
||||
{
|
||||
panel.visible = true;
|
||||
}
|
||||
});
|
||||
|
||||
panel.tag_pos = response.response.rect.min;
|
||||
}
|
||||
// else {
|
||||
// let response = egui::Area::new(egui::Id::new(format!("{id}_tag")))
|
||||
// .current_pos(panel.tag_pos)
|
||||
// .movable(true)
|
||||
// .order(egui::Order::Foreground)
|
||||
// .show(ctx, |ui| {
|
||||
// ui.set_min_width(86.0);
|
||||
// if ui
|
||||
// .add(tag_button(format!("▸ {title}")).min_size(egui::vec2(86.0, 22.0)))
|
||||
// .clicked()
|
||||
// {
|
||||
// panel.visible = true;
|
||||
// }
|
||||
// });
|
||||
|
||||
// panel.tag_pos = response.response.rect.min;
|
||||
// }
|
||||
}
|
||||
|
||||
fn draw_center_floating_panel(
|
||||
@@ -674,7 +677,7 @@ fn draw_center_floating_panel(
|
||||
collapsed_label: &'static str,
|
||||
add_contents: impl FnOnce(&mut egui::Ui),
|
||||
) {
|
||||
const PANEL_WIDTH: f32 = 430.0;
|
||||
const PANEL_WIDTH: f32 = 520.0;
|
||||
const SLIDE_DISTANCE: f32 = 18.0;
|
||||
|
||||
let anim = advance_center_panel_anim(ctx, panel);
|
||||
@@ -759,14 +762,10 @@ fn center_panel_shell<R>(
|
||||
width: f32,
|
||||
add_contents: impl FnOnce(&mut egui::Ui) -> R,
|
||||
) -> egui::InnerResponse<R> {
|
||||
egui::Frame::new()
|
||||
.fill(ONE_DARK_PRO.panel)
|
||||
.corner_radius(egui::CornerRadius::same(ONE_DARK_PRO.radius))
|
||||
.inner_margin(egui::Margin::symmetric(10, 8))
|
||||
.show(ui, |ui| {
|
||||
ui.set_width(width);
|
||||
add_contents(ui)
|
||||
})
|
||||
style::center_panel_frame().show(ui, |ui| {
|
||||
ui.set_width(width);
|
||||
add_contents(ui)
|
||||
})
|
||||
}
|
||||
|
||||
fn allocate_center_panel_handle(ui: &mut egui::Ui) -> egui::Rect {
|
||||
@@ -1059,10 +1058,10 @@ pub fn draw_recording_toolbar(ui: &mut egui::Ui, recorder: &Recorder, export_pat
|
||||
let rec_btn = if is_recording {
|
||||
tag_button("⏹ 停止")
|
||||
} else {
|
||||
egui::Button::new(egui::RichText::new("● 全量录制").color(egui::Color32::WHITE))
|
||||
.fill(ACCENT_RED)
|
||||
.stroke(egui::Stroke::new(1.0, ONE_DARK_PRO.border))
|
||||
.corner_radius(egui::CornerRadius::same(2))
|
||||
style::accent_button(
|
||||
egui::RichText::new("● 全量录制").color(egui::Color32::WHITE),
|
||||
ACCENT_RED,
|
||||
)
|
||||
};
|
||||
if ui.add(rec_btn).clicked() {
|
||||
if is_recording {
|
||||
@@ -1078,10 +1077,10 @@ pub fn draw_recording_toolbar(ui: &mut egui::Ui, recorder: &Recorder, export_pat
|
||||
let snap_btn = if is_recording {
|
||||
tag_button("⏹ 快照停止")
|
||||
} else {
|
||||
egui::Button::new(egui::RichText::new("✂ 快照录制").color(egui::Color32::WHITE))
|
||||
.fill(ACCENT_ORANGE)
|
||||
.stroke(egui::Stroke::new(1.0, ONE_DARK_PRO.border))
|
||||
.corner_radius(egui::CornerRadius::same(2))
|
||||
style::accent_button(
|
||||
egui::RichText::new("✂ 快照录制").color(egui::Color32::WHITE),
|
||||
ACCENT_ORANGE,
|
||||
)
|
||||
};
|
||||
if ui.add(snap_btn).clicked() {
|
||||
if is_recording {
|
||||
@@ -1104,12 +1103,10 @@ pub fn draw_recording_toolbar(ui: &mut egui::Ui, recorder: &Recorder, export_pat
|
||||
|
||||
// Export
|
||||
if ui
|
||||
.add(
|
||||
egui::Button::new(egui::RichText::new("📤 导出CSV").color(egui::Color32::WHITE))
|
||||
.fill(ACCENT_BLUE)
|
||||
.stroke(egui::Stroke::new(1.0, ONE_DARK_PRO.border))
|
||||
.corner_radius(egui::CornerRadius::same(2)),
|
||||
)
|
||||
.add(style::accent_button(
|
||||
egui::RichText::new("📤 导出CSV").color(egui::Color32::WHITE),
|
||||
ACCENT_BLUE,
|
||||
))
|
||||
.clicked()
|
||||
{
|
||||
let path = if export_path.is_empty() {
|
||||
@@ -1128,12 +1125,10 @@ pub fn draw_recording_toolbar(ui: &mut egui::Ui, recorder: &Recorder, export_pat
|
||||
|
||||
// Import
|
||||
if ui
|
||||
.add(
|
||||
egui::Button::new(egui::RichText::new("📥 导入CSV").color(egui::Color32::WHITE))
|
||||
.fill(ACCENT_GREEN)
|
||||
.stroke(egui::Stroke::new(1.0, ONE_DARK_PRO.border))
|
||||
.corner_radius(egui::CornerRadius::same(2)),
|
||||
)
|
||||
.add(style::accent_button(
|
||||
egui::RichText::new("📥 导入CSV").color(egui::Color32::WHITE),
|
||||
ACCENT_GREEN,
|
||||
))
|
||||
.clicked()
|
||||
{
|
||||
let import_path = export_path.clone();
|
||||
@@ -1147,7 +1142,10 @@ pub fn draw_recording_toolbar(ui: &mut egui::Ui, recorder: &Recorder, export_pat
|
||||
ui.horizontal(|ui| {
|
||||
ui.colored_label(dim_text(), "导出路径");
|
||||
ui.add_sized(
|
||||
egui::vec2(ui.available_width() - 80.0, 20.0),
|
||||
egui::vec2(
|
||||
(ui.available_width() - 80.0).max(160.0),
|
||||
METRICS.field_height,
|
||||
),
|
||||
egui::TextEdit::singleline(export_path).hint_text("eskin_export_*.csv"),
|
||||
);
|
||||
});
|
||||
@@ -1198,25 +1196,24 @@ pub fn draw_matrix_config_panel(
|
||||
ui.set_min_width(280.0);
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
ui.colored_label(dim_text(), "矩阵尺寸");
|
||||
ui.add_space(8.0);
|
||||
ui.colored_label(ONE_DARK_PRO.text, "行");
|
||||
ui.label(style::field_label("矩阵尺寸"));
|
||||
ui.add_space(METRICS.item_gap);
|
||||
ui.label(style::value_text("行"));
|
||||
ui.add_sized(
|
||||
egui::vec2(56.0, 20.0),
|
||||
egui::vec2(56.0, METRICS.field_height),
|
||||
egui::DragValue::new(&mut config.rows).range(1..=128),
|
||||
);
|
||||
ui.colored_label(ONE_DARK_PRO.text, "列");
|
||||
ui.label(style::value_text("列"));
|
||||
ui.add_sized(
|
||||
egui::vec2(56.0, 20.0),
|
||||
egui::vec2(56.0, METRICS.field_height),
|
||||
egui::DragValue::new(&mut config.cols).range(1..=128),
|
||||
);
|
||||
});
|
||||
|
||||
ui.add_space(4.0);
|
||||
ui.add_space(METRICS.item_gap);
|
||||
|
||||
// Presets
|
||||
ui.horizontal(|ui| {
|
||||
ui.colored_label(dim_text(), "预设");
|
||||
ui.label(style::field_label("预设"));
|
||||
for (r, c, name) in &[
|
||||
(12, 7, "12×7"),
|
||||
(24, 12, "24×12"),
|
||||
@@ -1231,31 +1228,40 @@ pub fn draw_matrix_config_panel(
|
||||
}
|
||||
});
|
||||
|
||||
ui.add_space(4.0);
|
||||
ui.add_space(METRICS.item_gap);
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
ui.colored_label(dim_text(), "色域范围");
|
||||
ui.add_space(8.0);
|
||||
ui.colored_label(ONE_DARK_PRO.text, "最小");
|
||||
ui.label(style::field_label("色域范围"));
|
||||
ui.add_space(METRICS.item_gap);
|
||||
ui.label(style::value_text("最小"));
|
||||
ui.add_sized(
|
||||
egui::vec2(72.0, 20.0),
|
||||
egui::vec2(72.0, METRICS.field_height),
|
||||
egui::DragValue::new(&mut config.color_min)
|
||||
.range(0.0..=10000.0)
|
||||
.speed(100.0),
|
||||
);
|
||||
ui.colored_label(ONE_DARK_PRO.text, "最大");
|
||||
ui.label(style::value_text("最大"));
|
||||
ui.add_sized(
|
||||
egui::vec2(72.0, 20.0),
|
||||
egui::vec2(72.0, METRICS.field_height),
|
||||
egui::DragValue::new(&mut config.color_max)
|
||||
.range(1.0..=10000.0)
|
||||
.speed(100.0),
|
||||
);
|
||||
});
|
||||
|
||||
ui.add_space(8.0);
|
||||
ui.add_space(METRICS.row_gap);
|
||||
|
||||
if ui.add(tag_button("重置默认")).clicked() {
|
||||
*config = MatrixConfigState::default();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn panel_restore_item(ui: &mut egui::Ui, title: &'static str, panel: &mut FloatingPanelState) {
|
||||
if panel.visible {
|
||||
ui.add_enabled(false, egui::Button::new(format!("{title} 已显示")));
|
||||
} else if ui.button(format!("显示 {title}")).clicked() {
|
||||
panel.visible = true;
|
||||
ui.close();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user