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