371 lines
12 KiB
Python
371 lines
12 KiB
Python
from fabric.widgets.box import Box
|
|
from fabric.widgets.label import Label
|
|
from fabric.widgets.button import Button
|
|
from fabric.utils.helpers import exec_shell_command_async, get_relative_path
|
|
import utils.icons as icons
|
|
from gi.repository import Gdk, GLib
|
|
import os
|
|
import subprocess
|
|
import threading
|
|
|
|
|
|
CAPTURE_SCRIPT = get_relative_path("../../../config/scripts/capture.sh")
|
|
GAMEMODE_SCRIPT = get_relative_path("../../../config/scripts/gamemode.sh")
|
|
|
|
|
|
class Toolbox(Box):
|
|
def __init__(self, **kwargs):
|
|
super().__init__(
|
|
name="toolbox",
|
|
orientation="h",
|
|
spacing=4,
|
|
v_align="center",
|
|
h_align="center",
|
|
visible=True,
|
|
**kwargs,
|
|
)
|
|
|
|
self.launcher = kwargs["launcher"]
|
|
|
|
self.btn_ssregion = Button(
|
|
name="toolbox-button",
|
|
child=Label(name="button-label", markup=icons.ssregion),
|
|
on_clicked=self.ssregion,
|
|
h_expand=False,
|
|
v_expand=False,
|
|
h_align="center",
|
|
v_align="center",
|
|
)
|
|
# Enable keyboard focus and connect events
|
|
self.btn_ssregion.set_can_focus(True)
|
|
self.btn_ssregion.connect("button-press-event", self.on_ssregion_click)
|
|
self.btn_ssregion.connect("key-press-event", self.on_ssregion_key)
|
|
|
|
self.btn_ssfull = Button(
|
|
name="toolbox-button",
|
|
child=Label(name="button-label", markup=icons.ssfull),
|
|
on_clicked=self.ssfull,
|
|
h_expand=False,
|
|
v_expand=False,
|
|
h_align="center",
|
|
v_align="center",
|
|
)
|
|
# Enable keyboard focus and connect events
|
|
self.btn_ssfull.set_can_focus(True)
|
|
self.btn_ssfull.connect("button-press-event", self.on_ssfull_click)
|
|
self.btn_ssfull.connect("key-press-event", self.on_ssfull_key)
|
|
|
|
self.btn_screenrecord = Button(
|
|
name="toolbox-button",
|
|
child=Label(name="button-label", markup=icons.screenrecord),
|
|
on_clicked=self.screenrecord,
|
|
h_expand=False,
|
|
v_expand=False,
|
|
h_align="center",
|
|
v_align="center",
|
|
)
|
|
|
|
self.btn_ocr = Button(
|
|
name="toolbox-button",
|
|
child=Label(name="button-label", markup=icons.ocr),
|
|
on_clicked=self.ocr,
|
|
h_expand=False,
|
|
v_expand=False,
|
|
h_align="center",
|
|
v_align="center",
|
|
)
|
|
|
|
self.btn_color = Button(
|
|
name="toolbox-button",
|
|
tooltip_text="Color Picker\nLeft Click: HEX\nMiddle Click: HSV\nRight Click: RGB\n\nKeyboard:\nEnter: HEX\nShift+Enter: RGB\nCtrl+Enter: HSV",
|
|
child=Label(name="button-bar-label", markup=icons.colorpicker),
|
|
h_expand=False,
|
|
v_expand=False,
|
|
h_align="center",
|
|
v_align="center",
|
|
)
|
|
|
|
self.btn_gamemode = Button(
|
|
name="toolbox-button",
|
|
child=Label(name="button-label", markup=icons.gamemode),
|
|
on_clicked=self.gamemode,
|
|
h_expand=False,
|
|
v_expand=False,
|
|
h_align="center",
|
|
v_align="center",
|
|
)
|
|
|
|
# Enable keyboard focus for the colorpicker button.
|
|
self.btn_color.set_can_focus(True)
|
|
# Connect both mouse and keyboard events.
|
|
self.btn_color.connect("button-press-event", self.colorpicker)
|
|
self.btn_color.connect("key_press_event", self.colorpicker_key)
|
|
|
|
self.btn_emoji = Button(
|
|
name="toolbox-button",
|
|
child=Label(name="button-label", markup=icons.emoji),
|
|
on_clicked=self.emoji,
|
|
h_expand=False,
|
|
v_expand=False,
|
|
h_align="center",
|
|
v_align="center",
|
|
)
|
|
|
|
self.btn_screenshots_folder = Button(
|
|
name="toolbox-button",
|
|
child=Label(name="button-label", markup=icons.screenshots),
|
|
on_clicked=self.open_screenshots_folder,
|
|
h_expand=False,
|
|
v_expand=False,
|
|
h_align="center",
|
|
v_align="center",
|
|
)
|
|
|
|
self.btn_recordings_folder = Button(
|
|
name="toolbox-button",
|
|
child=Label(name="button-label", markup=icons.recordings),
|
|
on_clicked=self.open_recordings_folder,
|
|
h_expand=False,
|
|
v_expand=False,
|
|
h_align="center",
|
|
v_align="center",
|
|
)
|
|
|
|
self.buttons = [
|
|
self.btn_ssregion,
|
|
self.btn_ssfull,
|
|
self.btn_screenshots_folder,
|
|
Box(
|
|
name="tool-sep",
|
|
h_expand=False,
|
|
v_expand=False,
|
|
h_align="center",
|
|
v_align="center",
|
|
),
|
|
self.btn_screenrecord,
|
|
self.btn_recordings_folder,
|
|
Box(
|
|
name="tool-sep",
|
|
h_expand=False,
|
|
v_expand=False,
|
|
h_align="center",
|
|
v_align="center",
|
|
),
|
|
self.btn_ocr,
|
|
self.btn_color,
|
|
Box(
|
|
name="tool-sep",
|
|
h_expand=False,
|
|
v_expand=False,
|
|
h_align="center",
|
|
v_align="center",
|
|
),
|
|
self.btn_gamemode,
|
|
self.btn_emoji,
|
|
]
|
|
|
|
for button in self.buttons:
|
|
self.add(button)
|
|
|
|
self.show_all()
|
|
|
|
# Start polling for process state every second.
|
|
self.recorder_timer_id = GLib.timeout_add_seconds(
|
|
1, self.update_screenrecord_state
|
|
)
|
|
|
|
def close_menu(self):
|
|
self.launcher.close()
|
|
|
|
# Action methods
|
|
def ssfull(self, *args):
|
|
exec_shell_command_async(f"bash {CAPTURE_SCRIPT} screenshot p")
|
|
self.close_menu()
|
|
|
|
def on_ssfull_click(self, button, event):
|
|
if event.type == Gdk.EventType.BUTTON_PRESS:
|
|
if event.button == 1: # Left click
|
|
self.ssfull()
|
|
elif event.button == 3: # Right click
|
|
exec_shell_command_async(
|
|
f"bash {CAPTURE_SCRIPT} screenshot p mockup")
|
|
self.close_menu()
|
|
return True
|
|
return False
|
|
|
|
def on_ssfull_key(self, widget, event):
|
|
if event.keyval in {Gdk.KEY_Return, Gdk.KEY_KP_Enter}:
|
|
modifiers = event.get_state()
|
|
if modifiers & Gdk.ModifierType.SHIFT_MASK:
|
|
exec_shell_command_async(
|
|
f"bash {CAPTURE_SCRIPT} screenshot p mockup")
|
|
self.close_menu()
|
|
else:
|
|
self.ssfull()
|
|
return True
|
|
return False
|
|
|
|
def ssregion(self, *args):
|
|
exec_shell_command_async(f"bash {CAPTURE_SCRIPT} screenshot sf")
|
|
self.close_menu()
|
|
|
|
def on_ssregion_click(self, button, event):
|
|
if event.type == Gdk.EventType.BUTTON_PRESS:
|
|
if event.button == 1: # Left click
|
|
self.ssregion()
|
|
elif event.button == 3: # Right click
|
|
exec_shell_command_async(
|
|
f"bash {CAPTURE_SCRIPT} screenshot sf mockup")
|
|
self.close_menu()
|
|
return True
|
|
return False
|
|
|
|
def on_ssregion_key(self, widget, event):
|
|
if event.keyval in {Gdk.KEY_Return, Gdk.KEY_KP_Enter}:
|
|
modifiers = event.get_state()
|
|
if modifiers & Gdk.ModifierType.SHIFT_MASK:
|
|
exec_shell_command_async(
|
|
f"bash {CAPTURE_SCRIPT} screenshot sf mockup")
|
|
self.close_menu()
|
|
else:
|
|
self.ssregion()
|
|
return True
|
|
return False
|
|
|
|
def screenrecord(self, *args):
|
|
# Launch screenrecord script in detached mode so that it remains running independently of this program.
|
|
exec_shell_command_async(
|
|
f"bash -c 'nohup bash {CAPTURE_SCRIPT} record > /dev/null 2>&1 & disown'"
|
|
)
|
|
self.close_menu()
|
|
|
|
def ocr(self, *args):
|
|
exec_shell_command_async(f"bash {CAPTURE_SCRIPT} ocr sf")
|
|
self.close_menu()
|
|
|
|
def gamemode(self, *args):
|
|
exec_shell_command_async(f"bash {GAMEMODE_SCRIPT}")
|
|
self.gamemode_check()
|
|
self.close_menu()
|
|
|
|
def gamemode_check(self):
|
|
def check():
|
|
try:
|
|
result = subprocess.run(
|
|
f"bash {GAMEMODE_SCRIPT} check",
|
|
shell=True,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
)
|
|
enabled = result.stdout == b"t\n"
|
|
except Exception:
|
|
enabled = False
|
|
|
|
def update_ui():
|
|
if enabled:
|
|
self.btn_gamemode.get_child().set_markup(icons.gamemode_off)
|
|
else:
|
|
self.btn_gamemode.get_child().set_markup(icons.gamemode)
|
|
return False
|
|
|
|
GLib.idle_add(update_ui)
|
|
return False
|
|
|
|
GLib.idle_add(lambda: threading.Thread(target=check).start())
|
|
return True
|
|
|
|
def ssregion(self, *args):
|
|
exec_shell_command_async(f"bash {CAPTURE_SCRIPT} screenshot sf")
|
|
self.close_menu()
|
|
|
|
def colorpicker(self, button, event):
|
|
if event.type == Gdk.EventType.BUTTON_PRESS:
|
|
cmd = {
|
|
1: "-hex", # Left click
|
|
2: "-hsv", # Middle click
|
|
3: "-rgb", # Right click
|
|
}.get(event.button)
|
|
|
|
if cmd:
|
|
exec_shell_command_async(
|
|
f"bash {
|
|
get_relative_path(
|
|
'../../../config/scripts/hyprpicker.sh')
|
|
} {cmd}"
|
|
)
|
|
self.close_menu()
|
|
|
|
def colorpicker_key(self, widget, event):
|
|
if event.keyval in {Gdk.KEY_Return, Gdk.KEY_KP_Enter}:
|
|
modifiers = event.get_state()
|
|
cmd = "-hex" # Default
|
|
|
|
match modifiers & (
|
|
Gdk.ModifierType.SHIFT_MASK | Gdk.ModifierType.CONTROL_MASK
|
|
):
|
|
case Gdk.ModifierType.SHIFT_MASK:
|
|
cmd = "-rgb"
|
|
case Gdk.ModifierType.CONTROL_MASK:
|
|
cmd = "-hsv"
|
|
|
|
exec_shell_command_async(
|
|
f"bash {get_relative_path('../../../config/scripts/hyprpicker.sh')} {
|
|
cmd
|
|
}"
|
|
)
|
|
self.close_menu()
|
|
return True
|
|
return False
|
|
|
|
def update_screenrecord_state(self):
|
|
def check():
|
|
try:
|
|
result = subprocess.run(
|
|
"pgrep -f gpu-screen-recorder",
|
|
shell=True,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
)
|
|
running = result.returncode == 0
|
|
except Exception:
|
|
running = False
|
|
|
|
def update_ui():
|
|
if running:
|
|
self.btn_screenrecord.get_child().set_markup(icons.stop)
|
|
self.btn_screenrecord.add_style_class("recording")
|
|
else:
|
|
self.btn_screenrecord.get_child().set_markup(icons.screenrecord)
|
|
self.btn_screenrecord.remove_style_class("recording")
|
|
return False
|
|
|
|
GLib.idle_add(update_ui)
|
|
return False
|
|
|
|
GLib.idle_add(lambda: threading.Thread(target=check).start())
|
|
return True
|
|
|
|
def open_screenshots_folder(self, *args):
|
|
screenshots_dir = os.path.join(
|
|
os.environ.get("XDG_PICTURES_DIR",
|
|
os.path.expanduser("~/Pictures")),
|
|
"Screenshots",
|
|
)
|
|
# Create directory if it doesn't exist
|
|
os.makedirs(screenshots_dir, exist_ok=True)
|
|
exec_shell_command_async(f"xdg-open {screenshots_dir}")
|
|
self.close_menu()
|
|
|
|
def open_recordings_folder(self, *args):
|
|
recordings_dir = os.path.join(
|
|
os.environ.get("XDG_VIDEOS_DIR", os.path.expanduser("~/Videos")),
|
|
"Recordings",
|
|
)
|
|
# Create directory if it doesn't exist
|
|
os.makedirs(recordings_dir, exist_ok=True)
|
|
exec_shell_command_async(f"xdg-open {recordings_dir}")
|
|
self.close_menu()
|
|
|
|
def emoji(self, *args):
|
|
self.launcher.open("emoji")
|