layout: Make it possible to opt out of latching per-key
This commit is contained in:
@ -29,6 +29,9 @@ pub enum Action {
|
|||||||
lock: View,
|
lock: View,
|
||||||
/// When unlocked by pressing it or emitting a key
|
/// When unlocked by pressing it or emitting a key
|
||||||
unlock: View,
|
unlock: View,
|
||||||
|
/// Whether key has a latched state
|
||||||
|
/// that pops when another key is pressed.
|
||||||
|
latches: bool,
|
||||||
},
|
},
|
||||||
/// Hold this modifier for as long as the button is pressed
|
/// Hold this modifier for as long as the button is pressed
|
||||||
ApplyModifier(Modifier),
|
ApplyModifier(Modifier),
|
||||||
@ -48,14 +51,14 @@ pub enum Action {
|
|||||||
impl Action {
|
impl Action {
|
||||||
pub fn is_locked(&self, view_name: &str) -> bool {
|
pub fn is_locked(&self, view_name: &str) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Action::LockView { lock, unlock: _ } => lock == view_name,
|
Action::LockView { lock, unlock: _, latches: _ } => lock == view_name,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn is_active(&self, view_name: &str) -> bool {
|
pub fn is_active(&self, view_name: &str) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Action::SetView(view) => view == view_name,
|
Action::SetView(view) => view == view_name,
|
||||||
Action::LockView { lock, unlock: _ } => lock == view_name,
|
Action::LockView { lock, unlock: _, latches: _ } => lock == view_name,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
src/data.rs
10
src/data.rs
@ -266,7 +266,11 @@ struct ButtonMeta {
|
|||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
enum Action {
|
enum Action {
|
||||||
#[serde(rename="locking")]
|
#[serde(rename="locking")]
|
||||||
Locking { lock_view: String, unlock_view: String },
|
Locking {
|
||||||
|
lock_view: String,
|
||||||
|
unlock_view: String,
|
||||||
|
pops: Option<bool>,
|
||||||
|
},
|
||||||
#[serde(rename="set_view")]
|
#[serde(rename="set_view")]
|
||||||
SetView(String),
|
SetView(String),
|
||||||
#[serde(rename="show_prefs")]
|
#[serde(rename="show_prefs")]
|
||||||
@ -577,7 +581,8 @@ fn create_action<H: logging::Handler>(
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
SubmitData::Action(Action::Locking {
|
SubmitData::Action(Action::Locking {
|
||||||
lock_view, unlock_view
|
lock_view, unlock_view,
|
||||||
|
pops,
|
||||||
}) => ::action::Action::LockView {
|
}) => ::action::Action::LockView {
|
||||||
lock: filter_view_name(
|
lock: filter_view_name(
|
||||||
name,
|
name,
|
||||||
@ -591,6 +596,7 @@ fn create_action<H: logging::Handler>(
|
|||||||
&view_names,
|
&view_names,
|
||||||
warning_handler,
|
warning_handler,
|
||||||
),
|
),
|
||||||
|
latches: pops.unwrap_or(true),
|
||||||
},
|
},
|
||||||
SubmitData::Action(
|
SubmitData::Action(
|
||||||
Action::ShowPrefs
|
Action::ShowPrefs
|
||||||
|
|||||||
@ -830,14 +830,14 @@ impl Layout {
|
|||||||
fn process_action_for_view<'a>(
|
fn process_action_for_view<'a>(
|
||||||
action: &'a Action,
|
action: &'a Action,
|
||||||
current_view: &str,
|
current_view: &str,
|
||||||
latch: &LatchedState,
|
latched: &LatchedState,
|
||||||
) -> (ViewTransition<'a>, LatchedState) {
|
) -> (ViewTransition<'a>, LatchedState) {
|
||||||
match action {
|
match action {
|
||||||
Action::Submit { text: _, keys: _ }
|
Action::Submit { text: _, keys: _ }
|
||||||
| Action::Erase
|
| Action::Erase
|
||||||
| Action::ApplyModifier(_)
|
| Action::ApplyModifier(_)
|
||||||
=> {
|
=> {
|
||||||
let t = match latch {
|
let t = match latched {
|
||||||
LatchedState::FromView(_) => ViewTransition::UnlatchAll,
|
LatchedState::FromView(_) => ViewTransition::UnlatchAll,
|
||||||
LatchedState::Not => ViewTransition::NoChange,
|
LatchedState::Not => ViewTransition::NoChange,
|
||||||
};
|
};
|
||||||
@ -847,29 +847,32 @@ impl Layout {
|
|||||||
ViewTransition::ChangeTo(view),
|
ViewTransition::ChangeTo(view),
|
||||||
LatchedState::Not,
|
LatchedState::Not,
|
||||||
),
|
),
|
||||||
Action::LockView { lock, unlock } => {
|
Action::LockView { lock, unlock, latches } => {
|
||||||
use self::ViewTransition as VT;
|
use self::ViewTransition as VT;
|
||||||
let locked = action.is_locked(current_view);
|
let locked = action.is_locked(current_view);
|
||||||
match (locked, latch) {
|
match (locked, latched, latches) {
|
||||||
// Was unlocked, now make locked but latched.
|
// Was unlocked, now make locked but latched.
|
||||||
(false, LatchedState::Not) => (
|
(false, LatchedState::Not, true) => (
|
||||||
VT::ChangeTo(lock),
|
VT::ChangeTo(lock),
|
||||||
LatchedState::FromView(current_view.into()),
|
LatchedState::FromView(current_view.into()),
|
||||||
),
|
),
|
||||||
// Layout is latched for reason other than this button.
|
// Layout is latched for reason other than this button.
|
||||||
(false, LatchedState::FromView(view)) => (
|
(false, LatchedState::FromView(view), true) => (
|
||||||
VT::ChangeTo(lock),
|
VT::ChangeTo(lock),
|
||||||
LatchedState::FromView(view.clone()),
|
LatchedState::FromView(view.clone()),
|
||||||
),
|
),
|
||||||
// Was latched, now only locked.
|
// Was latched, now only locked.
|
||||||
(true, LatchedState::FromView(_))
|
(true, LatchedState::FromView(_), true)
|
||||||
=> (VT::NoChange, LatchedState::Not),
|
=> (VT::NoChange, LatchedState::Not),
|
||||||
|
// Was unlocked, can't latch so now make fully locked.
|
||||||
|
(false, _, false)
|
||||||
|
=> (VT::ChangeTo(lock), LatchedState::Not),
|
||||||
// Was locked, now make unlocked.
|
// Was locked, now make unlocked.
|
||||||
(true, LatchedState::Not)
|
(true, _, _)
|
||||||
=> (VT::ChangeTo(unlock), LatchedState::Not),
|
=> (VT::ChangeTo(unlock), LatchedState::Not),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => (ViewTransition::NoChange, latch.clone()),
|
_ => (ViewTransition::NoChange, latched.clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1128,6 +1131,7 @@ mod test {
|
|||||||
let action = Action::LockView {
|
let action = Action::LockView {
|
||||||
lock: "lock".into(),
|
lock: "lock".into(),
|
||||||
unlock: "unlock".into(),
|
unlock: "unlock".into(),
|
||||||
|
latches: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -1156,6 +1160,7 @@ mod test {
|
|||||||
let switch = Action::LockView {
|
let switch = Action::LockView {
|
||||||
lock: "locked".into(),
|
lock: "locked".into(),
|
||||||
unlock: "base".into(),
|
unlock: "base".into(),
|
||||||
|
latches: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
let submit = Action::Erase;
|
let submit = Action::Erase;
|
||||||
@ -1217,16 +1222,82 @@ mod test {
|
|||||||
assert_eq!(&layout.current_view, "base");
|
assert_eq!(&layout.current_view, "base");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn reverse_unlatch_layout() {
|
||||||
|
let switch = Action::LockView {
|
||||||
|
lock: "locked".into(),
|
||||||
|
unlock: "base".into(),
|
||||||
|
latches: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
let unswitch = Action::LockView {
|
||||||
|
lock: "locked".into(),
|
||||||
|
unlock: "unlocked".into(),
|
||||||
|
latches: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let submit = Action::Erase;
|
||||||
|
|
||||||
|
let view = View::new(vec![(
|
||||||
|
0.0,
|
||||||
|
Row::new(vec![
|
||||||
|
(
|
||||||
|
0.0,
|
||||||
|
make_button_with_state(
|
||||||
|
"switch".into(),
|
||||||
|
make_state_with_action(switch.clone())
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
1.0,
|
||||||
|
make_button_with_state(
|
||||||
|
"submit".into(),
|
||||||
|
make_state_with_action(submit.clone())
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
)]);
|
||||||
|
|
||||||
|
let mut layout = Layout {
|
||||||
|
current_view: "base".into(),
|
||||||
|
view_latched: LatchedState::Not,
|
||||||
|
keymaps: Vec::new(),
|
||||||
|
kind: ArrangementKind::Base,
|
||||||
|
pressed_keys: HashSet::new(),
|
||||||
|
margins: Margins {
|
||||||
|
top: 0.0,
|
||||||
|
left: 0.0,
|
||||||
|
right: 0.0,
|
||||||
|
bottom: 0.0,
|
||||||
|
},
|
||||||
|
views: hashmap! {
|
||||||
|
// Both can use the same structure.
|
||||||
|
// Switching doesn't depend on the view shape
|
||||||
|
// as long as the switching button is present.
|
||||||
|
"base".into() => (c::Point { x: 0.0, y: 0.0 }, view.clone()),
|
||||||
|
"locked".into() => (c::Point { x: 0.0, y: 0.0 }, view.clone()),
|
||||||
|
"unlocked".into() => (c::Point { x: 0.0, y: 0.0 }, view),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
layout.apply_view_transition(&switch);
|
||||||
|
assert_eq!(&layout.current_view, "locked");
|
||||||
|
layout.apply_view_transition(&unswitch);
|
||||||
|
assert_eq!(&layout.current_view, "unlocked");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn latch_twopop_layout() {
|
fn latch_twopop_layout() {
|
||||||
let switch = Action::LockView {
|
let switch = Action::LockView {
|
||||||
lock: "locked".into(),
|
lock: "locked".into(),
|
||||||
unlock: "base".into(),
|
unlock: "base".into(),
|
||||||
|
latches: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
let switch_again = Action::LockView {
|
let switch_again = Action::LockView {
|
||||||
lock: "ĄĘ".into(),
|
lock: "ĄĘ".into(),
|
||||||
unlock: "locked".into(),
|
unlock: "locked".into(),
|
||||||
|
latches: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
let submit = Action::Erase;
|
let submit = Action::Erase;
|
||||||
|
|||||||
Reference in New Issue
Block a user