diff --git a/worf/src/lib/config.rs b/worf/src/lib/config.rs index 9718891..696bdc2 100644 --- a/worf/src/lib/config.rs +++ b/worf/src/lib/config.rs @@ -367,9 +367,17 @@ pub struct Config { #[clap(long = "hide-search")] hide_search: Option, + /// If enabled, worf will resize according to the amount of displayed rows + /// defaults to false #[clap(long = "dynamic-lines")] dynamic_lines: Option, + /// If enabled, dynamic lines do not exceed the maximum height specified in the + /// `height` option. It does ot evaluate the `lines` option though + /// defaults to true + #[clap(long = "dynamic-lines-limit")] + dynamic_lines_limit: Option, + #[clap(long = "layer")] layer: Option, @@ -640,6 +648,11 @@ impl Config { pub fn dynamic_lines(&self) -> bool { self.dynamic_lines.unwrap_or(false) } + + #[must_use] + pub fn dynamic_lines_limit(&self) -> bool { + self.dynamic_lines_limit.unwrap_or(true) + } } fn default_false() -> bool { diff --git a/worf/src/lib/gui.rs b/worf/src/lib/gui.rs index 67bf152..5ef1f3f 100644 --- a/worf/src/lib/gui.rs +++ b/worf/src/lib/gui.rs @@ -8,7 +8,7 @@ use std::{ use crossbeam::channel::{self, Sender}; use gdk4::{ - Display, + Display, Rectangle, gio::File, glib::{self, MainContext, Propagation}, prelude::{Cast, DisplayExt, MonitorExt, SurfaceExt}, @@ -992,11 +992,10 @@ fn handle_key_press( select_first_visible_child(&*lock, &ui.main_box); drop(lock); if meta.config.dynamic_lines() { - ui.window.set_height_request(calculate_row_height( - ui, - visible_row_count(ui), - &meta.config, - )); + if let Some(geometry) = get_monitor_geometry(ui) { + let height = calculate_dynamic_lines_window_height(&meta.config, ui, geometry); + ui.window.set_height_request(height); + } } }; @@ -1019,7 +1018,7 @@ fn handle_key_press( custom_key.key == keyboard_key.to_upper().into() } && mods.is_subset(&custom_key.modifiers); - log::debug!("customy key {custom_key:?}, match {custom_key_match}"); + log::debug!("custom key {custom_key:?}, match {custom_key_match}"); if custom_key_match { let search_lock = ui.search_text.lock().unwrap(); @@ -1161,16 +1160,7 @@ fn sort_menu_items_by_score( } fn window_show_resize(config: &Config, ui: &Rc>) { - // Get the surface and associated monitor geometry - let Some(surface) = ui.window.surface() else { - return; - }; - - let display = surface.display(); - let Some(monitor) = display.monitor_at_surface(&surface) else { - return; - }; - let geometry = monitor.geometry(); + let Some(geometry) = get_monitor_geometry(ui) else { return }; // Calculate target width from config, return early if not set let Some(target_width) = percent_or_absolute(&config.width(), geometry.width()) else { @@ -1181,7 +1171,7 @@ fn window_show_resize(config: &Config, ui: &Rc let target_height = if let Some(lines) = config.lines() { Some(calculate_row_height(ui, lines, config)) } else if config.dynamic_lines() { - Some(calculate_row_height(ui, visible_row_count(ui), config)) + Some(calculate_dynamic_lines_window_height(&config, ui, geometry)) } else if let Some(height) = percent_or_absolute(&config.height(), geometry.height()) { Some(height) } else { @@ -1198,6 +1188,29 @@ fn window_show_resize(config: &Config, ui: &Rc } } +fn calculate_dynamic_lines_window_height(config: &Config, ui: &UiElements, geometry: Rectangle) -> i32 { + if config.dynamic_lines_limit() { + calculate_row_height(ui, visible_row_count(ui), config) + .min(percent_or_absolute(&config.height(), geometry.height()).unwrap_or(0)) + } else { + calculate_row_height(ui, visible_row_count(ui), config) + } +} + +fn get_monitor_geometry(ui: &UiElements) -> Option { + // Get the surface and associated monitor geometry + let Some(surface) = ui.window.surface() else { + return None; + }; + + let display = surface.display(); + let Some(monitor) = display.monitor_at_surface(&surface) else { + return None; + }; + let geometry = monitor.geometry(); + Some(geometry) +} + #[allow(clippy::cast_possible_truncation)] // does not matter for calculating height fn calculate_row_height( ui: &UiElements, @@ -1218,7 +1231,7 @@ fn calculate_row_height( if baseline > 0 { let factor = if lines > 1 { 1.4 // todo find a better way to do this - // most likely it will not work with all styles + // most likely it will not work with all styles } else { 1.0 }; @@ -1264,7 +1277,7 @@ fn visible_row_count(ui: &UiElements) -> i32 { .filter(|(_, menu)| menu.visible) .count(), ) - .unwrap_or(i32::MAX) + .unwrap_or(i32::MAX) } fn handle_selected_item( @@ -1403,10 +1416,10 @@ fn create_menu_row( element_to_add.icon_path.as_ref().map(AsRef::as_ref), &meta.config, ) - .or(lookup_icon( - label_img.as_ref().map(AsRef::as_ref), - &meta.config, - )); + .or(lookup_icon( + label_img.as_ref().map(AsRef::as_ref), + &meta.config, + )); if let Some(image) = img { image.set_widget_name("img");