diff --git a/docs/Configuration guide.md b/docs/Configuration guide.md index 50682cf..a93b7c6 100644 --- a/docs/Configuration guide.md +++ b/docs/Configuration guide.md @@ -351,7 +351,14 @@ For information on the `Script` type, and embedding scripts in strings, see [her | Name | Type | Default | Description | |-----------|----------|---------|-----------------------------------------------------------------------------------| | `tooltip` | `string` | `null` | Shows this text on hover. Supports embedding scripts between `{{double braces}}`. | -| `name` | `string` | `null` | Sets the unique widget name, allowing you to style it using `#name`. | -| `class` | `string` | `null` | Sets one or more CSS classes, allowing you to style it using `.class`. | +| `name` | `string` | `null` | The unique widget name, allowing you to style it using `#name`. | +| `class` | `string` | `null` | One or more CSS classes, allowing you to style it using `.class`. | For more information on styling, please see the [styling guide](styling-guide). + +#### Formatting + +| Name | Type | Default | Description | +|---------------|--------------------------------------------------------|----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------| +| `orientation` | `horizontal` or `vertical` (shorthand: `'h'` or `'v'`) | `horizontal` or `vertical` | The direction in which the widget and its text are laid out. Some modules additionally provide a `direction` option to provide further control. | +| `justify` | `left`, `right`, `center`, `fill` | `left` | The justification (alignment) of the widget text shown on the bar. | diff --git a/docs/modules/Custom.md b/docs/modules/Custom.md index d93d7c7..ca9c430 100644 --- a/docs/modules/Custom.md +++ b/docs/modules/Custom.md @@ -71,12 +71,13 @@ A clickable button, which can run a command when clicked. > Type `button` -| Name | Type | Default | Description | -|------------|-------------------------------------------------|---------|--------------------------------------------------------------------------------------------------| -| `label` | [Dynamic String](dynamic-values#dynamic-string) | `null` | Widget text label. Pango markup and embedded scripts are supported. Ignored if `widgets` is set. | -| `widgets` | `(Module or Widget)[]` | `[]` | List of modules/widgets to add to this button. | -| `on_click` | `string [command]` | `null` | Command to execute. More on this [below](#commands). | -| `orientation` | `'horizontal'` or `'vertical'` (shorthand: `'h'` or `'v'`) | `'horizontal'` | Orientation of the button. | +| Name | Type | Default | Description | +|---------------|------------------------------------------------------------|----------------|--------------------------------------------------------------------------------------------------| +| `label` | [Dynamic String](dynamic-values#dynamic-string) | `null` | Widget text label. Pango markup and embedded scripts are supported. Ignored if `widgets` is set. | +| `widgets` | `(Module or Widget)[]` | `[]` | List of modules/widgets to add to this button. | +| `on_click` | `string [command]` | `null` | Command to execute. More on this [below](#commands). | +| `orientation` | `'horizontal'` or `'vertical'` (shorthand: `'h'` or `'v'`) | `'horizontal'` | Orientation of the label text. | +| `justify` | `'left'`, `'right'`, `'center'`, or `'fill'` | `'left'` | Justification (alignment) of the label text. | #### Image diff --git a/docs/modules/Network-Manager.md b/docs/modules/Network-Manager.md index 6dfadae..689de6e 100644 --- a/docs/modules/Network-Manager.md +++ b/docs/modules/Network-Manager.md @@ -17,6 +17,9 @@ Supports wired ethernet, wifi, cellular data and VPN connections among others. |-------------|-----------|---------|-------------------------| | `icon_size` | `integer` | `24` | Size to render icon at. | +> [!NOTE] +> This module does not support module-level [layout options](module-level-options#layout). +
JSON diff --git a/docs/modules/Notifications.md b/docs/modules/Notifications.md index 33617e3..2648432 100644 --- a/docs/modules/Notifications.md +++ b/docs/modules/Notifications.md @@ -21,6 +21,8 @@ Clicking the widget opens the SwayNC panel. | `icons.open_some` | `string` | `󱥁` | Icon to show when the panel is open, with notifications. | | `icons.open_dnd` | `string` | `󱅮` | Icon to show when the panel is open, with DnD enabled. Takes higher priority than count-based icons. | +> [!NOTE] +> This module does not support module-level [layout options](module-level-options#layout).
JSON diff --git a/src/config/impl.rs b/src/config/impl.rs index 696db62..dd64599 100644 --- a/src/config/impl.rs +++ b/src/config/impl.rs @@ -77,7 +77,7 @@ impl BarPosition { /// Gets the angle that label text should be displayed at /// based on this position. - pub const fn get_angle(self) -> f64 { + pub const fn angle(self) -> f64 { match self { Self::Top | Self::Bottom => 0.0, Self::Left => 90.0, diff --git a/src/config/layout.rs b/src/config/layout.rs new file mode 100644 index 0000000..bc2601c --- /dev/null +++ b/src/config/layout.rs @@ -0,0 +1,37 @@ +use crate::config::{ModuleJustification, ModuleOrientation}; +use crate::modules::ModuleInfo; +use serde::Deserialize; + +#[derive(Clone, Debug, Deserialize, Default)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] +pub struct LayoutConfig { + /// The orientation to display the widget contents. + /// Setting to vertical will rotate text 90 degrees. + /// + /// **Valid options**: `horizontal`, `vertical` + ///
+ /// **Default**: `horizontal` + orientation: Option, + + /// The justification (alignment) of the widget text shown on the bar. + /// + /// **Valid options**: `left`, `right`, `center`, `fill` + ///
+ /// **Default**: `left` + #[serde(default)] + pub justify: ModuleJustification, +} + +impl LayoutConfig { + pub fn orientation(&self, info: &ModuleInfo) -> gtk::Orientation { + self.orientation + .map(ModuleOrientation::into) + .unwrap_or(info.bar_position.orientation()) + } + + pub fn angle(&self, info: &ModuleInfo) -> f64 { + self.orientation + .map(ModuleOrientation::to_angle) + .unwrap_or(info.bar_position.angle()) + } +} diff --git a/src/config/mod.rs b/src/config/mod.rs index f4666d7..ae658da 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,5 +1,6 @@ mod common; mod r#impl; +mod layout; mod truncate; #[cfg(feature = "cairo")] @@ -46,6 +47,7 @@ use std::collections::HashMap; use schemars::JsonSchema; pub use self::common::{CommonConfig, ModuleJustification, ModuleOrientation, TransitionType}; +pub use self::layout::LayoutConfig; pub use self::truncate::{EllipsizeMode, TruncateMode}; #[derive(Debug, Deserialize, Clone)] diff --git a/src/image/gtk.rs b/src/image/gtk.rs index 6a59dcd..f2d2f83 100644 --- a/src/image/gtk.rs +++ b/src/image/gtk.rs @@ -5,30 +5,54 @@ use gtk::{Button, IconTheme, Image, Label, Orientation}; use std::ops::Deref; #[cfg(any(feature = "music", feature = "workspaces", feature = "clipboard"))] -pub fn new_icon_button(input: &str, icon_theme: &IconTheme, size: i32) -> Button { - let button = Button::new(); +#[derive(Debug, Clone)] +pub struct IconButton { + button: Button, + label: Label, +} - if ImageProvider::is_definitely_image_input(input) { +#[cfg(any(feature = "music", feature = "workspaces", feature = "clipboard"))] +impl IconButton { + pub fn new(input: &str, icon_theme: &IconTheme, size: i32) -> Self { + let button = Button::new(); let image = Image::new(); - image.add_class("image"); - image.add_class("icon"); + let label = Label::new(Some(input)); - match ImageProvider::parse(input, icon_theme, false, size) - .map(|provider| provider.load_into_image(&image)) - { - Some(_) => { - button.set_image(Some(&image)); - button.set_always_show_image(true); - } - None => { - button.set_label(input); + if ImageProvider::is_definitely_image_input(input) { + image.add_class("image"); + image.add_class("icon"); + + match ImageProvider::parse(input, icon_theme, false, size) + .map(|provider| provider.load_into_image(&image)) + { + Some(_) => { + button.set_image(Some(&image)); + button.set_always_show_image(true); + } + None => { + button.set_child(Some(&label)); + label.show(); + } } + } else { + button.set_child(Some(&label)); + label.show(); } - } else { - button.set_label(input); + + Self { button, label } } - button + pub fn label(&self) -> &Label { + &self.label + } +} + +impl Deref for IconButton { + type Target = Button; + + fn deref(&self) -> &Self::Target { + &self.button + } } #[cfg(any(feature = "music", feature = "keyboard"))] @@ -98,6 +122,10 @@ impl IconLabel { image.hide(); } } + + pub fn label(&self) -> &Label { + &self.label + } } impl Deref for IconLabel { diff --git a/src/modules/clipboard.rs b/src/modules/clipboard.rs index 9dbd68c..22648ed 100644 --- a/src/modules/clipboard.rs +++ b/src/modules/clipboard.rs @@ -1,8 +1,9 @@ use crate::clients::clipboard::{self, ClipboardEvent}; use crate::clients::wayland::{ClipboardItem, ClipboardValue}; -use crate::config::{CommonConfig, TruncateMode}; +use crate::config::{CommonConfig, LayoutConfig, TruncateMode}; +use crate::gtk_helpers::IronbarGtkExt; use crate::gtk_helpers::IronbarLabelExt; -use crate::image::new_icon_button; +use crate::image::IconButton; use crate::modules::{ Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, PopupButton, WidgetContext, }; @@ -14,6 +15,7 @@ use gtk::prelude::*; use gtk::{Button, EventBox, Image, Label, Orientation, RadioButton, Widget}; use serde::Deserialize; use std::collections::HashMap; +use std::ops::Deref; use tokio::sync::{broadcast, mpsc}; use tracing::{debug, error}; @@ -47,6 +49,10 @@ pub struct ClipboardModule { /// **Default**: `null` truncate: Option, + /// See [layout options](module-level-options#layout) + #[serde(default, flatten)] + layout: LayoutConfig, + /// See [common options](module-level-options#common-options). #[serde(flatten)] pub common: Option, @@ -142,8 +148,11 @@ impl Module