diff --git a/src/coordinator/mod.rs b/src/coordinator/mod.rs index a4247e0..f359fc7 100644 --- a/src/coordinator/mod.rs +++ b/src/coordinator/mod.rs @@ -72,6 +72,7 @@ impl<'a> CoordState<'a> { to_gui: Sender, rt: Handle, identity_boxes: Arc>>, + tracker_state: Arc>, ) -> Self { let this = CoordState { sck_outbound: None, @@ -91,11 +92,7 @@ impl<'a> CoordState<'a> { pipeline: gstreamer_pipeline::WebcamPipeline::new(), keep_windows_pipe_alive: Arc::new(AtomicBool::new(true)), - tracker_state: Arc::new(Mutex::new(TrackerState { - tracking_id: 0, - last_detect: Instant::now(), - has_active_connection: false, - })) + tracker_state, }; this.rt.spawn(crate::remote_sources::shared_video_pipe::create_outbound_pipe( this.pipeline.sink_frame.clone(), @@ -202,12 +199,13 @@ pub async fn start_coordinator( to_gui: Sender, runtime: Handle, identity_boxes: Arc>>, + tracker_state: Arc>, ) { info!("Starting coordinator!"); let mec = pin!(mec); - let mut state = CoordState::new(mec, to_mec, to_gui, runtime, identity_boxes); + let mut state = CoordState::new(mec, to_mec, to_gui, runtime, identity_boxes, tracker_state); state.pipeline .pipeline diff --git a/src/ui/mod.rs b/src/ui/mod.rs index a438892..d2107e3 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -1,16 +1,19 @@ use std::sync::{Arc, Mutex}; +use std::time::Instant; use gtk::cairo::Context; +use gtk::ffi::gtk_picture_set_keep_aspect_ratio; use gtk::gdk::Paintable; -use gtk::{glib, prelude::*, Box, Entry, Label, ListBox}; +use gtk::{glib, prelude::*, AspectFrame, Box, Entry, Label, ListBox}; use gtk::{Application, ApplicationWindow, Button}; -use log::error; +use log::{info, error}; use serde::{Deserialize, Serialize}; use tokio::runtime::Handle; use tokio_tungstenite::tungstenite::Message; use crate::config::{load_config, save_config}; use crate::coordinator::{start_coordinator, ApplicationEvent, MoveEvent}; +use crate::remote_sources::TrackerState; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct AppState { @@ -70,8 +73,8 @@ pub fn build_ui(app: &Application, runtime: Handle) { let window = ApplicationWindow::builder() .application(app) .title("VCC Camera Controller") - .default_width(840) - .default_height(480) + // .default_width(840) + // .default_height(480) .child(&main_box) .build(); @@ -79,6 +82,12 @@ pub fn build_ui(app: &Application, runtime: Handle) { let (to_mec, mec) = async_channel::unbounded::(); let (to_gui, gui_recv) = async_channel::bounded::(10); let identity_boxes: Arc>> = Arc::new(Mutex::new(vec![])); + let tracker_state = Arc::new(Mutex::new(TrackerState { + tracking_id: 0, + last_detect: Instant::now(), + has_active_connection: false, + })); + runtime.spawn(start_coordinator( mec, @@ -86,6 +95,7 @@ pub fn build_ui(app: &Application, runtime: Handle) { to_gui, runtime.clone(), identity_boxes.clone(), + tracker_state.clone(), )); // let conn_status_label = Label::new(Some(&"No Connection".to_string())); @@ -134,22 +144,30 @@ pub fn build_ui(app: &Application, runtime: Handle) { main_box.append(&left_box); let webcam_picture = gtk::Picture::builder() - .height_request(480) + // .height_request(270) .width_request(640) .can_focus(false) .build(); - let overlay_box = gtk::Overlay::new(); - main_box.append(&overlay_box); + let overlay_box = gtk::Overlay::builder() + .build(); + let aspect = AspectFrame::builder() + .ratio(16.0/9.0) + .obey_child(false) + .child(&overlay_box) + .build(); + main_box.append(&aspect); let drawable = gtk::DrawingArea::builder() - .content_height(480) - .content_width(640) + // .content_height(480) + // .content_width(640) .build(); + drawable.set_draw_func(move |_, ctx, width, height| { - draw_boxes(width, height,&ctx, identity_boxes.clone()); + draw_boxes(width, height, &ctx, identity_boxes.clone(), tracker_state.clone()); }); + overlay_box.set_child(Some(&webcam_picture)); overlay_box.add_overlay(&drawable); @@ -186,8 +204,9 @@ pub fn build_ui(app: &Application, runtime: Handle) { })); glib::spawn_future_local( - glib::clone!(@weak axis_label, @weak button, @weak conn_status_label, @weak ip_entry, @weak port_entry, @strong gui_recv => async move { + glib::clone!(@weak axis_label, @weak button, @weak conn_status_label, @weak ip_entry, @weak port_entry, @strong gui_recv, @weak drawable => async move { while let Ok(d) = gui_recv.recv().await { + drawable.queue_draw(); match d { GuiUpdate::MoveEvent(msg) => { axis_label.set_text( @@ -233,12 +252,25 @@ pub fn build_ui(app: &Application, runtime: Handle) { window.present(); } -fn draw_boxes(width: i32, height: i32, ctx: &Context, boxes: Arc>>) { - ctx.set_line_width(2.0); - ctx.set_source_rgb(0.0, 1.0, 0.0); +fn draw_boxes(width: i32, height: i32, ctx: &Context, boxes: Arc>>, tracker_state: Arc>) { + ctx.set_line_width(5.0); + ctx.select_font_face("Arial", gtk::cairo::FontSlant::Normal, gtk::cairo::FontWeight::Bold); + ctx.set_font_size(24.0); + + let active: u32 = match tracker_state.lock() { + Ok(e) => e.tracking_id, + Err(_) => 0 + }; + if let Ok(bxs) = boxes.lock() { for nb in bxs.iter() { + if nb.id == active { + ctx.set_source_rgb(1.0, 0.0, 0.0); + } else { + ctx.set_source_rgb(0.0, 0.0, 1.0); + } + let b = nb.into_relative(width, height); ctx.rectangle( b.x1 as f64, @@ -251,6 +283,13 @@ fn draw_boxes(width: i32, height: i32, ctx: &Context, boxes: Arc