mxl_player_components/ui/player/
model.rs1use crate::player::{MaxLateness, Player, PlayerBuilder};
2use crate::ui::player::messages::PlaybackState;
3use log::*;
4use mxl_relm4_components::relm4::{gtk, gtk::prelude::*};
5use std::{rc::Rc, sync::Mutex};
6
7type DrawCallbackFn = dyn Fn(>k::cairo::Context, &mut VideoViewData);
8
9pub struct PlayerComponentInit {
10 pub seek_accurate: bool,
11 pub show_seeking_overlay: bool,
12 pub compositor: Option<gst::Element>,
13 pub qos: bool,
14 pub max_lateness: MaxLateness,
15 pub draw_callback: Option<Box<DrawCallbackFn>>,
16 pub drag_gesture: Option<gtk::GestureDrag>,
17 pub motion_tracker: Option<gtk::EventControllerMotion>,
18}
19
20impl Default for PlayerComponentInit {
21 fn default() -> Self {
22 Self {
23 seek_accurate: true,
24 show_seeking_overlay: false,
25 compositor: None,
26 qos: false,
27 max_lateness: Default::default(),
28 draw_callback: None,
29 drag_gesture: None,
30 motion_tracker: None,
31 }
32 }
33}
34
35#[derive(Debug, Default)]
36pub struct VideoViewData {
37 pub drawing_area: Option<gst_video::VideoRectangle>,
38 pub view_rect: Option<gst_video::VideoRectangle>,
39 pub video_dimensions: Option<gst_video::VideoRectangle>,
40 pub scaled_paintable_rect: Option<gst_video::VideoRectangle>,
41 pub fitted_paintable_rect: Option<gst_video::VideoRectangle>,
42 pub zoom_factor: f64,
43 pub(super) cursor_widgets: Vec<gtk::Widget>,
44 cursor_name: Option<String>,
45}
46
47#[derive(Debug, Default)]
48pub(super) struct ViewData {
49 pub(super) video_view: VideoViewData,
50}
51
52pub struct PlayerComponentModel {
53 pub(super) player_builder: PlayerBuilder,
54 pub(super) player: Option<Player>,
55 pub(super) playback_state: PlaybackState,
56 pub(super) show_seeking_overlay: bool,
57 pub(super) seeking: bool,
58 pub(super) show_drawing_overlay: bool,
59 pub(super) view_data: Rc<Mutex<ViewData>>,
60 pub(super) drag_position: Option<(f64, f64)>,
61 pub(super) mouse_position: Option<(f64, f64)>,
62}
63
64impl VideoViewData {
65 pub(super) fn set_cursor_widgets(&mut self, video_view: Vec<gtk::Widget>) {
66 self.cursor_widgets = video_view;
67 }
68
69 pub(super) fn set_cursor(&mut self, cursor_name: Option<&str>) {
70 debug!("Video view set cursor: {cursor_name:?}");
71 self.cursor_widgets.iter().for_each(|w| {
72 w.set_cursor_from_name(cursor_name);
73 });
74 self.cursor_name = cursor_name.map(str::to_string);
75 }
76
77 pub fn set_custom_cursor_from_name(&mut self, cursor_name: Option<&str>) {
78 if cursor_name.is_some() {
79 debug!("Video view set custom cursor: {cursor_name:?}");
80 self.cursor_widgets.iter().for_each(|w| {
81 w.set_cursor_from_name(cursor_name);
82 });
83 } else {
84 debug!("Video view reset current cursor: {:?}", self.cursor_name);
85 self.cursor_widgets.iter().for_each(|w| {
86 w.set_cursor_from_name(self.cursor_name.as_deref());
87 });
88 }
89 }
90
91 pub(super) fn update(
92 &mut self,
93 new_zoom_factor: Option<f64>,
94 video_scrolled_window: >k::ScrolledWindow,
95 video_picture: >k::Picture,
96 ) {
97 if let Some(new_zoom_factor) = new_zoom_factor {
98 self.zoom_factor = new_zoom_factor;
99 }
100
101 let p_width = video_picture.paintable().unwrap().intrinsic_width();
103 let p_height = video_picture.paintable().unwrap().intrinsic_height();
104
105 let paintable_rect = gst_video::VideoRectangle::new(
107 0,
108 0,
109 (p_width as f64 * self.zoom_factor) as i32,
110 (p_height as f64 * self.zoom_factor) as i32,
111 );
112 self.scaled_paintable_rect = Some(paintable_rect.clone());
113
114 let view_rect =
115 gst_video::VideoRectangle::new(0, 0, video_scrolled_window.width(), video_scrolled_window.height());
116
117 self.view_rect = Some(view_rect.clone());
118
119 if self.zoom_factor == 1.0 {
120 self.fitted_paintable_rect = Some(gst_video::center_video_rectangle(&paintable_rect, &view_rect, true));
121 } else {
122 trace!("paintable orig: p_width={p_width} p_height={p_height}");
123
124 let new_view_w = (view_rect.w as f64 * self.zoom_factor) as i32;
125 let new_view_h = (view_rect.h as f64 * self.zoom_factor) as i32;
126 let new_view_rect = gst_video::VideoRectangle::new(0, 0, new_view_w, new_view_h);
127
128 trace!("Zoomed view size: {new_view_rect:?}");
129
130 let unscaled_fitted_paintable_rect = gst_video::center_video_rectangle(&paintable_rect, &view_rect, true);
131
132 let new_paintable_w = (unscaled_fitted_paintable_rect.w as f64 * self.zoom_factor) as i32;
133 let new_paintable_h = (unscaled_fitted_paintable_rect.h as f64 * self.zoom_factor) as i32;
134 let fitted_paintable_rect = gst_video::VideoRectangle::new(0, 0, new_paintable_w, new_paintable_h);
135
136 let fitted_paintable_rect = gst_video::center_video_rectangle(&fitted_paintable_rect, &new_view_rect, true);
137
138 let fitted_paintable_rect = gst_video::VideoRectangle::new(
139 ((view_rect.w - fitted_paintable_rect.w) / 2).clamp(0, i32::MAX),
140 ((view_rect.h - fitted_paintable_rect.h) / 2).clamp(0, i32::MAX),
141 fitted_paintable_rect.w,
142 fitted_paintable_rect.h,
143 );
144
145 self.fitted_paintable_rect = Some(fitted_paintable_rect.clone());
146 }
147 }
148}