mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2026-08-19 01:14:43 -05:00
feat: show latest plot frame as soon as it is available
This commit is contained in:
@@ -19,11 +19,11 @@ pub struct Plot {
|
||||
title: RefCell<String>,
|
||||
#[property(set)]
|
||||
dirty: Cell<bool>,
|
||||
render_thread: RenderThread,
|
||||
pub(super) render_thread: RenderThread,
|
||||
#[property(get, set)]
|
||||
time_period_seconds: Cell<i64>,
|
||||
pub stats: RefCell<Vec<StatType>>,
|
||||
pub data: RefCell<Arc<RwLock<StatsData>>>,
|
||||
pub(super) stats: RefCell<Vec<StatType>>,
|
||||
pub(super) data: RefCell<Arc<RwLock<StatsData>>>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
|
||||
@@ -30,6 +30,15 @@ impl Plot {
|
||||
pub fn set_stats(&self, stats: Vec<StatType>) {
|
||||
*self.imp().stats.borrow_mut() = stats;
|
||||
}
|
||||
|
||||
pub fn connect_frame_rendered<F: Fn() + 'static>(&self, f: F) {
|
||||
let mut rx = self.imp().render_thread.render_notifier();
|
||||
relm4::spawn_local(async move {
|
||||
while let Ok(()) = rx.recv().await {
|
||||
f();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -9,6 +9,7 @@ use indexmap::IndexSet;
|
||||
use plotters::prelude::*;
|
||||
use plotters::style::text_anchor::Pos;
|
||||
use plotters_cairo::CairoBackend;
|
||||
use relm4::tokio::sync::broadcast;
|
||||
use std::cmp::{self, max};
|
||||
use std::fmt::Write;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
@@ -49,6 +50,7 @@ pub struct RenderThread {
|
||||
/// Shared state is between the main thread and the rendering thread.
|
||||
state: Arc<RenderThreadState>,
|
||||
thread_handle: Option<std::thread::JoinHandle<()>>,
|
||||
render_notifier: broadcast::Sender<()>,
|
||||
}
|
||||
|
||||
/// Ensure the rendering thread is terminated properly when the RenderThread object is dropped.
|
||||
@@ -69,12 +71,14 @@ impl Drop for RenderThread {
|
||||
impl RenderThread {
|
||||
pub fn new() -> Self {
|
||||
let state = Arc::new(RenderThreadState::default());
|
||||
let render_tx = broadcast::Sender::new(1);
|
||||
|
||||
let thread_handle = std::thread::Builder::new()
|
||||
.name("Plot-Renderer".to_owned())
|
||||
// Render thread is very unimportant, skipping frames and rendering slowly is ok
|
||||
.spawn_with_priority(ThreadPriority::Min, {
|
||||
let state = state.clone();
|
||||
let render_tx = render_tx.clone();
|
||||
move |_| loop {
|
||||
let RenderThreadState {
|
||||
request_condition_variable,
|
||||
@@ -97,6 +101,7 @@ impl RenderThread {
|
||||
Some(Request::Terminate) => break,
|
||||
None => {}
|
||||
}
|
||||
let _ = render_tx.send(());
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
@@ -104,9 +109,14 @@ impl RenderThread {
|
||||
Self {
|
||||
state,
|
||||
thread_handle: Some(thread_handle),
|
||||
render_notifier: render_tx,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_notifier(&self) -> broadcast::Receiver<()> {
|
||||
self.render_notifier.subscribe()
|
||||
}
|
||||
|
||||
/// Replace the current render request with a new one (effectively dropping possible pending frame)
|
||||
/// Returns dropped request if any
|
||||
pub fn replace_render_request(&self, request: RenderRequest) -> Option<RenderRequest> {
|
||||
|
||||
@@ -39,6 +39,7 @@ pub struct PlotComponentConfig {
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PlotComponentMsg {
|
||||
Redraw,
|
||||
FrameRendered,
|
||||
UpdatedSelection,
|
||||
}
|
||||
|
||||
@@ -67,6 +68,10 @@ impl relm4::factory::FactoryComponent for PlotComponent {
|
||||
#[watch]
|
||||
set_time_period_seconds: self.time_period.value() as i64,
|
||||
|
||||
connect_frame_rendered[sender] => move || {
|
||||
sender.input(PlotComponentMsg::FrameRendered);
|
||||
},
|
||||
|
||||
#[wrap(Clone::clone)]
|
||||
add_controller = >k::DragSource {
|
||||
#[watch]
|
||||
@@ -190,6 +195,9 @@ impl relm4::factory::FactoryComponent for PlotComponent {
|
||||
widgets.plot.set_dirty(true);
|
||||
widgets.plot.queue_draw();
|
||||
}
|
||||
PlotComponentMsg::FrameRendered => {
|
||||
widgets.plot.queue_draw();
|
||||
}
|
||||
PlotComponentMsg::UpdatedSelection => {
|
||||
widgets.plot.set_stats(self.selected_stats());
|
||||
sender.input(PlotComponentMsg::Redraw);
|
||||
|
||||
Reference in New Issue
Block a user