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