Initial Version
This commit is contained in:
commit
bdf4330738
5 changed files with 383 additions and 0 deletions
171
hudfx.py
Normal file
171
hudfx.py
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import json
|
||||
import signal
|
||||
import os
|
||||
from PyQt5.QtCore import Qt, QUrl, QTimer
|
||||
from PyQt5.QtWidgets import (
|
||||
QApplication, QMainWindow, QSystemTrayIcon, QMenu, QAction,
|
||||
QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit,
|
||||
QComboBox, QPushButton, QMessageBox
|
||||
)
|
||||
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEngineProfile, QWebEnginePage, QWebEngineSettings
|
||||
from PyQt5.QtGui import QColor, QIcon
|
||||
|
||||
CONFIG_PATH = os.path.expanduser("~/.config/hudfx-lnx/config.json")
|
||||
|
||||
|
||||
def load_config():
|
||||
if os.path.exists(CONFIG_PATH):
|
||||
with open(CONFIG_PATH) as f:
|
||||
return json.load(f)
|
||||
return {"url": "", "screen_index": 0}
|
||||
|
||||
|
||||
def save_config(config):
|
||||
os.makedirs(os.path.dirname(CONFIG_PATH), exist_ok=True)
|
||||
with open(CONFIG_PATH, "w") as f:
|
||||
json.dump(config, f, indent=2)
|
||||
|
||||
|
||||
class Overlay(QMainWindow):
|
||||
def __init__(self, url, screen):
|
||||
super().__init__()
|
||||
self.setWindowFlags(
|
||||
Qt.FramelessWindowHint |
|
||||
Qt.WindowStaysOnTopHint |
|
||||
Qt.Tool |
|
||||
Qt.WindowTransparentForInput
|
||||
)
|
||||
self.setAttribute(Qt.WA_TranslucentBackground)
|
||||
|
||||
view = QWebEngineView()
|
||||
profile = QWebEngineProfile(view)
|
||||
page = QWebEnginePage(profile, view)
|
||||
view.setPage(page)
|
||||
view.page().setBackgroundColor(QColor(0, 0, 0, 0))
|
||||
view.page().setAudioMuted(False)
|
||||
|
||||
settings = view.page().settings()
|
||||
settings.setAttribute(QWebEngineSettings.PlaybackRequiresUserGesture, False)
|
||||
settings.setAttribute(QWebEngineSettings.JavascriptEnabled, True)
|
||||
|
||||
view.load(QUrl(url))
|
||||
self.setCentralWidget(view)
|
||||
self.setGeometry(screen.geometry())
|
||||
self.show()
|
||||
|
||||
|
||||
class SettingsDialog(QDialog):
|
||||
def __init__(self, config, screens, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("HudFX Settings")
|
||||
self.setMinimumWidth(420)
|
||||
self.config = config
|
||||
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
layout.addWidget(QLabel("Overlay URL:"))
|
||||
self.url_input = QLineEdit(config.get("url", ""))
|
||||
self.url_input.setPlaceholderText("https://...")
|
||||
layout.addWidget(self.url_input)
|
||||
|
||||
layout.addWidget(QLabel("Display monitor:"))
|
||||
self.screen_combo = QComboBox()
|
||||
for i, screen in enumerate(screens):
|
||||
s = screen.size()
|
||||
name = f"Monitor {i + 1} — {s.width()}x{s.height()} ({screen.name()})"
|
||||
self.screen_combo.addItem(name)
|
||||
self.screen_combo.setCurrentIndex(config.get("screen_index", 0))
|
||||
layout.addWidget(self.screen_combo)
|
||||
|
||||
buttons = QHBoxLayout()
|
||||
save_btn = QPushButton("Save")
|
||||
cancel_btn = QPushButton("Cancel")
|
||||
save_btn.clicked.connect(self.accept)
|
||||
cancel_btn.clicked.connect(self.reject)
|
||||
buttons.addWidget(save_btn)
|
||||
buttons.addWidget(cancel_btn)
|
||||
layout.addLayout(buttons)
|
||||
|
||||
def get_values(self):
|
||||
return {
|
||||
"url": self.url_input.text().strip(),
|
||||
"screen_index": self.screen_combo.currentIndex(),
|
||||
}
|
||||
|
||||
|
||||
class TrayApp:
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
self.config = load_config()
|
||||
self.overlay = None
|
||||
|
||||
self.tray = QSystemTrayIcon()
|
||||
self.tray.setToolTip("HudFX Overlay")
|
||||
|
||||
icon = QIcon.fromTheme("video-display")
|
||||
if icon.isNull():
|
||||
icon = QIcon.fromTheme("preferences-desktop-display")
|
||||
self.tray.setIcon(icon)
|
||||
|
||||
self.menu = QMenu()
|
||||
|
||||
self.toggle_action = QAction("Start overlay")
|
||||
self.toggle_action.triggered.connect(self.toggle_overlay)
|
||||
self.menu.addAction(self.toggle_action)
|
||||
|
||||
self.settings_action = QAction("Settings...")
|
||||
self.settings_action.triggered.connect(self.open_settings)
|
||||
self.menu.addAction(self.settings_action)
|
||||
|
||||
self.menu.addSeparator()
|
||||
|
||||
self.quit_action = QAction("Quit")
|
||||
self.quit_action.triggered.connect(self.quit)
|
||||
self.menu.addAction(self.quit_action)
|
||||
|
||||
self.tray.setContextMenu(self.menu)
|
||||
self.tray.show()
|
||||
|
||||
self.toggle_overlay()
|
||||
|
||||
def toggle_overlay(self):
|
||||
if self.overlay:
|
||||
self.overlay.close()
|
||||
self.overlay = None
|
||||
self.toggle_action.setText("Start overlay")
|
||||
else:
|
||||
url = self.config.get("url", "").strip()
|
||||
if not url:
|
||||
QMessageBox.warning(None, "HudFX", "No URL set. Open Settings first.")
|
||||
return
|
||||
idx = self.config.get("screen_index", 0)
|
||||
screens = self.app.screens()
|
||||
screen = screens[idx] if idx < len(screens) else self.app.primaryScreen()
|
||||
self.overlay = Overlay(url, screen)
|
||||
self.toggle_action.setText("Stop overlay")
|
||||
|
||||
def open_settings(self):
|
||||
dialog = SettingsDialog(self.config, self.app.screens())
|
||||
if dialog.exec_() == QDialog.Accepted:
|
||||
self.config = dialog.get_values()
|
||||
save_config(self.config)
|
||||
|
||||
def quit(self):
|
||||
if self.overlay:
|
||||
self.overlay.close()
|
||||
self.app.quit()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
app.setQuitOnLastWindowClosed(False)
|
||||
|
||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
timer = QTimer()
|
||||
timer.start(200)
|
||||
timer.timeout.connect(lambda: None)
|
||||
|
||||
tray = TrayApp(app)
|
||||
sys.exit(app.exec_())
|
||||
Loading…
Add table
Add a link
Reference in a new issue