Skip to main content

gstreamer_video/
video_event.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2use std::mem;
3
4use glib::{prelude::*, translate::*};
5use gst::EventType;
6
7#[cfg(feature = "v1_22")]
8#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
9use crate::NavigationModifierType;
10use crate::{NavigationCommand, NavigationEventType, ffi};
11
12// FIXME: Copy from gstreamer/src/event.rs
13macro_rules! event_builder_generic_impl {
14    ($new_fn:expr) => {
15        pub fn seqnum(self, seqnum: gst::Seqnum) -> Self {
16            Self {
17                seqnum: Some(seqnum),
18                ..self
19            }
20        }
21
22        pub fn seqnum_if(self, seqnum: gst::Seqnum, predicate: bool) -> Self {
23            if predicate { self.seqnum(seqnum) } else { self }
24        }
25
26        pub fn seqnum_if_some(self, seqnum: Option<gst::Seqnum>) -> Self {
27            if let Some(seqnum) = seqnum {
28                self.seqnum(seqnum)
29            } else {
30                self
31            }
32        }
33
34        pub fn running_time_offset(self, running_time_offset: i64) -> Self {
35            Self {
36                running_time_offset: Some(running_time_offset),
37                ..self
38            }
39        }
40
41        pub fn running_time_offset_if(self, running_time_offset: i64, predicate: bool) -> Self {
42            if predicate {
43                self.running_time_offset(running_time_offset)
44            } else {
45                self
46            }
47        }
48
49        pub fn running_time_offset_if_some(self, running_time_offset: Option<i64>) -> Self {
50            if let Some(running_time_offset) = running_time_offset {
51                self.running_time_offset(running_time_offset)
52            } else {
53                self
54            }
55        }
56
57        pub fn other_field(self, name: &'a str, value: impl ToSendValue) -> Self {
58            let mut other_fields = self.other_fields;
59            other_fields.push((name, value.to_send_value()));
60
61            Self {
62                other_fields,
63                ..self
64            }
65        }
66
67        gst::impl_builder_gvalue_extra_setters!(other_field);
68
69        #[must_use = "Building the event without using it has no effect"]
70        #[allow(clippy::redundant_closure_call)]
71        pub fn build(mut self) -> gst::Event {
72            skip_assert_initialized!();
73            unsafe {
74                let event = $new_fn(&mut self);
75                if let Some(seqnum) = self.seqnum {
76                    gst::ffi::gst_event_set_seqnum(event, seqnum.into_glib());
77                }
78
79                if let Some(running_time_offset) = self.running_time_offset {
80                    gst::ffi::gst_event_set_running_time_offset(event, running_time_offset);
81                }
82
83                {
84                    let s = gst::StructureRef::from_glib_borrow_mut(
85                        gst::ffi::gst_event_writable_structure(event),
86                    );
87
88                    for (k, v) in self.other_fields {
89                        s.set_value(k, v);
90                    }
91                }
92
93                from_glib_full(event)
94            }
95        }
96    };
97}
98
99#[must_use = "The builder must be built to be used"]
100pub struct DownstreamForceKeyUnitEventBuilder<'a> {
101    seqnum: Option<gst::Seqnum>,
102    running_time_offset: Option<i64>,
103    other_fields: Vec<(&'a str, glib::SendValue)>,
104    timestamp: Option<gst::ClockTime>,
105    stream_time: Option<gst::ClockTime>,
106    running_time: Option<gst::ClockTime>,
107    all_headers: bool,
108    count: u32,
109}
110
111impl<'a> DownstreamForceKeyUnitEventBuilder<'a> {
112    fn new() -> Self {
113        skip_assert_initialized!();
114        Self {
115            seqnum: None,
116            running_time_offset: None,
117            other_fields: Vec::new(),
118            timestamp: gst::ClockTime::NONE,
119            stream_time: gst::ClockTime::NONE,
120            running_time: gst::ClockTime::NONE,
121            all_headers: true,
122            count: 0,
123        }
124    }
125
126    pub fn timestamp(self, timestamp: impl Into<Option<gst::ClockTime>>) -> Self {
127        Self {
128            timestamp: timestamp.into(),
129            ..self
130        }
131    }
132
133    pub fn timestamp_if(self, timestamp: gst::ClockTime, predicate: bool) -> Self {
134        if predicate {
135            self.timestamp(timestamp)
136        } else {
137            self
138        }
139    }
140
141    pub fn timestamp_if_some(self, timestamp: Option<gst::ClockTime>) -> Self {
142        if let Some(timestamp) = timestamp {
143            self.timestamp(timestamp)
144        } else {
145            self
146        }
147    }
148
149    pub fn stream_time(self, stream_time: impl Into<Option<gst::ClockTime>>) -> Self {
150        Self {
151            stream_time: stream_time.into(),
152            ..self
153        }
154    }
155
156    pub fn stream_time_if(self, stream_time: gst::ClockTime, predicate: bool) -> Self {
157        if predicate {
158            self.stream_time(stream_time)
159        } else {
160            self
161        }
162    }
163
164    pub fn stream_time_if_some(self, stream_time: Option<gst::ClockTime>) -> Self {
165        if let Some(stream_time) = stream_time {
166            self.stream_time(stream_time)
167        } else {
168            self
169        }
170    }
171
172    pub fn running_time(self, running_time: impl Into<Option<gst::ClockTime>>) -> Self {
173        Self {
174            running_time: running_time.into(),
175            ..self
176        }
177    }
178
179    pub fn running_time_if(self, running_time: gst::ClockTime, predicate: bool) -> Self {
180        if predicate {
181            self.running_time(running_time)
182        } else {
183            self
184        }
185    }
186
187    pub fn running_time_if_some(self, running_time: Option<gst::ClockTime>) -> Self {
188        if let Some(running_time) = running_time {
189            self.running_time(running_time)
190        } else {
191            self
192        }
193    }
194
195    pub fn all_headers(self, all_headers: bool) -> Self {
196        Self {
197            all_headers,
198            ..self
199        }
200    }
201
202    pub fn all_headers_if_some(self, all_headers: Option<bool>) -> Self {
203        if let Some(all_headers) = all_headers {
204            self.all_headers(all_headers)
205        } else {
206            self
207        }
208    }
209
210    pub fn count(self, count: u32) -> Self {
211        Self { count, ..self }
212    }
213
214    pub fn count_if(self, count: u32, predicate: bool) -> Self {
215        if predicate { self.count(count) } else { self }
216    }
217
218    pub fn count_if_some(self, count: Option<u32>) -> Self {
219        if let Some(count) = count {
220            self.count(count)
221        } else {
222            self
223        }
224    }
225
226    event_builder_generic_impl!(|s: &mut Self| {
227        ffi::gst_video_event_new_downstream_force_key_unit(
228            s.timestamp.into_glib(),
229            s.stream_time.into_glib(),
230            s.running_time.into_glib(),
231            s.all_headers.into_glib(),
232            s.count,
233        )
234    });
235}
236
237#[derive(Clone, PartialEq, Eq, Debug)]
238pub struct DownstreamForceKeyUnitEvent {
239    pub timestamp: Option<gst::ClockTime>,
240    pub stream_time: Option<gst::ClockTime>,
241    pub running_time: Option<gst::ClockTime>,
242    pub all_headers: bool,
243    pub count: u32,
244}
245
246impl DownstreamForceKeyUnitEvent {
247    pub fn builder<'a>() -> DownstreamForceKeyUnitEventBuilder<'a> {
248        assert_initialized_main_thread!();
249        DownstreamForceKeyUnitEventBuilder::new()
250    }
251
252    #[doc(alias = "gst_video_event_parse_downstream_force_key_unit")]
253    pub fn parse(event: &gst::EventRef) -> Result<Self, glib::error::BoolError> {
254        skip_assert_initialized!();
255        unsafe {
256            let mut timestamp = mem::MaybeUninit::uninit();
257            let mut stream_time = mem::MaybeUninit::uninit();
258            let mut running_time = mem::MaybeUninit::uninit();
259            let mut all_headers = mem::MaybeUninit::uninit();
260            let mut count = mem::MaybeUninit::uninit();
261
262            let res: bool = from_glib(ffi::gst_video_event_parse_downstream_force_key_unit(
263                event.as_mut_ptr(),
264                timestamp.as_mut_ptr(),
265                stream_time.as_mut_ptr(),
266                running_time.as_mut_ptr(),
267                all_headers.as_mut_ptr(),
268                count.as_mut_ptr(),
269            ));
270            if res {
271                Ok(Self {
272                    timestamp: from_glib(timestamp.assume_init()),
273                    stream_time: from_glib(stream_time.assume_init()),
274                    running_time: from_glib(running_time.assume_init()),
275                    all_headers: from_glib(all_headers.assume_init()),
276                    count: count.assume_init(),
277                })
278            } else {
279                Err(glib::bool_error!("Failed to parse GstEvent"))
280            }
281        }
282    }
283}
284
285#[must_use = "The builder must be built to be used"]
286pub struct UpstreamForceKeyUnitEventBuilder<'a> {
287    seqnum: Option<gst::Seqnum>,
288    running_time_offset: Option<i64>,
289    other_fields: Vec<(&'a str, glib::SendValue)>,
290    running_time: Option<gst::ClockTime>,
291    all_headers: bool,
292    count: u32,
293}
294
295impl<'a> UpstreamForceKeyUnitEventBuilder<'a> {
296    fn new() -> Self {
297        skip_assert_initialized!();
298        Self {
299            seqnum: None,
300            running_time_offset: None,
301            other_fields: Vec::new(),
302            running_time: gst::ClockTime::NONE,
303            all_headers: true,
304            count: 0,
305        }
306    }
307
308    pub fn running_time(self, running_time: impl Into<Option<gst::ClockTime>>) -> Self {
309        Self {
310            running_time: running_time.into(),
311            ..self
312        }
313    }
314
315    pub fn running_time_if(self, running_time: gst::ClockTime, predicate: bool) -> Self {
316        if predicate {
317            self.running_time(running_time)
318        } else {
319            self
320        }
321    }
322
323    pub fn running_time_if_some(self, running_time: Option<gst::ClockTime>) -> Self {
324        if let Some(running_time) = running_time {
325            self.running_time(running_time)
326        } else {
327            self
328        }
329    }
330
331    pub fn all_headers(self, all_headers: bool) -> Self {
332        Self {
333            all_headers,
334            ..self
335        }
336    }
337
338    pub fn all_headers_if_some(self, all_headers: Option<bool>) -> Self {
339        if let Some(all_headers) = all_headers {
340            self.all_headers(all_headers)
341        } else {
342            self
343        }
344    }
345
346    pub fn count(self, count: u32) -> Self {
347        Self { count, ..self }
348    }
349
350    pub fn count_if(self, count: u32, predicate: bool) -> Self {
351        if predicate { self.count(count) } else { self }
352    }
353
354    pub fn count_if_some(self, count: Option<u32>) -> Self {
355        if let Some(count) = count {
356            self.count(count)
357        } else {
358            self
359        }
360    }
361
362    event_builder_generic_impl!(|s: &mut Self| {
363        ffi::gst_video_event_new_upstream_force_key_unit(
364            s.running_time.into_glib(),
365            s.all_headers.into_glib(),
366            s.count,
367        )
368    });
369}
370
371#[derive(Clone, PartialEq, Eq, Debug)]
372pub struct UpstreamForceKeyUnitEvent {
373    pub running_time: Option<gst::ClockTime>,
374    pub all_headers: bool,
375    pub count: u32,
376}
377
378impl UpstreamForceKeyUnitEvent {
379    pub fn builder<'a>() -> UpstreamForceKeyUnitEventBuilder<'a> {
380        assert_initialized_main_thread!();
381        UpstreamForceKeyUnitEventBuilder::new()
382    }
383
384    #[doc(alias = "gst_video_event_parse_upstream_force_key_unit")]
385    pub fn parse(event: &gst::EventRef) -> Result<Self, glib::error::BoolError> {
386        skip_assert_initialized!();
387        unsafe {
388            let mut running_time = mem::MaybeUninit::uninit();
389            let mut all_headers = mem::MaybeUninit::uninit();
390            let mut count = mem::MaybeUninit::uninit();
391
392            let res: bool = from_glib(ffi::gst_video_event_parse_upstream_force_key_unit(
393                event.as_mut_ptr(),
394                running_time.as_mut_ptr(),
395                all_headers.as_mut_ptr(),
396                count.as_mut_ptr(),
397            ));
398            if res {
399                Ok(Self {
400                    running_time: from_glib(running_time.assume_init()),
401                    all_headers: from_glib(all_headers.assume_init()),
402                    count: count.assume_init(),
403                })
404            } else {
405                Err(glib::bool_error!("Failed to parse GstEvent"))
406            }
407        }
408    }
409}
410
411#[derive(Clone, PartialEq, Eq, Debug)]
412pub enum ForceKeyUnitEvent {
413    Downstream(DownstreamForceKeyUnitEvent),
414    Upstream(UpstreamForceKeyUnitEvent),
415}
416
417impl ForceKeyUnitEvent {
418    #[doc(alias = "gst_video_event_is_force_key_unit")]
419    pub fn is(event: &gst::EventRef) -> bool {
420        skip_assert_initialized!();
421        unsafe { from_glib(ffi::gst_video_event_is_force_key_unit(event.as_mut_ptr())) }
422    }
423
424    pub fn parse(event: &gst::EventRef) -> Result<Self, glib::error::BoolError> {
425        skip_assert_initialized!();
426        if event.is_upstream() {
427            UpstreamForceKeyUnitEvent::parse(event).map(Self::Upstream)
428        } else {
429            DownstreamForceKeyUnitEvent::parse(event).map(Self::Downstream)
430        }
431    }
432}
433
434#[must_use = "The builder must be built to be used"]
435pub struct StillFrameEventBuilder<'a> {
436    seqnum: Option<gst::Seqnum>,
437    running_time_offset: Option<i64>,
438    other_fields: Vec<(&'a str, glib::SendValue)>,
439    in_still: bool,
440}
441
442impl<'a> StillFrameEventBuilder<'a> {
443    fn new(in_still: bool) -> Self {
444        skip_assert_initialized!();
445        Self {
446            seqnum: None,
447            running_time_offset: None,
448            other_fields: Vec::new(),
449            in_still,
450        }
451    }
452
453    event_builder_generic_impl!(|s: &mut Self| ffi::gst_video_event_new_still_frame(
454        s.in_still.into_glib()
455    ));
456}
457
458#[derive(Clone, PartialEq, Eq, Debug)]
459pub struct StillFrameEvent {
460    pub in_still: bool,
461}
462
463impl StillFrameEvent {
464    pub fn builder<'a>(in_still: bool) -> StillFrameEventBuilder<'a> {
465        assert_initialized_main_thread!();
466        StillFrameEventBuilder::new(in_still)
467    }
468
469    #[doc(alias = "gst_video_event_parse_still_frame")]
470    pub fn parse(event: &gst::EventRef) -> Result<Self, glib::error::BoolError> {
471        skip_assert_initialized!();
472        unsafe {
473            let mut in_still = mem::MaybeUninit::uninit();
474
475            let res: bool = from_glib(ffi::gst_video_event_parse_still_frame(
476                event.as_mut_ptr(),
477                in_still.as_mut_ptr(),
478            ));
479            if res {
480                Ok(Self {
481                    in_still: from_glib(in_still.assume_init()),
482                })
483            } else {
484                Err(glib::bool_error!("Invalid still-frame event"))
485            }
486        }
487    }
488}
489
490macro_rules! nav_event_builder {
491    ($builder:ident, $($event_field:ident: $event_type:ty,)? [$( $field_names:ident : $field_types:ty),*], $new_fn:expr) => {
492        #[must_use = "The builder must be built to be used"]
493        pub struct $builder<'a> {
494            seqnum: Option<gst::Seqnum>,
495            running_time_offset: Option<i64>,
496            other_fields: Vec<(&'a str, glib::SendValue)>,
497            $($field_names: $field_types,)*
498            #[cfg(feature = "v1_22")]
499            #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
500            modifier_state: NavigationModifierType,
501            $($event_field: $event_type,)?
502        }
503
504        impl<'a> $builder<'a> {
505            fn new($($event_field: $event_type)?) -> Self {
506                skip_assert_initialized!();
507                Self {
508                    seqnum: None,
509                    running_time_offset: None,
510                    other_fields: Vec::new(),
511                    $($field_names: <$field_types>::default(),)*
512                    #[cfg(feature = "v1_22")]
513                    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
514                    modifier_state: NavigationModifierType::empty(),
515                    $($event_field,)?
516                }
517            }
518
519            $(pub fn $field_names(self, $field_names: $field_types) -> Self {
520                Self { $field_names, ..self }
521            })*
522
523            #[cfg(feature = "v1_22")]
524            #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
525            pub fn modifier_state(self, modifier_state: NavigationModifierType) -> Self {
526                Self { modifier_state, ..self }
527            }
528
529            event_builder_generic_impl!($new_fn);
530        }
531    };
532}
533
534pub enum KeyEventType<'a> {
535    Press { key: &'a str },
536    Release { key: &'a str },
537}
538
539nav_event_builder!(
540    KeyEventBuilder,
541    kind: KeyEventType<'a>,
542    [],
543    |s: &mut Self| {
544        let event = match s.kind {
545            KeyEventType::Press { key } => NavigationEvent::KeyPress {
546                key: key.to_owned(),
547                #[cfg(feature = "v1_22")]
548                #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
549                modifier_state: s.modifier_state,
550            },
551            KeyEventType::Release { key } => NavigationEvent::KeyRelease {
552                key: key.to_owned(),
553                #[cfg(feature = "v1_22")]
554                #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
555                modifier_state: s.modifier_state,
556            },
557        };
558        gst::ffi::gst_event_new_navigation(event.structure().into_glib_ptr())
559    }
560);
561
562pub enum MouseEventType {
563    Move,
564    Press {
565        button: i32,
566    },
567    Release {
568        button: i32,
569    },
570    #[cfg(feature = "v1_18")]
571    #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
572    Scroll {
573        delta_x: f64,
574        delta_y: f64,
575    },
576    #[cfg(feature = "v1_26")]
577    #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
578    DoubleClick {
579        button: i32,
580    },
581}
582
583nav_event_builder!(
584    MouseEventBuilder,
585    kind: MouseEventType,
586    [x: f64, y: f64],
587    |s: &mut Self| {
588        let event = match s.kind {
589            MouseEventType::Move => NavigationEvent::MouseMove {
590                x: s.x,
591                y: s.y,
592                #[cfg(feature = "v1_22")]
593                #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
594                modifier_state: s.modifier_state,
595            },
596            MouseEventType::Press { button } => NavigationEvent::MouseButtonPress {
597                button,
598                x: s.x,
599                y: s.y,
600                #[cfg(feature = "v1_22")]
601                #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
602                modifier_state: s.modifier_state,
603            },
604            MouseEventType::Release { button } => NavigationEvent::MouseButtonRelease {
605                button,
606                x: s.x,
607                y: s.y,
608                #[cfg(feature = "v1_22")]
609                #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
610                modifier_state: s.modifier_state,
611            },
612            #[cfg(feature = "v1_18")]
613            #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
614            MouseEventType::Scroll { delta_x, delta_y } => NavigationEvent::MouseScroll {
615                x: s.x,
616                y: s.y,
617                delta_x,
618                delta_y,
619                #[cfg(feature = "v1_22")]
620                #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
621                modifier_state: s.modifier_state,
622            },
623            #[cfg(feature = "v1_26")]
624            #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
625            MouseEventType::DoubleClick { button } => NavigationEvent::MouseDoubleClick {
626                button,
627                x: s.x,
628                y: s.y,
629                modifier_state: s.modifier_state,
630            },
631        };
632        gst::ffi::gst_event_new_navigation(event.structure().into_glib_ptr())
633    }
634);
635
636#[must_use = "The builder must be built to be used"]
637pub struct CommandEventBuilder<'a> {
638    seqnum: Option<gst::Seqnum>,
639    running_time_offset: Option<i64>,
640    other_fields: Vec<(&'a str, glib::SendValue)>,
641    command: NavigationCommand,
642    #[cfg(feature = "v1_22")]
643    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
644    modifier_state: NavigationModifierType,
645}
646
647impl<'a> CommandEventBuilder<'a> {
648    fn new(command: NavigationCommand) -> Self {
649        skip_assert_initialized!();
650        Self {
651            seqnum: None,
652            running_time_offset: None,
653            other_fields: Vec::new(),
654            command,
655            #[cfg(feature = "v1_22")]
656            #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
657            modifier_state: NavigationModifierType::empty(),
658        }
659    }
660
661    #[cfg(feature = "v1_22")]
662    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
663    pub fn modifier_state(self, modifier_state: NavigationModifierType) -> Self {
664        Self {
665            modifier_state,
666            ..self
667        }
668    }
669
670    event_builder_generic_impl!(|s: &mut Self| {
671        let event = NavigationEvent::Command {
672            command: s.command,
673            #[cfg(feature = "v1_22")]
674            #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
675            modifier_state: s.modifier_state,
676        };
677        gst::ffi::gst_event_new_navigation(event.structure().into_glib_ptr())
678    });
679}
680
681#[cfg(feature = "v1_22")]
682#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
683pub enum TouchEventType {
684    Down { pressure: f64 },
685    Motion { pressure: f64 },
686    Up,
687}
688
689#[cfg(feature = "v1_22")]
690#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
691nav_event_builder!(
692    TouchEventBuilder,
693    kind: TouchEventType,
694    [identifier: u32, x: f64, y: f64],
695    |s: &mut Self| {
696        let event = match s.kind {
697            TouchEventType::Down { pressure } => NavigationEvent::TouchDown {
698                identifier: s.identifier,
699                x: s.x,
700                y: s.y,
701                modifier_state: s.modifier_state,
702                pressure,
703            },
704            TouchEventType::Motion { pressure } => NavigationEvent::TouchMotion {
705                identifier: s.identifier,
706                x: s.x,
707                y: s.y,
708                modifier_state: s.modifier_state,
709                pressure,
710            },
711            TouchEventType::Up => NavigationEvent::TouchUp {
712                identifier: s.identifier,
713                x: s.x,
714                y: s.y,
715                modifier_state: s.modifier_state,
716            },
717        };
718        gst::ffi::gst_event_new_navigation(event.structure().into_glib_ptr())
719    }
720);
721
722#[cfg(feature = "v1_22")]
723#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
724pub enum TouchMetaEventType {
725    Frame,
726    Cancel,
727}
728
729#[cfg(feature = "v1_22")]
730#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
731nav_event_builder!(
732    TouchMetaEventBuilder,
733    kind: TouchMetaEventType,
734    [],
735    |s: &mut Self| {
736        let event = match s.kind {
737            TouchMetaEventType::Frame => NavigationEvent::TouchFrame {
738                modifier_state: s.modifier_state,
739            },
740            TouchMetaEventType::Cancel => NavigationEvent::TouchCancel {
741                modifier_state: s.modifier_state,
742            },
743        };
744        gst::ffi::gst_event_new_navigation(event.structure().into_glib_ptr())
745    }
746);
747
748const NAVIGATION_EVENT_NAME: &str = "application/x-gst-navigation";
749#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
750#[cfg_attr(feature = "serde", serde(tag = "event"))]
751#[derive(Clone, PartialEq, Debug)]
752pub enum NavigationEvent {
753    KeyPress {
754        key: String,
755        #[cfg(feature = "v1_22")]
756        #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
757        modifier_state: NavigationModifierType,
758    },
759    KeyRelease {
760        key: String,
761        #[cfg(feature = "v1_22")]
762        #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
763        modifier_state: NavigationModifierType,
764    },
765    MouseMove {
766        x: f64,
767        y: f64,
768        #[cfg(feature = "v1_22")]
769        #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
770        modifier_state: NavigationModifierType,
771    },
772    MouseButtonPress {
773        button: i32,
774        x: f64,
775        y: f64,
776        #[cfg(feature = "v1_22")]
777        #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
778        modifier_state: NavigationModifierType,
779    },
780    MouseButtonRelease {
781        button: i32,
782        x: f64,
783        y: f64,
784        #[cfg(feature = "v1_22")]
785        #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
786        modifier_state: NavigationModifierType,
787    },
788    Command {
789        command: NavigationCommand,
790        #[cfg(feature = "v1_22")]
791        #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
792        modifier_state: NavigationModifierType,
793    },
794    #[cfg(feature = "v1_18")]
795    #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
796    MouseScroll {
797        x: f64,
798        y: f64,
799        delta_x: f64,
800        delta_y: f64,
801        #[cfg(feature = "v1_22")]
802        #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
803        modifier_state: NavigationModifierType,
804    },
805    #[cfg(feature = "v1_22")]
806    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
807    TouchDown {
808        identifier: u32,
809        x: f64,
810        y: f64,
811        pressure: f64,
812        modifier_state: NavigationModifierType,
813    },
814    #[cfg(feature = "v1_22")]
815    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
816    TouchMotion {
817        identifier: u32,
818        x: f64,
819        y: f64,
820        pressure: f64,
821        modifier_state: NavigationModifierType,
822    },
823    #[cfg(feature = "v1_22")]
824    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
825    TouchUp {
826        identifier: u32,
827        x: f64,
828        y: f64,
829        modifier_state: NavigationModifierType,
830    },
831    #[cfg(feature = "v1_22")]
832    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
833    TouchFrame {
834        modifier_state: NavigationModifierType,
835    },
836    #[cfg(feature = "v1_22")]
837    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
838    TouchCancel {
839        modifier_state: NavigationModifierType,
840    },
841    #[cfg(feature = "v1_26")]
842    #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
843    MouseDoubleClick {
844        button: i32,
845        x: f64,
846        y: f64,
847        modifier_state: NavigationModifierType,
848    },
849}
850
851impl NavigationEvent {
852    #[doc(alias = "gst_navigation_event_new_key_press")]
853    pub fn new_key_press(key: &str) -> NavigationEvent {
854        assert_initialized_main_thread!();
855        Self::KeyPress {
856            key: key.to_string(),
857            #[cfg(feature = "v1_22")]
858            #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
859            modifier_state: NavigationModifierType::empty(),
860        }
861    }
862
863    #[doc(alias = "gst_navigation_event_new_key_release")]
864    pub fn new_key_release(key: &str) -> NavigationEvent {
865        assert_initialized_main_thread!();
866        Self::KeyRelease {
867            key: key.to_string(),
868            #[cfg(feature = "v1_22")]
869            #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
870            modifier_state: NavigationModifierType::empty(),
871        }
872    }
873
874    #[doc(alias = "gst_navigation_event_new_mouse_move")]
875    pub fn new_mouse_move(x: f64, y: f64) -> NavigationEvent {
876        assert_initialized_main_thread!();
877        Self::MouseMove {
878            x,
879            y,
880            #[cfg(feature = "v1_22")]
881            #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
882            modifier_state: NavigationModifierType::empty(),
883        }
884    }
885
886    #[doc(alias = "gst_navigation_event_new_mouse_button_press")]
887    pub fn new_mouse_button_press(button: i32, x: f64, y: f64) -> NavigationEvent {
888        assert_initialized_main_thread!();
889        Self::MouseButtonPress {
890            button,
891            x,
892            y,
893            #[cfg(feature = "v1_22")]
894            #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
895            modifier_state: NavigationModifierType::empty(),
896        }
897    }
898
899    #[doc(alias = "gst_navigation_event_new_mouse_button_release")]
900    pub fn new_mouse_button_release(button: i32, x: f64, y: f64) -> NavigationEvent {
901        assert_initialized_main_thread!();
902        Self::MouseButtonRelease {
903            button,
904            x,
905            y,
906            #[cfg(feature = "v1_22")]
907            #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
908            modifier_state: NavigationModifierType::empty(),
909        }
910    }
911
912    #[cfg(feature = "v1_18")]
913    #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
914    #[doc(alias = "gst_navigation_event_new_mouse_scroll")]
915    pub fn new_mouse_scroll(x: f64, y: f64, delta_x: f64, delta_y: f64) -> NavigationEvent {
916        assert_initialized_main_thread!();
917        Self::MouseScroll {
918            x,
919            y,
920            delta_x,
921            delta_y,
922            #[cfg(feature = "v1_22")]
923            #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
924            modifier_state: NavigationModifierType::empty(),
925        }
926    }
927
928    #[doc(alias = "gst_navigation_event_new_command")]
929    pub fn new_command(command: NavigationCommand) -> NavigationEvent {
930        assert_initialized_main_thread!();
931        Self::Command {
932            command,
933            #[cfg(feature = "v1_22")]
934            #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
935            modifier_state: NavigationModifierType::empty(),
936        }
937    }
938
939    #[cfg(feature = "v1_22")]
940    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
941    #[doc(alias = "gst_navigation_event_new_touch_down")]
942    pub fn new_touch_down(identifier: u32, x: f64, y: f64, pressure: f64) -> NavigationEvent {
943        assert_initialized_main_thread!();
944        Self::TouchDown {
945            identifier,
946            x,
947            y,
948            pressure,
949            modifier_state: NavigationModifierType::empty(),
950        }
951    }
952
953    #[cfg(feature = "v1_22")]
954    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
955    #[doc(alias = "gst_navigation_event_new_touch_motion")]
956    pub fn new_touch_motion(identifier: u32, x: f64, y: f64, pressure: f64) -> NavigationEvent {
957        assert_initialized_main_thread!();
958        Self::TouchMotion {
959            identifier,
960            x,
961            y,
962            pressure,
963            modifier_state: NavigationModifierType::empty(),
964        }
965    }
966
967    #[cfg(feature = "v1_22")]
968    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
969    #[doc(alias = "gst_navigation_event_new_touch_up")]
970    pub fn new_touch_up(identifier: u32, x: f64, y: f64) -> NavigationEvent {
971        assert_initialized_main_thread!();
972        Self::TouchUp {
973            identifier,
974            x,
975            y,
976            modifier_state: NavigationModifierType::empty(),
977        }
978    }
979
980    #[cfg(feature = "v1_22")]
981    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
982    #[doc(alias = "gst_navigation_event_new_touch_frame")]
983    pub fn new_touch_frame() -> NavigationEvent {
984        assert_initialized_main_thread!();
985        Self::TouchFrame {
986            modifier_state: NavigationModifierType::empty(),
987        }
988    }
989
990    #[cfg(feature = "v1_22")]
991    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
992    #[doc(alias = "gst_navigation_event_new_touch_cancel")]
993    pub fn new_touch_cancel() -> NavigationEvent {
994        assert_initialized_main_thread!();
995        Self::TouchCancel {
996            modifier_state: NavigationModifierType::empty(),
997        }
998    }
999
1000    #[cfg(feature = "v1_26")]
1001    #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
1002    #[doc(alias = "gst_navigation_event_new_mouse_double_click")]
1003    pub fn new_mouse_double_click(button: i32, x: f64, y: f64) -> NavigationEvent {
1004        assert_initialized_main_thread!();
1005        Self::MouseDoubleClick {
1006            button,
1007            x,
1008            y,
1009            modifier_state: NavigationModifierType::empty(),
1010        }
1011    }
1012    pub fn key_press_builder(key: &str) -> KeyEventBuilder<'_> {
1013        assert_initialized_main_thread!();
1014        KeyEventBuilder::new(KeyEventType::Press { key })
1015    }
1016
1017    pub fn key_release_builder(key: &str) -> KeyEventBuilder<'_> {
1018        assert_initialized_main_thread!();
1019        KeyEventBuilder::new(KeyEventType::Release { key })
1020    }
1021
1022    pub fn mouse_move_builder(x: f64, y: f64) -> MouseEventBuilder<'static> {
1023        assert_initialized_main_thread!();
1024        MouseEventBuilder::new(MouseEventType::Move {}).x(x).y(y)
1025    }
1026
1027    pub fn mouse_button_press_builder(button: i32, x: f64, y: f64) -> MouseEventBuilder<'static> {
1028        assert_initialized_main_thread!();
1029        MouseEventBuilder::new(MouseEventType::Press { button })
1030            .x(x)
1031            .y(y)
1032    }
1033
1034    pub fn mouse_button_release_builder(button: i32, x: f64, y: f64) -> MouseEventBuilder<'static> {
1035        assert_initialized_main_thread!();
1036        MouseEventBuilder::new(MouseEventType::Press { button })
1037            .x(x)
1038            .y(y)
1039    }
1040
1041    #[cfg(feature = "v1_18")]
1042    #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
1043    pub fn mouse_scroll_builder(
1044        x: f64,
1045        y: f64,
1046        delta_x: f64,
1047        delta_y: f64,
1048    ) -> MouseEventBuilder<'static> {
1049        assert_initialized_main_thread!();
1050        MouseEventBuilder::new(MouseEventType::Scroll { delta_x, delta_y })
1051            .x(x)
1052            .y(y)
1053    }
1054
1055    pub fn command_builder(command: NavigationCommand) -> CommandEventBuilder<'static> {
1056        assert_initialized_main_thread!();
1057        CommandEventBuilder::new(command)
1058    }
1059
1060    #[cfg(feature = "v1_22")]
1061    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1062    pub fn touch_down_builder(
1063        identifier: u32,
1064        x: f64,
1065        y: f64,
1066        pressure: f64,
1067    ) -> TouchEventBuilder<'static> {
1068        assert_initialized_main_thread!();
1069        TouchEventBuilder::new(TouchEventType::Down { pressure })
1070            .identifier(identifier)
1071            .x(x)
1072            .y(y)
1073    }
1074
1075    #[cfg(feature = "v1_22")]
1076    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1077    pub fn touch_motion_builder(
1078        identifier: u32,
1079        x: f64,
1080        y: f64,
1081        pressure: f64,
1082    ) -> TouchEventBuilder<'static> {
1083        assert_initialized_main_thread!();
1084        TouchEventBuilder::new(TouchEventType::Motion { pressure })
1085            .identifier(identifier)
1086            .x(x)
1087            .y(y)
1088    }
1089
1090    #[cfg(feature = "v1_22")]
1091    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1092    pub fn touch_up_builder(identifier: u32, x: f64, y: f64) -> TouchEventBuilder<'static> {
1093        assert_initialized_main_thread!();
1094        TouchEventBuilder::new(TouchEventType::Up)
1095            .identifier(identifier)
1096            .x(x)
1097            .y(y)
1098    }
1099
1100    #[cfg(feature = "v1_22")]
1101    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1102    pub fn touch_frame_builder() -> TouchMetaEventBuilder<'static> {
1103        assert_initialized_main_thread!();
1104        TouchMetaEventBuilder::new(TouchMetaEventType::Frame)
1105    }
1106
1107    #[cfg(feature = "v1_22")]
1108    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1109    pub fn touch_cancel_builder() -> TouchMetaEventBuilder<'static> {
1110        assert_initialized_main_thread!();
1111        TouchMetaEventBuilder::new(TouchMetaEventType::Cancel)
1112    }
1113
1114    #[cfg(feature = "v1_26")]
1115    #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
1116    pub fn mouse_double_click_builder(button: i32, x: f64, y: f64) -> MouseEventBuilder<'static> {
1117        assert_initialized_main_thread!();
1118        MouseEventBuilder::new(MouseEventType::DoubleClick { button })
1119            .x(x)
1120            .y(y)
1121    }
1122
1123    #[doc(alias = "gst_navigation_event_get_type")]
1124    pub fn type_(event: &gst::EventRef) -> NavigationEventType {
1125        skip_assert_initialized!();
1126        unsafe { from_glib(ffi::gst_navigation_event_get_type(event.as_mut_ptr())) }
1127    }
1128
1129    #[doc(alias = "gst_navigation_event_parse_key_event")]
1130    #[doc(alias = "gst_navigation_event_parse_mouse_button_event")]
1131    #[doc(alias = "gst_navigation_event_parse_mouse_scroll_event")]
1132    #[doc(alias = "gst_navigation_event_parse_mouse_move_event")]
1133    #[doc(alias = "gst_navigation_event_parse_touch_event")]
1134    #[doc(alias = "gst_navigation_event_parse_touch_up_event")]
1135    #[doc(alias = "gst_navigation_event_parse_command")]
1136    pub fn parse(event: &gst::EventRef) -> Result<Self, glib::error::BoolError> {
1137        skip_assert_initialized!();
1138        if event.type_() != EventType::Navigation {
1139            return Err(glib::bool_error!("Invalid navigation event"));
1140        }
1141
1142        let structure = event
1143            .structure()
1144            .ok_or_else(|| glib::bool_error!("Invalid navigation event"))?;
1145        if structure.name() != NAVIGATION_EVENT_NAME {
1146            return Err(glib::bool_error!("Invalid navigation event"));
1147        }
1148
1149        #[cfg(feature = "v1_22")]
1150        #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1151        let modifier_state = structure
1152            .get("state")
1153            .unwrap_or(NavigationModifierType::empty());
1154        let event = match Self::type_(event) {
1155            NavigationEventType::MouseMove => NavigationEvent::MouseMove {
1156                x: structure
1157                    .get("pointer_x")
1158                    .map_err(|_| glib::bool_error!("Invalid mouse event"))?,
1159                y: structure
1160                    .get("pointer_y")
1161                    .map_err(|_| glib::bool_error!("Invalid mouse event"))?,
1162                #[cfg(feature = "v1_22")]
1163                #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1164                modifier_state,
1165            },
1166            NavigationEventType::MouseButtonPress => NavigationEvent::MouseButtonPress {
1167                button: structure
1168                    .get("button")
1169                    .map_err(|_| glib::bool_error!("Invalid mouse event"))?,
1170                x: structure
1171                    .get("pointer_x")
1172                    .map_err(|_| glib::bool_error!("Invalid mouse event"))?,
1173                y: structure
1174                    .get("pointer_y")
1175                    .map_err(|_| glib::bool_error!("Invalid mouse event"))?,
1176                #[cfg(feature = "v1_22")]
1177                #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1178                modifier_state,
1179            },
1180            NavigationEventType::MouseButtonRelease => NavigationEvent::MouseButtonRelease {
1181                button: structure
1182                    .get("button")
1183                    .map_err(|_| glib::bool_error!("Invalid mouse event"))?,
1184                x: structure
1185                    .get("pointer_x")
1186                    .map_err(|_| glib::bool_error!("Invalid mouse event"))?,
1187                y: structure
1188                    .get("pointer_y")
1189                    .map_err(|_| glib::bool_error!("Invalid mouse event"))?,
1190                #[cfg(feature = "v1_22")]
1191                #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1192                modifier_state,
1193            },
1194            #[cfg(feature = "v1_18")]
1195            #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
1196            NavigationEventType::MouseScroll => NavigationEvent::MouseScroll {
1197                x: structure
1198                    .get("pointer_x")
1199                    .map_err(|_| glib::bool_error!("Invalid mouse event"))?,
1200                y: structure
1201                    .get("pointer_y")
1202                    .map_err(|_| glib::bool_error!("Invalid mouse event"))?,
1203                delta_x: structure
1204                    .get("delta_pointer_x")
1205                    .map_err(|_| glib::bool_error!("Invalid mouse event"))?,
1206                delta_y: structure
1207                    .get("delta_pointer_y")
1208                    .map_err(|_| glib::bool_error!("Invalid mouse event"))?,
1209                #[cfg(feature = "v1_22")]
1210                #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1211                modifier_state,
1212            },
1213            NavigationEventType::KeyPress => NavigationEvent::KeyPress {
1214                key: structure
1215                    .get("key")
1216                    .map_err(|_| glib::bool_error!("Invalid key press event"))?,
1217                #[cfg(feature = "v1_22")]
1218                #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1219                modifier_state,
1220            },
1221            NavigationEventType::KeyRelease => NavigationEvent::KeyRelease {
1222                key: structure
1223                    .get("key")
1224                    .map_err(|_| glib::bool_error!("Invalid key press event"))?,
1225                #[cfg(feature = "v1_22")]
1226                #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1227                modifier_state,
1228            },
1229            NavigationEventType::Command => NavigationEvent::Command {
1230                command: structure
1231                    .get("command-code")
1232                    .map_err(|_| glib::bool_error!("Invalid key press event"))?,
1233                #[cfg(feature = "v1_22")]
1234                #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1235                modifier_state,
1236            },
1237            #[cfg(feature = "v1_22")]
1238            #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1239            NavigationEventType::TouchDown => NavigationEvent::TouchDown {
1240                identifier: structure
1241                    .get("identifier")
1242                    .map_err(|_| glib::bool_error!("Invalid touch event"))?,
1243                x: structure
1244                    .get("pointer_x")
1245                    .map_err(|_| glib::bool_error!("Invalid touch event"))?,
1246                y: structure
1247                    .get("pointer_y")
1248                    .map_err(|_| glib::bool_error!("Invalid touch event"))?,
1249                pressure: structure
1250                    .get("pressure")
1251                    .map_err(|_| glib::bool_error!("Invalid touch event"))?,
1252                modifier_state,
1253            },
1254            #[cfg(feature = "v1_22")]
1255            #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1256            NavigationEventType::TouchMotion => NavigationEvent::TouchMotion {
1257                identifier: structure
1258                    .get("identifier")
1259                    .map_err(|_| glib::bool_error!("Invalid touch event"))?,
1260                x: structure
1261                    .get("pointer_x")
1262                    .map_err(|_| glib::bool_error!("Invalid touch event"))?,
1263                y: structure
1264                    .get("pointer_y")
1265                    .map_err(|_| glib::bool_error!("Invalid touch event"))?,
1266                pressure: structure
1267                    .get("pressure")
1268                    .map_err(|_| glib::bool_error!("Invalid touch event"))?,
1269                modifier_state,
1270            },
1271            #[cfg(feature = "v1_22")]
1272            #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1273            NavigationEventType::TouchUp => NavigationEvent::TouchUp {
1274                identifier: structure
1275                    .get("identifier")
1276                    .map_err(|_| glib::bool_error!("Invalid touch event"))?,
1277                x: structure
1278                    .get("pointer_x")
1279                    .map_err(|_| glib::bool_error!("Invalid touch event"))?,
1280                y: structure
1281                    .get("pointer_y")
1282                    .map_err(|_| glib::bool_error!("Invalid touch event"))?,
1283                modifier_state,
1284            },
1285            #[cfg(feature = "v1_22")]
1286            #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1287            NavigationEventType::TouchFrame => NavigationEvent::TouchFrame { modifier_state },
1288            #[cfg(feature = "v1_22")]
1289            #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1290            NavigationEventType::TouchCancel => NavigationEvent::TouchCancel { modifier_state },
1291            #[cfg(feature = "v1_26")]
1292            #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
1293            NavigationEventType::MouseDoubleClick => NavigationEvent::MouseDoubleClick {
1294                button: structure
1295                    .get("button")
1296                    .map_err(|_| glib::bool_error!("Invalid mouse event"))?,
1297                x: structure
1298                    .get("pointer_x")
1299                    .map_err(|_| glib::bool_error!("Invalid mouse event"))?,
1300                y: structure
1301                    .get("pointer_y")
1302                    .map_err(|_| glib::bool_error!("Invalid mouse event"))?,
1303                modifier_state,
1304            },
1305
1306            NavigationEventType::Invalid | NavigationEventType::__Unknown(_) => {
1307                return Err(glib::bool_error!("Invalid navigation event"));
1308            }
1309        };
1310        Ok(event)
1311    }
1312
1313    pub fn structure(&self) -> gst::Structure {
1314        skip_assert_initialized!();
1315        #[allow(unused_mut)]
1316        let mut structure = match self {
1317            Self::MouseMove { x, y, .. } => gst::Structure::builder(NAVIGATION_EVENT_NAME)
1318                .field("event", "mouse-move")
1319                .field("pointer_x", x)
1320                .field("pointer_y", y),
1321            Self::MouseButtonPress { button, x, y, .. } => {
1322                gst::Structure::builder(NAVIGATION_EVENT_NAME)
1323                    .field("event", "mouse-button-press")
1324                    .field("button", button)
1325                    .field("pointer_x", x)
1326                    .field("pointer_y", y)
1327            }
1328            Self::MouseButtonRelease { button, x, y, .. } => {
1329                gst::Structure::builder(NAVIGATION_EVENT_NAME)
1330                    .field("event", "mouse-button-release")
1331                    .field("button", button)
1332                    .field("pointer_x", x)
1333                    .field("pointer_y", y)
1334            }
1335            #[cfg(feature = "v1_18")]
1336            #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
1337            Self::MouseScroll {
1338                x,
1339                y,
1340                delta_x,
1341                delta_y,
1342                ..
1343            } => gst::Structure::builder(NAVIGATION_EVENT_NAME)
1344                .field("event", "mouse-scroll")
1345                .field("pointer_x", x)
1346                .field("pointer_y", y)
1347                .field("delta_pointer_x", delta_x)
1348                .field("delta_pointer_y", delta_y),
1349            Self::KeyPress { key, .. } => gst::Structure::builder(NAVIGATION_EVENT_NAME)
1350                .field("event", "key-press")
1351                .field("key", key),
1352            Self::KeyRelease { key, .. } => gst::Structure::builder(NAVIGATION_EVENT_NAME)
1353                .field("event", "key-release")
1354                .field("key", key),
1355            Self::Command { command, .. } => gst::Structure::builder(NAVIGATION_EVENT_NAME)
1356                .field("event", "command")
1357                .field("command-code", command),
1358            #[cfg(feature = "v1_22")]
1359            #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1360            Self::TouchDown {
1361                identifier,
1362                x,
1363                y,
1364                pressure,
1365                ..
1366            } => gst::Structure::builder(NAVIGATION_EVENT_NAME)
1367                .field("event", "touch-down")
1368                .field("identifier", identifier)
1369                .field("pointer_x", x)
1370                .field("pointer_y", y)
1371                .field("pressure", pressure),
1372            #[cfg(feature = "v1_22")]
1373            #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1374            Self::TouchMotion {
1375                identifier,
1376                x,
1377                y,
1378                pressure,
1379                ..
1380            } => gst::Structure::builder(NAVIGATION_EVENT_NAME)
1381                .field("event", "touch-motion")
1382                .field("identifier", identifier)
1383                .field("pointer_x", x)
1384                .field("pointer_y", y)
1385                .field("pressure", pressure),
1386            #[cfg(feature = "v1_22")]
1387            #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1388            Self::TouchUp {
1389                identifier, x, y, ..
1390            } => gst::Structure::builder(NAVIGATION_EVENT_NAME)
1391                .field("event", "touch-up")
1392                .field("identifier", identifier)
1393                .field("pointer_x", x)
1394                .field("pointer_y", y),
1395            #[cfg(feature = "v1_22")]
1396            #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1397            Self::TouchFrame { .. } => {
1398                gst::Structure::builder(NAVIGATION_EVENT_NAME).field("event", "touch-frame")
1399            }
1400            #[cfg(feature = "v1_22")]
1401            #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1402            Self::TouchCancel { .. } => {
1403                gst::Structure::builder(NAVIGATION_EVENT_NAME).field("event", "touch-cancel")
1404            }
1405            #[cfg(feature = "v1_26")]
1406            #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
1407            Self::MouseDoubleClick { button, x, y, .. } => {
1408                gst::Structure::builder(NAVIGATION_EVENT_NAME)
1409                    .field("event", "mouse-double-click")
1410                    .field("button", button)
1411                    .field("pointer_x", x)
1412                    .field("pointer_y", y)
1413            }
1414        };
1415
1416        #[cfg(feature = "v1_22")]
1417        {
1418            structure = match self {
1419                Self::MouseMove { modifier_state, .. } => structure.field("state", modifier_state),
1420                Self::MouseButtonPress { modifier_state, .. } => {
1421                    structure.field("state", modifier_state)
1422                }
1423                Self::MouseButtonRelease { modifier_state, .. } => {
1424                    structure.field("state", modifier_state)
1425                }
1426                Self::MouseScroll { modifier_state, .. } => {
1427                    structure.field("state", modifier_state)
1428                }
1429                Self::KeyPress { modifier_state, .. } => structure.field("state", modifier_state),
1430                Self::KeyRelease { modifier_state, .. } => structure.field("state", modifier_state),
1431                Self::Command { modifier_state, .. } => structure.field("state", modifier_state),
1432                Self::TouchDown { modifier_state, .. } => structure.field("state", modifier_state),
1433                Self::TouchMotion { modifier_state, .. } => {
1434                    structure.field("state", modifier_state)
1435                }
1436                Self::TouchUp { modifier_state, .. } => structure.field("state", modifier_state),
1437                Self::TouchFrame { modifier_state, .. } => structure.field("state", modifier_state),
1438                Self::TouchCancel { modifier_state, .. } => {
1439                    structure.field("state", modifier_state)
1440                }
1441                #[cfg(feature = "v1_26")]
1442                #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
1443                Self::MouseDoubleClick { modifier_state, .. } => {
1444                    structure.field("state", modifier_state)
1445                }
1446            };
1447        }
1448
1449        structure.build()
1450    }
1451
1452    pub fn build(&self) -> gst::Event {
1453        skip_assert_initialized!();
1454
1455        gst::event::Navigation::new(self.structure())
1456    }
1457}
1458
1459#[cfg(test)]
1460mod tests {
1461    #[test]
1462    #[cfg(feature = "serde")]
1463    #[cfg(feature = "v1_22")]
1464    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1465    fn serialize_navigation_events() {
1466        use crate::{NavigationEvent, NavigationModifierType};
1467
1468        gst::init().unwrap();
1469
1470        let mods = NavigationModifierType::SHIFT_MASK | NavigationModifierType::CONTROL_MASK;
1471        let ev = NavigationEvent::mouse_scroll_builder(1.0, 2.0, 3.0, 4.0)
1472            .modifier_state(mods)
1473            .build();
1474        let navigation_event = NavigationEvent::parse(&ev).unwrap();
1475        match &navigation_event {
1476            NavigationEvent::MouseScroll {
1477                x,
1478                y,
1479                delta_x,
1480                delta_y,
1481                modifier_state,
1482            } => {
1483                assert!(
1484                    *x == 1.0
1485                        && *y == 2.0
1486                        && *delta_x == 3.0
1487                        && *delta_y == 4.0
1488                        && *modifier_state == mods
1489                );
1490            }
1491            _ => unreachable!(),
1492        }
1493
1494        let json_event = serde_json::to_string(&navigation_event).unwrap();
1495        assert_eq!(
1496            json_event,
1497            r#"{"event":"MouseScroll","x":1.0,"y":2.0,"delta_x":3.0,"delta_y":4.0,"modifier_state":"shift-mask+control-mask"}"#
1498        );
1499        let navigation_event: NavigationEvent = serde_json::from_str(&json_event).unwrap();
1500        match &navigation_event {
1501            NavigationEvent::MouseScroll {
1502                x,
1503                y,
1504                delta_x,
1505                delta_y,
1506                modifier_state,
1507            } => {
1508                assert!(
1509                    *x == 1.0
1510                        && *y == 2.0
1511                        && *delta_x == 3.0
1512                        && *delta_y == 4.0
1513                        && *modifier_state == mods
1514                );
1515            }
1516            _ => unreachable!(),
1517        }
1518
1519        let ev = NavigationEvent::new_mouse_button_press(1, 1.0, 2.0).build();
1520        let navigation_event = NavigationEvent::parse(&ev).unwrap();
1521        match &navigation_event {
1522            NavigationEvent::MouseButtonPress {
1523                button,
1524                x,
1525                y,
1526                modifier_state,
1527            } => {
1528                assert!(
1529                    *button == 1
1530                        && *x == 1.0
1531                        && *y == 2.0
1532                        && *modifier_state == NavigationModifierType::empty()
1533                );
1534            }
1535            _ => unreachable!(),
1536        }
1537        let json_event = serde_json::to_string(&navigation_event).unwrap();
1538        assert_eq!(
1539            json_event,
1540            r#"{"event":"MouseButtonPress","button":1,"x":1.0,"y":2.0,"modifier_state":""}"#
1541        );
1542        let navigation_event: NavigationEvent = serde_json::from_str(&json_event).unwrap();
1543        match &navigation_event {
1544            NavigationEvent::MouseButtonPress {
1545                button,
1546                x,
1547                y,
1548                modifier_state,
1549            } => {
1550                assert!(
1551                    *button == 1
1552                        && *x == 1.0
1553                        && *y == 2.0
1554                        && *modifier_state == NavigationModifierType::empty()
1555                );
1556            }
1557            _ => unreachable!(),
1558        }
1559
1560        let mods = NavigationModifierType::META_MASK;
1561        let ev = NavigationEvent::key_release_builder("a")
1562            .modifier_state(mods)
1563            .build();
1564        let navigation_event = NavigationEvent::parse(&ev).unwrap();
1565        match &navigation_event {
1566            NavigationEvent::KeyRelease {
1567                key,
1568                modifier_state,
1569            } => {
1570                assert!(*key == "a" && *modifier_state == mods);
1571            }
1572            _ => unreachable!(),
1573        }
1574
1575        let json_event = serde_json::to_string(&navigation_event).unwrap();
1576        assert_eq!(
1577            json_event,
1578            r#"{"event":"KeyRelease","key":"a","modifier_state":"meta-mask"}"#
1579        );
1580        let navigation_event: NavigationEvent = serde_json::from_str(&json_event).unwrap();
1581        match &navigation_event {
1582            NavigationEvent::KeyRelease {
1583                key,
1584                modifier_state,
1585            } => {
1586                assert!(*key == "a" && *modifier_state == mods);
1587            }
1588            _ => unreachable!(),
1589        }
1590
1591        let ev = NavigationEvent::new_touch_motion(0, 1.0, 2.0, 0.5).build();
1592        let navigation_event = NavigationEvent::parse(&ev).unwrap();
1593        match &navigation_event {
1594            NavigationEvent::TouchMotion {
1595                identifier,
1596                x,
1597                y,
1598                pressure,
1599                modifier_state,
1600            } => {
1601                assert!(
1602                    *identifier == 0
1603                        && *x == 1.0
1604                        && *y == 2.0
1605                        && *pressure == 0.5
1606                        && *modifier_state == NavigationModifierType::empty()
1607                );
1608            }
1609            _ => unreachable!(),
1610        }
1611
1612        let json_event = serde_json::to_string(&navigation_event).unwrap();
1613        assert_eq!(
1614            json_event,
1615            r#"{"event":"TouchMotion","identifier":0,"x":1.0,"y":2.0,"pressure":0.5,"modifier_state":""}"#
1616        );
1617        let navigation_event: NavigationEvent = serde_json::from_str(&json_event).unwrap();
1618        match &navigation_event {
1619            NavigationEvent::TouchMotion {
1620                identifier,
1621                x,
1622                y,
1623                pressure,
1624                modifier_state,
1625            } => {
1626                assert!(
1627                    *identifier == 0
1628                        && *x == 1.0
1629                        && *y == 2.0
1630                        && *pressure == 0.5
1631                        && *modifier_state == NavigationModifierType::empty()
1632                );
1633            }
1634            _ => unreachable!(),
1635        }
1636
1637        let ev = NavigationEvent::touch_cancel_builder().build();
1638        let navigation_event = NavigationEvent::parse(&ev).unwrap();
1639        match &navigation_event {
1640            NavigationEvent::TouchCancel { modifier_state } => {
1641                assert!(*modifier_state == NavigationModifierType::empty());
1642            }
1643            _ => unreachable!(),
1644        }
1645
1646        let json_event = serde_json::to_string(&navigation_event).unwrap();
1647        assert_eq!(json_event, r#"{"event":"TouchCancel","modifier_state":""}"#);
1648        let navigation_event: NavigationEvent = serde_json::from_str(&json_event).unwrap();
1649        match &navigation_event {
1650            NavigationEvent::TouchCancel { modifier_state } => {
1651                assert!(*modifier_state == NavigationModifierType::empty());
1652            }
1653            _ => unreachable!(),
1654        }
1655    }
1656}