Skip to content

Commit 66fe7ff

Browse files
committed
Draft version
0 parents  commit 66fe7ff

16 files changed

+710
-0
lines changed

.editorconfig

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# editorconfig.org
2+
root = true
3+
4+
[*]
5+
indent_style = space
6+
indent_size = 4
7+
end_of_line = lf
8+
charset = utf-8
9+
trim_trailing_whitespace = true
10+
insert_final_newline = true
11+
12+
[*.{yaml,yml}]
13+
indent_style = space
14+
indent_size = 2

.gitignore

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
*.pyc
2+
3+
# Packages
4+
*.egg
5+
/*.egg-info
6+
/dist/*
7+
build
8+
_build
9+
.cache
10+
*.so
11+
12+
# Installer logs
13+
pip-log.txt
14+
15+
# Unit test / coverage reports
16+
.coverage
17+
.tox
18+
.pytest_cache
19+
20+
.DS_Store
21+
.idea/*
22+
.python-version
23+
.vscode/*
24+
25+
.mypy_cache
26+
27+
.venv

.isort.cfg

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[settings]
2+
default_section=THIRDPARTY
3+
indent=' '
4+
sections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
5+
multi_line_output=3
6+
line_length=88
7+
include_trailing_comma=True
8+
use_parentheses=True

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# rofi-menu: lib for building rofi menu via python
2+
3+

example.py

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/usr/bin/env python
2+
import rofi_menu
3+
4+
5+
class ProjectsMenu(rofi_menu.Menu):
6+
prompt = "Projects"
7+
items = [
8+
rofi_menu.BackItem(),
9+
rofi_menu.ShellItem("Project 1", "code-insiders ~/Develop/project1"),
10+
rofi_menu.ShellItem("Project 2", "code-insiders ~/Develop/project2"),
11+
rofi_menu.ShellItem("Project X", "code-insiders ~/Develop/projectx"),
12+
]
13+
14+
15+
class LogoutMenu(rofi_menu.Menu):
16+
prompt = "Logout"
17+
items = [
18+
rofi_menu.ShellItem("Yes", "i3-msg exit", flags={rofi_menu.FLAG_STYLE_URGENT}),
19+
rofi_menu.ExitItem("No", flags={rofi_menu.FLAG_STYLE_ACTIVE}),
20+
]
21+
22+
23+
class MainMenu(rofi_menu.Menu):
24+
prompt = "menu"
25+
items = [
26+
rofi_menu.TouchpadItem(),
27+
rofi_menu.NestedMenu("Projects >", ProjectsMenu()),
28+
rofi_menu.ShellItem(
29+
"Downloads (show size)", "du -csh ~/Downloads", show_output=True
30+
),
31+
rofi_menu.NestedMenu("Second monitor", rofi_menu.SecondMonitorMenu()),
32+
rofi_menu.ShellItem("Lock screen", "i3lock -i ~/.config/i3/bg.png"),
33+
rofi_menu.ShellItem("Sleep", "systemctl suspend"),
34+
rofi_menu.NestedMenu("Logout", LogoutMenu()),
35+
]
36+
37+
38+
if __name__ == "__main__":
39+
rofi_menu.run(MainMenu())

poetry.lock

+176
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[tool.poetry]
2+
name = "rofi-menu"
3+
version = "0.1.0"
4+
description = "Create rofi menus via python"
5+
authors = ["miphreal <[email protected]>"]
6+
license = "MIT"
7+
8+
[tool.poetry.dependencies]
9+
python = "^3.8"
10+
11+
[tool.poetry.dev-dependencies]
12+
black = "^19.10b0"
13+
isort = "^4.3.21"
14+
15+
[build-system]
16+
requires = ["poetry>=0.12"]
17+
build-backend = "poetry.masonry.api"

rofi_menu/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from .constants import *
2+
from .contrib import *
3+
from .main import run
4+
from .menu import Menu, NestedMenu, Item, BackItem, ExitItem

rofi_menu/constants.py

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
MENU_ITEM_META_DELIM = "\r!"
2+
3+
FLAG_STYLE_URGENT = "URGENT"
4+
FLAG_STYLE_ACTIVE = "ACTIVE"
5+
6+
OP_OUTPUT = "OUTPUT_MENU"
7+
OP_REFRESH_MENU = "REFRESH_MENU"
8+
OP_BACK_TO_PARENT_MENU = "BACK_TO_PARENT_MENU"
9+
OP_EXIT = "EXIT"
10+
11+
ROOT_MENU_ID = "root"

rofi_menu/contrib/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .monitor import SecondMonitorMenu
2+
from .shell import ShellItem
3+
from .touchpad import TouchpadItem

rofi_menu/contrib/monitor.py

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from rofi_menu.menu import NestedMenu, Menu
2+
from .shell import ShellItem
3+
4+
5+
class SecondMonitorMenu(Menu):
6+
prompt = "Second monitor"
7+
secod_monitor_options = [
8+
{
9+
"text": '<span background="green"><b>Off</b></span>',
10+
"command": "xrandr --output {mon1} --auto --output {mon2} --off",
11+
},
12+
{
13+
"text": '<span background="blue"><b>Mirror</b></span>',
14+
"command": "xrandr --output {mon1} --auto --output {mon2} --auto --same-as {mon1}",
15+
},
16+
{
17+
"text": '<span background="gray"><b>Above</b></span>',
18+
"command": "xrandr --output {mon1} --auto --output {mon2} --auto --above {mon1}",
19+
},
20+
{
21+
"text": '<span background="gray"><b>Left</b></span>',
22+
"command": "xrandr --output {mon1} --auto --output {mon2} --auto --left-of {mon1}",
23+
},
24+
{
25+
"text": '<span background="gray"><b>Right</b></span>',
26+
"command": "xrandr --output {mon1} --auto --output {mon2} --auto --right-of {mon1}",
27+
},
28+
{
29+
"text": '<span background="gray"><b>Below</b></span>',
30+
"command": "xrandr --output {mon1} --auto --output {mon2} --auto --below {mon1}",
31+
},
32+
]
33+
34+
def __init__(
35+
self,
36+
prompt="Second monitor",
37+
primary_monitor="eDP1",
38+
secondary_monitor="HDMI1",
39+
):
40+
items = [
41+
ShellItem(
42+
text=option["text"].format(
43+
mon1=primary_monitor, mon2=secondary_monitor
44+
),
45+
command=option["command"].format(
46+
mon1=primary_monitor, mon2=secondary_monitor
47+
),
48+
)
49+
for option in self.secod_monitor_options
50+
]
51+
super().__init__(prompt=prompt, items=items)

rofi_menu/contrib/shell.py

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import asyncio
2+
3+
from rofi_menu.constants import OP_EXIT, OP_OUTPUT
4+
from rofi_menu.menu import Item, Operation
5+
6+
7+
class ShellItem(Item):
8+
def __init__(self, text=None, command="echo OK", **kwargs):
9+
self._command = command
10+
self.show_output = kwargs.pop("show_output", False)
11+
self.detached = kwargs.pop("detached", True)
12+
super().__init__(text, **kwargs)
13+
14+
@property
15+
def command(self):
16+
return self._command
17+
18+
async def on_select(self, item_id, meta):
19+
command = f"nohup {self.command}" if self.detached else self.command
20+
proc = await asyncio.create_subprocess_shell(
21+
command,
22+
stdout=(
23+
asyncio.subprocess.PIPE
24+
if self.show_output
25+
else asyncio.subprocess.DEVNULL
26+
),
27+
stderr=asyncio.subprocess.DEVNULL,
28+
)
29+
if self.show_output:
30+
data = await proc.stdout.read()
31+
return Operation(OP_OUTPUT, data.decode("utf-8"))
32+
return Operation(OP_EXIT)

0 commit comments

Comments
 (0)