Add access to the Element attributes related to scrolling (#2338)

* Add access to the Element attributes related to scrolling

* Fix clippy warnings

* Restore interpreter/src/js/hash.txt content

* Update generated interpreter files

* Use euclid types as return types

* Remove redundant functions

* It's not necessary for PixelsSize to be in 3D

* Rename PixelsVector to PixelsVector3D and add a PixelsVector2D type

* Remove unused PixelsLength type
This commit is contained in:
ASR-ASU 2024-05-21 19:56:49 +02:00 committed by GitHub
parent e2002d6ea4
commit 460b70e0f0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 188 additions and 70 deletions

View file

@ -1,5 +1,8 @@
use dioxus_core::ElementId;
use dioxus_html::{geometry::euclid::Rect, MountedResult, RenderedElementBacking};
use dioxus_html::{
geometry::{PixelsRect, PixelsSize, PixelsVector2D},
MountedResult, RenderedElementBacking,
};
use crate::{desktop_context::DesktopContext, query::QueryEngine};
@ -17,38 +20,56 @@ impl DesktopElement {
}
}
macro_rules! scripted_getter {
($meth_name:ident, $script:literal, $output_type:path) => {
fn $meth_name(
&self,
) -> std::pin::Pin<
Box<dyn futures_util::Future<Output = dioxus_html::MountedResult<$output_type>>>,
> {
let script = format!($script, id = self.id.0);
let fut = self
.query
.new_query::<Option<$output_type>>(&script, self.webview.clone())
.resolve();
Box::pin(async move {
match fut.await {
Ok(Some(res)) => Ok(res),
Ok(None) => MountedResult::Err(dioxus_html::MountedError::OperationFailed(
Box::new(DesktopQueryError::FailedToQuery),
)),
Err(err) => MountedResult::Err(dioxus_html::MountedError::OperationFailed(
Box::new(err),
)),
}
})
}
};
}
impl RenderedElementBacking for DesktopElement {
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn get_client_rect(
&self,
) -> std::pin::Pin<
Box<
dyn futures_util::Future<
Output = dioxus_html::MountedResult<dioxus_html::geometry::euclid::Rect<f64, f64>>,
>,
>,
> {
let script = format!("return window.interpreter.getClientRect({});", self.id.0);
scripted_getter!(
get_scroll_offset,
"return [window.interpreter.getScrollLeft({id}), window.interpreter.getScrollTop({id})]",
PixelsVector2D
);
let fut = self
.query
.new_query::<Option<Rect<f64, f64>>>(&script, self.webview.clone())
.resolve();
Box::pin(async move {
match fut.await {
Ok(Some(rect)) => Ok(rect),
Ok(None) => MountedResult::Err(dioxus_html::MountedError::OperationFailed(
Box::new(DesktopQueryError::FailedToQuery),
)),
Err(err) => {
MountedResult::Err(dioxus_html::MountedError::OperationFailed(Box::new(err)))
}
}
})
}
scripted_getter!(
get_scroll_size,
"return [window.interpreter.getScrollWidth({id}), window.interpreter.getScrollHeight({id})]",
PixelsSize
);
scripted_getter!(
get_client_rect,
"return window.interpreter.getClientRect({id});",
PixelsRect
);
fn scroll_to(
&self,

View file

@ -1,7 +1,5 @@
//! Handles querying data from the renderer
use euclid::Rect;
use std::{
fmt::{Display, Formatter},
future::Future,
@ -16,9 +14,20 @@ pub trait RenderedElementBacking: std::any::Any {
/// return self as Any
fn as_any(&self) -> &dyn std::any::Any;
/// Get the number of pixels that an element's content is scrolled
fn get_scroll_offset(&self) -> Pin<Box<dyn Future<Output = MountedResult<PixelsVector2D>>>> {
Box::pin(async { Err(MountedError::NotSupported) })
}
/// Get the size of an element's content, including content not visible on the screen due to overflow
#[allow(clippy::type_complexity)]
fn get_scroll_size(&self) -> Pin<Box<dyn Future<Output = MountedResult<PixelsSize>>>> {
Box::pin(async { Err(MountedError::NotSupported) })
}
/// Get the bounding rectangle of the element relative to the viewport (this does not include the scroll position)
#[allow(clippy::type_complexity)]
fn get_client_rect(&self) -> Pin<Box<dyn Future<Output = MountedResult<Rect<f64, f64>>>>> {
fn get_client_rect(&self) -> Pin<Box<dyn Future<Output = MountedResult<PixelsRect>>>> {
Box::pin(async { Err(MountedError::NotSupported) })
}
@ -74,8 +83,18 @@ impl MountedData {
}
}
/// Get the number of pixels that an element's content is scrolled
pub async fn get_scroll_offset(&self) -> MountedResult<PixelsVector2D> {
self.inner.get_scroll_offset().await
}
/// Get the size of an element's content, including content not visible on the screen due to overflow
pub async fn get_scroll_size(&self) -> MountedResult<PixelsSize> {
self.inner.get_scroll_size().await
}
/// Get the bounding rectangle of the element relative to the viewport (this does not include the scroll position)
pub async fn get_client_rect(&self) -> MountedResult<Rect<f64, f64>> {
pub async fn get_client_rect(&self) -> MountedResult<PixelsRect> {
self.inner.get_client_rect().await
}
@ -100,6 +119,8 @@ impl MountedData {
use dioxus_core::Event;
use crate::geometry::{PixelsRect, PixelsSize, PixelsVector2D};
pub type MountedEvent = Event<MountedData>;
impl_event! [

View file

@ -27,8 +27,14 @@ pub type PagePoint = Point2D<f64, PageSpace>;
/// A pixel unit: one unit corresponds to 1 pixel
pub struct Pixels;
/// A vector expressed in Pixels
pub type PixelsVector = Vector3D<f64, Pixels>;
/// A size expressed in Pixels
pub type PixelsSize = Size2D<f64, Pixels>;
/// A rectangle expressed in Pixels
pub type PixelsRect = Rect<f64, Pixels>;
/// A 2D vector expressed in Pixels
pub type PixelsVector2D = Vector2D<f64, Pixels>;
/// A 3D vector expressed in Pixels
pub type PixelsVector3D = Vector3D<f64, Pixels>;
/// A unit in terms of Lines
///
@ -51,7 +57,7 @@ pub type PagesVector = Vector3D<f64, Pages>;
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
pub enum WheelDelta {
/// Movement in Pixels
Pixels(PixelsVector),
Pixels(PixelsVector3D),
/// Movement in Lines
Lines(LinesVector),
/// Movement in Pages
@ -62,7 +68,7 @@ impl WheelDelta {
/// Construct from the attributes of the web wheel event
pub fn from_web_attributes(delta_mode: u32, delta_x: f64, delta_y: f64, delta_z: f64) -> Self {
match delta_mode {
0 => WheelDelta::Pixels(PixelsVector::new(delta_x, delta_y, delta_z)),
0 => WheelDelta::Pixels(PixelsVector3D::new(delta_x, delta_y, delta_z)),
1 => WheelDelta::Lines(LinesVector::new(delta_x, delta_y, delta_z)),
2 => WheelDelta::Pages(PagesVector::new(delta_x, delta_y, delta_z)),
_ => panic!("Invalid delta mode, {:?}", delta_mode),
@ -71,7 +77,7 @@ impl WheelDelta {
/// Convenience function for constructing a WheelDelta with pixel units
pub fn pixels(x: f64, y: f64, z: f64) -> Self {
WheelDelta::Pixels(PixelsVector::new(x, y, z))
WheelDelta::Pixels(PixelsVector3D::new(x, y, z))
}
/// Convenience function for constructing a WheelDelta with line units

View file

@ -4,7 +4,9 @@ use crate::events::{
TransitionData, WheelData,
};
use crate::file_data::{FileEngine, HasFileData};
use crate::geometry::{ClientPoint, ElementPoint, PagePoint, ScreenPoint};
use crate::geometry::{
ClientPoint, ElementPoint, PagePoint, PixelsRect, PixelsSize, PixelsVector2D, ScreenPoint,
};
use crate::input_data::{decode_key_location, decode_mouse_button_set, MouseButton};
use crate::prelude::*;
use keyboard_types::{Code, Key, Modifiers};
@ -423,13 +425,32 @@ impl From<&web_sys::Element> for MountedData {
#[cfg(feature = "mounted")]
impl crate::RenderedElementBacking for web_sys::Element {
fn get_scroll_offset(
&self,
) -> std::pin::Pin<Box<dyn std::future::Future<Output = crate::MountedResult<PixelsVector2D>>>>
{
let left = self.scroll_left();
let top = self.scroll_top();
let result = Ok(PixelsVector2D::new(left as f64, top as f64));
Box::pin(async { result })
}
fn get_scroll_size(
&self,
) -> std::pin::Pin<Box<dyn std::future::Future<Output = crate::MountedResult<PixelsSize>>>>
{
let left = self.scroll_left();
let top = self.scroll_top();
let result = Ok(PixelsSize::new(left as f64, top as f64));
Box::pin(async { result })
}
fn get_client_rect(
&self,
) -> std::pin::Pin<
Box<dyn std::future::Future<Output = crate::MountedResult<euclid::Rect<f64, f64>>>>,
> {
) -> std::pin::Pin<Box<dyn std::future::Future<Output = crate::MountedResult<PixelsRect>>>>
{
let rect = self.get_bounding_client_rect();
let result = Ok(euclid::Rect::new(
let result = Ok(PixelsRect::new(
euclid::Point2D::new(rect.left(), rect.top()),
euclid::Size2D::new(rect.width(), rect.height()),
));

View file

@ -1 +1 @@
5713307201725207733
8520528080524713002

File diff suppressed because one or more lines are too long

View file

@ -110,6 +110,34 @@ export class NativeInterpreter extends JSChannel_ {
}
}
getScrollHeight(id: NodeId): number | undefined {
const node = this.nodes[id];
if (node instanceof HTMLElement) {
return node.scrollHeight;
}
}
getScrollLeft(id: NodeId): number | undefined {
const node = this.nodes[id];
if (node instanceof HTMLElement) {
return node.scrollLeft;
}
}
getScrollTop(id: NodeId): number | undefined {
const node = this.nodes[id];
if (node instanceof HTMLElement) {
return node.scrollTop;
}
}
getScrollWidth(id: NodeId): number | undefined {
const node = this.nodes[id];
if (node instanceof HTMLElement) {
return node.scrollWidth;
}
}
getClientRect(
id: NodeId
): { type: string; origin: number[]; size: number[] } | undefined {

View file

@ -1,5 +1,8 @@
use dioxus_core::ElementId;
use dioxus_html::{geometry::euclid::Rect, MountedResult, RenderedElementBacking};
use dioxus_html::{
geometry::{PixelsRect, PixelsSize, PixelsVector2D},
MountedResult, RenderedElementBacking,
};
use crate::query::QueryEngine;
@ -16,38 +19,56 @@ impl LiveviewElement {
}
}
macro_rules! scripted_getter {
($meth_name:ident, $script:literal, $output_type:path) => {
fn $meth_name(
&self,
) -> std::pin::Pin<
Box<dyn futures_util::Future<Output = dioxus_html::MountedResult<$output_type>>>,
> {
let script = format!($script, id = self.id.0);
let fut = self
.query
.new_query::<Option<$output_type>>(&script)
.resolve();
Box::pin(async move {
match fut.await {
Ok(Some(res)) => Ok(res),
Ok(None) => MountedResult::Err(dioxus_html::MountedError::OperationFailed(
Box::new(DesktopQueryError::FailedToQuery),
)),
Err(err) => MountedResult::Err(dioxus_html::MountedError::OperationFailed(
Box::new(err),
)),
}
})
}
};
}
impl RenderedElementBacking for LiveviewElement {
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn get_client_rect(
&self,
) -> std::pin::Pin<
Box<
dyn futures_util::Future<
Output = dioxus_html::MountedResult<dioxus_html::geometry::euclid::Rect<f64, f64>>,
>,
>,
> {
let script = format!("return window.interpreter.getClientRect({});", self.id.0);
scripted_getter!(
get_scroll_offset,
"return [window.interpreter.getScrollLeft({id}), window.interpreter.getScrollTop({id})]",
PixelsVector2D
);
let fut = self
.query
.new_query::<Option<Rect<f64, f64>>>(&script)
.resolve();
Box::pin(async move {
match fut.await {
Ok(Some(rect)) => Ok(rect),
Ok(None) => MountedResult::Err(dioxus_html::MountedError::OperationFailed(
Box::new(DesktopQueryError::FailedToQuery),
)),
Err(err) => {
MountedResult::Err(dioxus_html::MountedError::OperationFailed(Box::new(err)))
}
}
})
}
scripted_getter!(
get_scroll_size,
"return [window.interpreter.getScrollWidth({id}), window.interpreter.getScrollHeight({id})]",
PixelsSize
);
scripted_getter!(
get_client_rect,
"return window.interpreter.getClientRect({id});",
PixelsRect
);
fn scroll_to(
&self,