diff --git a/worf/src/lib/config.rs b/worf/src/lib/config.rs index bbae244..9718891 100644 --- a/worf/src/lib/config.rs +++ b/worf/src/lib/config.rs @@ -368,7 +368,7 @@ pub struct Config { hide_search: Option, #[clap(long = "dynamic-lines")] - dynamic_lines: Option, // todo support this + dynamic_lines: Option, #[clap(long = "layer")] layer: Option, @@ -635,6 +635,11 @@ impl Config { pub fn layer(&self) -> Layer { self.layer.clone().unwrap_or(Layer::Top) } + + #[must_use] + pub fn dynamic_lines(&self) -> bool { + self.dynamic_lines.unwrap_or(false) + } } fn default_false() -> bool { @@ -645,83 +650,6 @@ fn default_false() -> bool { // true // } -// -// // TODO -// // GtkOrientation orientation = config_get_mnemonic(config, "orientation", "vertical", 2, "vertical", "horizontal"); -// // outer_orientation = config_get_mnemonic(cstoonfig, "orientation", "vertical", 2, "horizontal", "vertical"); -// // GtkAlign halign = config_get_mnemonic(config, "halign", "fill", 4, "fill", "start", "end", "center"); -// // content_halign = config_get_mnemonic(config, "content_halign", "fill", 4, "fill", "start", "end", "center"); -// // char* default_valign = "start"; -// // if(outer_orientation == GTK_ORIENTATION_HORIZONTAL) { -// // default_valign = "center"; -// // } -// // GtkAlign valign = config_get_mnemonic(config, "valign", default_valign, 4, "fill", "start", "end", "center"); -// // char* prompt = config_get(config, "prompt", mode); -// // uint64_t filter_rate = strtol(config_get(config, "filter_rate", "100"), NULL, 10); -// // allow_markup = strcmp(config_get(config, "allow_markup", "false"), "true") == 0; -// // image_size = strtol(config_get(config, "image_size", "32"), NULL, 10); -// // cache_file = map_get(config, "cache_file"); -// // config_dir = map_get(config, "config_dir"); -// // terminal = map_get(config, "term"); -// // exec_search = strcmp(config_get(config, "exec_search", "false"), "true") == 0; -// // bool hide_scroll = strcmp(config_get(config, "hide_scroll", "false"), "true") == 0; -// // matching = config_get_mnemonic(config, "matching", "contains", 3, "contains", "multi-contains", "fuzzy"); -// // insensitive = strcmp(config_get(config, "insensitive", "false"), "true") == 0; -// // parse_search = strcmp(config_get(config, "parse_search", "false"), "true") == 0; -// // location = config_get_mnemonic(config, "location", "center", 18, -// // "center", "top_left", "top", "top_right", "right", "bottom_right", "bottom", "bottom_left", "left", -// // "0", "1", "2", "3", "4", "5", "6", "7", "8"); -// // no_actions = strcmp(config_get(config, "no_actions", "false"), "true") == 0; -// // lines = strtol(config_get(config, "lines", "0"), NULL, 10); -// // max_lines = lines; -// // columns = strtol(config_get(config, "columns", "1"), NULL, 10); -// // sort_order = config_get_mnemonic(config, "sort_order", "default", 2, "default", "alphabetical"); -// // bool global_coords = strcmp(config_get(config, "global_coords", "false"), "true") == 0; -// // hide_search = strcmp(config_get(config, "hide_search", "false"), "true") == 0; -// // char* search = map_get(config, "search"); -// // dynamic_lines = strcmp(config_get(config, "dynamic_lines", "false"), "true") == 0; -// // char* monitor = map_get(config, "monitor"); -// // char* layer = config_get(config, "layer", "top"); -// // copy_exec = config_get(config, "copy_exec", "wl-copy"); -// // pre_display_cmd = map_get(config, "pre_display_cmd"); -// // pre_display_exec = strcmp(config_get(config, "pre_display_exec", "false"), "true") == 0; -// // single_click = strcmp(config_get(config, "single_click", "false"), "true") == 0; -// // -// // keys = map_init_void(); -// // mods = map_init_void(); -// // -// // map_put_void(mods, "Shift", &shift_mask); -// // map_put_void(mods, "Ctrl", &ctrl_mask); -// // map_put_void(mods, "Alt", &alt_mask); -// // -// // key_default = "Up"; -// // char* key_up = (i == 0) ? "Up" : config_get(config, "key_up", key_default); -// // key_default = "Down"; -// // char* key_down = (i == 0) ? key_default : config_get(config, "key_down", key_default); -// // key_default = "Left"; -// // char* key_left = (i == 0) ? key_default : config_get(config, "key_left", key_default); -// // key_default = "Right"; -// // char* key_right = (i == 0) ? key_default : config_get(config, "key_right", key_default); -// // key_default = "Tab"; -// // char* key_forward = (i == 0) ? key_default : config_get(config, "key_forward", key_default); -// // key_default = "Shift-ISO_Left_Tab"; -// // char* key_backward = (i == 0) ? key_default : config_get(config, "key_backward", key_default); -// // key_default = "Return"; -// // char* key_submit = (i == 0) ? key_default : config_get(config, "key_submit", key_default); -// // key_default = "Escape"; -// // char* key_exit = (i == 0) ? key_default : config_get(config, "key_exit", key_default); -// // key_default = "Page_Up"; -// // char* key_pgup = (i == 0) ? key_default : config_get(config, "key_pgup", key_default); -// // key_default = "Page_Down"; -// // char* key_pgdn = (i == 0) ? key_default : config_get(config, "key_pgdn", key_default); -// // key_default = ""; -// // char* key_expand = (i == 0) ? key_default: config_get(config, "key_expand", key_default); -// // key_default = ""; -// // char* key_hide_search = (i == 0) ? key_default: config_get(config, "key_hide_search", key_default); -// // key_default = "Ctrl-c"; -// // char* key_copy = (i == 0) ? key_default : config_get(config, "key_copy", key_default); -// } - #[must_use] pub fn parse_args() -> Config { Config::parse() diff --git a/worf/src/lib/gui.rs b/worf/src/lib/gui.rs index ab6c9ba..67bf152 100644 --- a/worf/src/lib/gui.rs +++ b/worf/src/lib/gui.rs @@ -988,7 +988,16 @@ fn handle_key_press( &meta.config, meta.search_ignored_words.as_ref(), ); + 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, + )); + } }; let update_view_from_provider = |query: &String| { @@ -1151,7 +1160,6 @@ fn sort_menu_items_by_score( } } -#[allow(clippy::cast_possible_truncation)] // does not matter for calculating height fn window_show_resize(config: &Config, ui: &Rc>) { // Get the surface and associated monitor geometry let Some(surface) = ui.window.surface() else { @@ -1171,57 +1179,9 @@ fn window_show_resize(config: &Config, ui: &Rc }; let target_height = if let Some(lines) = config.lines() { - let (_, _, _, height_search) = ui.search.measure(Orientation::Vertical, 10_000); - let (height_box, _, _, _) = ui.custom_key_box.measure(Orientation::Vertical, 10_000); - let (_, scroll_height, _, _) = ui.scroll.measure(Orientation::Vertical, 10_000); - let (_, window_height, _, _) = ui.window.measure(Orientation::Vertical, 10_000); - - let height = { - let lock = ui.menu_rows.read().unwrap(); - lock.iter() - .find_map(|(fb, _)| { - let (_, _, _, baseline) = fb.measure(Orientation::Vertical, 10_000); - 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 - } else { - 1.0 - }; - - if config.allow_images() && baseline < i32::from(config.image_size()) { - Some(i32::from(config.image_size())) - } else { - Some((f64::from(baseline) * factor) as i32) - } - } else { - None - } - }) - .or_else(|| { - lock.iter().find_map(|(fb, _)| { - let (_, nat, _, _) = fb.measure(Orientation::Vertical, 10_000); - if nat > 0 { Some(nat) } else { None } - }) - }) - }; - - log::debug!( - "heights: scroll {scroll_height}, window {window_height}, keys {height_box}, height {height:?}" - ); - - if let Some(height) = height { - Some( - height_box - + scroll_height - + height_search - + height * lines - + config.lines_additional_space(), - ) - } else { - log::warn!("No widget for height calculation available"); - Some(0) - } + Some(calculate_row_height(ui, lines, config)) + } else if config.dynamic_lines() { + Some(calculate_row_height(ui, visible_row_count(ui), config)) } else if let Some(height) = percent_or_absolute(&config.height(), geometry.height()) { Some(height) } else { @@ -1238,10 +1198,75 @@ fn window_show_resize(config: &Config, ui: &Rc } } +#[allow(clippy::cast_possible_truncation)] // does not matter for calculating height +fn calculate_row_height( + ui: &UiElements, + lines: i32, + config: &Config, +) -> i32 { + const MEAS_SIZE: i32 = 10_000; + let (_, _, _, height_search) = ui.search.measure(Orientation::Vertical, MEAS_SIZE); + let (height_box, _, _, _) = ui.custom_key_box.measure(Orientation::Vertical, MEAS_SIZE); + let (_, scroll_height, _, _) = ui.scroll.measure(Orientation::Vertical, MEAS_SIZE); + let (_, window_height, _, _) = ui.window.measure(Orientation::Vertical, MEAS_SIZE); + + let height = { + let lock = ui.menu_rows.read().unwrap(); + lock.iter() + .find_map(|(fb, _)| { + let (_, _, _, baseline) = fb.measure(Orientation::Vertical, MEAS_SIZE); + 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 + } else { + 1.0 + }; + + if config.allow_images() && baseline < i32::from(config.image_size()) { + Some(i32::from(config.image_size())) + } else { + Some((f64::from(baseline) * factor) as i32) + } + } else { + None + } + }) + .or_else(|| { + lock.iter().find_map(|(fb, _)| { + let (_, nat, _, _) = fb.measure(Orientation::Vertical, MEAS_SIZE); + if nat > 0 { Some(nat) } else { None } + }) + }) + }; + + log::debug!( + "heights: scroll {scroll_height}, window {window_height}, keys {height_box}, height {height:?}" + ); + + height_box + + scroll_height + + height_search + + height.map_or(0, |h| h * lines) + + config.lines_additional_space() +} + fn close_gui(app: &Application) { app.quit(); } +fn visible_row_count(ui: &UiElements) -> i32 { + i32::try_from( + ui.menu_rows + .read() + .unwrap() + .iter() + .filter(|(_, menu)| menu.visible) + .count(), + ) + .unwrap_or(i32::MAX) +} + fn handle_selected_item( ui: &Rc>, meta: Rc>,