Skip to content

Commit

Permalink
Merge pull request #505 from JakeStanger/feat/modules-in-custom
Browse files Browse the repository at this point in the history
Native modules inside custom modules
  • Loading branch information
JakeStanger authored Apr 1, 2024
2 parents 80dd2cc + ee8873a commit e1a9f73
Show file tree
Hide file tree
Showing 23 changed files with 518 additions and 253 deletions.
1 change: 1 addition & 0 deletions docs/Configuration guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ For information on the `Script` type, and embedding scripts in strings, see [her
| `show_if` | [Dynamic Boolean](dynamic-values#dynamic-boolean) | `null` | Polls the script to check its exit code. If exit code is zero, the module is shown. For other codes, it is hidden. |
| `transition_type` | `slide_start` or `slide_end` or `crossfade` or `none` | `slide_start` | The transition animation to use when showing/hiding the widget. |
| `transition_duration` | `integer` | `250` | The length of the transition animation to use when showing/hiding the widget. |
| `disable_popup` | `boolean` | `false` | Prevents the popup from opening on-click for this widget. |

#### Appearance

Expand Down
26 changes: 24 additions & 2 deletions docs/modules/Custom.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
Allows you to compose custom modules consisting of multiple widgets, including popups.
Allows you to compose custom modules consisting of multiple modules and widgets, including popups.
Labels can display dynamic content from scripts, and buttons can interact with the bar or execute commands on click.

The module provides a set of utility widgets, such as containers, labels and buttons.
In addition to these, you can also add any native module.
Paired with the other custom modules such as Cairo,
this provides a powerful declarative interface for constructing your own interfaces.

If you only intend to run a single script, prefer the [script](script) module,
or [label](label) if you only need a single text label.

Expand All @@ -13,6 +18,11 @@ or [label](label) if you only need a single text label.
This module can be quite fiddly to configure as you effectively have to build a tree of widgets by hand.
It is well worth looking at the examples.

| Name | Type | Default | Description |
|---------|------------------------|------------|------------------------------------------|
| `bar` | `(Module or Widget)[]` | `[]` | Modules and widgets to add to the bar. |
| `popup` | `(Module or Widget)[]` | `null` | Modules and widgets to add to the popup. |

### `Widget`

There are many widget types, each with their own config options.
Expand All @@ -36,7 +46,7 @@ A container to place nested widgets inside.
| Name | Type | Default | Description |
|---------------|------------------------------------------------------------|----------------|-------------------------------------------------------------------|
| `orientation` | `'horizontal'` or `'vertical'` (shorthand: `'h'` or `'v'`) | `'horizontal'` | Whether child widgets should be horizontally or vertically added. |
| `widgets` | `Widget[]` | `[]` | List of widgets to add to this box. |
| `widgets` | `(Module or Widget)[]` | `[]` | List of widgets to add to this box. |

#### Label

Expand Down Expand Up @@ -197,6 +207,7 @@ to help get your head around what's going on:
<button class="power-btn" label="" on_click="!reboot" />
</box>
<label name="uptime" label="Uptime: {{30000:uptime -p | cut -d ' ' -f2-}}" />
<clock disable_popup="true" />
</box>
</popup>
</custom>
Expand Down Expand Up @@ -252,6 +263,10 @@ to help get your head around what's going on:
"label": "Uptime: {{30000:uptime -p | cut -d ' ' -f2-}}",
"name": "uptime",
"type": "label"
},
{
"type": "clock",
"disable_popup": true
}
]
}
Expand Down Expand Up @@ -309,6 +324,10 @@ type = 'button'
label = '''Uptime: {{30000:uptime -p | cut -d ' ' -f2-}}'''
name = 'uptime'
type = 'label'

[[end.popup.widgets]]
type = 'clock'
disable_popup = true
```

</details>
Expand Down Expand Up @@ -345,6 +364,8 @@ end:
- label: 'Uptime: {{30000:uptime -p | cut -d '' '' -f2-}}'
name: uptime
type: label
- type: clock
disable_popup: true
type: custom
```
Expand All @@ -370,6 +391,7 @@ let {
]
}
{ type = "label" name = "uptime" label = "Uptime: {{30000:uptime -p | cut -d ' ' -f2-}}" }
{ type = "clock" disable_popup = true }
]
}

