mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2026-08-19 01:14:43 -05:00
feat: point hover effect in fan curve (#947)
This commit is contained in:
@@ -20,7 +20,11 @@ use plotters::{
|
||||
chart::ChartBuilder,
|
||||
prelude::{Circle, EmptyElement, IntoDrawingArea, Text},
|
||||
series::{LineSeries, PointSeries},
|
||||
style::{Color, ShapeStyle, TextStyle, full_palette::LIGHTBLUE, text_anchor::Pos},
|
||||
style::{
|
||||
Color, ShapeStyle, TextStyle,
|
||||
full_palette::{INDIGO, LIGHTBLUE},
|
||||
text_anchor::Pos,
|
||||
},
|
||||
};
|
||||
use plotters_cairo::CairoBackend;
|
||||
use relm4::{
|
||||
@@ -41,6 +45,9 @@ const DEFAULT_CHANGE_THRESHOLD: u64 = 2;
|
||||
const DEFAULT_AUTO_THRESHOLD: u64 = 0;
|
||||
const DEFAULT_SPINDOWN_DELAY_MS: u64 = 5000;
|
||||
|
||||
const TEMPERATURE_DRAG_MARGIN: f32 = 4.0;
|
||||
const PERCENTAGE_DRAG_MARGIN: f32 = 0.04;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(super) struct FanCurveFrame {
|
||||
pmfw_options: PmfwOptions,
|
||||
@@ -61,6 +68,11 @@ pub(super) struct FanCurveFrame {
|
||||
drag_point: Rc<Cell<Option<usize>>>,
|
||||
/// Where the point was last moved to
|
||||
drag_coord: Rc<Cell<Option<(f64, f64)>>>,
|
||||
|
||||
/// Index of the point currently being hovered on
|
||||
hover_point: Rc<Cell<Option<usize>>>,
|
||||
/// Where the point was last hovered on
|
||||
hover_coord: Rc<Cell<Option<(f64, f64)>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -349,6 +361,8 @@ impl relm4::Component for FanCurveFrame {
|
||||
data: Rc::default(),
|
||||
drag_coord: Rc::default(),
|
||||
drag_point: Rc::default(),
|
||||
hover_coord: Rc::default(),
|
||||
hover_point: Rc::default(),
|
||||
};
|
||||
|
||||
let label_size_group = gtk::SizeGroup::new(gtk::SizeGroupMode::Horizontal);
|
||||
@@ -431,9 +445,13 @@ impl relm4::Component for FanCurveFrame {
|
||||
self.is_dragging.store(true, Ordering::SeqCst);
|
||||
}
|
||||
FanCurveFrameMsg::DragUpdate(x, y) => {
|
||||
self.hover_coord.set(Some((x, y)));
|
||||
|
||||
if self.is_dragging.load(Ordering::SeqCst) {
|
||||
self.drag_coord.set(Some((x, y)));
|
||||
}
|
||||
|
||||
widgets.drawing_area.queue_draw();
|
||||
}
|
||||
FanCurveFrameMsg::DragEnd => {
|
||||
self.drag_coord.take();
|
||||
@@ -526,36 +544,46 @@ impl FanCurveFrame {
|
||||
fn draw_chart(&self, ctx: &cairo::Context, width: i32, height: i32, colors: PlotColorScheme) {
|
||||
let cairo_backend = CairoBackend::new(ctx, (width as u32, height as u32)).unwrap();
|
||||
|
||||
let drag_coord = self.drag_coord.take();
|
||||
let translate_coords = [self.drag_coord.take(), self.hover_coord.take()];
|
||||
|
||||
let new_value = draw_chart(
|
||||
let translated_coords = draw_chart(
|
||||
cairo_backend,
|
||||
&self.data.borrow(),
|
||||
drag_coord,
|
||||
translate_coords,
|
||||
self.hover_point.get(),
|
||||
colors,
|
||||
&self.temperature_range.borrow(),
|
||||
&self.speed_range.borrow(),
|
||||
);
|
||||
if let Some(mut new_value) = new_value {
|
||||
|
||||
if let Some(mut moved_value) = translated_coords[0] {
|
||||
let drag_point_idx = match self.drag_point.get() {
|
||||
Some(idx) => Some(idx),
|
||||
None => {
|
||||
let point = self.data.borrow().iter().position(|(data_x, data_y)| {
|
||||
(*data_x as f32 - new_value.0).abs() <= 3.0
|
||||
&& (*data_y - new_value.1).abs() <= 0.03
|
||||
(*data_x as f32 - moved_value.0).abs() <= TEMPERATURE_DRAG_MARGIN
|
||||
&& (*data_y - moved_value.1).abs() <= PERCENTAGE_DRAG_MARGIN
|
||||
});
|
||||
self.drag_point.set(point);
|
||||
point
|
||||
}
|
||||
};
|
||||
if let Some(idx) = drag_point_idx {
|
||||
normalize_to_range(&mut new_value.0, &self.temperature_range.borrow());
|
||||
normalize_to_range(&mut new_value.1, &self.speed_range.borrow());
|
||||
self.data.borrow_mut()[idx] = (new_value.0 as i32, new_value.1);
|
||||
normalize_to_range(&mut moved_value.0, &self.temperature_range.borrow());
|
||||
normalize_to_range(&mut moved_value.1, &self.speed_range.borrow());
|
||||
self.data.borrow_mut()[idx] = (moved_value.0 as i32, moved_value.1);
|
||||
|
||||
APP_BROKER.send(AppMsg::SettingsChanged);
|
||||
}
|
||||
}
|
||||
|
||||
let hovered_point = translated_coords[1].and_then(|(x, y)| {
|
||||
self.data.borrow().iter().position(|(data_x, data_y)| {
|
||||
(*data_x as f32 - x).abs() <= TEMPERATURE_DRAG_MARGIN
|
||||
&& (*data_y - y).abs() <= PERCENTAGE_DRAG_MARGIN
|
||||
})
|
||||
});
|
||||
self.hover_point.set(hovered_point);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -578,14 +606,15 @@ fn normalize_to_range(value: &mut f32, range: &RangeInclusive<f32>) {
|
||||
*value = (*value * 100.0).round() / 100.0;
|
||||
}
|
||||
|
||||
fn draw_chart(
|
||||
fn draw_chart<const I: usize>(
|
||||
backend: CairoBackend,
|
||||
data: &[(i32, f32)],
|
||||
translate_coord: Option<(f64, f64)>,
|
||||
translate_coords: [Option<(f64, f64)>; I],
|
||||
hovered_point: Option<usize>,
|
||||
colors: PlotColorScheme,
|
||||
temp_range: &RangeInclusive<f32>,
|
||||
speed_range: &RangeInclusive<f32>,
|
||||
) -> Option<(f32, f32)> {
|
||||
) -> [Option<(f32, f32)>; I] {
|
||||
let root = backend.into_drawing_area();
|
||||
root.fill(&colors.background).unwrap();
|
||||
|
||||
@@ -626,10 +655,14 @@ fn draw_chart(
|
||||
|
||||
chart
|
||||
.draw_series(PointSeries::of_element(
|
||||
data.iter().map(|(x, y)| (*x as f32, *y)),
|
||||
data.iter().map(|(x, y)| (*x as f32, *y)).enumerate(),
|
||||
8,
|
||||
ShapeStyle::from(&LIGHTBLUE).filled(),
|
||||
&|coord, size, style| {
|
||||
&|(i, coord), size, mut style| {
|
||||
if hovered_point == Some(i) {
|
||||
style.color = INDIGO.to_rgba();
|
||||
}
|
||||
|
||||
EmptyElement::at(coord)
|
||||
+ Circle::new((0, 0), size, style)
|
||||
+ Text::new(
|
||||
@@ -658,8 +691,8 @@ fn draw_chart(
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
let mapped_coord = translate_coord
|
||||
.map(|(x, y)| {
|
||||
let mapped_coords = translate_coords.map(|coords| {
|
||||
coords.map(|(x, y)| {
|
||||
let coord_spec = chart.as_coord_spec();
|
||||
let x_range = coord_spec.get_x_axis_pixel_range();
|
||||
let y_range = coord_spec.get_y_axis_pixel_range();
|
||||
@@ -669,9 +702,13 @@ fn draw_chart(
|
||||
(y as i32).clamp(y_range.start, y_range.end),
|
||||
)
|
||||
})
|
||||
.and_then(|(x, y)| chart.into_coord_trans()((x, y)));
|
||||
});
|
||||
|
||||
let coord_trans = chart.into_coord_trans();
|
||||
|
||||
let mapped_coords = mapped_coords.map(|coord| coord.and_then(|(x, y)| coord_trans((x, y))));
|
||||
|
||||
root.present().unwrap();
|
||||
|
||||
mapped_coord
|
||||
mapped_coords
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user