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