Expand Down
53 changes: 3 additions & 50 deletions src/bar.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use crate::config::{BarConfig, BarPosition, MarginConfig, ModuleConfig};
use crate::modules::{
create_module, set_widget_identifiers, wrap_widget, ModuleInfo, ModuleLocation,
};
use crate::modules::{BarModuleFactory, ModuleInfo, ModuleLocation};
use crate::popup::Popup;
use crate::Ironbar;
use color_eyre::Result;
Expand Down Expand Up @@ -350,55 +348,10 @@ fn add_modules(
ironbar: &Rc<Ironbar>,
popup: &Rc<Popup>,
) -> Result<()> {
let orientation = info.bar_position.orientation();

macro_rules! add_module {
($module:expr, $id:expr) => {{
let common = $module.common.take().expect("common config to exist");
let widget_parts = create_module(
*$module,
$id,
ironbar.clone(),
common.name.clone(),
&info,
&Rc::clone(&popup),
)?;
set_widget_identifiers(&widget_parts, &common);

let container = wrap_widget(&widget_parts.widget, common, orientation);
content.add(&container);
}};
}
let module_factory = BarModuleFactory::new(ironbar.clone(), popup.clone()).into();

for config in modules {
let id = Ironbar::unique_id();
match config {
#[cfg(feature = "clipboard")]
ModuleConfig::Clipboard(mut module) => add_module!(module, id),
#[cfg(feature = "clock")]
ModuleConfig::Clock(mut module) => add_module!(module, id),
ModuleConfig::Custom(mut module) => add_module!(module, id),
#[cfg(feature = "focused")]
ModuleConfig::Focused(mut module) => add_module!(module, id),
ModuleConfig::Label(mut module) => add_module!(module, id),
#[cfg(feature = "launcher")]
ModuleConfig::Launcher(mut module) => add_module!(module, id),
#[cfg(feature = "music")]
ModuleConfig::Music(mut module) => add_module!(module, id),
#[cfg(feature = "notifications")]
ModuleConfig::Notifications(mut module) => add_module!(module, id),
ModuleConfig::Script(mut module) => add_module!(module, id),
#[cfg(feature = "sys_info")]
ModuleConfig::SysInfo(mut module) => add_module!(module, id),
#[cfg(feature = "tray")]
ModuleConfig::Tray(mut module) => add_module!(module, id),
#[cfg(feature = "upower")]
ModuleConfig::Upower(mut module) => add_module!(module, id),
#[cfg(feature = "volume")]
ModuleConfig::Volume(mut module) => add_module!(module, id),
#[cfg(feature = "workspaces")]
ModuleConfig::Workspaces(mut module) => add_module!(module, id),
}
config.create(&module_factory, content, info)?;
}

Ok(())
Expand Down
1 change: 1 addition & 0 deletions src/config/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub struct CommonConfig {
pub on_mouse_exit: Option<ScriptInput>,

pub tooltip: Option<String>,
pub disable_popup: bool,
}

#[derive(Debug, Deserialize, Clone)]
Expand Down
46 changes: 46 additions & 0 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ use crate::modules::upower::UpowerModule;
use crate::modules::volume::VolumeModule;
#[cfg(feature = "workspaces")]
use crate::modules::workspaces::WorkspacesModule;

use crate::modules::{AnyModuleFactory, ModuleFactory, ModuleInfo};
use cfg_if::cfg_if;
use color_eyre::Result;
use serde::Deserialize;
use std::collections::HashMap;

Expand Down Expand Up @@ -64,6 +67,49 @@ pub enum ModuleConfig {
Workspaces(Box<WorkspacesModule>),
}

impl ModuleConfig {
pub fn create(
self,
module_factory: &AnyModuleFactory,
container: &gtk::Box,
info: &ModuleInfo,
) -> Result<()> {
macro_rules! create {
($module:expr) => {
module_factory.create(*$module, container, info)
};
}

match self {
#[cfg(feature = "clipboard")]
Self::Clipboard(module) => create!(module),
#[cfg(feature = "clock")]
Self::Clock(module) => create!(module),
Self::Custom(module) => create!(module),
#[cfg(feature = "focused")]
Self::Focused(module) => create!(module),
Self::Label(module) => create!(module),
#[cfg(feature = "launcher")]
Self::Launcher(module) => create!(module),
#[cfg(feature = "music")]
Self::Music(module) => create!(module),
#[cfg(feature = "notifications")]
Self::Notifications(module) => create!(module),
Self::Script(module) => create!(module),
#[cfg(feature = "sys_info")]
Self::SysInfo(module) => create!(module),
#[cfg(feature = "tray")]
Self::Tray(module) => create!(module),
#[cfg(feature = "upower")]
Self::Upower(module) => create!(module),
#[cfg(feature = "volume")]
Self::Volume(module) => create!(module),
#[cfg(feature = "workspaces")]
Self::Workspaces(module) => create!(module),
}
}
}

#[derive(Debug, Deserialize, Clone)]
pub enum BarEntryConfig {
Single(BarConfig),
Expand Down
4 changes: 2 additions & 2 deletions src/ipc/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ impl Ipc {
popup.hide();

let data = popup
.cache
.container_cache
.borrow()
.iter()
.find(|(_, value)| value.name == name)
Expand Down Expand Up @@ -209,7 +209,7 @@ impl Ipc {
popup.hide();

let data = popup
.cache
.container_cache
.borrow()
.iter()
.find(|(_, value)| value.name == name)
Expand Down
28 changes: 28 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@
/// Provides implementations of methods required by the `Module` trait
/// which cannot be included as part of the trait.
///
/// This removes the need to add the same boilerplate method definitions
/// to every module implementation.
///
/// # Usage:
///
/// ```rs
/// impl Module for ClockModule {
/// type SendMessage = DateTime<Local>;
/// type ReceiveMessage = ();
///
/// module_impl!("clock");
/// }
#[macro_export]
macro_rules! module_impl {
($name:literal) => {
fn name() -> &'static str {
$name
}

fn take_common(&mut self) -> $crate::config::CommonConfig {
self.common.take().expect("common config to exist")
}
};
}

/// Sends a message on an asynchronous `Sender` using `send()`
/// Panics if the message cannot be sent.
///
Expand Down
9 changes: 4 additions & 5 deletions src/modules/clipboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::image::new_icon_button;
use crate::modules::{
Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, PopupButton, WidgetContext,
};
use crate::{glib_recv, spawn, try_send};
use crate::{glib_recv, module_impl, spawn, try_send};
use glib::Propagation;
use gtk::gdk_pixbuf::Pixbuf;
use gtk::gio::{Cancellable, MemoryInputStream};
Expand Down Expand Up @@ -65,9 +65,7 @@ impl Module<Button> for ClipboardModule {
type SendMessage = ControllerEvent;
type ReceiveMessage = UIEvent;

fn name() -> &'static str {
"clipboard"
}
module_impl!("clipboard");

fn spawn_controller(
&self,
Expand Down Expand Up @@ -137,7 +135,7 @@ impl Module<Button> for ClipboardModule {

let rx = context.subscribe();
let popup = self
.into_popup(context.controller_tx, rx, info)
.into_popup(context.controller_tx.clone(), rx, context, info)
.into_popup_parts(vec![&button]);

Ok(ModuleParts::new(button, popup))
Expand All @@ -147,6 +145,7 @@ impl Module<Button> for ClipboardModule {
self,
tx: mpsc::Sender<Self::ReceiveMessage>,
rx: broadcast::Receiver<Self::SendMessage>,
_context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
_info: &ModuleInfo,
) -> Option<gtk::Box>
where
Expand Down
14 changes: 9 additions & 5 deletions src/modules/clock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::gtk_helpers::IronbarGtkExt;
use crate::modules::{
Module, ModuleInfo, ModuleParts, ModulePopup, ModuleUpdateEvent, PopupButton, WidgetContext,
};
use crate::{glib_recv, send_async, spawn, try_send};
use crate::{glib_recv, module_impl, send_async, spawn, try_send};

#[derive(Debug, Deserialize, Clone)]
pub struct ClockModule {
Expand Down Expand Up @@ -71,9 +71,7 @@ impl Module<Button> for ClockModule {
type SendMessage = DateTime<Local>;
type ReceiveMessage = ();

fn name() -> &'static str {
"clock"
}
module_impl!("clock");

fn spawn_controller(
&self,
Expand Down Expand Up @@ -120,7 +118,12 @@ impl Module<Button> for ClockModule {
});

let popup = self
.into_popup(context.controller_tx.clone(), context.subscribe(), info)
.into_popup(
context.controller_tx.clone(),
context.subscribe(),
context,
info,
)
.into_popup_parts(vec![&button]);

Ok(ModuleParts::new(button, popup))
Expand All @@ -130,6 +133,7 @@ impl Module<Button> for ClockModule {
self,
_tx: mpsc::Sender<Self::ReceiveMessage>,
rx: broadcast::Receiver<Self::SendMessage>,
_context: WidgetContext<Self::SendMessage, Self::ReceiveMessage>,
_info: &ModuleInfo,
) -> Option<gtk::Box> {
let container = gtk::Box::new(Orientation::Vertical, 0);
Expand Down
Loading

0 comments on commit e1a9f73

Please sign in to comment.