refactor: 配置面板改造为顶部固定栏 + 压力归一化优化

This commit is contained in:
lenn
2026-07-06 14:07:23 +08:00
parent 5264f0c247
commit c4bccc1747
4 changed files with 194 additions and 44 deletions

149
src/ui.rs
View File

@@ -387,47 +387,134 @@ fn draw_connect_action_row(
pub fn draw_config_panel(
ctx: &egui::Context,
panel: &mut FloatingPanelState,
_panel: &mut FloatingPanelState,
config: &mut ConfigPanelState,
connection: &ConnectionManager,
recorder: &Recorder,
stats: SerialIoStats,
_stats: SerialIoStats,
sample_rate_hz: f32,
render_rate_hz: f32,
) -> Option<SerialMode> {
let mut changed_mode = None;
let changed_mode = None;
let conn_state = connection.state();
let panel_width = responsive_panel_width(ctx, 560.0, 340.0);
config.connected = matches!(
conn_state,
ConnectionState::Connected | ConnectionState::Streaming
);
panel.visible = true;
draw_pinned_panel(ctx, panel, "配置", "config_panel", 560.0, 340.0, |ui| {
ui.set_min_width(panel_width);
ui.set_max_width(panel_width);
let screen = ctx.content_rect();
let bar_rect = egui::Rect::from_min_size(
egui::pos2(screen.left(), screen.top() + layout::TITLE_BAR_HEIGHT),
egui::vec2(screen.width(), layout::CONFIG_BAR_HEIGHT),
);
if let Some(mode) = draw_mode_row(ui, config) {
changed_mode = Some(mode);
}
egui::Area::new(egui::Id::new("config_top_bar"))
.fixed_pos(bar_rect.min)
.order(egui::Order::Foreground)
.show(ctx, |ui| {
ui.set_min_size(bar_rect.size());
ui.painter()
.rect_filled(ui.max_rect(), egui::CornerRadius::ZERO, ONE_DARK_PRO.panel_deep);
ui.painter().line_segment(
[ui.max_rect().left_top(), ui.max_rect().right_top()],
egui::Stroke::new(1.0, ONE_DARK_PRO.border_soft),
);
ui.painter().line_segment(
[ui.max_rect().left_bottom(), ui.max_rect().right_bottom()],
egui::Stroke::new(1.0, ONE_DARK_PRO.border_soft),
);
ui.add_space(5.0);
ui.horizontal(|ui| {
ui.add_space(8.0);
ui.spacing_mut().item_spacing = egui::vec2(8.0, 0.0);
config.mode = SerialMode::Hand;
config.baud_rate = SerialMode::Hand.baud_rate();
ui.colored_label(dim_text(), "配置面板");
ui.add_space(8.0);
ui.colored_label(dim_text(), "模式");
ui.add_sized(
egui::vec2(102.0, 28.0),
style::mode_button("手掌模块", true),
);
ui.add_space(12.0);
ui.label(style::field_label("端口"));
egui::ComboBox::from_id_salt("config_top_bar_ports")
.width(180.0)
.selected_text(if config.port.is_empty() {
"无可用串口".to_owned()
} else {
config.port.clone()
})
.show_ui(ui, |ui| {
for port in &config.available_ports {
ui.selectable_value(&mut config.port, port.clone(), port.as_str());
}
});
if ui
.add(style::icon_button(
egui::RichText::new("").color(ONE_DARK_PRO.text).size(16.0),
METRICS.icon_button,
))
.on_hover_text("刷新串口")
.clicked()
{
refresh_config_ports(config);
}
ui.add_space(10.0);
ui.label(style::value_text(format!("波特率 {}", config.baud_rate)));
ui.add_space(10.0);
ui.colored_label(dim_text(), "状态");
ui.colored_label(
connection_status_color(conn_state),
connection_status_text(conn_state),
);
ui.add_space(8.0);
let is_connected = matches!(
conn_state,
ConnectionState::Connected | ConnectionState::Streaming
);
let button_text = if is_connected { "断开" } else { "连接" };
if ui
.add_sized(
egui::vec2(118.0, 28.0),
if is_connected {
style::danger_button(button_text)
} else {
style::primary_button(button_text)
},
)
.clicked()
{
if is_connected {
connection.disconnect();
} else if !config.port.is_empty() {
connection.connect(
&config.port,
12,
7,
config.mode.baud_rate(),
config.mode.protocol(),
recorder.clone(),
);
}
}
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
ui.label(style::value_text(format!("{render_rate_hz:.1} Hz")));
ui.colored_label(dim_text(), "画面刷新率");
ui.add_space(18.0);
ui.label(style::value_text(format!("{sample_rate_hz:.1} Hz")));
ui.colored_label(dim_text(), "采样率");
});
});
});
// draw_mode_row(ui, config);
ui.separator();
draw_connection_row(ui, config, connection, recorder, conn_state);
ui.add_space(8.0);
// Legacy serial parameter grid is intentionally kept commented for future hardware:
// draw_serial_grid(ui, config);
// ui.add_space(8.0);
draw_mode_body(
ui,
config,
conn_state,
stats,
sample_rate_hz,
render_rate_hz,
);
});
changed_mode
}
@@ -1261,7 +1348,7 @@ fn paint_spatial_force_gauge(
fn draw_pinned_panel(
ctx: &egui::Context,
panel: &mut FloatingPanelState,
_panel: &mut FloatingPanelState,
title: &'static str,
id: &'static str,
preferred_width: f32,
@@ -1270,7 +1357,11 @@ fn draw_pinned_panel(
) {
let panel_width = responsive_panel_width(ctx, preferred_width, min_width);
let max_height = responsive_panel_height(ctx, ctx.content_rect().height(), 180.0);
let pos = responsive_panel_pos(ctx, panel.default_pos, panel_width);
let viewport = viewport_panel_rect(ctx);
let x = (viewport.center().x - panel_width * 0.5)
.clamp(viewport.left(), (viewport.right() - panel_width).max(viewport.left()));
let y = viewport.top() + layout::TITLE_BAR_HEIGHT + PANEL_VIEWPORT_MARGIN;
let pos = egui::pos2(x, y);
egui::Window::new(title)
.id(egui::Id::new(id))