layout: Split out static data
This will make it possible later to cache this data or compare for best size selection without hassle.
This commit is contained in:
@ -192,7 +192,7 @@ fn iter_layout_sources(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn load_layout_data(source: DataSource)
|
fn load_layout_data(source: DataSource)
|
||||||
-> Result<::layout::LayoutData, LoadError>
|
-> Result<::layout::LayoutParseData, LoadError>
|
||||||
{
|
{
|
||||||
let handler = logging::Print {};
|
let handler = logging::Print {};
|
||||||
match source {
|
match source {
|
||||||
@ -217,7 +217,7 @@ fn load_layout_data_with_fallback(
|
|||||||
kind: ArrangementKind,
|
kind: ArrangementKind,
|
||||||
purpose: ContentPurpose,
|
purpose: ContentPurpose,
|
||||||
overlay: Option<&str>,
|
overlay: Option<&str>,
|
||||||
) -> (ArrangementKind, layout::LayoutData) {
|
) -> (ArrangementKind, layout::LayoutParseData) {
|
||||||
|
|
||||||
// Build the path to the right keyboard layout subdirectory
|
// Build the path to the right keyboard layout subdirectory
|
||||||
let path = env::var_os("SQUEEKBOARD_KEYBOARDSDIR")
|
let path = env::var_os("SQUEEKBOARD_KEYBOARDSDIR")
|
||||||
|
|||||||
@ -157,7 +157,7 @@ impl Layout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn build<H: logging::Handler>(self, mut warning_handler: H)
|
pub fn build<H: logging::Handler>(self, mut warning_handler: H)
|
||||||
-> (Result<::layout::LayoutData, FormattingError>, H)
|
-> (Result<::layout::LayoutParseData, FormattingError>, H)
|
||||||
{
|
{
|
||||||
let button_names = self.views.values()
|
let button_names = self.views.values()
|
||||||
.flat_map(|rows| {
|
.flat_map(|rows| {
|
||||||
@ -279,7 +279,7 @@ impl Layout {
|
|||||||
};
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
Ok(::layout::LayoutData {
|
Ok(layout::LayoutParseData {
|
||||||
views: views,
|
views: views,
|
||||||
keymaps: keymaps.into_iter().map(|keymap_str|
|
keymaps: keymaps.into_iter().map(|keymap_str|
|
||||||
CString::new(keymap_str)
|
CString::new(keymap_str)
|
||||||
|
|||||||
160
src/layout.rs
160
src/layout.rs
@ -182,7 +182,7 @@ pub mod c {
|
|||||||
allocation_height: f64,
|
allocation_height: f64,
|
||||||
) -> Transformation {
|
) -> Transformation {
|
||||||
let layout = unsafe { &*layout };
|
let layout = unsafe { &*layout };
|
||||||
layout.calculate_transformation(Size {
|
layout.shape.calculate_transformation(Size {
|
||||||
width: allocation_width,
|
width: allocation_width,
|
||||||
height: allocation_height,
|
height: allocation_height,
|
||||||
})
|
})
|
||||||
@ -192,14 +192,14 @@ pub mod c {
|
|||||||
pub extern "C"
|
pub extern "C"
|
||||||
fn squeek_layout_get_kind(layout: *const Layout) -> u32 {
|
fn squeek_layout_get_kind(layout: *const Layout) -> u32 {
|
||||||
let layout = unsafe { &*layout };
|
let layout = unsafe { &*layout };
|
||||||
layout.kind.clone() as u32
|
layout.shape.kind.clone() as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C"
|
pub extern "C"
|
||||||
fn squeek_layout_get_purpose(layout: *const Layout) -> u32 {
|
fn squeek_layout_get_purpose(layout: *const Layout) -> u32 {
|
||||||
let layout = unsafe { &*layout };
|
let layout = unsafe { &*layout };
|
||||||
layout.purpose.clone() as u32
|
layout.shape.purpose.clone() as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -654,28 +654,15 @@ pub enum LatchedState {
|
|||||||
Not,
|
Not,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: split into sth like
|
/// Associates the state of a layout with its definition.
|
||||||
// Arrangement (views) + details (keymap) + State (keys)
|
/// Contains everything necessary to present this layout to the user
|
||||||
/// State of the UI, contains the backend as well
|
/// and to determine its reactions to inputs.
|
||||||
pub struct Layout {
|
pub struct Layout {
|
||||||
pub state: LayoutState,
|
pub state: LayoutState,
|
||||||
|
pub shape: LayoutData,
|
||||||
pub margins: Margins,
|
|
||||||
pub kind: ArrangementKind,
|
|
||||||
pub purpose: ContentPurpose,
|
|
||||||
|
|
||||||
// Views own the actual buttons which have state
|
|
||||||
// Maybe they should own UI only,
|
|
||||||
// and keys should be owned by a dedicated non-UI-State?
|
|
||||||
/// Point is the offset within the layout
|
|
||||||
pub views: HashMap<String, (c::Point, View)>,
|
|
||||||
|
|
||||||
// Non-UI stuff
|
|
||||||
/// xkb keymaps applicable to the contained keys. Unchangeable
|
|
||||||
pub keymaps: Vec<CString>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Changeable state that can't be derived from the definition of the layout
|
/// Changeable state that can't be derived from the definition of the layout.
|
||||||
pub struct LayoutState {
|
pub struct LayoutState {
|
||||||
pub current_view: String,
|
pub current_view: String,
|
||||||
|
|
||||||
@ -694,13 +681,31 @@ pub struct LayoutState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A builder structure for picking up layout data from storage
|
/// A builder structure for picking up layout data from storage
|
||||||
pub struct LayoutData {
|
pub struct LayoutParseData {
|
||||||
/// Point is the offset within layout
|
/// Point is the offset within layout
|
||||||
pub views: HashMap<String, (c::Point, View)>,
|
pub views: HashMap<String, (c::Point, View)>,
|
||||||
|
/// xkb keymaps applicable to the contained keys
|
||||||
pub keymaps: Vec<CString>,
|
pub keymaps: Vec<CString>,
|
||||||
pub margins: Margins,
|
pub margins: Margins,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Static, cacheable information for the layout
|
||||||
|
pub struct LayoutData {
|
||||||
|
pub margins: Margins,
|
||||||
|
pub kind: ArrangementKind,
|
||||||
|
pub purpose: ContentPurpose,
|
||||||
|
|
||||||
|
// Views own the actual buttons which have state
|
||||||
|
// Maybe they should own UI only,
|
||||||
|
// and keys should be owned by a dedicated non-UI-State?
|
||||||
|
/// Point is the offset within the layout
|
||||||
|
pub views: HashMap<String, (c::Point, View)>,
|
||||||
|
|
||||||
|
// Non-UI stuff
|
||||||
|
/// xkb keymaps applicable to the contained keys. Unchangeable
|
||||||
|
pub keymaps: Vec<CString>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct NoSuchView;
|
struct NoSuchView;
|
||||||
|
|
||||||
@ -710,50 +715,8 @@ impl fmt::Display for NoSuchView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unfortunately, changes are not atomic due to mutability :(
|
|
||||||
// An error will not be recoverable
|
|
||||||
// The usage of &mut on Rc<RefCell<KeyState>> doesn't mean anything special.
|
|
||||||
// Cloning could also be used.
|
|
||||||
impl Layout {
|
|
||||||
pub fn new(data: LayoutData, kind: ArrangementKind, purpose: ContentPurpose) -> Layout {
|
|
||||||
Layout {
|
|
||||||
kind,
|
|
||||||
views: data.views,
|
|
||||||
keymaps: data.keymaps,
|
|
||||||
margins: data.margins,
|
|
||||||
purpose,
|
|
||||||
state: LayoutState {
|
|
||||||
current_view: "base".to_owned(),
|
|
||||||
view_latched: LatchedState::Not,
|
|
||||||
pressed_keys: HashSet::new(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_current_view_position(&self) -> &(c::Point, View) {
|
|
||||||
&self.views
|
|
||||||
.get(&self.state.current_view).expect("Selected nonexistent view")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_current_view(&self) -> &View {
|
|
||||||
&self.views.get(&self.state.current_view).expect("Selected nonexistent view").1
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_view(&mut self, view: String) -> Result<(), NoSuchView> {
|
|
||||||
if self.views.contains_key(&view) {
|
|
||||||
self.state.current_view = view;
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(NoSuchView)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Layout is passed around mutably,
|
|
||||||
// so better keep the field away from direct access.
|
|
||||||
pub fn get_view_latched(&self) -> &LatchedState {
|
|
||||||
&self.state.view_latched
|
|
||||||
}
|
|
||||||
|
|
||||||
|
impl LayoutData {
|
||||||
/// Calculates size without margins
|
/// Calculates size without margins
|
||||||
fn calculate_inner_size(&self) -> Size {
|
fn calculate_inner_size(&self) -> Size {
|
||||||
View::calculate_super_size(
|
View::calculate_super_size(
|
||||||
@ -797,6 +760,53 @@ impl Layout {
|
|||||||
scale_y: 1.0,
|
scale_y: 1.0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unfortunately, changes are not atomic due to mutability :(
|
||||||
|
// An error will not be recoverable
|
||||||
|
// The usage of &mut on Rc<RefCell<KeyState>> doesn't mean anything special.
|
||||||
|
// Cloning could also be used.
|
||||||
|
impl Layout {
|
||||||
|
pub fn new(data: LayoutParseData, kind: ArrangementKind, purpose: ContentPurpose) -> Layout {
|
||||||
|
Layout {
|
||||||
|
shape: LayoutData {
|
||||||
|
kind,
|
||||||
|
views: data.views,
|
||||||
|
keymaps: data.keymaps,
|
||||||
|
margins: data.margins,
|
||||||
|
purpose,
|
||||||
|
},
|
||||||
|
state: LayoutState {
|
||||||
|
current_view: "base".to_owned(),
|
||||||
|
view_latched: LatchedState::Not,
|
||||||
|
pressed_keys: HashSet::new(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_current_view_position(&self) -> &(c::Point, View) {
|
||||||
|
&self.shape.views
|
||||||
|
.get(&self.state.current_view).expect("Selected nonexistent view")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_current_view(&self) -> &View {
|
||||||
|
&self.shape.views.get(&self.state.current_view).expect("Selected nonexistent view").1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_view(&mut self, view: String) -> Result<(), NoSuchView> {
|
||||||
|
if self.shape.views.contains_key(&view) {
|
||||||
|
self.state.current_view = view;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(NoSuchView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layout is passed around mutably,
|
||||||
|
// so better keep the field away from direct access.
|
||||||
|
pub fn get_view_latched(&self) -> &LatchedState {
|
||||||
|
&self.state.view_latched
|
||||||
|
}
|
||||||
|
|
||||||
fn find_button_by_position(&self, point: c::Point) -> Option<ButtonPlace> {
|
fn find_button_by_position(&self, point: c::Point) -> Option<ButtonPlace> {
|
||||||
let (offset, layout) = self.get_current_view_position();
|
let (offset, layout) = self.get_current_view_position();
|
||||||
@ -1232,6 +1242,7 @@ mod test {
|
|||||||
view_latched: LatchedState::Not,
|
view_latched: LatchedState::Not,
|
||||||
pressed_keys: HashSet::new(),
|
pressed_keys: HashSet::new(),
|
||||||
},
|
},
|
||||||
|
shape: LayoutData {
|
||||||
keymaps: Vec::new(),
|
keymaps: Vec::new(),
|
||||||
kind: ArrangementKind::Base,
|
kind: ArrangementKind::Base,
|
||||||
margins: Margins {
|
margins: Margins {
|
||||||
@ -1248,6 +1259,7 @@ mod test {
|
|||||||
"locked".into() => (c::Point { x: 0.0, y: 0.0 }, view),
|
"locked".into() => (c::Point { x: 0.0, y: 0.0 }, view),
|
||||||
},
|
},
|
||||||
purpose: ContentPurpose::Normal,
|
purpose: ContentPurpose::Normal,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Basic cycle
|
// Basic cycle
|
||||||
@ -1310,6 +1322,7 @@ mod test {
|
|||||||
view_latched: LatchedState::Not,
|
view_latched: LatchedState::Not,
|
||||||
pressed_keys: HashSet::new(),
|
pressed_keys: HashSet::new(),
|
||||||
},
|
},
|
||||||
|
shape: LayoutData {
|
||||||
keymaps: Vec::new(),
|
keymaps: Vec::new(),
|
||||||
kind: ArrangementKind::Base,
|
kind: ArrangementKind::Base,
|
||||||
margins: Margins {
|
margins: Margins {
|
||||||
@ -1327,6 +1340,7 @@ mod test {
|
|||||||
"unlocked".into() => (c::Point { x: 0.0, y: 0.0 }, view),
|
"unlocked".into() => (c::Point { x: 0.0, y: 0.0 }, view),
|
||||||
},
|
},
|
||||||
purpose: ContentPurpose::Normal,
|
purpose: ContentPurpose::Normal,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
layout.apply_view_transition(&switch);
|
layout.apply_view_transition(&switch);
|
||||||
@ -1379,6 +1393,7 @@ mod test {
|
|||||||
view_latched: LatchedState::Not,
|
view_latched: LatchedState::Not,
|
||||||
pressed_keys: HashSet::new(),
|
pressed_keys: HashSet::new(),
|
||||||
},
|
},
|
||||||
|
shape: LayoutData {
|
||||||
keymaps: Vec::new(),
|
keymaps: Vec::new(),
|
||||||
kind: ArrangementKind::Base,
|
kind: ArrangementKind::Base,
|
||||||
margins: Margins {
|
margins: Margins {
|
||||||
@ -1396,6 +1411,7 @@ mod test {
|
|||||||
"ĄĘ".into() => (c::Point { x: 0.0, y: 0.0 }, view),
|
"ĄĘ".into() => (c::Point { x: 0.0, y: 0.0 }, view),
|
||||||
},
|
},
|
||||||
purpose: ContentPurpose::Normal,
|
purpose: ContentPurpose::Normal,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Latch twice, then Ąto-unlatch across 2 levels
|
// Latch twice, then Ąto-unlatch across 2 levels
|
||||||
@ -1480,12 +1496,7 @@ mod test {
|
|||||||
)]),
|
)]),
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
let layout = Layout {
|
let layout = LayoutData {
|
||||||
state: LayoutState {
|
|
||||||
current_view: String::new(),
|
|
||||||
view_latched: LatchedState::Not,
|
|
||||||
pressed_keys: HashSet::new(),
|
|
||||||
},
|
|
||||||
keymaps: Vec::new(),
|
keymaps: Vec::new(),
|
||||||
kind: ArrangementKind::Base,
|
kind: ArrangementKind::Base,
|
||||||
// Lots of bottom margin
|
// Lots of bottom margin
|
||||||
@ -1535,12 +1546,7 @@ mod test {
|
|||||||
)]),
|
)]),
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
let layout = Layout {
|
let layout = LayoutData {
|
||||||
state: LayoutState {
|
|
||||||
current_view: String::new(),
|
|
||||||
view_latched: LatchedState::Not,
|
|
||||||
pressed_keys: HashSet::new(),
|
|
||||||
},
|
|
||||||
keymaps: Vec::new(),
|
keymaps: Vec::new(),
|
||||||
kind: ArrangementKind::Base,
|
kind: ArrangementKind::Base,
|
||||||
margins: Margins {
|
margins: Margins {
|
||||||
|
|||||||
@ -52,7 +52,7 @@ pub mod c {
|
|||||||
let submission = submission.clone_ref();
|
let submission = submission.clone_ref();
|
||||||
let mut submission = submission.borrow_mut();
|
let mut submission = submission.borrow_mut();
|
||||||
let layout = unsafe { &*layout };
|
let layout = unsafe { &*layout };
|
||||||
submission.use_layout(layout, Timestamp(time));
|
submission.use_layout(&layout.shape, Timestamp(time));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -303,7 +303,7 @@ impl Submission {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn use_layout(&mut self, layout: &layout::Layout, time: Timestamp) {
|
pub fn use_layout(&mut self, layout: &layout::LayoutData, time: Timestamp) {
|
||||||
self.keymap_fds = layout.keymaps.iter()
|
self.keymap_fds = layout.keymaps.iter()
|
||||||
.map(|keymap_str| vkeyboard::c::KeyMap::from_cstr(
|
.map(|keymap_str| vkeyboard::c::KeyMap::from_cstr(
|
||||||
keymap_str.as_c_str()
|
keymap_str.as_c_str()
|
||||||
|
|||||||
Reference in New Issue
Block a user