rework wrap mode

This commit is contained in:
Alexander Mohr 2025-04-21 17:27:28 +02:00
parent d08893d545
commit a655658493
3 changed files with 67 additions and 62 deletions

View file

@ -38,6 +38,7 @@ layerrule = blur, worf
because worf is build on GTK4 instead of GTK3 there will be differences in the look and feel. because worf is build on GTK4 instead of GTK3 there will be differences in the look and feel.
* Configuration files are not 100% compatible, Worf is using toml files instead, for most part this only means strings have to be quoted * Configuration files are not 100% compatible, Worf is using toml files instead, for most part this only means strings have to be quoted
* Color files are not supported * Color files are not supported
* `line_wrap` is now called `line-wrap`
## Dropped arguments ## Dropped arguments
* `mode`, use show * `mode`, use show

View file

@ -51,6 +51,13 @@ pub enum Animation {
ExpandHorizontal, ExpandHorizontal,
} }
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum WrapMode {
None,
Word,
Inherit,
}
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub enum Mode { pub enum Mode {
/// searches `$PATH` for executables and allows them to be run by selecting them. /// searches `$PATH` for executables and allows them to be run by selecting them.
@ -90,7 +97,22 @@ impl FromStr for Mode {
"math" => Ok(Mode::Math), "math" => Ok(Mode::Math),
"auto" => Ok(Mode::Auto), "auto" => Ok(Mode::Auto),
_ => Err(ArgsError::InvalidParameter( _ => Err(ArgsError::InvalidParameter(
format!("{s} is not a valid argument show this, see help for details").to_owned(), format!("{s} is not a valid argument, see help for details").to_owned(),
)),
}
}
}
impl FromStr for WrapMode {
type Err = ArgsError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"none" => Ok(WrapMode::None),
"word" => Ok(WrapMode::Word),
"inherit" => Ok(WrapMode::Inherit),
_ => Err(ArgsError::InvalidParameter(
format!("{s} is not a valid argument, see help for details").to_owned(),
)), )),
} }
} }
@ -215,19 +237,23 @@ pub struct Config {
#[clap(long = "orientation")] #[clap(long = "orientation")]
pub orientation: Option<Orientation>, pub orientation: Option<Orientation>,
/// Horizontal alignment
#[serde(default = "default_halign")] #[serde(default = "default_halign")]
#[clap(long = "halign")] #[clap(long = "halign")]
pub halign: Option<Align>, pub halign: Option<Align>,
/// Alignment of content
#[serde(default = "default_content_halign")] #[serde(default = "default_content_halign")]
#[clap(long = "content-halign")] #[clap(long = "content-halign")]
pub content_halign: Option<Align>, pub content_halign: Option<Align>,
/// Vertical alignment
#[clap(long = "valign")] #[clap(long = "valign")]
pub valign: Option<Align>, pub valign: Option<Align>,
pub filter_rate: Option<u32>, pub filter_rate: Option<u32>,
/// Defines the image size in pixels
#[serde(default = "default_image_size")] #[serde(default = "default_image_size")]
#[clap(long = "image-size")] #[clap(long = "image-size")]
pub image_size: Option<i32>, pub image_size: Option<i32>,
@ -249,7 +275,6 @@ pub struct Config {
// todo re-add this // todo re-add this
// #[serde(flatten)] // #[serde(flatten)]
// pub key_custom: Option<HashMap<String, String>>, // pub key_custom: Option<HashMap<String, String>>,
pub line_wrap: Option<String>,
pub global_coords: Option<bool>, pub global_coords: Option<bool>,
pub hide_search: Option<bool>, pub hide_search: Option<bool>,
pub dynamic_lines: Option<bool>, pub dynamic_lines: Option<bool>,
@ -268,17 +293,16 @@ pub struct Config {
#[clap(long = "row-box-orientation")] #[clap(long = "row-box-orientation")]
pub row_bow_orientation: Option<Orientation>, pub row_bow_orientation: Option<Orientation>,
/// Set to to true to wrap text after a given amount of chars // /// Set to to true to wrap text after a given amount of chars
#[serde(default = "default_text_wrap")] // #[serde(default = "default_text_wrap")]
#[clap(long = "text-wrap")] // #[clap(long = "text-wrap")]
pub text_wrap: Option<bool>, // pub text_wrap: Option<bool>,
//
/// Defines after how many chars a line is broken over. // /// Defines after how many chars a line is broken over.
/// Only cuts at spaces. // /// Only cuts at spaces.
#[serde(default = "default_text_wrap_length")] // #[serde(default = "default_text_wrap_length")]
#[clap(long = "text-wrap-length")] // #[clap(long = "text-wrap-length")]
pub text_wrap_length: Option<usize>, // pub text_wrap_length: Option<usize>,
/// Defines the animation when the window is show. /// Defines the animation when the window is show.
/// Defaults to Expand /// Defaults to Expand
#[serde(default = "default_show_animation")] #[serde(default = "default_show_animation")]
@ -303,6 +327,10 @@ pub struct Config {
#[serde(default = "default_hide_animation_time")] #[serde(default = "default_hide_animation_time")]
#[clap(long = "hide-animation-time")] #[clap(long = "hide-animation-time")]
pub hide_animation_time: Option<u64>, pub hide_animation_time: Option<u64>,
#[serde(default = "default_line_wrap")]
#[clap(long = "line-wrap")]
pub line_wrap: Option<WrapMode>,
} }
impl Default for Config { impl Default for Config {
@ -359,7 +387,7 @@ impl Default for Config {
key_hide_search: None, key_hide_search: None,
key_copy: None, key_copy: None,
//key_custom: None, //key_custom: None,
line_wrap: None, line_wrap: default_line_wrap(),
global_coords: None, global_coords: None,
hide_search: None, hide_search: None,
dynamic_lines: None, dynamic_lines: None,
@ -369,8 +397,6 @@ impl Default for Config {
pre_display_exec: None, pre_display_exec: None,
fuzzy_min_score: default_fuzzy_min_score(), fuzzy_min_score: default_fuzzy_min_score(),
row_bow_orientation: default_row_box_orientation(), row_bow_orientation: default_row_box_orientation(),
text_wrap: default_text_wrap(),
text_wrap_length: default_text_wrap_length(),
show_animation: default_show_animation(), show_animation: default_show_animation(),
show_animation_time: default_show_animation_time(), show_animation_time: default_show_animation_time(),
hide_animation: default_hide_animation(), hide_animation: default_hide_animation(),
@ -449,6 +475,13 @@ pub fn default_normal_window() -> bool {
false false
} }
// allowed because option is needed for serde macro
#[allow(clippy::unnecessary_wraps)]
#[must_use]
pub fn default_line_wrap() -> Option<WrapMode> {
Some(WrapMode::Word)
}
// TODO // TODO
// GtkOrientation orientation = config_get_mnemonic(config, "orientation", "vertical", 2, "vertical", "horizontal"); // GtkOrientation orientation = config_get_mnemonic(config, "orientation", "vertical", 2, "vertical", "horizontal");
// outer_orientation = config_get_mnemonic(cstoonfig, "orientation", "vertical", 2, "horizontal", "vertical"); // outer_orientation = config_get_mnemonic(cstoonfig, "orientation", "vertical", 2, "horizontal", "vertical");
@ -588,20 +621,6 @@ pub fn default_image_size() -> Option<i32> {
Some(32) Some(32)
} }
// allowed because option is needed for serde macro
#[allow(clippy::unnecessary_wraps)]
#[must_use]
pub fn default_text_wrap_length() -> Option<usize> {
Some(15)
}
// allowed because option is needed for serde macro
#[allow(clippy::unnecessary_wraps)]
#[must_use]
pub fn default_text_wrap() -> Option<bool> {
Some(false)
}
#[must_use] #[must_use]
pub fn parse_args() -> Config { pub fn parse_args() -> Config {
Config::parse() Config::parse()

View file

@ -15,16 +15,13 @@ use gtk4::prelude::{
ApplicationExt, ApplicationExtManual, BoxExt, EditableExt, FlowBoxChildExt, GestureSingleExt, ApplicationExt, ApplicationExtManual, BoxExt, EditableExt, FlowBoxChildExt, GestureSingleExt,
GtkWindowExt, ListBoxRowExt, NativeExt, WidgetExt, GtkWindowExt, ListBoxRowExt, NativeExt, WidgetExt,
}; };
use gtk4::{ use gtk4::{Align, EventControllerKey, Expander, FlowBox, FlowBoxChild, GestureClick, Image, Label, ListBox, ListBoxRow, Ordering, PolicyType, ScrolledWindow, SearchEntry, Widget, gdk, NaturalWrapMode};
Align, EventControllerKey, Expander, FlowBox, FlowBoxChild, GestureClick, Image, Label,
ListBox, ListBoxRow, Ordering, PolicyType, ScrolledWindow, SearchEntry, Widget, gdk,
};
use gtk4::{Application, ApplicationWindow, CssProvider, Orientation}; use gtk4::{Application, ApplicationWindow, CssProvider, Orientation};
use gtk4_layer_shell::{Edge, KeyboardMode, LayerShell}; use gtk4_layer_shell::{Edge, KeyboardMode, LayerShell};
use log; use log;
use crate::config; use crate::config;
use crate::config::{Animation, Config, MatchMethod}; use crate::config::{Animation, Config, MatchMethod, WrapMode};
type ArcMenuMap<T> = Arc<Mutex<HashMap<FlowBoxChild, MenuItem<T>>>>; type ArcMenuMap<T> = Arc<Mutex<HashMap<FlowBoxChild, MenuItem<T>>>>;
type ArcProvider<T> = Arc<Mutex<dyn ItemProvider<T>>>; type ArcProvider<T> = Arc<Mutex<dyn ItemProvider<T>>>;
@ -44,6 +41,16 @@ impl From<config::Orientation> for Orientation {
} }
} }
impl From<&WrapMode> for NaturalWrapMode {
fn from(value: &WrapMode) -> Self {
match value {
WrapMode::None => {NaturalWrapMode::None},
WrapMode::Word => {NaturalWrapMode::Word},
WrapMode::Inherit => {NaturalWrapMode::Inherit},
}
}
}
impl From<config::Align> for Align { impl From<config::Align> for Align {
fn from(align: config::Align) -> Self { fn from(align: config::Align) -> Self {
match align { match align {
@ -808,14 +815,14 @@ fn create_menu_row<T: Clone + 'static>(
row_box.append(&image); row_box.append(&image);
} }
// todo make max length configurable let label = Label::new(Some(menu_item.label.as_str()));
let text = if config.text_wrap.is_some_and(|x| x) { let wrap_mode : NaturalWrapMode = if let Some(config_wrap) = &config.line_wrap {
&wrap_text(&menu_item.label, config.text_wrap_length) config_wrap.into()
} else { } else {
menu_item.label.as_str() NaturalWrapMode::Word
}; };
let label = Label::new(Some(text)); label.set_natural_wrap_mode(wrap_mode);
label.set_hexpand(true); label.set_hexpand(true);
label.set_widget_name("label"); label.set_widget_name("label");
label.set_wrap(true); label.set_wrap(true);
@ -955,25 +962,3 @@ pub fn sort_menu_items_alphabetically_honor_initial_score<T: std::clone::Clone>(
} }
} }
} }
fn wrap_text(text: &str, line_length: Option<usize>) -> String {
let mut result = String::new();
let mut line = String::new();
let len = line_length.unwrap_or(text.len());
for word in text.split_whitespace() {
if line.len() + word.len() + 1 > len && !line.is_empty() {
result.push_str(line.trim_end());
result.push('\n');
line.clear();
}
line.push_str(word);
line.push(' ');
}
if !line.is_empty() {
result.push_str(line.trim_end());
}
result
}