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:
Dorota Czaplejewicz
2022-06-03 17:27:47 +00:00
parent 590cd71f49
commit b634e2bfa4
3 changed files with 120 additions and 68 deletions

View File

@ -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,61 +355,91 @@ 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;
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();
// 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 {
// Wide
Rational {
numerator: 172,
denominator: 540,
}
let (arrangement, height_as_widths) = {
if abstract_width < 540 {(
ArrangementKind::Base,
Rational {
numerator: 210,
denominator: 360,
},
)} 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),
}
);
(
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,
(_, visibility::State::ForcedVisible) => visible,
@ -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 {
scale_factor: 2,
pixels: 420,
}),
Some((
PixelSize {
scale_factor: 2,
pixels: 420,
},
ArrangementKind::Base,
)),
);
}
}