state: Decide panel arrangement
Combines arrangement with layout to get panel contents as outcome. Includes some path syntax changes for 2018 compatibility.
This commit is contained in:
@ -8,16 +8,26 @@ use std::time::Duration;
|
||||
|
||||
use crate::outputs::OutputId;
|
||||
use crate::panel::PixelSize;
|
||||
use crate::layout::ArrangementKind;
|
||||
|
||||
/// The keyboard should hide after this has elapsed to prevent flickering.
|
||||
pub const HIDING_TIMEOUT: Duration = Duration::from_millis(200);
|
||||
|
||||
/// Panel contents
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
pub struct Contents {
|
||||
pub name: String,
|
||||
pub kind: ArrangementKind,
|
||||
pub overlay_name: Option<String>,
|
||||
}
|
||||
|
||||
/// The outwardly visible state of visibility
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub enum Outcome {
|
||||
Visible {
|
||||
output: OutputId,
|
||||
height: PixelSize,
|
||||
contents: Contents,
|
||||
},
|
||||
Hidden,
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ use std::convert::TryFrom;
|
||||
use super::{ Error, LoadError };
|
||||
use super::parsing;
|
||||
|
||||
use crate::layout;
|
||||
use ::layout::ArrangementKind;
|
||||
use ::logging;
|
||||
use ::util::c::as_str;
|
||||
@ -33,8 +34,10 @@ pub mod c {
|
||||
name: *const c_char, // name of the keyboard
|
||||
type_: u32, // type like Wide
|
||||
variant: u32, // purpose variant like numeric, terminal...
|
||||
overlay: *const c_char, // the overlay (looking for "terminal")
|
||||
) -> *mut ::layout::Layout {
|
||||
// Overlay forces a variant other than specified
|
||||
// (typically "terminal", "emoji")
|
||||
overlay: *const c_char,
|
||||
) -> *mut layout::Layout {
|
||||
let type_ = match type_ {
|
||||
0 => ArrangementKind::Base,
|
||||
1 => ArrangementKind::Wide,
|
||||
@ -60,8 +63,10 @@ pub mod c {
|
||||
other => Some(other),
|
||||
};
|
||||
|
||||
dbg!(&name, type_, variant, overlay_str);
|
||||
|
||||
let (kind, layout) = load_layout_data_with_fallback(&name, type_, variant, overlay_str);
|
||||
let layout = ::layout::Layout::new(layout, kind, variant);
|
||||
let layout = layout::Layout::new(layout, kind, variant);
|
||||
Box::into_raw(Box::new(layout))
|
||||
}
|
||||
}
|
||||
@ -265,7 +270,7 @@ fn load_layout_data_with_fallback(
|
||||
kind: ArrangementKind,
|
||||
purpose: ContentPurpose,
|
||||
overlay: Option<&str>,
|
||||
) -> (ArrangementKind, ::layout::LayoutData) {
|
||||
) -> (ArrangementKind, layout::LayoutData) {
|
||||
|
||||
// Build the path to the right keyboard layout subdirectory
|
||||
let path = env::var_os("SQUEEKBOARD_KEYBOARDSDIR")
|
||||
|
||||
115
src/state.rs
115
src/state.rs
@ -8,6 +8,7 @@
|
||||
use crate::animation;
|
||||
use crate::debug;
|
||||
use crate::imservice::{ ContentHint, ContentPurpose };
|
||||
use crate::layout::ArrangementKind;
|
||||
use crate::main::Commands;
|
||||
use crate::outputs;
|
||||
use crate::outputs::{Millimeter, OutputId, OutputState};
|
||||
@ -113,9 +114,8 @@ pub mod visibility {
|
||||
/// The outwardly visible state.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Outcome {
|
||||
pub visibility: animation::Outcome,
|
||||
pub panel: animation::Outcome,
|
||||
pub im: InputMethod,
|
||||
pub layout: LayoutChoice,
|
||||
}
|
||||
|
||||
impl Outcome {
|
||||
@ -127,13 +127,13 @@ impl Outcome {
|
||||
pub fn get_commands_to_reach(&self, new_state: &Self) -> Commands {
|
||||
let layout_hint_set = match new_state {
|
||||
Outcome {
|
||||
visibility: animation::Outcome::Visible{..},
|
||||
panel: animation::Outcome::Visible{..},
|
||||
im: InputMethod::Active(hints),
|
||||
..
|
||||
} => Some(hints.clone()),
|
||||
|
||||
Outcome {
|
||||
visibility: animation::Outcome::Visible{..},
|
||||
panel: animation::Outcome::Visible{..},
|
||||
im: InputMethod::InactiveSince(_),
|
||||
..
|
||||
} => Some(InputMethodDetails {
|
||||
@ -142,13 +142,13 @@ impl Outcome {
|
||||
}),
|
||||
|
||||
Outcome {
|
||||
visibility: animation::Outcome::Hidden,
|
||||
panel: animation::Outcome::Hidden,
|
||||
..
|
||||
} => None,
|
||||
};
|
||||
// FIXME: handle switching outputs
|
||||
let (dbus_visible_set, panel_visibility) = match new_state.visibility {
|
||||
animation::Outcome::Visible{output, height}
|
||||
let (dbus_visible_set, panel_visibility) = match new_state.panel {
|
||||
animation::Outcome::Visible{output, height, ..}
|
||||
=> (Some(true), Some(panel::Command::Show{output, height})),
|
||||
animation::Outcome::Hidden => (Some(false), Some(panel::Command::Hide)),
|
||||
};
|
||||
@ -325,7 +325,9 @@ Outcome:
|
||||
state
|
||||
}
|
||||
|
||||
fn get_preferred_height(output: &OutputState) -> Option<PixelSize> {
|
||||
fn get_preferred_height_and_arrangement(output: &OutputState)
|
||||
-> Option<(PixelSize, ArrangementKind)>
|
||||
{
|
||||
output.get_pixel_size()
|
||||
.map(|px_size| {
|
||||
// Assume isotropy.
|
||||
@ -353,7 +355,6 @@ Outcome:
|
||||
// TODO: calculate based on selected layout
|
||||
const ROW_COUNT: u32 = 4;
|
||||
|
||||
let height = {
|
||||
let ideal_height = IDEAL_TARGET_SIZE * ROW_COUNT as i32;
|
||||
let ideal_height_px = (ideal_height * density).ceil().0 as u32;
|
||||
|
||||
@ -368,45 +369,76 @@ Outcome:
|
||||
}
|
||||
.as_scaled_ceiling();
|
||||
|
||||
let height_as_widths = {
|
||||
if abstract_width < 540 {
|
||||
// Normal
|
||||
let (arrangement, height_as_widths) = {
|
||||
if abstract_width < 540 {(
|
||||
ArrangementKind::Base,
|
||||
Rational {
|
||||
numerator: 210,
|
||||
denominator: 360,
|
||||
}
|
||||
} else {
|
||||
// Wide
|
||||
},
|
||||
)} else {(
|
||||
ArrangementKind::Wide,
|
||||
Rational {
|
||||
numerator: 172,
|
||||
denominator: 540,
|
||||
}
|
||||
}
|
||||
)}
|
||||
};
|
||||
cmp::min(
|
||||
|
||||
let height
|
||||
= cmp::min(
|
||||
ideal_height_px,
|
||||
(height_as_widths * px_size.width as i32).ceil() as u32,
|
||||
)
|
||||
};
|
||||
);
|
||||
|
||||
(
|
||||
PixelSize {
|
||||
scale_factor: output.scale as u32,
|
||||
pixels: cmp::min(height, px_size.height / 2),
|
||||
}
|
||||
},
|
||||
arrangement,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns layout name, overlay name
|
||||
fn get_layout_names(&self) -> (String, Option<String>) {
|
||||
(
|
||||
String::from(match &self.overlay_layout {
|
||||
Some(popover::LayoutId::System { name, .. }) => name,
|
||||
_ => &self.layout_choice.name,
|
||||
}),
|
||||
match &self.overlay_layout {
|
||||
Some(popover::LayoutId::Local(name)) => Some(name.clone()),
|
||||
_ => None,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_outcome(&self, now: Instant) -> Outcome {
|
||||
// FIXME: include physical keyboard presence
|
||||
Outcome {
|
||||
visibility: match self.preferred_output {
|
||||
panel: match self.preferred_output {
|
||||
None => animation::Outcome::Hidden,
|
||||
Some(output) => {
|
||||
// Hoping that this will get optimized out on branches not using `visible`.
|
||||
let height = Self::get_preferred_height(self.outputs.get(&output).unwrap())
|
||||
.unwrap_or(PixelSize{pixels: 0, scale_factor: 1});
|
||||
let (height, arrangement) = Self::get_preferred_height_and_arrangement(self.outputs.get(&output).unwrap())
|
||||
.unwrap_or((
|
||||
PixelSize{pixels: 0, scale_factor: 1},
|
||||
ArrangementKind::Base,
|
||||
));
|
||||
let (layout_name, overlay) = self.get_layout_names();
|
||||
|
||||
// TODO: Instead of setting size to 0 when the output is invalid,
|
||||
// simply go invisible.
|
||||
let visible = animation::Outcome::Visible{ output, height };
|
||||
let visible = animation::Outcome::Visible{
|
||||
output,
|
||||
height,
|
||||
contents: animation::Contents {
|
||||
kind: arrangement,
|
||||
name: layout_name,
|
||||
overlay_name: overlay,
|
||||
}
|
||||
};
|
||||
|
||||
match (self.physical_keyboard, self.visibility_override) {
|
||||
(_, visibility::State::ForcedHidden) => animation::Outcome::Hidden,
|
||||
@ -423,7 +455,6 @@ Outcome:
|
||||
}
|
||||
},
|
||||
im: self.im.clone(),
|
||||
layout: self.layout_choice.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -499,7 +530,7 @@ pub mod test {
|
||||
for _i in 0..100 {
|
||||
now += Duration::from_millis(1);
|
||||
assert_matches!(
|
||||
state.get_outcome(now).visibility,
|
||||
state.get_outcome(now).panel,
|
||||
animation::Outcome::Visible{..},
|
||||
"Hidden when it should remain visible: {:?}",
|
||||
now.saturating_duration_since(start),
|
||||
@ -508,7 +539,10 @@ pub mod test {
|
||||
|
||||
let state = state.apply_event(Event::InputMethod(InputMethod::Active(imdetails_new())), now);
|
||||
|
||||
assert_matches!(state.get_outcome(now).visibility, animation::Outcome::Visible{..});
|
||||
assert_matches!(
|
||||
state.get_outcome(now).panel,
|
||||
animation::Outcome::Visible{..}
|
||||
);
|
||||
}
|
||||
|
||||
/// Make sure that hiding works when input method goes away
|
||||
@ -525,7 +559,7 @@ pub mod test {
|
||||
|
||||
let state = state.apply_event(Event::InputMethod(InputMethod::InactiveSince(now)), now);
|
||||
|
||||
while let animation::Outcome::Visible{..} = state.get_outcome(now).visibility {
|
||||
while let animation::Outcome::Visible{..} = state.get_outcome(now).panel {
|
||||
now += Duration::from_millis(1);
|
||||
assert!(
|
||||
now < start + Duration::from_millis(250),
|
||||
@ -555,7 +589,7 @@ pub mod test {
|
||||
let state = state.apply_event(Event::InputMethod(InputMethod::Active(imdetails_new())), now);
|
||||
let state = state.apply_event(Event::InputMethod(InputMethod::InactiveSince(now)), now);
|
||||
|
||||
while let animation::Outcome::Visible{..} = state.get_outcome(now).visibility {
|
||||
while let animation::Outcome::Visible{..} = state.get_outcome(now).panel {
|
||||
now += Duration::from_millis(1);
|
||||
assert!(
|
||||
now < start + Duration::from_millis(250),
|
||||
@ -568,7 +602,7 @@ pub mod test {
|
||||
for _i in 0..1000 {
|
||||
now += Duration::from_millis(1);
|
||||
assert_eq!(
|
||||
state.get_outcome(now).visibility,
|
||||
state.get_outcome(now).panel,
|
||||
animation::Outcome::Hidden,
|
||||
"Appeared unnecessarily: {:?}",
|
||||
now.saturating_duration_since(start),
|
||||
@ -590,7 +624,7 @@ pub mod test {
|
||||
|
||||
let state = state.apply_event(Event::Visibility(visibility::Event::ForceVisible), now);
|
||||
assert_matches!(
|
||||
state.get_outcome(now).visibility,
|
||||
state.get_outcome(now).panel,
|
||||
animation::Outcome::Visible{..},
|
||||
"Failed to show: {:?}",
|
||||
now.saturating_duration_since(start),
|
||||
@ -603,7 +637,7 @@ pub mod test {
|
||||
now += Duration::from_secs(1);
|
||||
|
||||
assert_eq!(
|
||||
state.get_outcome(now).visibility,
|
||||
state.get_outcome(now).panel,
|
||||
animation::Outcome::Hidden,
|
||||
"Failed to release forced visibility: {:?}",
|
||||
now.saturating_duration_since(start),
|
||||
@ -624,7 +658,7 @@ pub mod test {
|
||||
|
||||
let state = state.apply_event(Event::PhysicalKeyboard(Presence::Present), now);
|
||||
assert_eq!(
|
||||
state.get_outcome(now).visibility,
|
||||
state.get_outcome(now).panel,
|
||||
animation::Outcome::Hidden,
|
||||
"Failed to hide: {:?}",
|
||||
now.saturating_duration_since(start),
|
||||
@ -636,7 +670,7 @@ pub mod test {
|
||||
let state = state.apply_event(Event::InputMethod(InputMethod::Active(imdetails_new())), now);
|
||||
|
||||
assert_eq!(
|
||||
state.get_outcome(now).visibility,
|
||||
state.get_outcome(now).panel,
|
||||
animation::Outcome::Hidden,
|
||||
"Failed to remain hidden: {:?}",
|
||||
now.saturating_duration_since(start),
|
||||
@ -646,7 +680,7 @@ pub mod test {
|
||||
let state = state.apply_event(Event::PhysicalKeyboard(Presence::Missing), now);
|
||||
|
||||
assert_matches!(
|
||||
state.get_outcome(now).visibility,
|
||||
state.get_outcome(now).panel,
|
||||
animation::Outcome::Visible{..},
|
||||
"Failed to appear: {:?}",
|
||||
now.saturating_duration_since(start),
|
||||
@ -658,7 +692,7 @@ pub mod test {
|
||||
fn size_l5() {
|
||||
use crate::outputs::{Mode, Geometry, c, Size};
|
||||
assert_eq!(
|
||||
Application::get_preferred_height(&OutputState {
|
||||
Application::get_preferred_height_and_arrangement(&OutputState {
|
||||
current_mode: Some(Mode {
|
||||
width: 720,
|
||||
height: 1440,
|
||||
@ -672,10 +706,13 @@ pub mod test {
|
||||
}),
|
||||
scale: 2,
|
||||
}),
|
||||
Some(PixelSize {
|
||||
Some((
|
||||
PixelSize {
|
||||
scale_factor: 2,
|
||||
pixels: 420,
|
||||
}),
|
||||
},
|
||||
ArrangementKind::Base,
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user