mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-24 02:01:18 +07:00
screenshot-ui: Animate opening
This commit is contained in:
@@ -571,6 +571,8 @@ pub struct Animations {
|
||||
pub window_resize: WindowResizeAnim,
|
||||
#[knuffel(child, default)]
|
||||
pub config_notification_open_close: ConfigNotificationOpenCloseAnim,
|
||||
#[knuffel(child, default)]
|
||||
pub screenshot_ui_open: ScreenshotUiOpenAnim,
|
||||
}
|
||||
|
||||
impl Default for Animations {
|
||||
@@ -585,6 +587,7 @@ impl Default for Animations {
|
||||
window_close: Default::default(),
|
||||
window_resize: Default::default(),
|
||||
config_notification_open_close: Default::default(),
|
||||
screenshot_ui_open: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -717,6 +720,21 @@ impl Default for ConfigNotificationOpenCloseAnim {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct ScreenshotUiOpenAnim(pub Animation);
|
||||
|
||||
impl Default for ScreenshotUiOpenAnim {
|
||||
fn default() -> Self {
|
||||
Self(Animation {
|
||||
off: false,
|
||||
kind: AnimationKind::Easing(EasingParams {
|
||||
duration_ms: 200,
|
||||
curve: AnimationCurve::EaseOutQuad,
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct Animation {
|
||||
pub off: bool,
|
||||
@@ -1802,6 +1820,21 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> knuffel::Decode<S> for ScreenshotUiOpenAnim
|
||||
where
|
||||
S: knuffel::traits::ErrorSpan,
|
||||
{
|
||||
fn decode_node(
|
||||
node: &knuffel::ast::SpannedNode<S>,
|
||||
ctx: &mut knuffel::decode::Context<S>,
|
||||
) -> Result<Self, DecodeError<S>> {
|
||||
let default = Self::default().0;
|
||||
Ok(Self(Animation::decode_node(node, ctx, default, |_, _| {
|
||||
Ok(false)
|
||||
})?))
|
||||
}
|
||||
}
|
||||
|
||||
impl Animation {
|
||||
pub fn new_off() -> Self {
|
||||
Self {
|
||||
|
||||
+1
-1
@@ -2569,7 +2569,7 @@ mod tests {
|
||||
let comp_mod = CompositorMod::Super;
|
||||
let mut suppressed_keys = HashSet::new();
|
||||
|
||||
let screenshot_ui = ScreenshotUi::new();
|
||||
let screenshot_ui = ScreenshotUi::new(Default::default());
|
||||
let disable_power_key_handling = false;
|
||||
|
||||
// The key_code we pick is arbitrary, the only thing
|
||||
|
||||
+5
-1
@@ -1589,7 +1589,7 @@ impl Niri {
|
||||
let mods_with_finger_scroll_binds =
|
||||
mods_with_finger_scroll_binds(backend.mod_key(), &config_.binds);
|
||||
|
||||
let screenshot_ui = ScreenshotUi::new();
|
||||
let screenshot_ui = ScreenshotUi::new(config.clone());
|
||||
let config_error_notification = ConfigErrorNotification::new(config.clone());
|
||||
|
||||
let mut hotkey_overlay = HotkeyOverlay::new(config.clone(), backend.mod_key());
|
||||
@@ -2973,6 +2973,10 @@ impl Niri {
|
||||
state.unfinished_animations_remain |=
|
||||
self.config_error_notification.are_animations_ongoing();
|
||||
|
||||
self.screenshot_ui
|
||||
.advance_animations(target_presentation_time);
|
||||
state.unfinished_animations_remain |= self.screenshot_ui.are_animations_ongoing();
|
||||
|
||||
// Also keep redrawing if the current cursor is animated.
|
||||
state.unfinished_animations_remain |= self
|
||||
.cursor_manager
|
||||
|
||||
+52
-20
@@ -1,11 +1,13 @@
|
||||
use std::cell::RefCell;
|
||||
use std::cmp::{max, min};
|
||||
use std::collections::HashMap;
|
||||
use std::iter::zip;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::Context;
|
||||
use arrayvec::ArrayVec;
|
||||
use niri_config::Action;
|
||||
use niri_config::{Action, Config};
|
||||
use pango::{Alignment, FontDescription};
|
||||
use pangocairo::cairo::{self, ImageSurface};
|
||||
use smithay::backend::allocator::Fourcc;
|
||||
@@ -18,6 +20,7 @@ use smithay::input::keyboard::{Keysym, ModifiersState};
|
||||
use smithay::output::{Output, WeakOutput};
|
||||
use smithay::utils::{Physical, Point, Rectangle, Scale, Size, Transform};
|
||||
|
||||
use crate::animation::Animation;
|
||||
use crate::niri_render_elements;
|
||||
use crate::render_helpers::primary_gpu_texture::PrimaryGpuTextureRenderElement;
|
||||
use crate::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement};
|
||||
@@ -42,15 +45,19 @@ const TEXT_SHOW_P: &str =
|
||||
// allows only single-output selections for now.
|
||||
//
|
||||
// As a consequence of this, selection coordinates are in output-local coordinate space.
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum ScreenshotUi {
|
||||
Closed {
|
||||
last_selection: Option<(WeakOutput, Rectangle<i32, Physical>)>,
|
||||
config: Rc<RefCell<Config>>,
|
||||
},
|
||||
Open {
|
||||
selection: (Output, Point<i32, Physical>, Point<i32, Physical>),
|
||||
output_data: HashMap<Output, OutputData>,
|
||||
mouse_down: bool,
|
||||
show_pointer: bool,
|
||||
open_anim: Animation,
|
||||
config: Rc<RefCell<Config>>,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -79,9 +86,10 @@ niri_render_elements! {
|
||||
}
|
||||
|
||||
impl ScreenshotUi {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(config: Rc<RefCell<Config>>) -> Self {
|
||||
Self::Closed {
|
||||
last_selection: None,
|
||||
config,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +104,11 @@ impl ScreenshotUi {
|
||||
return false;
|
||||
}
|
||||
|
||||
let Self::Closed { last_selection } = self else {
|
||||
let Self::Closed {
|
||||
last_selection,
|
||||
config,
|
||||
} = self
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
|
||||
@@ -167,11 +179,18 @@ impl ScreenshotUi {
|
||||
})
|
||||
.collect();
|
||||
|
||||
let open_anim = {
|
||||
let c = config.borrow();
|
||||
Animation::new(0., 1., 0., c.animations.screenshot_ui_open.0)
|
||||
};
|
||||
|
||||
*self = Self::Open {
|
||||
selection,
|
||||
output_data,
|
||||
mouse_down: false,
|
||||
show_pointer: true,
|
||||
open_anim,
|
||||
config: config.clone(),
|
||||
};
|
||||
|
||||
self.update_buffers();
|
||||
@@ -180,13 +199,11 @@ impl ScreenshotUi {
|
||||
}
|
||||
|
||||
pub fn close(&mut self) -> bool {
|
||||
let selection = match mem::take(self) {
|
||||
Self::Open { selection, .. } => selection,
|
||||
closed @ Self::Closed { .. } => {
|
||||
// Put it back.
|
||||
*self = closed;
|
||||
return false;
|
||||
}
|
||||
let Self::Open {
|
||||
selection, config, ..
|
||||
} = self
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let last_selection = Some((
|
||||
@@ -194,7 +211,10 @@ impl ScreenshotUi {
|
||||
rect_from_corner_points(selection.1, selection.2),
|
||||
));
|
||||
|
||||
*self = Self::Closed { last_selection };
|
||||
*self = Self::Closed {
|
||||
last_selection,
|
||||
config: config.clone(),
|
||||
};
|
||||
|
||||
true
|
||||
}
|
||||
@@ -209,6 +229,22 @@ impl ScreenshotUi {
|
||||
matches!(self, ScreenshotUi::Open { .. })
|
||||
}
|
||||
|
||||
pub fn advance_animations(&mut self, current_time: Duration) {
|
||||
let Self::Open { open_anim, .. } = self else {
|
||||
return;
|
||||
};
|
||||
|
||||
open_anim.set_current_time(current_time);
|
||||
}
|
||||
|
||||
pub fn are_animations_ongoing(&self) -> bool {
|
||||
let Self::Open { open_anim, .. } = self else {
|
||||
return false;
|
||||
};
|
||||
|
||||
!open_anim.is_done()
|
||||
}
|
||||
|
||||
fn update_buffers(&mut self) {
|
||||
let Self::Open {
|
||||
selection,
|
||||
@@ -293,6 +329,7 @@ impl ScreenshotUi {
|
||||
output_data,
|
||||
show_pointer,
|
||||
mouse_down,
|
||||
open_anim,
|
||||
..
|
||||
} = self
|
||||
else {
|
||||
@@ -306,6 +343,7 @@ impl ScreenshotUi {
|
||||
};
|
||||
|
||||
let scale = output_data.scale;
|
||||
let progress = open_anim.clamped_value().clamp(0., 1.) as f32;
|
||||
|
||||
// The help panel goes on top.
|
||||
if let Some((show, hide)) = &output_data.panel {
|
||||
@@ -324,7 +362,7 @@ impl ScreenshotUi {
|
||||
let elem = PrimaryGpuTextureRenderElement(TextureRenderElement::from_texture_buffer(
|
||||
buffer.clone(),
|
||||
location,
|
||||
alpha,
|
||||
alpha * progress,
|
||||
None,
|
||||
None,
|
||||
Kind::Unspecified,
|
||||
@@ -337,7 +375,7 @@ impl ScreenshotUi {
|
||||
SolidColorRenderElement::from_buffer(
|
||||
buffer,
|
||||
loc.to_f64().to_logical(scale),
|
||||
1.,
|
||||
progress,
|
||||
Kind::Unspecified,
|
||||
)
|
||||
.into()
|
||||
@@ -530,12 +568,6 @@ impl ScreenshotUi {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ScreenshotUi {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl OutputScreenshot {
|
||||
pub fn from_textures(
|
||||
renderer: &mut GlesRenderer,
|
||||
|
||||
@@ -45,6 +45,11 @@ animations {
|
||||
config-notification-open-close {
|
||||
spring damping-ratio=0.6 stiffness=1000 epsilon=0.001
|
||||
}
|
||||
|
||||
screenshot-ui-open {
|
||||
duration-ms 200
|
||||
curve "ease-out-quad"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -354,6 +359,21 @@ animations {
|
||||
}
|
||||
```
|
||||
|
||||
#### `screenshot-ui-open`
|
||||
|
||||
<sup>Since: 0.1.8</sup>
|
||||
|
||||
The open (fade-in) animation of the screenshot UI.
|
||||
|
||||
```
|
||||
animations {
|
||||
screenshot-ui-open {
|
||||
duration-ms 200
|
||||
curve "ease-out-quad"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Synchronized Animations
|
||||
|
||||
<sup>Since: 0.1.5</sup>
|
||||
|
||||
Reference in New Issue
Block a user