diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2024-02-21 10:50:30 +0400 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2024-02-21 10:50:30 +0400 |
| commit | d1fe6930a7bc5b78b0f005c2105c92094fc4ec52 (patch) | |
| tree | 724f55cfb29695f74bf1689ea108da4ca63f36fa /src/config_error_notification.rs | |
| parent | 9e60b344d06979ade51e49eaa766198e3133b909 (diff) | |
| download | niri-d1fe6930a7bc5b78b0f005c2105c92094fc4ec52.tar.gz niri-d1fe6930a7bc5b78b0f005c2105c92094fc4ec52.tar.bz2 niri-d1fe6930a7bc5b78b0f005c2105c92094fc4ec52.zip | |
Move UI elements into submodule
Diffstat (limited to 'src/config_error_notification.rs')
| -rw-r--r-- | src/config_error_notification.rs | 252 |
1 files changed, 0 insertions, 252 deletions
diff --git a/src/config_error_notification.rs b/src/config_error_notification.rs deleted file mode 100644 index 12d92b85..00000000 --- a/src/config_error_notification.rs +++ /dev/null @@ -1,252 +0,0 @@ -use std::cell::RefCell; -use std::collections::HashMap; -use std::path::{Path, PathBuf}; -use std::rc::Rc; -use std::time::Duration; - -use niri_config::Config; -use pangocairo::cairo::{self, ImageSurface}; -use pangocairo::pango::FontDescription; -use smithay::backend::renderer::element::memory::{ - MemoryRenderBuffer, MemoryRenderBufferRenderElement, -}; -use smithay::backend::renderer::element::utils::{Relocate, RelocateRenderElement}; -use smithay::backend::renderer::element::{Element, Kind}; -use smithay::output::Output; -use smithay::reexports::gbm::Format as Fourcc; -use smithay::utils::Transform; - -use crate::animation::Animation; -use crate::render_helpers::renderer::NiriRenderer; - -const TEXT: &str = "Failed to parse the config file. \ - Please run <span face='monospace' bgcolor='#000000'>niri validate</span> \ - to see the errors."; -const PADDING: i32 = 8; -const FONT: &str = "sans 14px"; -const BORDER: i32 = 4; - -pub struct ConfigErrorNotification { - state: State, - buffers: RefCell<HashMap<i32, Option<MemoryRenderBuffer>>>, - - // If set, this is a "Created config at {path}" notification. If unset, this is a config error - // notification. - created_path: Option<PathBuf>, - - config: Rc<RefCell<Config>>, -} - -enum State { - Hidden, - Showing(Animation), - Shown(Duration), - Hiding(Animation), -} - -pub type ConfigErrorNotificationRenderElement<R> = - RelocateRenderElement<MemoryRenderBufferRenderElement<R>>; - -impl ConfigErrorNotification { - pub fn new(config: Rc<RefCell<Config>>) -> Self { - Self { - state: State::Hidden, - buffers: RefCell::new(HashMap::new()), - created_path: None, - config, - } - } - - fn animation(&self, from: f64, to: f64) -> Animation { - let c = self.config.borrow(); - Animation::new( - from, - to, - c.animations.config_notification_open_close, - niri_config::Animation::default_config_notification_open_close(), - ) - } - - pub fn show_created(&mut self, created_path: Option<PathBuf>) { - if self.created_path != created_path { - self.created_path = created_path; - self.buffers.borrow_mut().clear(); - } - - self.state = State::Showing(self.animation(0., 1.)); - } - - pub fn show(&mut self) { - if self.created_path.is_some() { - self.created_path = None; - self.buffers.borrow_mut().clear(); - } - - // Show from scratch even if already showing to bring attention. - self.state = State::Showing(self.animation(0., 1.)); - } - - pub fn hide(&mut self) { - if matches!(self.state, State::Hidden) { - return; - } - - self.state = State::Hiding(self.animation(1., 0.)); - } - - pub fn advance_animations(&mut self, target_presentation_time: Duration) { - match &mut self.state { - State::Hidden => (), - State::Showing(anim) => { - anim.set_current_time(target_presentation_time); - if anim.is_done() { - let duration = if self.created_path.is_some() { - // Make this quite a bit longer because it comes with a monitor modeset - // (can take a while) and an important hotkeys popup diverting the - // attention. - Duration::from_secs(8) - } else { - Duration::from_secs(4) - }; - self.state = State::Shown(target_presentation_time + duration); - } - } - State::Shown(deadline) => { - if target_presentation_time >= *deadline { - self.hide(); - } - } - State::Hiding(anim) => { - anim.set_current_time(target_presentation_time); - if anim.is_done() { - self.state = State::Hidden; - } - } - } - } - - pub fn are_animations_ongoing(&self) -> bool { - !matches!(self.state, State::Hidden) - } - - pub fn render<R: NiriRenderer>( - &self, - renderer: &mut R, - output: &Output, - ) -> Option<ConfigErrorNotificationRenderElement<R>> { - if matches!(self.state, State::Hidden) { - return None; - } - - let scale = output.current_scale().integer_scale(); - let path = self.created_path.as_deref(); - - let mut buffers = self.buffers.borrow_mut(); - let buffer = buffers - .entry(scale) - .or_insert_with_key(move |&scale| render(scale, path).ok()); - let buffer = buffer.as_ref()?; - - let elem = MemoryRenderBufferRenderElement::from_buffer( - renderer, - (0., 0.), - buffer, - Some(0.9), - None, - None, - Kind::Unspecified, - ) - .ok()?; - - let output_transform = output.current_transform(); - let output_mode = output.current_mode().unwrap(); - let output_size = output_transform.transform_size(output_mode.size); - - let buffer_size = elem - .geometry(output.current_scale().fractional_scale().into()) - .size; - - let y_range = buffer_size.h + PADDING * 2 * scale; - - let x = (output_size.w / 2 - buffer_size.w / 2).max(0); - let y = match &self.state { - State::Hidden => unreachable!(), - State::Showing(anim) | State::Hiding(anim) => { - (-buffer_size.h as f64 + anim.value() * y_range as f64).round() as i32 - } - State::Shown(_) => PADDING * 2 * scale, - }; - let elem = RelocateRenderElement::from_element(elem, (x, y), Relocate::Absolute); - - Some(elem) - } -} - -fn render(scale: i32, created_path: Option<&Path>) -> anyhow::Result<MemoryRenderBuffer> { - let _span = tracy_client::span!("config_error_notification::render"); - - let padding = PADDING * scale; - - let mut text = String::from(TEXT); - let mut border_color = (1., 0.3, 0.3); - if let Some(path) = created_path { - text = format!( - "Created a default config file at \ - <span face='monospace' bgcolor='#000000'>{:?}</span>", - path - ); - border_color = (0.5, 1., 0.5); - }; - - let mut font = FontDescription::from_string(FONT); - font.set_absolute_size((font.size() * scale).into()); - - let surface = ImageSurface::create(cairo::Format::ARgb32, 0, 0)?; - let cr = cairo::Context::new(&surface)?; - let layout = pangocairo::functions::create_layout(&cr); - layout.set_font_description(Some(&font)); - layout.set_markup(&text); - - let (mut width, mut height) = layout.pixel_size(); - width += padding * 2; - height += padding * 2; - - // FIXME: fix bug in Smithay that rounds pixel sizes down to scale. - width = (width + scale - 1) / scale * scale; - height = (height + scale - 1) / scale * scale; - - let surface = ImageSurface::create(cairo::Format::ARgb32, width, height)?; - let cr = cairo::Context::new(&surface)?; - cr.set_source_rgb(0.1, 0.1, 0.1); - cr.paint()?; - - cr.move_to(padding.into(), padding.into()); - let layout = pangocairo::functions::create_layout(&cr); - layout.set_font_description(Some(&font)); - layout.set_markup(&text); - - cr.set_source_rgb(1., 1., 1.); - pangocairo::functions::show_layout(&cr, &layout); - - cr.move_to(0., 0.); - cr.line_to(width.into(), 0.); - cr.line_to(width.into(), height.into()); - cr.line_to(0., height.into()); - cr.line_to(0., 0.); - cr.set_source_rgb(border_color.0, border_color.1, border_color.2); - cr.set_line_width((BORDER * scale).into()); - cr.stroke()?; - drop(cr); - - let data = surface.take_data().unwrap(); - let buffer = MemoryRenderBuffer::from_slice( - &data, - Fourcc::Argb8888, - (width, height), - scale, - Transform::Normal, - None, - ); - - Ok(buffer) -} |
