state: Derive panel size from physical click target size
This commit is contained in:
@ -4,9 +4,11 @@
|
|||||||
|
|
||||||
/*! Managing Wayland outputs */
|
/*! Managing Wayland outputs */
|
||||||
|
|
||||||
|
use std::ops;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
use crate::event_loop;
|
use crate::event_loop;
|
||||||
use ::logging;
|
use ::logging;
|
||||||
|
use crate::util::DivCeil;
|
||||||
|
|
||||||
// traits
|
// traits
|
||||||
use ::logging::Warn;
|
use ::logging::Warn;
|
||||||
@ -319,6 +321,20 @@ pub struct Mode {
|
|||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Millimeter(pub i32);
|
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
|
/// All geometry parameters
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Geometry {
|
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;
|
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 {
|
match self {
|
||||||
OutputState {
|
OutputState {
|
||||||
current_mode: Some(Mode { width, height } ),
|
current_mode: Some(Mode { width, height } ),
|
||||||
geometry: Some(Geometry { transform, .. } ),
|
geometry: Some(Geometry { transform, .. } ),
|
||||||
scale: _,
|
scale: _,
|
||||||
} => Some(
|
} => Some(Self::transform_size(*width as u32, *height as u32, *transform)),
|
||||||
match transform {
|
OutputState {
|
||||||
Transform::Normal
|
current_mode: Some(Mode { width, height } ),
|
||||||
| Transform::Rotated180
|
..
|
||||||
| Transform::Flipped
|
} => Some(Size { width: *width as u32, height: *height as u32 } ),
|
||||||
| Transform::FlippedRotated180 => Size {
|
_ => None,
|
||||||
width: *width as u32,
|
}
|
||||||
height: *height as u32,
|
}
|
||||||
},
|
|
||||||
_ => Size {
|
/// Return physical dimensions adjusted for current transform
|
||||||
width: *height as u32,
|
pub fn get_physical_size(&self) -> Option<GSize<Option<Millimeter>>> {
|
||||||
height: *width as u32,
|
match self {
|
||||||
},
|
OutputState {
|
||||||
}
|
geometry: Some(Geometry { transform, phys_size } ),
|
||||||
),
|
..
|
||||||
|
} => Some(Self::transform_size(phys_size.width, phys_size.height, *transform)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
72
src/state.rs
72
src/state.rs
@ -9,7 +9,7 @@ use crate::animation;
|
|||||||
use crate::imservice::{ ContentHint, ContentPurpose };
|
use crate::imservice::{ ContentHint, ContentPurpose };
|
||||||
use crate::main::{ Commands, PanelCommand, PixelSize };
|
use crate::main::{ Commands, PanelCommand, PixelSize };
|
||||||
use crate::outputs;
|
use crate::outputs;
|
||||||
use crate::outputs::{OutputId, OutputState};
|
use crate::outputs::{Millimeter, OutputId, OutputState};
|
||||||
use crate::util::Rational;
|
use crate::util::Rational;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@ -242,23 +242,65 @@ impl Application {
|
|||||||
fn get_preferred_height(output: &OutputState) -> Option<PixelSize> {
|
fn get_preferred_height(output: &OutputState) -> Option<PixelSize> {
|
||||||
output.get_pixel_size()
|
output.get_pixel_size()
|
||||||
.map(|px_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 = {
|
let height = {
|
||||||
if px_size.width > px_size.height {
|
let ideal_height = IDEAL_TARGET_SIZE * ROW_COUNT as i32;
|
||||||
px_size.width / 5
|
let ideal_height_px = (ideal_height * density).ceil().0 as u32;
|
||||||
} else {
|
|
||||||
let abstract_width
|
// Reduce height to match what the layout can fill.
|
||||||
= PixelSize {
|
// For this, we need to guess if normal or wide will be picked up.
|
||||||
scale_factor: output.scale as u32,
|
// This must match `eek_gtk_keyboard.c::get_type`.
|
||||||
pixels: px_size.width,
|
// TODO: query layout database and choose one directly
|
||||||
}
|
let abstract_width
|
||||||
.as_scaled_ceiling();
|
= PixelSize {
|
||||||
if (abstract_width < 540) && (px_size.width > 0) {
|
scale_factor: output.scale as u32,
|
||||||
px_size.width * 7 / 12 // to match 360×210
|
pixels: px_size.width,
|
||||||
|
}
|
||||||
|
.as_scaled_ceiling();
|
||||||
|
|
||||||
|
let height_as_widths = {
|
||||||
|
if abstract_width < 540 {
|
||||||
|
// Normal
|
||||||
|
Rational {
|
||||||
|
numerator: 210,
|
||||||
|
denominator: 360,
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Here we switch to wide layout, less height needed
|
// Wide
|
||||||
px_size.width * 7 / 22
|
Rational {
|
||||||
|
numerator: 172,
|
||||||
|
denominator: 540,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
cmp::min(
|
||||||
|
ideal_height_px,
|
||||||
|
(height_as_widths * px_size.width as i32).ceil() as u32,
|
||||||
|
)
|
||||||
};
|
};
|
||||||
PixelSize {
|
PixelSize {
|
||||||
scale_factor: output.scale as u32,
|
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::borrow::Borrow;
|
||||||
use std::hash::{ Hash, Hasher };
|
use std::hash::{ Hash, Hasher };
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
|
use std::ops::Mul;
|
||||||
|
|
||||||
pub mod c {
|
pub mod c {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -157,12 +158,54 @@ pub fn find_max_double<T, I, F>(iterator: I, get: F)
|
|||||||
.0
|
.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)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Rational {
|
pub struct Rational<T> {
|
||||||
pub numerator: i32,
|
pub numerator: T,
|
||||||
pub denominator: u32,
|
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
|
/// Compares pointers but not internal values of Rc
|
||||||
pub struct Pointer<T>(pub Rc<T>);
|
pub struct Pointer<T>(pub Rc<T>);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user