Skip to content

Commit 44246d5

Browse files
feat: add menu module
Adds a new Menu module which allows users to create XDG or custom menus that open after clicking on a button. Resolves JakeStanger#534 Co-authored-by: Jake Stanger <mail@jstanger.dev>
1 parent 60b42c4 commit 44246d5

File tree

9 files changed

+955
-1
lines changed

9 files changed

+955
-1
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ jobs:
113113
- keyboard+hyprland
114114
- label
115115
- launcher
116+
- menu
116117
- music+all
117118
- music+mpris
118119
- music+mpd

Cargo.lock

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ default = [
2323
"keyboard+all",
2424
"launcher",
2525
"label",
26+
"menu",
2627
"music+all",
2728
"network_manager",
2829
"notifications",
@@ -76,6 +77,8 @@ label = []
7677

7778
launcher = []
7879

80+
menu = ["dep:freedesktop_entry_parser", "dep:unicode-segmentation"]
81+
7982
music = ["dep:regex"]
8083
"music+all" = ["music", "music+mpris", "music+mpd"]
8184
"music+mpris" = ["music", "mpris"]
@@ -159,6 +162,10 @@ chrono = { version = "0.4.41", optional = true, default-features = false, featur
159162
colpetto = { version = "0.6.0", features = ["tokio", "tracing"], optional = true }
160163
evdev-rs = { version = "0.6.1", optional = true }
161164

165+
# menu
166+
freedesktop_entry_parser = { version = "1.3.0", optional = true }
167+
unicode-segmentation = { version = "1.11.0", optional = true }
168+
162169
# music
163170
mpd-utils = { version = "0.2.1", optional = true }
164171
mpris = { version = "2.0.1", optional = true }

docs/modules/Menu.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
Application menu that shows installed programs and optionally custom entries. Clicking the menu button will open the main menu, clicking on any application category will open a sub-menu with any installed applications that match.
2+
3+
## Configuration
4+
5+
> Type: `menu`
6+
7+
| | Type | Default | Description |
8+
|--------------|------------|---------|-----------------------------------------------------------------------------------------------------|
9+
| `start` | `MenuEntry[]` | `[]` | List of menu entries |
10+
| `center` | `MenuEntry[]` | default XDG menu | List of menu entries. By default this shows a number of XDG entries that should cover all common applications |
11+
| `end` | `MenuEntry[]` | `[]` | List of menu entries |
12+
| `height` | `integer | null` | `null` | The height of the menu, leave null for it to resize dynamically |
13+
| `width` | `integer | null` | `null` | The width of the menu, leave null for it to resize dynamically |
14+
| `max_label_length` | `integer` | `25` | Maximum length for the label of an XDG entry |
15+
| `label` | `string | null` | `` | The label of the button that opens the menu |
16+
| `label_icon` | `string | null` | `null` | An icon (from icon theme) to display on the button which opens the application menu |
17+
| `label_icon_size` | `integer` | `16` | Size of the label_icon if one is supplied |
18+
19+
20+
> Type: `MenuEntry`
21+
22+
| | Type | Default | Description |
23+
|--------------|------------|---------|-----------------------------------------------------------------------------------------------------|
24+
| `type` | `xdg_entry | xdg_other | custom` | | Type of the entry |
25+
| `label` | `string` | | Label of the entry's button |
26+
| `icon` | `string | null` | `null` | Icon for the entry's button |
27+
| `categories` | `string[]` | | If `xdg_entry` this is is the list of freedesktop.org categories to include in this entry's sub menu |
28+
| `on_click` | `string` | | If `custom` this is a shell command to execute when the entry's button is clicked |
29+
30+
<details>
31+
32+
<summary>JSON</summary>
33+
34+
```json
35+
{
36+
"start": [
37+
{
38+
"type": "menu",
39+
"start": [
40+
{
41+
"type": "custom",
42+
"label": "Terminal",
43+
"on_click": "xterm",
44+
}
45+
],
46+
"height": 440,
47+
"width": 200,
48+
"icon": "archlinux",
49+
"label": null
50+
}
51+
]
52+
}
53+
54+
55+
```
56+
57+
</details>
58+
59+
<details>
60+
<summary>TOML</summary>
61+
62+
```toml
63+
[[start.menu]]
64+
height = 400
65+
width = 200
66+
icon = "archlinux"
67+
label = null
68+
69+
[[start.menu.start]]
70+
type = "custom"
71+
label = "Terminal"
72+
on_click = "xterm"
73+
```
74+
75+
</details>
76+
77+
<details>
78+
<summary>YAML</summary>
79+
80+
```yaml
81+
start:
82+
- type: "menu"
83+
start:
84+
- type: custom
85+
label: Terminal
86+
on_click: xterm
87+
height: 440
88+
width: 200
89+
icon: archlinux
90+
label: null
91+
```
92+
93+
</details>
94+
95+
<details>
96+
<summary>Corn</summary>
97+
98+
```corn
99+
{
100+
start = [
101+
{
102+
type = "menu"
103+
start = [
104+
{
105+
type = "custom"
106+
label = "Terminal"
107+
on_click = "xterm"
108+
}
109+
]
110+
height = 440
111+
width = 200
112+
icon = "archlinux"
113+
label = null
114+
}
115+
]
116+
}
117+
```
118+
119+
</details>
120+
121+
## Styling
122+
123+
| Selector | Description |
124+
|-------------------------------|--------------------------------|
125+
| `.menu` | Menu button |
126+
| `.menu-popup` | Main container of the popup |
127+
| `.menu-popup_main` | Main menu of the menu |
128+
| `.menu-popup_main_start` | Container for `start` entries |
129+
| `.menu-popup_main_center` | Container for `center` entries |
130+
| `.menu-popup_main_end` | Container for `end` entries |
131+
| `.menu-popup_sub-menu` | All sub-menues |
132+
133+
For more information on styling, please see the [styling guide](styling-guide).

src/config/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ use crate::modules::keyboard::KeyboardModule;
2121
use crate::modules::label::LabelModule;
2222
#[cfg(feature = "launcher")]
2323
use crate::modules::launcher::LauncherModule;
24+
#[cfg(feature = "menu")]
25+
use crate::modules::menu::MenuModule;
2426
#[cfg(feature = "music")]
2527
use crate::modules::music::MusicModule;
2628
#[cfg(feature = "network_manager")]
@@ -75,6 +77,8 @@ pub enum ModuleConfig {
7577
Label(Box<LabelModule>),
7678
#[cfg(feature = "launcher")]
7779
Launcher(Box<LauncherModule>),
80+
#[cfg(feature = "menu")]
81+
Menu(Box<MenuModule>),
7882
#[cfg(feature = "music")]
7983
Music(Box<MusicModule>),
8084
#[cfg(feature = "network_manager")]
@@ -127,6 +131,8 @@ impl ModuleConfig {
127131
Self::Label(module) => create!(module),
128132
#[cfg(feature = "launcher")]
129133
Self::Launcher(module) => create!(module),
134+
#[cfg(feature = "menu")]
135+
Self::Menu(module) => create!(module),
130136
#[cfg(feature = "music")]
131137
Self::Music(module) => create!(module),
132138
#[cfg(feature = "network_manager")]

src/desktop_file.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ fn find_application_dirs() -> Vec<PathBuf> {
4747
}
4848

4949
/// Finds all the desktop files
50-
fn find_desktop_files() -> Vec<PathBuf> {
50+
pub fn find_desktop_files() -> Vec<PathBuf> {
5151
let dirs = find_application_dirs();
5252
dirs.into_iter()
5353
.flat_map(|dir| {

0 commit comments

Comments
 (0)