mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-22 02:01:55 +07:00
feat(move-floating-window): percentage change (#2371)
* feat: add percentage change to move-floating-window * fixes --------- Co-authored-by: Ivan Molodetskikh <yalterz@gmail.com>
This commit is contained in:
committed by
GitHub
parent
d31a90edb0
commit
79cdbc5748
+48
-14
@@ -813,14 +813,14 @@ pub enum Action {
|
|||||||
/// How to change the X position.
|
/// How to change the X position.
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "clap",
|
feature = "clap",
|
||||||
arg(short, long, default_value = "+0", allow_negative_numbers = true)
|
arg(short, long, default_value = "+0", allow_hyphen_values = true)
|
||||||
)]
|
)]
|
||||||
x: PositionChange,
|
x: PositionChange,
|
||||||
|
|
||||||
/// How to change the Y position.
|
/// How to change the Y position.
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "clap",
|
feature = "clap",
|
||||||
arg(short, long, default_value = "+0", allow_negative_numbers = true)
|
arg(short, long, default_value = "+0", allow_hyphen_values = true)
|
||||||
)]
|
)]
|
||||||
y: PositionChange,
|
y: PositionChange,
|
||||||
},
|
},
|
||||||
@@ -913,8 +913,12 @@ pub enum SizeChange {
|
|||||||
pub enum PositionChange {
|
pub enum PositionChange {
|
||||||
/// Set the position in logical pixels.
|
/// Set the position in logical pixels.
|
||||||
SetFixed(f64),
|
SetFixed(f64),
|
||||||
|
/// Set the position as a proportion of the working area.
|
||||||
|
SetProportion(f64),
|
||||||
/// Add or subtract to the current position in logical pixels.
|
/// Add or subtract to the current position in logical pixels.
|
||||||
AdjustFixed(f64),
|
AdjustFixed(f64),
|
||||||
|
/// Add or subtract to the current position as a proportion of the working area.
|
||||||
|
AdjustProportion(f64),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Workspace reference (id, index or name) to operate on.
|
/// Workspace reference (id, index or name) to operate on.
|
||||||
@@ -1519,17 +1523,38 @@ impl FromStr for PositionChange {
|
|||||||
type Err = &'static str;
|
type Err = &'static str;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
let value = s;
|
match s.split_once('%') {
|
||||||
match value.bytes().next() {
|
Some((value, empty)) => {
|
||||||
Some(b'-' | b'+') => {
|
if !empty.is_empty() {
|
||||||
let value = value.parse().map_err(|_| "error parsing value")?;
|
return Err("trailing characters after '%' are not allowed");
|
||||||
Ok(Self::AdjustFixed(value))
|
}
|
||||||
|
|
||||||
|
match value.bytes().next() {
|
||||||
|
Some(b'-' | b'+') => {
|
||||||
|
let value = value.parse().map_err(|_| "error parsing value")?;
|
||||||
|
Ok(Self::AdjustProportion(value))
|
||||||
|
}
|
||||||
|
Some(_) => {
|
||||||
|
let value = value.parse().map_err(|_| "error parsing value")?;
|
||||||
|
Ok(Self::SetProportion(value))
|
||||||
|
}
|
||||||
|
None => Err("value is missing"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Some(_) => {
|
None => {
|
||||||
let value = value.parse().map_err(|_| "error parsing value")?;
|
let value = s;
|
||||||
Ok(Self::SetFixed(value))
|
match value.bytes().next() {
|
||||||
|
Some(b'-' | b'+') => {
|
||||||
|
let value = value.parse().map_err(|_| "error parsing value")?;
|
||||||
|
Ok(Self::AdjustFixed(value))
|
||||||
|
}
|
||||||
|
Some(_) => {
|
||||||
|
let value = value.parse().map_err(|_| "error parsing value")?;
|
||||||
|
Ok(Self::SetFixed(value))
|
||||||
|
}
|
||||||
|
None => Err("value is missing"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
None => Err("value is missing"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1686,9 +1711,18 @@ mod tests {
|
|||||||
PositionChange::AdjustFixed(-10.),
|
PositionChange::AdjustFixed(-10.),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!("10%".parse::<PositionChange>().is_err());
|
assert_eq!(
|
||||||
assert!("+10%".parse::<PositionChange>().is_err());
|
"10%".parse::<PositionChange>().unwrap(),
|
||||||
assert!("-10%".parse::<PositionChange>().is_err());
|
PositionChange::SetProportion(10.)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
"+10%".parse::<PositionChange>().unwrap(),
|
||||||
|
PositionChange::AdjustProportion(10.)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
"-10%".parse::<PositionChange>().unwrap(),
|
||||||
|
PositionChange::AdjustProportion(-10.)
|
||||||
|
);
|
||||||
assert!("-".parse::<PositionChange>().is_err());
|
assert!("-".parse::<PositionChange>().is_err());
|
||||||
assert!("10% ".parse::<PositionChange>().is_err());
|
assert!("10% ".parse::<PositionChange>().is_err());
|
||||||
}
|
}
|
||||||
|
|||||||
+31
-6
@@ -961,17 +961,42 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
|||||||
};
|
};
|
||||||
let idx = self.idx_of(id).unwrap();
|
let idx = self.idx_of(id).unwrap();
|
||||||
|
|
||||||
let mut new_pos = self.data[idx].logical_pos;
|
let mut pos = self.data[idx].logical_pos;
|
||||||
|
|
||||||
|
let available_width = self.working_area.size.w;
|
||||||
|
let available_height = self.working_area.size.h;
|
||||||
|
let working_area_loc = self.working_area.loc;
|
||||||
|
|
||||||
|
const MAX_F: f64 = 10000.;
|
||||||
|
|
||||||
match x {
|
match x {
|
||||||
PositionChange::SetFixed(x) => new_pos.x = x + self.working_area.loc.x,
|
PositionChange::SetFixed(x) => pos.x = x + working_area_loc.x,
|
||||||
PositionChange::AdjustFixed(x) => new_pos.x += x,
|
PositionChange::SetProportion(prop) => {
|
||||||
|
let prop = (prop / 100.).clamp(0., MAX_F);
|
||||||
|
pos.x = available_width * prop + working_area_loc.x;
|
||||||
|
}
|
||||||
|
PositionChange::AdjustFixed(x) => pos.x += x,
|
||||||
|
PositionChange::AdjustProportion(prop) => {
|
||||||
|
let current_prop = (pos.x - working_area_loc.x) / available_width.max(1.);
|
||||||
|
let prop = (current_prop + prop / 100.).clamp(0., MAX_F);
|
||||||
|
pos.x = available_width * prop + working_area_loc.x;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
match y {
|
match y {
|
||||||
PositionChange::SetFixed(y) => new_pos.y = y + self.working_area.loc.y,
|
PositionChange::SetFixed(y) => pos.y = y + working_area_loc.y,
|
||||||
PositionChange::AdjustFixed(y) => new_pos.y += y,
|
PositionChange::SetProportion(prop) => {
|
||||||
|
let prop = (prop / 100.).clamp(0., MAX_F);
|
||||||
|
pos.y = available_height * prop + working_area_loc.y;
|
||||||
|
}
|
||||||
|
PositionChange::AdjustFixed(y) => pos.y += y,
|
||||||
|
PositionChange::AdjustProportion(prop) => {
|
||||||
|
let current_prop = (pos.y - working_area_loc.y) / available_height.max(1.);
|
||||||
|
let prop = (current_prop + prop / 100.).clamp(0., MAX_F);
|
||||||
|
pos.y = available_height * prop + working_area_loc.y;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.move_to(idx, new_pos, animate);
|
self.move_to(idx, pos, animate);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn center_window(&mut self, id: Option<&W::Id>) {
|
pub fn center_window(&mut self, id: Option<&W::Id>) {
|
||||||
|
|||||||
@@ -311,7 +311,9 @@ fn arbitrary_size_change() -> impl Strategy<Value = SizeChange> {
|
|||||||
fn arbitrary_position_change() -> impl Strategy<Value = PositionChange> {
|
fn arbitrary_position_change() -> impl Strategy<Value = PositionChange> {
|
||||||
prop_oneof![
|
prop_oneof![
|
||||||
(-1000f64..1000f64).prop_map(PositionChange::SetFixed),
|
(-1000f64..1000f64).prop_map(PositionChange::SetFixed),
|
||||||
|
any::<f64>().prop_map(PositionChange::SetProportion),
|
||||||
(-1000f64..1000f64).prop_map(PositionChange::AdjustFixed),
|
(-1000f64..1000f64).prop_map(PositionChange::AdjustFixed),
|
||||||
|
any::<f64>().prop_map(PositionChange::AdjustProportion),
|
||||||
any::<f64>().prop_map(PositionChange::SetFixed),
|
any::<f64>().prop_map(PositionChange::SetFixed),
|
||||||
any::<f64>().prop_map(PositionChange::AdjustFixed),
|
any::<f64>().prop_map(PositionChange::AdjustFixed),
|
||||||
]
|
]
|
||||||
|
|||||||
+32
-3
@@ -1511,14 +1511,18 @@ impl<W: LayoutElement> Workspace<W> {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let working_area_loc = self.floating.working_area().loc;
|
|
||||||
let pos = self.floating.stored_or_default_tile_pos(tile);
|
let pos = self.floating.stored_or_default_tile_pos(tile);
|
||||||
|
|
||||||
// If there's no stored floating position, we can only set both components at once, not
|
// If there's no stored floating position, we can only set both components at once, not
|
||||||
// adjust.
|
// adjust.
|
||||||
let pos = pos.or_else(|| {
|
let pos = pos.or_else(|| {
|
||||||
(matches!(x, PositionChange::SetFixed(_))
|
(matches!(
|
||||||
&& matches!(y, PositionChange::SetFixed(_)))
|
x,
|
||||||
|
PositionChange::SetFixed(_) | PositionChange::SetProportion(_)
|
||||||
|
) && matches!(
|
||||||
|
y,
|
||||||
|
PositionChange::SetFixed(_) | PositionChange::SetProportion(_)
|
||||||
|
))
|
||||||
.then_some(Point::default())
|
.then_some(Point::default())
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1526,13 +1530,38 @@ impl<W: LayoutElement> Workspace<W> {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let working_area = self.floating.working_area();
|
||||||
|
let available_width = working_area.size.w;
|
||||||
|
let available_height = working_area.size.h;
|
||||||
|
let working_area_loc = working_area.loc;
|
||||||
|
|
||||||
|
const MAX_F: f64 = 10000.;
|
||||||
|
|
||||||
match x {
|
match x {
|
||||||
PositionChange::SetFixed(x) => pos.x = x + working_area_loc.x,
|
PositionChange::SetFixed(x) => pos.x = x + working_area_loc.x,
|
||||||
|
PositionChange::SetProportion(prop) => {
|
||||||
|
let prop = (prop / 100.).clamp(0., MAX_F);
|
||||||
|
pos.x = available_width * prop + working_area_loc.x;
|
||||||
|
}
|
||||||
PositionChange::AdjustFixed(x) => pos.x += x,
|
PositionChange::AdjustFixed(x) => pos.x += x,
|
||||||
|
PositionChange::AdjustProportion(prop) => {
|
||||||
|
let current_prop = (pos.x - working_area_loc.x) / available_width.max(1.);
|
||||||
|
let prop = (current_prop + prop / 100.).clamp(0., MAX_F);
|
||||||
|
pos.x = available_width * prop + working_area_loc.x;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
match y {
|
match y {
|
||||||
PositionChange::SetFixed(y) => pos.y = y + working_area_loc.y,
|
PositionChange::SetFixed(y) => pos.y = y + working_area_loc.y,
|
||||||
|
PositionChange::SetProportion(prop) => {
|
||||||
|
let prop = (prop / 100.).clamp(0., MAX_F);
|
||||||
|
pos.y = available_height * prop + working_area_loc.y;
|
||||||
|
}
|
||||||
PositionChange::AdjustFixed(y) => pos.y += y,
|
PositionChange::AdjustFixed(y) => pos.y += y,
|
||||||
|
PositionChange::AdjustProportion(prop) => {
|
||||||
|
let current_prop = (pos.y - working_area_loc.y) / available_height.max(1.);
|
||||||
|
let prop = (current_prop + prop / 100.).clamp(0., MAX_F);
|
||||||
|
pos.y = available_height * prop + working_area_loc.y;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let pos = self.floating.logical_to_size_frac(pos);
|
let pos = self.floating.logical_to_size_frac(pos);
|
||||||
|
|||||||
Reference in New Issue
Block a user