#[derive(Copy, Default, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[repr(C)]
pub struct LogicalRect {
pub origin: LogicalPosition,
pub size: LogicalSize,
}
impl core::fmt::Debug for LogicalRect {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{} @ {}", self.size, self.origin)
}
}
impl core::fmt::Display for LogicalRect {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{} @ {}", self.size, self.origin)
}
}
impl LogicalRect {
pub const fn zero() -> Self {
Self::new(LogicalPosition::zero(), LogicalSize::zero())
}
pub const fn new(origin: LogicalPosition, size: LogicalSize) -> Self {
Self { origin, size }
}
#[inline]
pub fn scale_for_dpi(&mut self, scale_factor: f32) {
self.origin.x *= scale_factor;
self.origin.y *= scale_factor;
self.size.width *= scale_factor;
self.size.height *= scale_factor;
}
#[inline(always)]
pub fn max_x(&self) -> f32 {
self.origin.x + self.size.width
}
#[inline(always)]
pub fn min_x(&self) -> f32 {
self.origin.x
}
#[inline(always)]
pub fn max_y(&self) -> f32 {
self.origin.y + self.size.height
}
#[inline(always)]
pub fn min_y(&self) -> f32 {
self.origin.y
}
#[inline]
pub fn intersects(&self, other: Self) -> bool {
if self.max_x() <= other.min_x() || other.max_x() <= self.min_x() {
return false;
}
if self.max_y() <= other.min_y() || other.max_y() <= self.min_y() {
return false;
}
true
}
#[inline]
pub fn contains(&self, point: LogicalPosition) -> bool {
point.x >= self.min_x()
&& point.x < self.max_x()
&& point.y >= self.min_y()
&& point.y < self.max_y()
}
#[inline]
pub fn union<I: Iterator<Item = Self>>(mut rects: I) -> Option<Self> {
let first = rects.next()?;
let mut max_width = first.size.width;
let mut max_height = first.size.height;
let mut min_x = first.origin.x;
let mut min_y = first.origin.y;
while let Some(Self {
origin: LogicalPosition { x, y },
size: LogicalSize { width, height },
}) = rects.next()
{
let cur_lower_right_x = x + width;
let cur_lower_right_y = y + height;
max_width = max_width.max(cur_lower_right_x - min_x);
max_height = max_height.max(cur_lower_right_y - min_y);
min_x = min_x.min(x);
min_y = min_y.min(y);
}
Some(Self {
origin: LogicalPosition { x: min_x, y: min_y },
size: LogicalSize {
width: max_width,
height: max_height,
},
})
}
#[inline]
pub fn hit_test(&self, other: &LogicalPosition) -> Option<LogicalPosition> {
let dx_left_edge = other.x - self.min_x();
let dx_right_edge = self.max_x() - other.x;
let dy_top_edge = other.y - self.min_y();
let dy_bottom_edge = self.max_y() - other.y;
if dx_left_edge > 0.0 && dx_right_edge > 0.0 && dy_top_edge > 0.0 && dy_bottom_edge > 0.0 {
Some(LogicalPosition::new(dx_left_edge, dy_top_edge))
} else {
None
}
}
pub fn to_layout_rect(&self) -> LayoutRect {
LayoutRect {
origin: LayoutPoint::new(
libm::roundf(self.origin.x) as isize,
libm::roundf(self.origin.y) as isize,
),
size: LayoutSize::new(
libm::roundf(self.size.width) as isize,
libm::roundf(self.size.height) as isize,
),
}
}
}
impl_vec!(LogicalRect, LogicalRectVec, LogicalRectVecDestructor, LogicalRectVecDestructorType, LogicalRectVecSlice, OptionLogicalRect);
impl_vec_clone!(LogicalRect, LogicalRectVec, LogicalRectVecDestructor);
impl_vec_debug!(LogicalRect, LogicalRectVec);
impl_vec_partialeq!(LogicalRect, LogicalRectVec);
impl_vec_partialord!(LogicalRect, LogicalRectVec);
impl_vec_ord!(LogicalRect, LogicalRectVec);
impl_vec_hash!(LogicalRect, LogicalRectVec);
impl_vec_eq!(LogicalRect, LogicalRectVec);
use core::{
cmp::Ordering,
hash::{Hash, Hasher},
ops::{self, AddAssign, SubAssign},
};
use azul_css::props::{
basic::{LayoutPoint, LayoutRect, LayoutSize},
layout::LayoutWritingMode,
};
#[derive(Default, Copy, Clone, PartialEq, PartialOrd)]
#[repr(C)]
pub struct LogicalPosition {
pub x: f32,
pub y: f32,
}
impl LogicalPosition {
pub fn scale_for_dpi(&mut self, scale_factor: f32) {
self.x *= scale_factor;
self.y *= scale_factor;
}
}
impl SubAssign<LogicalPosition> for LogicalPosition {
fn sub_assign(&mut self, other: LogicalPosition) {
self.x -= other.x;
self.y -= other.y;
}
}
impl AddAssign<LogicalPosition> for LogicalPosition {
fn add_assign(&mut self, other: LogicalPosition) {
self.x += other.x;
self.y += other.y;
}
}
impl core::fmt::Debug for LogicalPosition {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
impl core::fmt::Display for LogicalPosition {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
impl ops::Add for LogicalPosition {
type Output = Self;
#[inline]
fn add(self, other: Self) -> Self {
Self {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
impl ops::Sub for LogicalPosition {
type Output = Self;
#[inline]
fn sub(self, other: Self) -> Self {
Self {
x: self.x - other.x,
y: self.y - other.y,
}
}
}
const DECIMAL_MULTIPLIER: f32 = 1000.0;
impl_option!(
LogicalPosition,
OptionLogicalPosition,
[Debug, Copy, Clone, PartialEq, PartialOrd]
);
impl Ord for LogicalPosition {
fn cmp(&self, other: &LogicalPosition) -> Ordering {
let self_x = (self.x * DECIMAL_MULTIPLIER) as usize;
let self_y = (self.y * DECIMAL_MULTIPLIER) as usize;
let other_x = (other.x * DECIMAL_MULTIPLIER) as usize;
let other_y = (other.y * DECIMAL_MULTIPLIER) as usize;
self_x.cmp(&other_x).then(self_y.cmp(&other_y))
}
}
impl Eq for LogicalPosition {}
impl Hash for LogicalPosition {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
let self_x = (self.x * DECIMAL_MULTIPLIER) as usize;
let self_y = (self.y * DECIMAL_MULTIPLIER) as usize;
self_x.hash(state);
self_y.hash(state);
}
}
impl LogicalPosition {
pub fn main(&self, wm: LayoutWritingMode) -> f32 {
match wm {
LayoutWritingMode::HorizontalTb => self.y,
LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => self.x,
}
}
pub fn cross(&self, wm: LayoutWritingMode) -> f32 {
match wm {
LayoutWritingMode::HorizontalTb => self.x,
LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => self.y,
}
}
pub fn from_main_cross(main: f32, cross: f32, wm: LayoutWritingMode) -> Self {
match wm {
LayoutWritingMode::HorizontalTb => Self::new(cross, main),
LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => Self::new(main, cross),
}
}
}
#[derive(Default, Copy, Clone, PartialEq, PartialOrd)]
#[repr(C)]
pub struct LogicalSize {
pub width: f32,
pub height: f32,
}
impl LogicalSize {
pub fn scale_for_dpi(&mut self, scale_factor: f32) -> Self {
self.width *= scale_factor;
self.height *= scale_factor;
*self
}
pub fn from_main_cross(main: f32, cross: f32, wm: LayoutWritingMode) -> Self {
match wm {
LayoutWritingMode::HorizontalTb => Self::new(cross, main),
LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => Self::new(main, cross),
}
}
}
impl core::fmt::Debug for LogicalSize {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}x{}", self.width, self.height)
}
}
impl core::fmt::Display for LogicalSize {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "{}x{}", self.width, self.height)
}
}
impl_option!(
LogicalSize,
OptionLogicalSize,
[Debug, Copy, Clone, PartialEq, PartialOrd]
);
impl_option!(
LogicalRect,
OptionLogicalRect,
[Debug, Copy, Clone, PartialEq, PartialOrd]
);
impl Ord for LogicalSize {
fn cmp(&self, other: &LogicalSize) -> Ordering {
let self_width = (self.width * DECIMAL_MULTIPLIER) as usize;
let self_height = (self.height * DECIMAL_MULTIPLIER) as usize;
let other_width = (other.width * DECIMAL_MULTIPLIER) as usize;
let other_height = (other.height * DECIMAL_MULTIPLIER) as usize;
self_width
.cmp(&other_width)
.then(self_height.cmp(&other_height))
}
}
impl Eq for LogicalSize {}
impl Hash for LogicalSize {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
let self_width = (self.width * DECIMAL_MULTIPLIER) as usize;
let self_height = (self.height * DECIMAL_MULTIPLIER) as usize;
self_width.hash(state);
self_height.hash(state);
}
}
impl LogicalSize {
pub fn main(&self, wm: LayoutWritingMode) -> f32 {
match wm {
LayoutWritingMode::HorizontalTb => self.height,
LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => self.width,
}
}
pub fn cross(&self, wm: LayoutWritingMode) -> f32 {
match wm {
LayoutWritingMode::HorizontalTb => self.width,
LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => self.height,
}
}
pub fn with_main(self, wm: LayoutWritingMode, value: f32) -> Self {
match wm {
LayoutWritingMode::HorizontalTb => Self {
height: value,
..self
},
LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => Self {
width: value,
..self
},
}
}
pub fn with_cross(self, wm: LayoutWritingMode, value: f32) -> Self {
match wm {
LayoutWritingMode::HorizontalTb => Self {
width: value,
..self
},
LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => Self {
height: value,
..self
},
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct PhysicalPosition<T> {
pub x: T,
pub y: T,
}
impl<T: ::core::fmt::Display> ::core::fmt::Debug for PhysicalPosition<T> {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
pub type PhysicalPositionI32 = PhysicalPosition<i32>;
impl_option!(
PhysicalPositionI32,
OptionPhysicalPositionI32,
[Debug, Copy, Clone, PartialEq, PartialOrd]
);
#[derive(Ord, Hash, Eq, Copy, Clone, PartialEq, PartialOrd)]
#[repr(C)]
pub struct PhysicalSize<T> {
pub width: T,
pub height: T,
}
impl<T: ::core::fmt::Display> ::core::fmt::Debug for PhysicalSize<T> {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
write!(f, "{}x{}", self.width, self.height)
}
}
pub type PhysicalSizeU32 = PhysicalSize<u32>;
impl_option!(
PhysicalSizeU32,
OptionPhysicalSizeU32,
[Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash]
);
pub type PhysicalSizeF32 = PhysicalSize<f32>;
impl_option!(
PhysicalSizeF32,
OptionPhysicalSizeF32,
[Debug, Copy, Clone, PartialEq, PartialOrd]
);
impl LogicalPosition {
#[inline(always)]
pub const fn new(x: f32, y: f32) -> Self {
Self { x, y }
}
#[inline(always)]
pub const fn zero() -> Self {
Self::new(0.0, 0.0)
}
#[inline(always)]
pub fn to_physical(self, hidpi_factor: f32) -> PhysicalPosition<u32> {
PhysicalPosition {
x: (self.x * hidpi_factor) as u32,
y: (self.y * hidpi_factor) as u32,
}
}
}
impl<T> PhysicalPosition<T> {
#[inline(always)]
pub const fn new(x: T, y: T) -> Self {
Self { x, y }
}
}
impl PhysicalPosition<i32> {
#[inline(always)]
pub const fn zero() -> Self {
Self::new(0, 0)
}
#[inline(always)]
pub fn to_logical(self, hidpi_factor: f32) -> LogicalPosition {
LogicalPosition {
x: self.x as f32 / hidpi_factor,
y: self.y as f32 / hidpi_factor,
}
}
}
impl PhysicalPosition<f64> {
#[inline(always)]
pub const fn zero() -> Self {
Self::new(0.0, 0.0)
}
#[inline(always)]
pub fn to_logical(self, hidpi_factor: f32) -> LogicalPosition {
LogicalPosition {
x: self.x as f32 / hidpi_factor,
y: self.y as f32 / hidpi_factor,
}
}
}
impl LogicalSize {
#[inline(always)]
pub const fn new(width: f32, height: f32) -> Self {
Self { width, height }
}
#[inline(always)]
pub const fn zero() -> Self {
Self::new(0.0, 0.0)
}
#[inline(always)]
pub fn to_physical(self, hidpi_factor: f32) -> PhysicalSize<u32> {
PhysicalSize {
width: (self.width * hidpi_factor) as u32,
height: (self.height * hidpi_factor) as u32,
}
}
}
impl<T> PhysicalSize<T> {
#[inline(always)]
pub const fn new(width: T, height: T) -> Self {
Self { width, height }
}
}
impl PhysicalSize<u32> {
#[inline(always)]
pub const fn zero() -> Self {
Self::new(0, 0)
}
#[inline(always)]
pub fn to_logical(self, hidpi_factor: f32) -> LogicalSize {
LogicalSize {
width: self.width as f32 / hidpi_factor,
height: self.height as f32 / hidpi_factor,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(C)]
pub enum CoordinateSpace {
Window,
ScrollFrame,
Parent,
ReferenceFrame,
}
impl CoordinateSpace {
pub const fn description(&self) -> &'static str {
match self {
CoordinateSpace::Window => "Absolute window coordinates (layout engine output)",
CoordinateSpace::ScrollFrame => "Relative to scroll frame origin (for WebRender scroll nodes)",
CoordinateSpace::Parent => "Relative to parent node origin",
CoordinateSpace::ReferenceFrame => "Relative to CSS transform origin",
}
}
}
#[derive(Default, Debug, Copy, Clone, PartialEq, PartialOrd)]
#[repr(C)]
pub struct ScreenPosition {
pub x: f32,
pub y: f32,
}
impl ScreenPosition {
#[inline(always)]
pub const fn new(x: f32, y: f32) -> Self {
Self { x, y }
}
#[inline(always)]
pub const fn zero() -> Self {
Self::new(0.0, 0.0)
}
#[inline(always)]
pub const fn to_logical(self) -> LogicalPosition {
LogicalPosition { x: self.x, y: self.y }
}
#[inline(always)]
pub const fn from_logical(p: LogicalPosition) -> Self {
Self { x: p.x, y: p.y }
}
}
impl_option!(
ScreenPosition,
OptionScreenPosition,
[Debug, Copy, Clone, PartialEq, PartialOrd]
);
#[derive(Default, Debug, Copy, Clone, PartialEq, PartialOrd)]
#[repr(C)]
pub struct CursorNodePosition {
pub x: f32,
pub y: f32,
}
impl CursorNodePosition {
#[inline(always)]
pub const fn new(x: f32, y: f32) -> Self {
Self { x, y }
}
#[inline(always)]
pub const fn zero() -> Self {
Self::new(0.0, 0.0)
}
#[inline(always)]
pub const fn to_logical(self) -> LogicalPosition {
LogicalPosition { x: self.x, y: self.y }
}
#[inline(always)]
pub const fn from_logical(p: LogicalPosition) -> Self {
Self { x: p.x, y: p.y }
}
}
impl_option!(
CursorNodePosition,
OptionCursorNodePosition,
[Debug, Copy, Clone, PartialEq, PartialOrd]
);
#[derive(Default, Debug, Copy, Clone, PartialEq, PartialOrd)]
#[repr(C)]
pub struct DragDelta {
pub dx: f32,
pub dy: f32,
}
impl DragDelta {
#[inline(always)]
pub const fn new(dx: f32, dy: f32) -> Self {
Self { dx, dy }
}
#[inline(always)]
pub const fn zero() -> Self {
Self::new(0.0, 0.0)
}
}
impl_option!(
DragDelta,
OptionDragDelta,
[Debug, Copy, Clone, PartialEq, PartialOrd]
);