state: Derive panel size from physical click target size
This commit is contained in:
		@ -4,9 +4,11 @@
 | 
			
		||||
 | 
			
		||||
/*! Managing Wayland outputs */
 | 
			
		||||
 | 
			
		||||
use std::ops;
 | 
			
		||||
use std::vec::Vec;
 | 
			
		||||
use crate::event_loop;
 | 
			
		||||
use ::logging;
 | 
			
		||||
use crate::util::DivCeil;
 | 
			
		||||
 | 
			
		||||
// traits
 | 
			
		||||
use ::logging::Warn;
 | 
			
		||||
@ -319,6 +321,20 @@ pub struct Mode {
 | 
			
		||||
#[derive(Clone, Copy, Debug)]
 | 
			
		||||
pub struct Millimeter(pub i32);
 | 
			
		||||
 | 
			
		||||
impl DivCeil<i32> for Millimeter {
 | 
			
		||||
    type Output = Millimeter;
 | 
			
		||||
    fn div_ceil(self, other: i32) -> Self {
 | 
			
		||||
        Self(self.0.div_ceil(other))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ops::Mul<i32> for Millimeter {
 | 
			
		||||
    type Output = Self;
 | 
			
		||||
    fn mul(self, m: i32) -> Self {
 | 
			
		||||
        Self(self.0 * m as i32)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// All geometry parameters
 | 
			
		||||
#[derive(Clone, Copy, Debug)]
 | 
			
		||||
pub struct Geometry {
 | 
			
		||||
@ -348,28 +364,51 @@ impl OutputState {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_pixel_size(&self) -> Option<Size> {
 | 
			
		||||
    fn transform_size<T>(
 | 
			
		||||
        width: T,
 | 
			
		||||
        height: T,
 | 
			
		||||
        transform: self::c::Transform,
 | 
			
		||||
    ) -> GSize<T> {
 | 
			
		||||
        use self::c::Transform;
 | 
			
		||||
 | 
			
		||||
        match transform {
 | 
			
		||||
            Transform::Normal
 | 
			
		||||
            | Transform::Rotated180
 | 
			
		||||
            | Transform::Flipped
 | 
			
		||||
            | Transform::FlippedRotated180 => GSize {
 | 
			
		||||
                width,
 | 
			
		||||
                height,
 | 
			
		||||
            },
 | 
			
		||||
            _ => GSize {
 | 
			
		||||
                width: height,
 | 
			
		||||
                height: width,
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Return resolution adjusted for current transform
 | 
			
		||||
    pub fn get_pixel_size(&self) -> Option<Size> {
 | 
			
		||||
        match self {
 | 
			
		||||
            OutputState {
 | 
			
		||||
                current_mode: Some(Mode { width, height } ),
 | 
			
		||||
                geometry: Some(Geometry { transform, .. } ),
 | 
			
		||||
                scale: _,
 | 
			
		||||
            } => Some(
 | 
			
		||||
                match transform {
 | 
			
		||||
                    Transform::Normal
 | 
			
		||||
                    | Transform::Rotated180
 | 
			
		||||
                    | Transform::Flipped
 | 
			
		||||
                    | Transform::FlippedRotated180 => Size {
 | 
			
		||||
                        width: *width as u32,
 | 
			
		||||
                        height: *height as u32,
 | 
			
		||||
                    },
 | 
			
		||||
                    _ => Size {
 | 
			
		||||
                        width: *height as u32,
 | 
			
		||||
                        height: *width as u32,
 | 
			
		||||
                    },
 | 
			
		||||
                }
 | 
			
		||||
            ),
 | 
			
		||||
            } => Some(Self::transform_size(*width as u32, *height as u32, *transform)),
 | 
			
		||||
            OutputState {
 | 
			
		||||
                current_mode: Some(Mode { width, height } ),
 | 
			
		||||
                ..
 | 
			
		||||
            } => Some(Size { width: *width as u32, height: *height as u32 } ),
 | 
			
		||||
            _ => None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Return physical dimensions adjusted for current transform
 | 
			
		||||
    pub fn get_physical_size(&self) -> Option<GSize<Option<Millimeter>>> {
 | 
			
		||||
        match self {
 | 
			
		||||
            OutputState {
 | 
			
		||||
                geometry: Some(Geometry { transform, phys_size } ),
 | 
			
		||||
                ..
 | 
			
		||||
            } => Some(Self::transform_size(phys_size.width, phys_size.height, *transform)),
 | 
			
		||||
            _ => None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										72
									
								
								src/state.rs
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								src/state.rs
									
									
									
									
									
								
							@ -9,7 +9,7 @@ use crate::animation;
 | 
			
		||||
use crate::imservice::{ ContentHint, ContentPurpose };
 | 
			
		||||
use crate::main::{ Commands, PanelCommand, PixelSize };
 | 
			
		||||
use crate::outputs;
 | 
			
		||||
use crate::outputs::{OutputId, OutputState};
 | 
			
		||||
use crate::outputs::{Millimeter, OutputId, OutputState};
 | 
			
		||||
use crate::util::Rational;
 | 
			
		||||
use std::cmp;
 | 
			
		||||
use std::collections::HashMap;
 | 
			
		||||
@ -242,23 +242,65 @@ impl Application {
 | 
			
		||||
    fn get_preferred_height(output: &OutputState) -> Option<PixelSize> {
 | 
			
		||||
        output.get_pixel_size()
 | 
			
		||||
            .map(|px_size| {
 | 
			
		||||
                // Assume isotropy.
 | 
			
		||||
                // Pixels/mm.
 | 
			
		||||
                let density = output.get_physical_size()
 | 
			
		||||
                    .and_then(|size| size.width)
 | 
			
		||||
                    .map(|width| Rational {
 | 
			
		||||
                        numerator: px_size.width as i32,
 | 
			
		||||
                        denominator: width.0 as u32,
 | 
			
		||||
                    })
 | 
			
		||||
                    // Whatever the Librem 5 has,
 | 
			
		||||
                    // as a good default.
 | 
			
		||||
                    .unwrap_or(Rational {
 | 
			
		||||
                        numerator: 720,
 | 
			
		||||
                        denominator: 65,
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                // Based on what works on the L5.
 | 
			
		||||
                // Exceeding that probably wastes space. Reducing makes typing harder.
 | 
			
		||||
                const IDEAL_TARGET_SIZE: Rational<Millimeter> = Rational {
 | 
			
		||||
                    numerator: Millimeter(948),
 | 
			
		||||
                    denominator: 100,
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                // TODO: calculate based on selected layout
 | 
			
		||||
                const ROW_COUNT: u32 = 4;
 | 
			
		||||
 | 
			
		||||
                let height = {
 | 
			
		||||
                    if px_size.width > px_size.height {
 | 
			
		||||
                        px_size.width / 5
 | 
			
		||||
                    } else {
 | 
			
		||||
                        let abstract_width
 | 
			
		||||
                            = PixelSize {
 | 
			
		||||
                                scale_factor: output.scale as u32,
 | 
			
		||||
                                pixels: px_size.width,
 | 
			
		||||
                            } 
 | 
			
		||||
                            .as_scaled_ceiling();
 | 
			
		||||
                        if (abstract_width < 540) && (px_size.width > 0) {
 | 
			
		||||
                            px_size.width * 7 / 12 // to match 360×210
 | 
			
		||||
                    let ideal_height = IDEAL_TARGET_SIZE * ROW_COUNT as i32;
 | 
			
		||||
                    let ideal_height_px = (ideal_height * density).ceil().0 as u32;
 | 
			
		||||
 | 
			
		||||
                    // Reduce height to match what the layout can fill.
 | 
			
		||||
                    // For this, we need to guess if normal or wide will be picked up.
 | 
			
		||||
                    // This must match `eek_gtk_keyboard.c::get_type`.
 | 
			
		||||
                    // TODO: query layout database and choose one directly
 | 
			
		||||
                    let abstract_width
 | 
			
		||||
                        = PixelSize {
 | 
			
		||||
                            scale_factor: output.scale as u32,
 | 
			
		||||
                            pixels: px_size.width,
 | 
			
		||||
                        } 
 | 
			
		||||
                        .as_scaled_ceiling();
 | 
			
		||||
 | 
			
		||||
                    let height_as_widths = {
 | 
			
		||||
                        if abstract_width < 540 {
 | 
			
		||||
                            // Normal
 | 
			
		||||
                            Rational {
 | 
			
		||||
                                numerator: 210,
 | 
			
		||||
                                denominator: 360,
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            // Here we switch to wide layout, less height needed
 | 
			
		||||
                            px_size.width * 7 / 22
 | 
			
		||||
                            // Wide
 | 
			
		||||
                            Rational {
 | 
			
		||||
                                numerator: 172,
 | 
			
		||||
                                denominator: 540,
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    };
 | 
			
		||||
                    cmp::min(
 | 
			
		||||
                        ideal_height_px,
 | 
			
		||||
                        (height_as_widths * px_size.width as i32).ceil() as u32,
 | 
			
		||||
                    )
 | 
			
		||||
                };
 | 
			
		||||
                PixelSize {
 | 
			
		||||
                    scale_factor: output.scale as u32,
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										47
									
								
								src/util.rs
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								src/util.rs
									
									
									
									
									
								
							@ -7,6 +7,7 @@ use ::float_ord::FloatOrd;
 | 
			
		||||
use std::borrow::Borrow;
 | 
			
		||||
use std::hash::{ Hash, Hasher };
 | 
			
		||||
use std::iter::FromIterator;
 | 
			
		||||
use std::ops::Mul;
 | 
			
		||||
 | 
			
		||||
pub mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
@ -157,12 +158,54 @@ pub fn find_max_double<T, I, F>(iterator: I, get: F)
 | 
			
		||||
        .0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait DivCeil<Rhs = Self> {
 | 
			
		||||
    type Output;
 | 
			
		||||
    fn div_ceil(self, rhs: Rhs) -> Self::Output;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Newer Rust introduces this natively,
 | 
			
		||||
/// but we don't always have newer Rust.
 | 
			
		||||
impl DivCeil for i32 {
 | 
			
		||||
    type Output = Self;
 | 
			
		||||
    fn div_ceil(self, other: i32) -> Self::Output {
 | 
			
		||||
        let d = self / other;
 | 
			
		||||
        let m = self % other;
 | 
			
		||||
        if m == 0 { d } else { d + 1}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy)]
 | 
			
		||||
pub struct Rational {
 | 
			
		||||
    pub numerator: i32,
 | 
			
		||||
pub struct Rational<T> {
 | 
			
		||||
    pub numerator: T,
 | 
			
		||||
    pub denominator: u32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<U, T: DivCeil<i32, Output=U>> Rational<T> {
 | 
			
		||||
    pub fn ceil(self) -> U {
 | 
			
		||||
        self.numerator.div_ceil(self.denominator as i32)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: Mul<i32, Output=T>> Mul<i32> for Rational<T> {
 | 
			
		||||
    type Output = Self;
 | 
			
		||||
    fn mul(self, m: i32) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            numerator: self.numerator * m,
 | 
			
		||||
            denominator: self.denominator,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<U, T: Mul<U, Output=T>> Mul<Rational<U>> for Rational<T> {
 | 
			
		||||
    type Output = Self;
 | 
			
		||||
    fn mul(self, m: Rational<U>) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            numerator: self.numerator * m.numerator,
 | 
			
		||||
            denominator: self.denominator * m.denominator,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Compares pointers but not internal values of Rc
 | 
			
		||||
pub struct Pointer<T>(pub Rc<T>);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user