script/dom/
wheelevent.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use euclid::Point2D;
9use js::rust::HandleObject;
10use keyboard_types::Modifiers;
11use style_traits::CSSPixel;
12
13use crate::dom::bindings::codegen::Bindings::MouseEventBinding::MouseEventMethods;
14use crate::dom::bindings::codegen::Bindings::WheelEventBinding;
15use crate::dom::bindings::codegen::Bindings::WheelEventBinding::WheelEventMethods;
16use crate::dom::bindings::error::Fallible;
17use crate::dom::bindings::inheritance::Castable;
18use crate::dom::bindings::num::Finite;
19use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
20use crate::dom::bindings::root::DomRoot;
21use crate::dom::bindings::str::DOMString;
22use crate::dom::event::{Event, EventBubbles, EventCancelable};
23use crate::dom::eventtarget::EventTarget;
24use crate::dom::mouseevent::MouseEvent;
25use crate::dom::window::Window;
26use crate::script_runtime::CanGc;
27
28#[dom_struct]
29pub(crate) struct WheelEvent {
30    mouseevent: MouseEvent,
31    delta_x: Cell<Finite<f64>>,
32    delta_y: Cell<Finite<f64>>,
33    delta_z: Cell<Finite<f64>>,
34    delta_mode: Cell<u32>,
35}
36
37impl WheelEvent {
38    fn new_inherited() -> WheelEvent {
39        WheelEvent {
40            mouseevent: MouseEvent::new_inherited(),
41            delta_x: Cell::new(Finite::wrap(0.0)),
42            delta_y: Cell::new(Finite::wrap(0.0)),
43            delta_z: Cell::new(Finite::wrap(0.0)),
44            delta_mode: Cell::new(0),
45        }
46    }
47
48    fn new_unintialized(
49        window: &Window,
50        proto: Option<HandleObject>,
51        can_gc: CanGc,
52    ) -> DomRoot<WheelEvent> {
53        reflect_dom_object_with_proto(Box::new(WheelEvent::new_inherited()), window, proto, can_gc)
54    }
55
56    #[allow(clippy::too_many_arguments)]
57    pub(crate) fn new(
58        window: &Window,
59        type_: DOMString,
60        can_bubble: EventBubbles,
61        cancelable: EventCancelable,
62        view: Option<&Window>,
63        detail: i32,
64        screen_point: Point2D<i32, CSSPixel>,
65        client_point: Point2D<i32, CSSPixel>,
66        page_point: Point2D<i32, CSSPixel>,
67        modifiers: Modifiers,
68        button: i16,
69        buttons: u16,
70        related_target: Option<&EventTarget>,
71        point_in_target: Option<Point2D<f32, CSSPixel>>,
72        delta_x: Finite<f64>,
73        delta_y: Finite<f64>,
74        delta_z: Finite<f64>,
75        delta_mode: u32,
76        can_gc: CanGc,
77    ) -> DomRoot<WheelEvent> {
78        Self::new_with_proto(
79            window,
80            None,
81            type_,
82            can_bubble,
83            cancelable,
84            view,
85            detail,
86            screen_point,
87            client_point,
88            page_point,
89            modifiers,
90            button,
91            buttons,
92            related_target,
93            point_in_target,
94            delta_x,
95            delta_y,
96            delta_z,
97            delta_mode,
98            can_gc,
99        )
100    }
101
102    #[allow(clippy::too_many_arguments)]
103    fn new_with_proto(
104        window: &Window,
105        proto: Option<HandleObject>,
106        type_: DOMString,
107        can_bubble: EventBubbles,
108        cancelable: EventCancelable,
109        view: Option<&Window>,
110        detail: i32,
111        screen_point: Point2D<i32, CSSPixel>,
112        client_point: Point2D<i32, CSSPixel>,
113        page_point: Point2D<i32, CSSPixel>,
114        modifiers: Modifiers,
115        button: i16,
116        buttons: u16,
117        related_target: Option<&EventTarget>,
118        point_in_target: Option<Point2D<f32, CSSPixel>>,
119        delta_x: Finite<f64>,
120        delta_y: Finite<f64>,
121        delta_z: Finite<f64>,
122        delta_mode: u32,
123        can_gc: CanGc,
124    ) -> DomRoot<WheelEvent> {
125        let ev = WheelEvent::new_unintialized(window, proto, can_gc);
126        ev.intitialize_wheel_event(
127            type_,
128            can_bubble,
129            cancelable,
130            view,
131            detail,
132            screen_point,
133            client_point,
134            page_point,
135            modifiers,
136            button,
137            buttons,
138            related_target,
139            point_in_target,
140            delta_x,
141            delta_y,
142            delta_z,
143            delta_mode,
144        );
145
146        ev
147    }
148
149    #[allow(clippy::too_many_arguments)]
150    pub(crate) fn intitialize_wheel_event(
151        &self,
152        type_: DOMString,
153        can_bubble: EventBubbles,
154        cancelable: EventCancelable,
155        view: Option<&Window>,
156        detail: i32,
157        screen_point: Point2D<i32, CSSPixel>,
158        client_point: Point2D<i32, CSSPixel>,
159        page_point: Point2D<i32, CSSPixel>,
160        modifiers: Modifiers,
161        button: i16,
162        buttons: u16,
163        related_target: Option<&EventTarget>,
164        point_in_target: Option<Point2D<f32, CSSPixel>>,
165        delta_x: Finite<f64>,
166        delta_y: Finite<f64>,
167        delta_z: Finite<f64>,
168        delta_mode: u32,
169    ) {
170        if self.upcast::<Event>().dispatching() {
171            return;
172        }
173
174        self.upcast::<MouseEvent>().initialize_mouse_event(
175            type_,
176            can_bubble,
177            cancelable,
178            view,
179            detail,
180            screen_point,
181            client_point,
182            page_point,
183            modifiers,
184            button,
185            buttons,
186            related_target,
187            point_in_target,
188        );
189        self.delta_x.set(delta_x);
190        self.delta_y.set(delta_y);
191        self.delta_z.set(delta_z);
192        self.delta_mode.set(delta_mode);
193    }
194}
195
196impl WheelEventMethods<crate::DomTypeHolder> for WheelEvent {
197    // https://w3c.github.io/uievents/#dom-wheelevent-wheelevent
198    fn Constructor(
199        window: &Window,
200        proto: Option<HandleObject>,
201        can_gc: CanGc,
202        type_: DOMString,
203        init: &WheelEventBinding::WheelEventInit,
204    ) -> Fallible<DomRoot<WheelEvent>> {
205        let bubbles = EventBubbles::from(init.parent.parent.parent.parent.bubbles);
206        let cancelable = EventCancelable::from(init.parent.parent.parent.parent.cancelable);
207        let scroll_offset = window.scroll_offset();
208
209        let page_point = Point2D::<i32, CSSPixel>::new(
210            scroll_offset.x as i32 + init.parent.clientX,
211            scroll_offset.y as i32 + init.parent.clientY,
212        );
213
214        let event = WheelEvent::new_with_proto(
215            window,
216            proto,
217            type_,
218            bubbles,
219            cancelable,
220            init.parent.parent.parent.view.as_deref(),
221            init.parent.parent.parent.detail,
222            Point2D::new(init.parent.screenX, init.parent.screenY),
223            Point2D::new(init.parent.clientX, init.parent.clientY),
224            Point2D::new(page_point.x, page_point.y),
225            init.parent.parent.modifiers(),
226            init.parent.button,
227            init.parent.buttons,
228            init.parent.relatedTarget.as_deref(),
229            None,
230            init.deltaX,
231            init.deltaY,
232            init.deltaZ,
233            init.deltaMode,
234            can_gc,
235        );
236
237        Ok(event)
238    }
239
240    // https://w3c.github.io/uievents/#widl-WheelEvent-deltaX
241    fn DeltaX(&self) -> Finite<f64> {
242        self.delta_x.get()
243    }
244
245    // https://w3c.github.io/uievents/#widl-WheelEvent-deltaY
246    fn DeltaY(&self) -> Finite<f64> {
247        self.delta_y.get()
248    }
249
250    // https://w3c.github.io/uievents/#widl-WheelEvent-deltaZ
251    fn DeltaZ(&self) -> Finite<f64> {
252        self.delta_z.get()
253    }
254
255    // https://w3c.github.io/uievents/#widl-WheelEvent-deltaMode
256    fn DeltaMode(&self) -> u32 {
257        self.delta_mode.get()
258    }
259
260    // https://w3c.github.io/uievents/#widl-WheelEvent-initWheelEvent
261    fn InitWheelEvent(
262        &self,
263        type_arg: DOMString,
264        can_bubble_arg: bool,
265        cancelable_arg: bool,
266        view_arg: Option<&Window>,
267        detail_arg: i32,
268        delta_x_arg: Finite<f64>,
269        delta_y_arg: Finite<f64>,
270        delta_z_arg: Finite<f64>,
271        delta_mode_arg: u32,
272    ) {
273        if self.upcast::<Event>().dispatching() {
274            return;
275        }
276
277        self.upcast::<MouseEvent>().InitMouseEvent(
278            type_arg,
279            can_bubble_arg,
280            cancelable_arg,
281            view_arg,
282            detail_arg,
283            self.mouseevent.ScreenX(),
284            self.mouseevent.ScreenY(),
285            self.mouseevent.ClientX(),
286            self.mouseevent.ClientY(),
287            self.mouseevent.CtrlKey(),
288            self.mouseevent.AltKey(),
289            self.mouseevent.ShiftKey(),
290            self.mouseevent.MetaKey(),
291            self.mouseevent.Button(),
292            self.mouseevent.GetRelatedTarget().as_deref(),
293        );
294        self.delta_x.set(delta_x_arg);
295        self.delta_y.set(delta_y_arg);
296        self.delta_z.set(delta_z_arg);
297        self.delta_mode.set(delta_mode_arg);
298    }
299
300    // https://dom.spec.whatwg.org/#dom-event-istrusted
301    fn IsTrusted(&self) -> bool {
302        self.mouseevent.IsTrusted()
303    }
304}