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