feat: groom charts dialog (#983)

* groom charts dialog

* move edit buttons to overlay

* remove frame

* use "natural" backgrounds for plots

* remove unused css

* remove background fill in thermals chart

* return background

* move edit chart buttons to top-right corner

* revert vf_curve.rs changes
This commit is contained in:
Roman Makarov
2026-04-24 23:08:58 +03:00
committed by GitHub
parent 3e9add3172
commit 28d67af5c7
2 changed files with 142 additions and 143 deletions
+63 -62
View File
@@ -63,83 +63,84 @@ impl relm4::Component for GraphsWindow {
type CommandOutput = ();
view! {
gtk::Window {
adw::Window {
set_default_height: 700,
set_default_width: 1200,
set_title: Some(&fl!(I18N, "historical-data-title")),
set_hide_on_close: true,
gtk::ScrolledWindow {
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_spacing: 5,
set_margin_all: 10,
append = model.plots.widget() {
set_margin_all: 10,
set_row_spacing: 10,
set_column_spacing: 10,
adw::ToolbarView {
add_top_bar = &adw::HeaderBar {
pack_end = &gtk::Button {
set_label: &fl!(I18N, "export-csv"),
connect_clicked => GraphsWindowMsg::ExportData,
},
append = &gtk::Box {
set_halign: gtk::Align::End,
set_orientation: gtk::Orientation::Horizontal,
set_spacing: 10,
pack_end = &gtk::ToggleButton {
set_label: &fl!(I18N, "edit-graphs"),
bind: &model.edit_mode,
connect_active_notify => GraphsWindowMsg::NotifyEditing,
},
},
append = &gtk::Box {
set_halign: gtk::Align::End,
set_orientation: gtk::Orientation::Horizontal,
set_spacing: 5,
#[watch]
set_visible: model.edit_mode.value(),
add_top_bar = &gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_spacing: 10,
set_margin_horizontal: 10,
set_margin_top: 5,
set_halign: gtk::Align::End,
#[watch]
set_visible: model.edit_mode.value(),
append = &gtk::Label {
set_label: &fl!(I18N, "graphs-per-row"),
},
gtk::Label {
set_label: &fl!(I18N, "graphs-per-row"),
},
append = &gtk::SpinButton {
set_numeric: true,
set_snap_to_ticks: true,
set_range: (1.0, 5.0),
set_increments: (1.0, 1.0),
bind: &model.plots_per_row,
connect_value_notify => GraphsWindowMsg::NotifyPlotsPerRow,
},
gtk::SpinButton {
set_numeric: true,
set_snap_to_ticks: true,
set_range: (1.0, 5.0),
set_increments: (1.0, 1.0),
bind: &model.plots_per_row,
connect_value_notify => GraphsWindowMsg::NotifyPlotsPerRow,
},
append = &gtk::Label {
set_label: &fl!(I18N, "time-period-seconds"),
},
gtk::Label {
set_label: &fl!(I18N, "time-period-seconds"),
},
append = &gtk::SpinButton {
set_adjustment: &model.time_period_seconds_adj,
connect_value_notify => GraphsWindowMsg::NotifyPlotsPerRow,
},
gtk::SpinButton {
set_adjustment: &model.time_period_seconds_adj,
connect_value_notify => GraphsWindowMsg::NotifyPlotsPerRow,
},
append = &gtk::Button {
set_label: &fl!(I18N, "reset-button"),
set_tooltip: &fl!(I18N, "reset-all-graphs-tooltip"),
set_css_classes: &["destructive-action"],
connect_clicked => GraphsWindowMsg::SetConfig(default_plots()),
},
gtk::Button {
set_label: &fl!(I18N, "reset-button"),
set_tooltip: &fl!(I18N, "reset-all-graphs-tooltip"),
add_css_class: "destructive-action",
connect_clicked => GraphsWindowMsg::SetConfig(default_plots()),
},
append = &gtk::Button {
set_icon_name: "list-add-symbolic",
connect_clicked => GraphsWindowMsg::AddPlot,
set_tooltip: &fl!(I18N, "add-graph"),
},
gtk::Button {
set_icon_name: "list-add-symbolic",
connect_clicked => GraphsWindowMsg::AddPlot,
set_tooltip: &fl!(I18N, "add-graph"),
},
},
#[wrap(Some)]
set_content = &gtk::ScrolledWindow {
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_spacing: 5,
append = model.plots.widget() {
set_margin_all: 10,
set_margin_top: 7,
set_row_spacing: 10,
set_column_spacing: 10,
},
append = &gtk::ToggleButton {
set_label: &fl!(I18N, "edit-graphs"),
bind: &model.edit_mode,
connect_active_notify => GraphsWindowMsg::NotifyEditing,
},
append = &gtk::Button {
set_label: &fl!(I18N, "export-csv"),
connect_clicked => GraphsWindowMsg::ExportData,
}
}
},
},
},
}
@@ -17,6 +17,7 @@ use i18n_embed_fl::fl;
use relm4::{
RelmObjectExt, RelmWidgetExt,
binding::{BoolBinding, ConnectBinding, F64Binding},
css,
factory::positions::GridPosition,
prelude::{DynamicIndex, FactoryVecDeque},
};
@@ -57,93 +58,40 @@ impl relm4::factory::FactoryComponent for PlotComponent {
view! {
gtk::Frame {
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_spacing: 5,
gtk::Overlay {
#[name = "plot"]
Plot {
set_data: self.data.clone(),
set_margin_all: 5,
gtk::Overlay {
#[name = "plot"]
Plot {
set_data: self.data.clone(),
set_margin_all: 5,
#[watch]
set_cursor: self.get_cursor().as_ref(),
#[watch]
set_time_period_seconds: self.time_period.value() as i64,
add_binding: (&self.print_extra_info, "print-extra-info"),
#[watch]
set_cursor: self.get_cursor().as_ref(),
#[watch]
set_time_period_seconds: self.time_period.value() as i64,
add_binding: (&self.print_extra_info, "print-extra-info"),
connect_frame_rendered[sender] => move || {
sender.input(PlotComponentMsg::FrameRendered);
},
},
add_overlay = &gtk::ToggleButton {
set_halign: gtk::Align::End,
set_valign: gtk::Align::Start,
set_margin_all: 20,
set_icon_name: "info-outline-symbolic",
set_tooltip: &fl!(I18N, "plot-show-detailed-info"),
set_opacity: 0.8,
bind: &self.print_extra_info,
},
#[wrap(Clone::clone)]
add_controller = &gtk::DragSource {
#[watch]
set_actions: if self.edit_mode.value() { gdk::DragAction::MOVE } else { gdk::DragAction::empty() },
connect_prepare[plot, index, edit_mode = self.edit_mode.clone()] => move |drag_source, _, _| {
if edit_mode.value() {
if let Some(texture) = plot.imp().get_last_texture() {
drag_source.set_icon(Some(&texture), 0, 0);
}
Some(gdk::ContentProvider::for_value(&DynamicIndexValue(index.clone()).to_value()))
} else {
None
}
}
},
add_controller = gtk::DropTarget {
set_actions: gdk::DragAction::MOVE,
set_types: &[DynamicIndexValue::static_type()],
connect_enter[root = root.downgrade()] => move |_, _, _| {
if let Some(root) = root.upgrade() {
root.set_opacity(0.5);
}
gdk::DragAction::MOVE
},
connect_leave[root = root.downgrade()] => move |_| {
if let Some(root) = root.upgrade() {
root.set_opacity(1.0);
}
},
connect_drop[root = root.downgrade(), index, sender] => move |_, value, _, _| {
if let Some(root) = root.upgrade() {
root.set_opacity(1.0);
}
if let Ok(DynamicIndexValue(source_index)) = value.get::<DynamicIndexValue>() {
sender.output(GraphsWindowMsg::SwapPlots(index.clone(), source_index)).unwrap();
}
true
},
connect_frame_rendered[sender] => move || {
sender.input(PlotComponentMsg::FrameRendered);
},
},
gtk::Box {
add_overlay = &gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_spacing: 5,
#[watch]
set_visible: self.edit_mode.value(),
set_align: gtk::Align::End,
set_halign: gtk::Align::End,
set_valign: gtk::Align::Start,
set_margin_all: 20,
set_opacity: 0.9,
append = &gtk::MenuButton {
gtk::ToggleButton {
set_icon_name: "info-outline-symbolic",
set_tooltip: &fl!(I18N, "plot-show-detailed-info"),
bind: &self.print_extra_info,
},
gtk::MenuButton {
#[watch]
set_visible: self.edit_mode.value(),
set_icon_name: "view-list-symbolic",
set_tooltip: &fl!(I18N, "edit-graph-sensors"),
@@ -159,12 +107,15 @@ impl relm4::factory::FactoryComponent for PlotComponent {
set_orientation: gtk::Orientation::Vertical,
set_margin_all: 10,
}
} ,
},
},
},
append = &gtk::Button {
gtk::Button {
#[watch]
set_visible: self.edit_mode.value(),
set_icon_name: "edit-delete-symbolic",
add_css_class: css::DESTRUCTIVE_ACTION,
set_tooltip: &fl!(I18N, "delete-graph"),
connect_clicked[sender, index] => move |_| {
@@ -172,6 +123,53 @@ impl relm4::factory::FactoryComponent for PlotComponent {
}
},
},
#[wrap(Clone::clone)]
add_controller = &gtk::DragSource {
#[watch]
set_actions: if self.edit_mode.value() { gdk::DragAction::MOVE } else { gdk::DragAction::empty() },
connect_prepare[plot, index, edit_mode = self.edit_mode.clone()] => move |drag_source, _, _| {
if edit_mode.value() {
if let Some(texture) = plot.imp().get_last_texture() {
drag_source.set_icon(Some(&texture), 0, 0);
}
Some(gdk::ContentProvider::for_value(&DynamicIndexValue(index.clone()).to_value()))
} else {
None
}
}
},
add_controller = gtk::DropTarget {
set_actions: gdk::DragAction::MOVE,
set_types: &[DynamicIndexValue::static_type()],
connect_enter[root = root.downgrade()] => move |_, _, _| {
if let Some(root) = root.upgrade() {
root.set_opacity(0.5);
}
gdk::DragAction::MOVE
},
connect_leave[root = root.downgrade()] => move |_| {
if let Some(root) = root.upgrade() {
root.set_opacity(1.0);
}
},
connect_drop[root = root.downgrade(), index, sender] => move |_, value, _, _| {
if let Some(root) = root.upgrade() {
root.set_opacity(1.0);
}
if let Ok(DynamicIndexValue(source_index)) = value.get::<DynamicIndexValue>() {
sender.output(GraphsWindowMsg::SwapPlots(index.clone(), source_index)).unwrap();
}
true
},
},
},
},
}