1pub trait Pixel: Copy + Into<f64> {
108 fn from_f64(f: f64) -> Self;
109 fn cast<P: Pixel>(self) -> P {
110 P::from_f64(self.into())
111 }
112}
113
114impl Pixel for u8 {
115 fn from_f64(f: f64) -> Self {
116 f.round() as u8
117 }
118}
119impl Pixel for u16 {
120 fn from_f64(f: f64) -> Self {
121 f.round() as u16
122 }
123}
124impl Pixel for u32 {
125 fn from_f64(f: f64) -> Self {
126 f.round() as u32
127 }
128}
129impl Pixel for i8 {
130 fn from_f64(f: f64) -> Self {
131 f.round() as i8
132 }
133}
134impl Pixel for i16 {
135 fn from_f64(f: f64) -> Self {
136 f.round() as i16
137 }
138}
139impl Pixel for i32 {
140 fn from_f64(f: f64) -> Self {
141 f.round() as i32
142 }
143}
144impl Pixel for f32 {
145 fn from_f64(f: f64) -> Self {
146 f as f32
147 }
148}
149impl Pixel for f64 {
150 fn from_f64(f: f64) -> Self {
151 f
152 }
153}
154
155#[inline]
161pub fn validate_scale_factor(scale_factor: f64) -> bool {
162 scale_factor.is_sign_positive() && scale_factor.is_normal()
163}
164
165#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash)]
171#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
172pub struct LogicalPosition<P> {
173 pub x: P,
174 pub y: P,
175}
176
177impl<P> LogicalPosition<P> {
178 #[inline]
179 pub const fn new(x: P, y: P) -> Self {
180 LogicalPosition { x, y }
181 }
182}
183
184impl<P: Pixel> LogicalPosition<P> {
185 #[inline]
186 pub fn from_physical<T: Into<PhysicalPosition<X>>, X: Pixel>(
187 physical: T,
188 scale_factor: f64,
189 ) -> Self {
190 physical.into().to_logical(scale_factor)
191 }
192
193 #[inline]
194 pub fn to_physical<X: Pixel>(&self, scale_factor: f64) -> PhysicalPosition<X> {
195 assert!(validate_scale_factor(scale_factor));
196 let x = self.x.into() * scale_factor;
197 let y = self.y.into() * scale_factor;
198 PhysicalPosition::new(x, y).cast()
199 }
200
201 #[inline]
202 pub fn cast<X: Pixel>(&self) -> LogicalPosition<X> {
203 LogicalPosition {
204 x: self.x.cast(),
205 y: self.y.cast(),
206 }
207 }
208}
209
210impl<P: Pixel, X: Pixel> From<(X, X)> for LogicalPosition<P> {
211 fn from((x, y): (X, X)) -> LogicalPosition<P> {
212 LogicalPosition::new(x.cast(), y.cast())
213 }
214}
215
216impl<P: Pixel, X: Pixel> From<LogicalPosition<P>> for (X, X) {
217 fn from(p: LogicalPosition<P>) -> (X, X) {
218 (p.x.cast(), p.y.cast())
219 }
220}
221
222impl<P: Pixel, X: Pixel> From<[X; 2]> for LogicalPosition<P> {
223 fn from([x, y]: [X; 2]) -> LogicalPosition<P> {
224 LogicalPosition::new(x.cast(), y.cast())
225 }
226}
227
228impl<P: Pixel, X: Pixel> From<LogicalPosition<P>> for [X; 2] {
229 fn from(p: LogicalPosition<P>) -> [X; 2] {
230 [p.x.cast(), p.y.cast()]
231 }
232}
233
234#[cfg(feature = "mint")]
235impl<P: Pixel> From<mint::Point2<P>> for LogicalPosition<P> {
236 fn from(p: mint::Point2<P>) -> Self {
237 Self::new(p.x, p.y)
238 }
239}
240
241#[cfg(feature = "mint")]
242impl<P: Pixel> From<LogicalPosition<P>> for mint::Point2<P> {
243 fn from(p: LogicalPosition<P>) -> Self {
244 mint::Point2 { x: p.x, y: p.y }
245 }
246}
247
248#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash)]
250#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
251pub struct PhysicalPosition<P> {
252 pub x: P,
253 pub y: P,
254}
255
256impl<P> PhysicalPosition<P> {
257 #[inline]
258 pub const fn new(x: P, y: P) -> Self {
259 PhysicalPosition { x, y }
260 }
261}
262
263impl<P: Pixel> PhysicalPosition<P> {
264 #[inline]
265 pub fn from_logical<T: Into<LogicalPosition<X>>, X: Pixel>(
266 logical: T,
267 scale_factor: f64,
268 ) -> Self {
269 logical.into().to_physical(scale_factor)
270 }
271
272 #[inline]
273 pub fn to_logical<X: Pixel>(&self, scale_factor: f64) -> LogicalPosition<X> {
274 assert!(validate_scale_factor(scale_factor));
275 let x = self.x.into() / scale_factor;
276 let y = self.y.into() / scale_factor;
277 LogicalPosition::new(x, y).cast()
278 }
279
280 #[inline]
281 pub fn cast<X: Pixel>(&self) -> PhysicalPosition<X> {
282 PhysicalPosition {
283 x: self.x.cast(),
284 y: self.y.cast(),
285 }
286 }
287}
288
289impl<P: Pixel, X: Pixel> From<(X, X)> for PhysicalPosition<P> {
290 fn from((x, y): (X, X)) -> PhysicalPosition<P> {
291 PhysicalPosition::new(x.cast(), y.cast())
292 }
293}
294
295impl<P: Pixel, X: Pixel> From<PhysicalPosition<P>> for (X, X) {
296 fn from(p: PhysicalPosition<P>) -> (X, X) {
297 (p.x.cast(), p.y.cast())
298 }
299}
300
301impl<P: Pixel, X: Pixel> From<[X; 2]> for PhysicalPosition<P> {
302 fn from([x, y]: [X; 2]) -> PhysicalPosition<P> {
303 PhysicalPosition::new(x.cast(), y.cast())
304 }
305}
306
307impl<P: Pixel, X: Pixel> From<PhysicalPosition<P>> for [X; 2] {
308 fn from(p: PhysicalPosition<P>) -> [X; 2] {
309 [p.x.cast(), p.y.cast()]
310 }
311}
312
313#[cfg(feature = "mint")]
314impl<P: Pixel> From<mint::Point2<P>> for PhysicalPosition<P> {
315 fn from(p: mint::Point2<P>) -> Self {
316 Self::new(p.x, p.y)
317 }
318}
319
320#[cfg(feature = "mint")]
321impl<P: Pixel> From<PhysicalPosition<P>> for mint::Point2<P> {
322 fn from(p: PhysicalPosition<P>) -> Self {
323 mint::Point2 { x: p.x, y: p.y }
324 }
325}
326
327#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash)]
329#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
330pub struct LogicalSize<P> {
331 pub width: P,
332 pub height: P,
333}
334
335impl<P> LogicalSize<P> {
336 #[inline]
337 pub const fn new(width: P, height: P) -> Self {
338 LogicalSize { width, height }
339 }
340}
341
342impl<P: Pixel> LogicalSize<P> {
343 #[inline]
344 pub fn from_physical<T: Into<PhysicalSize<X>>, X: Pixel>(
345 physical: T,
346 scale_factor: f64,
347 ) -> Self {
348 physical.into().to_logical(scale_factor)
349 }
350
351 #[inline]
352 pub fn to_physical<X: Pixel>(&self, scale_factor: f64) -> PhysicalSize<X> {
353 assert!(validate_scale_factor(scale_factor));
354 let width = self.width.into() * scale_factor;
355 let height = self.height.into() * scale_factor;
356 PhysicalSize::new(width, height).cast()
357 }
358
359 #[inline]
360 pub fn cast<X: Pixel>(&self) -> LogicalSize<X> {
361 LogicalSize {
362 width: self.width.cast(),
363 height: self.height.cast(),
364 }
365 }
366}
367
368impl<P: Pixel, X: Pixel> From<(X, X)> for LogicalSize<P> {
369 fn from((x, y): (X, X)) -> LogicalSize<P> {
370 LogicalSize::new(x.cast(), y.cast())
371 }
372}
373
374impl<P: Pixel, X: Pixel> From<LogicalSize<P>> for (X, X) {
375 fn from(s: LogicalSize<P>) -> (X, X) {
376 (s.width.cast(), s.height.cast())
377 }
378}
379
380impl<P: Pixel, X: Pixel> From<[X; 2]> for LogicalSize<P> {
381 fn from([x, y]: [X; 2]) -> LogicalSize<P> {
382 LogicalSize::new(x.cast(), y.cast())
383 }
384}
385
386impl<P: Pixel, X: Pixel> From<LogicalSize<P>> for [X; 2] {
387 fn from(s: LogicalSize<P>) -> [X; 2] {
388 [s.width.cast(), s.height.cast()]
389 }
390}
391
392#[cfg(feature = "mint")]
393impl<P: Pixel> From<mint::Vector2<P>> for LogicalSize<P> {
394 fn from(v: mint::Vector2<P>) -> Self {
395 Self::new(v.x, v.y)
396 }
397}
398
399#[cfg(feature = "mint")]
400impl<P: Pixel> From<LogicalSize<P>> for mint::Vector2<P> {
401 fn from(s: LogicalSize<P>) -> Self {
402 mint::Vector2 {
403 x: s.width,
404 y: s.height,
405 }
406 }
407}
408
409#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash)]
411#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
412pub struct PhysicalSize<P> {
413 pub width: P,
414 pub height: P,
415}
416
417impl<P> PhysicalSize<P> {
418 #[inline]
419 pub const fn new(width: P, height: P) -> Self {
420 PhysicalSize { width, height }
421 }
422}
423
424impl<P: Pixel> PhysicalSize<P> {
425 #[inline]
426 pub fn from_logical<T: Into<LogicalSize<X>>, X: Pixel>(logical: T, scale_factor: f64) -> Self {
427 logical.into().to_physical(scale_factor)
428 }
429
430 #[inline]
431 pub fn to_logical<X: Pixel>(&self, scale_factor: f64) -> LogicalSize<X> {
432 assert!(validate_scale_factor(scale_factor));
433 let width = self.width.into() / scale_factor;
434 let height = self.height.into() / scale_factor;
435 LogicalSize::new(width, height).cast()
436 }
437
438 #[inline]
439 pub fn cast<X: Pixel>(&self) -> PhysicalSize<X> {
440 PhysicalSize {
441 width: self.width.cast(),
442 height: self.height.cast(),
443 }
444 }
445}
446
447impl<P: Pixel, X: Pixel> From<(X, X)> for PhysicalSize<P> {
448 fn from((x, y): (X, X)) -> PhysicalSize<P> {
449 PhysicalSize::new(x.cast(), y.cast())
450 }
451}
452
453impl<P: Pixel, X: Pixel> From<PhysicalSize<P>> for (X, X) {
454 fn from(s: PhysicalSize<P>) -> (X, X) {
455 (s.width.cast(), s.height.cast())
456 }
457}
458
459impl<P: Pixel, X: Pixel> From<[X; 2]> for PhysicalSize<P> {
460 fn from([x, y]: [X; 2]) -> PhysicalSize<P> {
461 PhysicalSize::new(x.cast(), y.cast())
462 }
463}
464
465impl<P: Pixel, X: Pixel> From<PhysicalSize<P>> for [X; 2] {
466 fn from(s: PhysicalSize<P>) -> [X; 2] {
467 [s.width.cast(), s.height.cast()]
468 }
469}
470
471#[cfg(feature = "mint")]
472impl<P: Pixel> From<mint::Vector2<P>> for PhysicalSize<P> {
473 fn from(v: mint::Vector2<P>) -> Self {
474 Self::new(v.x, v.y)
475 }
476}
477
478#[cfg(feature = "mint")]
479impl<P: Pixel> From<PhysicalSize<P>> for mint::Vector2<P> {
480 fn from(s: PhysicalSize<P>) -> Self {
481 mint::Vector2 {
482 x: s.width,
483 y: s.height,
484 }
485 }
486}
487
488#[derive(Debug, Copy, Clone, PartialEq)]
490#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
491pub enum Size {
492 Physical(PhysicalSize<u32>),
493 Logical(LogicalSize<f64>),
494}
495
496impl Size {
497 pub fn new<S: Into<Size>>(size: S) -> Size {
498 size.into()
499 }
500
501 pub fn to_logical<P: Pixel>(&self, scale_factor: f64) -> LogicalSize<P> {
502 match *self {
503 Size::Physical(size) => size.to_logical(scale_factor),
504 Size::Logical(size) => size.cast(),
505 }
506 }
507
508 pub fn to_physical<P: Pixel>(&self, scale_factor: f64) -> PhysicalSize<P> {
509 match *self {
510 Size::Physical(size) => size.cast(),
511 Size::Logical(size) => size.to_physical(scale_factor),
512 }
513 }
514
515 pub fn clamp<S: Into<Size>>(input: S, min: S, max: S, scale_factor: f64) -> Size {
516 let (input, min, max) = (
517 input.into().to_physical::<f64>(scale_factor),
518 min.into().to_physical::<f64>(scale_factor),
519 max.into().to_physical::<f64>(scale_factor),
520 );
521
522 let width = input.width.clamp(min.width, max.width);
523 let height = input.height.clamp(min.height, max.height);
524
525 PhysicalSize::new(width, height).into()
526 }
527}
528
529impl<P: Pixel> From<PhysicalSize<P>> for Size {
530 #[inline]
531 fn from(size: PhysicalSize<P>) -> Size {
532 Size::Physical(size.cast())
533 }
534}
535
536impl<P: Pixel> From<LogicalSize<P>> for Size {
537 #[inline]
538 fn from(size: LogicalSize<P>) -> Size {
539 Size::Logical(size.cast())
540 }
541}
542
543#[derive(Debug, Copy, Clone, PartialEq)]
545#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
546pub enum Position {
547 Physical(PhysicalPosition<i32>),
548 Logical(LogicalPosition<f64>),
549}
550
551impl Position {
552 pub fn new<S: Into<Position>>(position: S) -> Position {
553 position.into()
554 }
555
556 pub fn to_logical<P: Pixel>(&self, scale_factor: f64) -> LogicalPosition<P> {
557 match *self {
558 Position::Physical(position) => position.to_logical(scale_factor),
559 Position::Logical(position) => position.cast(),
560 }
561 }
562
563 pub fn to_physical<P: Pixel>(&self, scale_factor: f64) -> PhysicalPosition<P> {
564 match *self {
565 Position::Physical(position) => position.cast(),
566 Position::Logical(position) => position.to_physical(scale_factor),
567 }
568 }
569}
570
571impl<P: Pixel> From<PhysicalPosition<P>> for Position {
572 #[inline]
573 fn from(position: PhysicalPosition<P>) -> Position {
574 Position::Physical(position.cast())
575 }
576}
577
578impl<P: Pixel> From<LogicalPosition<P>> for Position {
579 #[inline]
580 fn from(position: LogicalPosition<P>) -> Position {
581 Position::Logical(position.cast())
582 }
583}