render: Render resize indicator
This commit is contained in:
parent
2004705080
commit
99f29187af
7 changed files with 407 additions and 83 deletions
|
|
@ -476,19 +476,10 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
state
|
||||
.shell
|
||||
.space_for_handle_mut(¤t.0)
|
||||
.ok_or(OutputNoMode)?
|
||||
.update_animations(&state.event_loop_handle);
|
||||
if let Some((previous, _, _)) = previous.as_ref() {
|
||||
state
|
||||
.shell
|
||||
.space_for_handle_mut(&previous)
|
||||
.ok_or(OutputNoMode)?
|
||||
.update_animations(&state.event_loop_handle);
|
||||
}
|
||||
let overview = state.shell.overview_mode();
|
||||
let (resize_mode, resize_indicator) = state.shell.resize_mode();
|
||||
let resize_indicator = resize_indicator.map(|indicator| (resize_mode, indicator));
|
||||
|
||||
let last_active_seat = state.last_active_seat().clone();
|
||||
let move_active = last_active_seat
|
||||
.user_data()
|
||||
|
|
@ -552,6 +543,7 @@ where
|
|||
state.xwayland_state.as_mut(),
|
||||
(!move_active && is_active_space).then_some(&last_active_seat),
|
||||
overview.clone(),
|
||||
resize_indicator.clone(),
|
||||
state.config.static_conf.active_hint,
|
||||
)
|
||||
.map_err(|_| OutputNoMode)?
|
||||
|
|
@ -598,6 +590,7 @@ where
|
|||
state.xwayland_state.as_mut(),
|
||||
(!move_active && is_active_space).then_some(&last_active_seat),
|
||||
overview,
|
||||
resize_indicator,
|
||||
state.config.static_conf.active_hint,
|
||||
)
|
||||
.map_err(|_| OutputNoMode)?
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ pub mod stack;
|
|||
pub use self::stack::CosmicStack;
|
||||
pub mod window;
|
||||
pub use self::window::CosmicWindow;
|
||||
pub mod resize_indicator;
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
use egui::plot::{Corner, Legend, Plot, PlotPoints, Polygon};
|
||||
|
|
|
|||
223
src/shell/element/resize_indicator.rs
Normal file
223
src/shell/element/resize_indicator.rs
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
use std::sync::Mutex;
|
||||
|
||||
use crate::{
|
||||
config::{Action, Config},
|
||||
fl,
|
||||
shell::{grabs::ResizeEdge, ResizeDirection},
|
||||
utils::iced::{IcedElement, Program},
|
||||
};
|
||||
|
||||
use apply::Apply;
|
||||
use calloop::LoopHandle;
|
||||
use cosmic::{
|
||||
iced::widget::{column, container, horizontal_space, row, vertical_space},
|
||||
iced_core::{Background, Color, Length},
|
||||
theme,
|
||||
widget::{icon, text},
|
||||
};
|
||||
use smithay::utils::Size;
|
||||
|
||||
pub type ResizeIndicator = IcedElement<ResizeIndicatorInternal>;
|
||||
|
||||
pub fn resize_indicator(
|
||||
direction: ResizeDirection,
|
||||
config: &Config,
|
||||
evlh: LoopHandle<'static, crate::state::Data>,
|
||||
) -> ResizeIndicator {
|
||||
ResizeIndicator::new(
|
||||
ResizeIndicatorInternal {
|
||||
edges: Mutex::new(ResizeEdge::all()),
|
||||
direction,
|
||||
shortcut1: config
|
||||
.static_conf
|
||||
.key_bindings
|
||||
.iter()
|
||||
.find_map(|(pattern, action)| {
|
||||
(*action == Action::Resizing(ResizeDirection::Outwards)).then_some(pattern)
|
||||
})
|
||||
.map(|pattern| format!("{}: ", pattern.to_string()))
|
||||
.unwrap_or_else(|| crate::fl!("unknown-keybinding")),
|
||||
shortcut2: config
|
||||
.static_conf
|
||||
.key_bindings
|
||||
.iter()
|
||||
.find_map(|(pattern, action)| {
|
||||
(*action == Action::Resizing(ResizeDirection::Inwards)).then_some(pattern)
|
||||
})
|
||||
.map(|pattern| format!("{}: ", pattern.to_string()))
|
||||
.unwrap_or_else(|| crate::fl!("unknown-keybinding")),
|
||||
},
|
||||
Size::from((1, 1)),
|
||||
evlh,
|
||||
)
|
||||
}
|
||||
|
||||
pub struct ResizeIndicatorInternal {
|
||||
pub edges: Mutex<ResizeEdge>,
|
||||
pub direction: ResizeDirection,
|
||||
pub shortcut1: String,
|
||||
pub shortcut2: String,
|
||||
}
|
||||
|
||||
impl Program for ResizeIndicatorInternal {
|
||||
type Message = ();
|
||||
|
||||
fn view(&self) -> crate::utils::iced::Element<'_, Self::Message> {
|
||||
let edges = self.edges.lock().unwrap();
|
||||
column(vec![
|
||||
if edges.contains(ResizeEdge::TOP) {
|
||||
icon(
|
||||
if self.direction == ResizeDirection::Outwards {
|
||||
"go-up-symbolic"
|
||||
} else {
|
||||
"go-down-symbolic"
|
||||
},
|
||||
32,
|
||||
)
|
||||
.force_svg(true)
|
||||
.apply(container)
|
||||
.padding(2)
|
||||
.style(theme::Container::custom(|theme| container::Appearance {
|
||||
text_color: Some(Color::from(theme.cosmic().accent.on)),
|
||||
background: Some(Background::Color(theme.cosmic().accent_color().into())),
|
||||
border_radius: 18.0.into(),
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
}))
|
||||
.width(Length::Shrink)
|
||||
.apply(container)
|
||||
.center_x()
|
||||
.width(Length::Fill)
|
||||
.into()
|
||||
} else {
|
||||
vertical_space(36).into()
|
||||
},
|
||||
row(vec![
|
||||
if edges.contains(ResizeEdge::LEFT) {
|
||||
icon(
|
||||
if self.direction == ResizeDirection::Outwards {
|
||||
"go-previous-symbolic"
|
||||
} else {
|
||||
"go-next-symbolic"
|
||||
},
|
||||
32,
|
||||
)
|
||||
.force_svg(true)
|
||||
.apply(container)
|
||||
.padding(4)
|
||||
.style(theme::Container::custom(|theme| container::Appearance {
|
||||
text_color: Some(Color::from(theme.cosmic().accent.on)),
|
||||
background: Some(Background::Color(theme.cosmic().accent_color().into())),
|
||||
border_radius: 18.0.into(),
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
}))
|
||||
.width(Length::Shrink)
|
||||
.apply(container)
|
||||
.center_y()
|
||||
.height(Length::Fill)
|
||||
.into()
|
||||
} else {
|
||||
horizontal_space(36).into()
|
||||
},
|
||||
row(vec![
|
||||
text(&self.shortcut1)
|
||||
.font(cosmic::font::FONT_SEMIBOLD)
|
||||
.size(14)
|
||||
.into(),
|
||||
text(fl!("grow-window"))
|
||||
.font(cosmic::font::FONT)
|
||||
.size(14)
|
||||
.into(),
|
||||
horizontal_space(40).into(),
|
||||
text(&self.shortcut2)
|
||||
.font(cosmic::font::FONT_SEMIBOLD)
|
||||
.size(14)
|
||||
.into(),
|
||||
text(fl!("shrink-window"))
|
||||
.font(cosmic::font::FONT)
|
||||
.size(14)
|
||||
.into(),
|
||||
])
|
||||
.apply(container)
|
||||
.center_x()
|
||||
.center_y()
|
||||
.padding(16)
|
||||
.apply(container)
|
||||
.style(theme::Container::custom(|theme| container::Appearance {
|
||||
text_color: Some(Color::from(theme.cosmic().accent.on)),
|
||||
background: Some(Background::Color(theme.cosmic().accent_color().into())),
|
||||
border_radius: 18.0.into(),
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
}))
|
||||
.width(Length::Shrink)
|
||||
.height(Length::Shrink)
|
||||
.apply(container)
|
||||
.height(Length::Fill)
|
||||
.width(Length::Fill)
|
||||
.center_x()
|
||||
.center_y()
|
||||
.into(),
|
||||
if edges.contains(ResizeEdge::RIGHT) {
|
||||
icon(
|
||||
if self.direction == ResizeDirection::Outwards {
|
||||
"go-next-symbolic"
|
||||
} else {
|
||||
"go-previous-symbolic"
|
||||
},
|
||||
32,
|
||||
)
|
||||
.force_svg(true)
|
||||
.apply(container)
|
||||
.padding(4)
|
||||
.style(theme::Container::custom(|theme| container::Appearance {
|
||||
text_color: Some(Color::from(theme.cosmic().accent.on)),
|
||||
background: Some(Background::Color(theme.cosmic().accent_color().into())),
|
||||
border_radius: 18.0.into(),
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
}))
|
||||
.height(Length::Shrink)
|
||||
.apply(container)
|
||||
.center_y()
|
||||
.height(Length::Fill)
|
||||
.into()
|
||||
} else {
|
||||
horizontal_space(36).into()
|
||||
},
|
||||
])
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.into(),
|
||||
if edges.contains(ResizeEdge::BOTTOM) {
|
||||
icon(
|
||||
if self.direction == ResizeDirection::Outwards {
|
||||
"go-down-symbolic"
|
||||
} else {
|
||||
"go-up-symbolic"
|
||||
},
|
||||
32,
|
||||
)
|
||||
.force_svg(true)
|
||||
.apply(container)
|
||||
.padding(4)
|
||||
.style(theme::Container::custom(|theme| container::Appearance {
|
||||
text_color: Some(Color::from(theme.cosmic().accent.on)),
|
||||
background: Some(Background::Color(theme.cosmic().accent_color().into())),
|
||||
border_radius: 18.0.into(),
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
}))
|
||||
.width(Length::Shrink)
|
||||
.apply(container)
|
||||
.center_x()
|
||||
.width(Length::Fill)
|
||||
.into()
|
||||
} else {
|
||||
vertical_space(36).into()
|
||||
},
|
||||
])
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
|
@ -16,8 +16,8 @@ use crate::{
|
|||
backend::render::{element::AsGlowRenderer, IndicatorShader},
|
||||
shell::{
|
||||
element::{
|
||||
stack::CosmicStackRenderElement, window::CosmicWindowRenderElement, CosmicMapped,
|
||||
CosmicMappedRenderElement,
|
||||
resize_indicator::ResizeIndicator, stack::CosmicStackRenderElement,
|
||||
window::CosmicWindowRenderElement, CosmicMapped, CosmicMappedRenderElement,
|
||||
},
|
||||
focus::target::KeyboardFocusTarget,
|
||||
grabs::ResizeEdge,
|
||||
|
|
@ -421,6 +421,7 @@ impl FloatingLayout {
|
|||
renderer: &mut R,
|
||||
output: &Output,
|
||||
focused: Option<&CosmicMapped>,
|
||||
mut resize_indicator: Option<(ResizeMode, ResizeIndicator)>,
|
||||
indicator_thickness: u8,
|
||||
alpha: f32,
|
||||
) -> Vec<CosmicMappedRenderElement<R>>
|
||||
|
|
@ -435,14 +436,15 @@ impl FloatingLayout {
|
|||
puffin::profile_function!();
|
||||
|
||||
let output_scale = output.current_scale().fractional_scale();
|
||||
let output_loc = self.space.output_geometry(output).unwrap().loc;
|
||||
let output_geo = self.space.output_geometry(output).unwrap();
|
||||
|
||||
self.space
|
||||
.elements_for_output(output)
|
||||
.rev()
|
||||
.flat_map(|elem| {
|
||||
let render_location =
|
||||
self.space.element_location(elem).unwrap() - output_loc - elem.geometry().loc;
|
||||
let render_location = self.space.element_location(elem).unwrap()
|
||||
- output_geo.loc
|
||||
- elem.geometry().loc;
|
||||
let mut elements = elem.render_elements(
|
||||
renderer,
|
||||
render_location.to_physical_precise_round(output_scale),
|
||||
|
|
@ -450,19 +452,41 @@ impl FloatingLayout {
|
|||
alpha,
|
||||
);
|
||||
if focused == Some(elem) {
|
||||
let mut indicator_geometry = Rectangle::from_loc_and_size(
|
||||
self.space.element_location(elem).unwrap() - output_geo.loc,
|
||||
elem.geometry().size,
|
||||
);
|
||||
|
||||
if indicator_thickness > 0 {
|
||||
let element = IndicatorShader::focus_element(
|
||||
renderer,
|
||||
elem.clone(),
|
||||
Rectangle::from_loc_and_size(
|
||||
self.space.element_location(elem).unwrap() - output_loc,
|
||||
elem.geometry().size,
|
||||
),
|
||||
indicator_geometry,
|
||||
indicator_thickness,
|
||||
alpha,
|
||||
);
|
||||
elements.insert(0, element.into());
|
||||
}
|
||||
|
||||
if let Some((mode, resize)) = resize_indicator.as_mut() {
|
||||
indicator_geometry.loc -= (18, 18).into();
|
||||
indicator_geometry.size += (36, 36).into();
|
||||
resize.resize(indicator_geometry.size);
|
||||
resize.output_enter(output, output_geo);
|
||||
elements = resize
|
||||
.render_elements::<CosmicWindowRenderElement<R>>(
|
||||
renderer,
|
||||
indicator_geometry
|
||||
.loc
|
||||
.to_physical_precise_round(output_scale),
|
||||
output_scale.into(),
|
||||
alpha * mode.alpha().unwrap_or(1.0),
|
||||
)
|
||||
.into_iter()
|
||||
.map(CosmicMappedRenderElement::Window)
|
||||
.chain(elements.into_iter())
|
||||
.collect();
|
||||
}
|
||||
}
|
||||
elements
|
||||
})
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use crate::{
|
|||
backend::render::{element::AsGlowRenderer, BackdropShader, IndicatorShader, Key, GROUP_COLOR},
|
||||
shell::{
|
||||
element::{
|
||||
resize_indicator::ResizeIndicator,
|
||||
stack::{CosmicStackRenderElement, MoveResult as StackMoveResult},
|
||||
window::CosmicWindowRenderElement,
|
||||
CosmicMapped, CosmicMappedRenderElement, CosmicStack, CosmicWindow,
|
||||
|
|
@ -1915,6 +1916,7 @@ impl TilingLayout {
|
|||
seat: Option<&Seat<State>>,
|
||||
non_exclusive_zone: Rectangle<i32, Logical>,
|
||||
overview: OverviewMode,
|
||||
resize_indicator: Option<(ResizeMode, ResizeIndicator)>,
|
||||
indicator_thickness: u8,
|
||||
) -> Result<Vec<CosmicMappedRenderElement<R>>, OutputNotMapped>
|
||||
where
|
||||
|
|
@ -1955,26 +1957,7 @@ impl TilingLayout {
|
|||
} else {
|
||||
1.0
|
||||
};
|
||||
let draw_groups = match overview {
|
||||
OverviewMode::Started(_, start) => {
|
||||
let percentage = (Instant::now().duration_since(start).as_millis() as f32
|
||||
/ ANIMATION_DURATION.as_millis() as f32)
|
||||
.min(1.0);
|
||||
Some(Ease::Cubic(Cubic::Out).tween(percentage))
|
||||
}
|
||||
OverviewMode::Ended(end) => {
|
||||
let percentage = (1.0
|
||||
- Instant::now().duration_since(end).as_millis() as f32
|
||||
/ ANIMATION_DURATION.as_millis() as f32)
|
||||
.max(0.0);
|
||||
if percentage > 0.0 {
|
||||
Some(Ease::Cubic(Cubic::Out).tween(percentage))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
OverviewMode::None => None,
|
||||
};
|
||||
let draw_groups = overview.alpha();
|
||||
|
||||
let mut elements = Vec::new();
|
||||
|
||||
|
|
@ -2032,7 +2015,7 @@ impl TilingLayout {
|
|||
geometries,
|
||||
old_geometries,
|
||||
seat,
|
||||
output_scale,
|
||||
output,
|
||||
percentage,
|
||||
if let Some(transition) = draw_groups {
|
||||
let diff = (4u8.abs_diff(indicator_thickness) as f32 * transition).round() as u8;
|
||||
|
|
@ -2044,6 +2027,7 @@ impl TilingLayout {
|
|||
} else {
|
||||
indicator_thickness
|
||||
},
|
||||
resize_indicator,
|
||||
));
|
||||
|
||||
// tiling hints
|
||||
|
|
@ -2425,9 +2409,10 @@ fn render_new_tree<R>(
|
|||
geometries: Option<HashMap<NodeId, Rectangle<i32, Logical>>>,
|
||||
old_geometries: Option<HashMap<NodeId, Rectangle<i32, Logical>>>,
|
||||
seat: Option<&Seat<State>>,
|
||||
output_scale: f64,
|
||||
output: &Output,
|
||||
percentage: f32,
|
||||
indicator_thickness: u8,
|
||||
mut resize_indicator: Option<(ResizeMode, ResizeIndicator)>,
|
||||
) -> Vec<CosmicMappedRenderElement<R>>
|
||||
where
|
||||
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||
|
|
@ -2452,11 +2437,16 @@ where
|
|||
.map(|(id, _)| id);
|
||||
|
||||
let mut group_backdrop = None;
|
||||
let mut indicator = None;
|
||||
let mut resize_elements = None;
|
||||
|
||||
let output_geo = output.geometry();
|
||||
let output_scale = output.current_scale().fractional_scale();
|
||||
|
||||
if let Some(root) = target_tree.root_node_id() {
|
||||
let old_geometries = old_geometries.unwrap_or_default();
|
||||
let geometries = geometries.unwrap_or_default();
|
||||
let mut elements: Vec<CosmicMappedRenderElement<R>> = target_tree
|
||||
let elements: Vec<CosmicMappedRenderElement<R>> = target_tree
|
||||
.traverse_pre_order_ids(root)
|
||||
.unwrap()
|
||||
.flat_map(|node_id| {
|
||||
|
|
@ -2546,7 +2536,7 @@ where
|
|||
|
||||
let mut elements = Vec::new();
|
||||
|
||||
if focused == Some(node_id) {
|
||||
if focused.as_ref() == Some(&node_id) {
|
||||
if indicator_thickness > 0 || data.is_group() {
|
||||
let mut geo = geo.clone();
|
||||
if data.is_group() {
|
||||
|
|
@ -2554,25 +2544,56 @@ where
|
|||
geo.loc += (outer_gap, outer_gap).into();
|
||||
geo.size -= (outer_gap * 2, outer_gap * 2).into();
|
||||
|
||||
group_backdrop = Some(
|
||||
BackdropShader::element(
|
||||
renderer,
|
||||
match data {
|
||||
Data::Group { alive, .. } => {
|
||||
Key::Group(Arc::downgrade(alive))
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
geo,
|
||||
8.,
|
||||
0.4,
|
||||
GROUP_COLOR,
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
group_backdrop = Some(BackdropShader::element(
|
||||
renderer,
|
||||
match data {
|
||||
Data::Group { alive, .. } => Key::Group(Arc::downgrade(alive)),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
geo,
|
||||
8.,
|
||||
0.4,
|
||||
GROUP_COLOR,
|
||||
));
|
||||
}
|
||||
|
||||
let element = IndicatorShader::focus_element(
|
||||
if let Some((mode, resize)) = resize_indicator.as_mut() {
|
||||
let mut geo = geo.clone();
|
||||
geo.loc -= (18, 18).into();
|
||||
geo.size += (36, 36).into();
|
||||
|
||||
resize.resize(geo.size);
|
||||
resize.output_enter(output, output_geo);
|
||||
let possible_edges =
|
||||
TilingLayout::possible_resizes(target_tree, node_id);
|
||||
if !possible_edges.is_empty() {
|
||||
if resize.with_program(|internal| {
|
||||
let mut edges = internal.edges.lock().unwrap();
|
||||
if *edges != possible_edges {
|
||||
*edges = possible_edges;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}) {
|
||||
resize.force_update();
|
||||
}
|
||||
resize_elements = Some(
|
||||
resize
|
||||
.render_elements::<CosmicWindowRenderElement<R>>(
|
||||
renderer,
|
||||
geo.loc.to_physical_precise_round(output_scale),
|
||||
output_scale.into(),
|
||||
alpha * mode.alpha().unwrap_or(1.0),
|
||||
)
|
||||
.into_iter()
|
||||
.map(CosmicMappedRenderElement::from)
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
indicator = Some(IndicatorShader::focus_element(
|
||||
renderer,
|
||||
match data {
|
||||
Data::Mapped { mapped, .. } => mapped.clone().into(),
|
||||
|
|
@ -2585,8 +2606,7 @@ where
|
|||
indicator_thickness
|
||||
},
|
||||
1.0,
|
||||
);
|
||||
elements.push(element.into());
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2654,8 +2674,14 @@ where
|
|||
elements
|
||||
})
|
||||
.collect();
|
||||
elements.extend(group_backdrop);
|
||||
elements
|
||||
|
||||
resize_elements
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.chain(indicator.into_iter().map(Into::into))
|
||||
.chain(elements)
|
||||
.chain(group_backdrop.into_iter().map(Into::into))
|
||||
.collect()
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,13 @@ use std::{
|
|||
cell::RefCell,
|
||||
collections::HashMap,
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
time::Instant,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tracing::warn;
|
||||
use wayland_backend::server::ClientId;
|
||||
|
||||
use cosmic_protocols::workspace::v1::server::zcosmic_workspace_handle_v1::State as WState;
|
||||
use cosmic_time::{Cubic, Ease, Tween};
|
||||
use smithay::{
|
||||
desktop::{
|
||||
layer_map_for_output, space::SpaceElement, LayerSurface, PopupManager, WindowSurfaceType,
|
||||
|
|
@ -63,10 +64,12 @@ use self::{
|
|||
grabs::ResizeEdge,
|
||||
layout::{
|
||||
floating::{FloatingLayout, ResizeState},
|
||||
tiling::{Direction, TilingLayout, ANIMATION_DURATION},
|
||||
tiling::{Direction, TilingLayout},
|
||||
},
|
||||
};
|
||||
|
||||
const ANIMATION_DURATION: Duration = Duration::from_millis(200);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum OverviewMode {
|
||||
None,
|
||||
|
|
@ -74,6 +77,31 @@ pub enum OverviewMode {
|
|||
Ended(Instant),
|
||||
}
|
||||
|
||||
impl OverviewMode {
|
||||
pub fn alpha(&self) -> Option<f32> {
|
||||
match self {
|
||||
OverviewMode::Started(_, start) => {
|
||||
let percentage = (Instant::now().duration_since(*start).as_millis() as f32
|
||||
/ ANIMATION_DURATION.as_millis() as f32)
|
||||
.min(1.0);
|
||||
Some(Ease::Cubic(Cubic::Out).tween(percentage))
|
||||
}
|
||||
OverviewMode::Ended(end) => {
|
||||
let percentage = (1.0
|
||||
- Instant::now().duration_since(*end).as_millis() as f32
|
||||
/ ANIMATION_DURATION.as_millis() as f32)
|
||||
.max(0.0);
|
||||
if percentage > 0.0 {
|
||||
Some(Ease::Cubic(Cubic::Out).tween(percentage))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
OverviewMode::None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, serde::Deserialize, PartialEq, Eq, Hash)]
|
||||
pub enum ResizeDirection {
|
||||
Inwards,
|
||||
|
|
@ -87,6 +115,31 @@ pub enum ResizeMode {
|
|||
Ended(Instant, ResizeDirection),
|
||||
}
|
||||
|
||||
impl ResizeMode {
|
||||
pub fn alpha(&self) -> Option<f32> {
|
||||
match self {
|
||||
ResizeMode::Started(_, start, _) => {
|
||||
let percentage = (Instant::now().duration_since(*start).as_millis() as f32
|
||||
/ ANIMATION_DURATION.as_millis() as f32)
|
||||
.min(1.0);
|
||||
Some(Ease::Cubic(Cubic::Out).tween(percentage))
|
||||
}
|
||||
ResizeMode::Ended(end, _) => {
|
||||
let percentage = (1.0
|
||||
- Instant::now().duration_since(*end).as_millis() as f32
|
||||
/ ANIMATION_DURATION.as_millis() as f32)
|
||||
.max(0.0);
|
||||
if percentage > 0.0 {
|
||||
Some(Ease::Cubic(Cubic::Out).tween(percentage))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
ResizeMode::None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Shell {
|
||||
pub popups: PopupManager,
|
||||
pub outputs: Vec<Output>,
|
||||
|
|
@ -114,6 +167,7 @@ pub struct Shell {
|
|||
usize,
|
||||
Output,
|
||||
)>,
|
||||
resize_indicator: Option<ResizeIndicator>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -574,6 +628,7 @@ impl Shell {
|
|||
overview_mode: OverviewMode::None,
|
||||
resize_mode: ResizeMode::None,
|
||||
resize_state: None,
|
||||
resize_indicator: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1177,7 +1232,12 @@ impl Shell {
|
|||
self.overview_mode.clone()
|
||||
}
|
||||
|
||||
pub fn set_resize_mode(&mut self, enabled: Option<(KeyPattern, ResizeDirection)>) {
|
||||
pub fn set_resize_mode(
|
||||
&mut self,
|
||||
enabled: Option<(KeyPattern, ResizeDirection)>,
|
||||
config: &Config,
|
||||
evlh: LoopHandle<'static, crate::state::Data>,
|
||||
) {
|
||||
if let Some((pattern, direction)) = enabled {
|
||||
if let ResizeMode::Started(old_pattern, _, old_direction) = &mut self.resize_mode {
|
||||
*old_pattern = pattern;
|
||||
|
|
@ -1185,6 +1245,7 @@ impl Shell {
|
|||
} else {
|
||||
self.resize_mode = ResizeMode::Started(pattern, Instant::now(), direction);
|
||||
}
|
||||
self.resize_indicator = Some(resize_indicator(direction, config, evlh));
|
||||
} else {
|
||||
if let ResizeMode::Started(_, _, direction) = &self.resize_mode {
|
||||
self.resize_mode = ResizeMode::Ended(Instant::now(), *direction);
|
||||
|
|
@ -1192,25 +1253,15 @@ impl Shell {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn resize_mode(&mut self) -> ResizeMode {
|
||||
pub fn resize_mode(&mut self) -> (ResizeMode, Option<ResizeIndicator>) {
|
||||
if let ResizeMode::Ended(timestamp, _) = self.resize_mode {
|
||||
if Instant::now().duration_since(timestamp) > ANIMATION_DURATION {
|
||||
self.resize_mode = ResizeMode::None;
|
||||
self.resize_indicator = None;
|
||||
}
|
||||
}
|
||||
|
||||
self.resize_mode.clone()
|
||||
}
|
||||
|
||||
pub fn resize_active_window(
|
||||
&mut self,
|
||||
seat: &Seat<State>,
|
||||
direction: ResizeDirection,
|
||||
edge: ResizeEdge,
|
||||
) {
|
||||
self.workspaces
|
||||
.active_mut(&seat.active_output())
|
||||
.resize(seat, direction, edge);
|
||||
(self.resize_mode.clone(), self.resize_indicator.clone())
|
||||
}
|
||||
|
||||
pub fn refresh(&mut self) {
|
||||
|
|
|
|||
|
|
@ -47,7 +47,10 @@ use tracing::warn;
|
|||
use wayland_backend::server::ClientId;
|
||||
|
||||
use super::{
|
||||
element::{stack::CosmicStackRenderElement, window::CosmicWindowRenderElement, CosmicMapped},
|
||||
element::{
|
||||
resize_indicator::ResizeIndicator, stack::CosmicStackRenderElement,
|
||||
window::CosmicWindowRenderElement, CosmicMapped,
|
||||
},
|
||||
focus::{target::KeyboardFocusTarget, FocusStack, FocusStackMut},
|
||||
grabs::{ResizeEdge, ResizeGrab},
|
||||
CosmicMappedRenderElement, CosmicSurface, ResizeDirection, ResizeMode,
|
||||
|
|
@ -500,6 +503,7 @@ impl Workspace {
|
|||
xwm_state: Option<&'a mut XWaylandState>,
|
||||
draw_focus_indicator: Option<&Seat<State>>,
|
||||
overview: OverviewMode,
|
||||
resize_indicator: Option<(ResizeMode, ResizeIndicator)>,
|
||||
indicator_thickness: u8,
|
||||
) -> Result<Vec<WorkspaceRenderElement<R>>, OutputNotMapped>
|
||||
where
|
||||
|
|
@ -606,6 +610,7 @@ impl Workspace {
|
|||
renderer,
|
||||
output,
|
||||
focused.as_ref(),
|
||||
resize_indicator.clone(),
|
||||
indicator_thickness,
|
||||
alpha,
|
||||
)
|
||||
|
|
@ -622,6 +627,7 @@ impl Workspace {
|
|||
draw_focus_indicator,
|
||||
layer_map.non_exclusive_zone(),
|
||||
overview.clone(),
|
||||
resize_indicator,
|
||||
indicator_thickness,
|
||||
)?
|
||||
.into_iter()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue