mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2024-12-26 21:58:10 +01:00
Fix layout cycler
This commit is contained in:
parent
1680acc5e9
commit
f1c9d19708
3 changed files with 88 additions and 56 deletions
|
@ -1,7 +1,10 @@
|
|||
// You should glob import these to prevent your config from getting cluttered.
|
||||
use pinnacle_api::prelude::*;
|
||||
use pinnacle_api::*;
|
||||
|
||||
fn main() {
|
||||
// Connect to the Pinnacle server.
|
||||
// This needs to be called before you start calling any config functions.
|
||||
pinnacle_api::connect().unwrap();
|
||||
|
||||
let mod_key = Modifier::Ctrl;
|
||||
|
@ -10,8 +13,17 @@ fn main() {
|
|||
|
||||
process::set_env("MOZ_ENABLE_WAYLAND", "1");
|
||||
|
||||
// You must create a callback_vec to hold your callbacks.
|
||||
// Rust is not Lua, so it takes a bit more work to get captures working.
|
||||
//
|
||||
// Anything that requires a callback will also require a mut reference to this struct.
|
||||
//
|
||||
// Additionally, all callbacks also take in `&mut CallbackVec`.
|
||||
// This allows you to call functions that need callbacks within other callbacks.
|
||||
let mut callback_vec = CallbackVec::new();
|
||||
|
||||
// Keybinds.
|
||||
|
||||
input::mousebind(
|
||||
&[mod_key],
|
||||
MouseButton::Left,
|
||||
|
@ -102,19 +114,35 @@ fn main() {
|
|||
&mut callback_vec,
|
||||
);
|
||||
|
||||
// let layout_cycler = tag.layout_cycler(&[
|
||||
// Layout::MasterStack,
|
||||
// Layout::Dwindle,
|
||||
// Layout::Spiral,
|
||||
// Layout::CornerTopLeft,
|
||||
// Layout::CornerTopRight,
|
||||
// Layout::CornerBottomLeft,
|
||||
// Layout::CornerBottomRight,
|
||||
// ]);
|
||||
//
|
||||
// input.keybind(&[mod_key], xkbcommon::xkb::keysyms::KEY_space, move || {
|
||||
// layout_cycler.next(None);
|
||||
// });
|
||||
let mut layout_cycler = tag::layout_cycler(&[
|
||||
Layout::MasterStack,
|
||||
Layout::Dwindle,
|
||||
Layout::Spiral,
|
||||
Layout::CornerTopLeft,
|
||||
Layout::CornerTopRight,
|
||||
Layout::CornerBottomLeft,
|
||||
Layout::CornerBottomRight,
|
||||
]);
|
||||
|
||||
input::keybind(
|
||||
&[mod_key],
|
||||
xkbcommon::xkb::keysyms::KEY_space,
|
||||
move |_| {
|
||||
(layout_cycler.next)(None);
|
||||
},
|
||||
&mut callback_vec,
|
||||
);
|
||||
|
||||
input::keybind(
|
||||
&[mod_key, Modifier::Shift],
|
||||
xkbcommon::xkb::keysyms::KEY_space,
|
||||
move |_| {
|
||||
(layout_cycler.prev)(None);
|
||||
},
|
||||
&mut callback_vec,
|
||||
);
|
||||
|
||||
// Keybinds for tags
|
||||
|
||||
for tag_name in tags.iter().map(|t| t.to_string()) {
|
||||
let t = tag_name.clone();
|
||||
|
@ -159,5 +187,9 @@ fn main() {
|
|||
);
|
||||
}
|
||||
|
||||
// At the very end of your config, you will need to start listening to Pinnacle in order for
|
||||
// your callbacks to be correctly called.
|
||||
//
|
||||
// This will not return unless an error occurs.
|
||||
pinnacle_api::listen(callback_vec);
|
||||
}
|
||||
|
|
|
@ -11,13 +11,15 @@ use crate::{
|
|||
|
||||
/// Set a keybind.
|
||||
///
|
||||
/// This function takes in three parameters:
|
||||
/// This function takes in four parameters:
|
||||
/// - `modifiers`: A slice of the modifiers you want held for the keybind to trigger.
|
||||
/// - `key`: The key that needs to be pressed. This takes `impl Into<KeyIntOrString>` and can
|
||||
/// take the following three types:
|
||||
/// - [`char`]: A character of the key you want. This can be `a`, `~`, `@`, and so on.
|
||||
/// - [`u32`]: The key in numeric form. You can use the keys defined in [`xkbcommon::xkb::keysyms`] for this.
|
||||
/// - [`Keysym`]: The key in `Keysym` form, from [xkbcommon::xkb::Keysym].
|
||||
/// - `action`: What you want to run.
|
||||
/// - `callback_vec`: Your [`CallbackVec`] to insert `action` into.
|
||||
///
|
||||
/// `action` takes in a `&mut `[`CallbackVec`] for use in the closure.
|
||||
pub fn keybind<'a, F>(
|
||||
|
|
|
@ -53,10 +53,12 @@ pub fn add(output: &OutputHandle, names: &[&str]) {
|
|||
/// todo!()
|
||||
/// ```
|
||||
pub fn layout_cycler(layouts: &[Layout]) -> LayoutCycler {
|
||||
let mut indices = HashMap::<TagId, usize>::new();
|
||||
let indices = std::rc::Rc::new(std::cell::RefCell::new(HashMap::<TagId, usize>::new()));
|
||||
let indices_clone = indices.clone();
|
||||
let layouts = layouts.to_vec();
|
||||
let layouts_clone = layouts.clone();
|
||||
let len = layouts.len();
|
||||
let cycle = move |cycle: Cycle, output: Option<&OutputHandle>| {
|
||||
let next = move |output: Option<&OutputHandle>| {
|
||||
let Some(output) = output.cloned().or_else(crate::output::get_focused) else {
|
||||
return;
|
||||
};
|
||||
|
@ -70,61 +72,57 @@ pub fn layout_cycler(layouts: &[Layout]) -> LayoutCycler {
|
|||
return;
|
||||
};
|
||||
|
||||
let mut indices = indices.borrow_mut();
|
||||
let index = indices.entry(tag.0).or_insert(0);
|
||||
|
||||
match cycle {
|
||||
Cycle::Forward => {
|
||||
if *index + 1 >= len {
|
||||
*index = 0;
|
||||
} else {
|
||||
*index += 1;
|
||||
}
|
||||
}
|
||||
Cycle::Backward => {
|
||||
if index.wrapping_sub(1) == usize::MAX {
|
||||
*index = len - 1;
|
||||
} else {
|
||||
*index -= 1;
|
||||
}
|
||||
}
|
||||
if *index + 1 >= len {
|
||||
*index = 0;
|
||||
} else {
|
||||
*index += 1;
|
||||
}
|
||||
|
||||
tag.set_layout(layouts[*index]);
|
||||
};
|
||||
let prev = move |output: Option<&OutputHandle>| {
|
||||
let Some(output) = output.cloned().or_else(crate::output::get_focused) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(tag) = output
|
||||
.properties()
|
||||
.tags
|
||||
.into_iter()
|
||||
.find(|tag| tag.properties().active == Some(true))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let mut indices = indices_clone.borrow_mut();
|
||||
let index = indices.entry(tag.0).or_insert(0);
|
||||
|
||||
if index.wrapping_sub(1) == usize::MAX {
|
||||
*index = len - 1;
|
||||
} else {
|
||||
*index -= 1;
|
||||
}
|
||||
|
||||
tag.set_layout(layouts_clone[*index]);
|
||||
};
|
||||
|
||||
LayoutCycler {
|
||||
cycle: Box::new(cycle),
|
||||
next: Box::new(next),
|
||||
prev: Box::new(prev),
|
||||
}
|
||||
}
|
||||
|
||||
/// Which direction to cycle layouts.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum Cycle {
|
||||
/// Cycle layouts forward.
|
||||
Forward,
|
||||
/// Cycle layouts backward.
|
||||
Backward,
|
||||
}
|
||||
|
||||
/// A layout cycler that keeps track of tags and their layouts and provides methods to cycle
|
||||
/// layouts on them.
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub struct LayoutCycler {
|
||||
cycle: Box<dyn FnMut(Cycle, Option<&OutputHandle>)>,
|
||||
}
|
||||
|
||||
impl LayoutCycler {
|
||||
/// Cycle to the next layout for the first active tag on `output`.
|
||||
/// If `output` is `None`, the currently focused output is used.
|
||||
pub fn next(&mut self, output: Option<&OutputHandle>) {
|
||||
(self.cycle)(Cycle::Forward, output);
|
||||
}
|
||||
|
||||
/// Cycle to the previous layout for the first active tag on `output`.
|
||||
/// If `output` is `None`, the currently focused output is used.
|
||||
pub fn prev(&mut self, output: Option<&OutputHandle>) {
|
||||
(self.cycle)(Cycle::Backward, output);
|
||||
}
|
||||
/// Cycle to the next layout on the given output, or the focused output if `None`.
|
||||
pub next: Box<dyn FnMut(Option<&OutputHandle>)>,
|
||||
/// Cycle to the previous layout on the given output, or the focused output if `None`.
|
||||
pub prev: Box<dyn FnMut(Option<&OutputHandle>)>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, serde::Serialize, serde::Deserialize)]
|
||||
|
|
Loading…
Reference in a new issue