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