You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

157 lines
4.7 KiB
Python

#!/usr/bin/env python3
import argparse
import base64
import io
import json
import subprocess
import sys
import time
from pathlib import Path
import pygame
from PIL import Image
import sdl2
import sdl2.ext
# ---------- Configuration ----------
DEFAULT_SCRIPTS_PATH = "/home/kuba/kazzite"
TITLE = "Select script"
BIG_FONT_SIZE = 100
SMALL_FONT_SIZE = 40
AXIS_DEADZONE = 0.6
HAT_REPEAT_DELAY = 0.18
FPS = 60
# ---------- Helpers ----------
def load_scripts(directory):
return [
{
"name": p.stem,
"path": str(p.resolve())
}
for p in Path(directory).iterdir()
]
# ---------- UI with SDL2 input ----------
def run_ui(scripts):
pygame.init()
screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
screen_w, screen_h = screen.get_size()
pygame.display.set_caption(TITLE)
scale = min(screen_w / 3840.0, screen_h / 2160.0)
big_font = pygame.font.SysFont(None, int(BIG_FONT_SIZE * scale))
small_font = pygame.font.SysFont(None, int(SMALL_FONT_SIZE * scale))
clock = pygame.time.Clock()
selected = 0
last_nav = 0
# ---------- SDL2 joystick init ----------
if sdl2.SDL_Init(sdl2.SDL_INIT_JOYSTICK) != 0:
print("SDL_Init Error:", sdl2.SDL_GetError().decode())
sys.exit(1)
joystick_count = sdl2.SDL_NumJoysticks()
sdl_joysticks = []
for i in range(joystick_count):
js = sdl2.SDL_JoystickOpen(i)
if js:
sdl_joysticks.append(js)
running = True
event = sdl2.SDL_Event()
while running:
now = time.time()
pygame.event.pump() # Update pygame keyboard events
# Handle pygame keyboard events
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
selected = max(0, selected - 1)
elif event.key == pygame.K_DOWN:
selected = min(len(scripts) - 1, selected + 1)
elif event.key in (pygame.K_RETURN, pygame.K_KP_ENTER):
path = scripts[selected]['path']
print(path)
running = False
elif event.key == pygame.K_ESCAPE:
print("ESCAPE")
running = False
sdl2.SDL_JoystickUpdate()
for i, js in enumerate(sdl_joysticks):
# Buttons
for b in range(sdl2.SDL_JoystickNumButtons(js)):
if sdl2.SDL_JoystickGetButton(js, b):
if b == 0: # confirm button
path = scripts[selected]['path']
print(path)
running = False
elif b == 1: # cancel button
print("CANCEL")
running = False
# Hats (D-pad)
for h in range(sdl2.SDL_JoystickNumHats(js)):
hat = sdl2.SDL_JoystickGetHat(js, h)
if hat & sdl2.SDL_HAT_UP and now - last_nav > HAT_REPEAT_DELAY:
selected = max(0, selected - 1)
last_nav = now
elif hat & sdl2.SDL_HAT_DOWN and now - last_nav > HAT_REPEAT_DELAY:
selected = min(len(scripts) - 1, selected + 1)
last_nav = now
# ---------- Render pygame UI ----------
screen.fill((10, 10, 10))
title_surf = small_font.render(TITLE, True, (230, 230, 230))
screen.blit(title_surf, ((screen_w - title_surf.get_width()) // 2, int(screen_h * 0.08)))
total = len(scripts)
item_height = int(300 * scale)
start_y = (screen_h - total * item_height) // 2
for i, script in enumerate(scripts):
y = start_y + i * item_height
color = (255, 255, 255) if i == selected else (180, 180, 180)
if i == selected:
pygame.draw.rect(screen, (50, 50, 50), (screen_w * 0.1, y - 20, screen_w * 0.8, item_height - 40), border_radius=20)
name_surf = big_font.render(script['name'], True, color)
screen.blit(name_surf, (int(screen_w * 0.4), y + item_height // 3))
pygame.display.flip()
clock.tick(FPS)
# Cleanup SDL2 joysticks
for js in sdl_joysticks:
sdl2.SDL_JoystickClose(js)
sdl2.SDL_QuitSubSystem(sdl2.SDL_INIT_JOYSTICK)
pygame.quit()
# ---------- Main ----------
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--scripts", default=str(DEFAULT_SCRIPTS_PATH))
args = parser.parse_args()
scripts = load_scripts(Path(args.scripts))
run_ui(scripts)
if __name__ == "__main__":
main()