feat: AR Display Manager — multi-monitor floating app switcher
Adds the AR Display Manager daemon (Task #9): - display_manager/ package with 8 modules: - app_registry.py : static metadata for the 4 bridge apps - config.py : JSON-persisted config + per-screen layout store - win32_utils.py : ctypes wrappers (EnumWindows, SetWindowPos, ShowWindow) - process_manager.py: launch + track app processes, HWND lookup - floating_button.py: always-on-top 52×52 px AR button per monitor with draggable placement + custom-painted popup - display_manager.py: orchestrator (QScreens → buttons → app placement + system tray with Settings/Launch/Quit) - settings_dialog.py: modal dialog for exe paths, button position, and Windows autostart toggle - autostart.py : HKCU Run registry read/write helpers - display_manager_main.py at repo root: launcher script - Studio Overview tab: "Lanzar Display Manager" button - pyproject.toml: display-manager optional dependency group (PySide6) Layout persistence: ~/.ar-autopilot/display_manager/layout.json Config: ~/.ar-autopilot/display_manager/config.json Supports up to 4 monitors (2 HDMI native + 2 USB DisplayLink). Double-click tray icon to toggle button visibility. AR_electronics — AR-Autopilot Project
This commit is contained in:
@@ -18,9 +18,12 @@ from PySide6.QtCore import Qt
|
||||
from PySide6.QtGui import QFont, QPixmap
|
||||
from PySide6.QtWidgets import (
|
||||
QFrame,
|
||||
QHBoxLayout,
|
||||
QLabel,
|
||||
QListWidget,
|
||||
QMainWindow,
|
||||
QMessageBox,
|
||||
QPushButton,
|
||||
QSplitter,
|
||||
QStatusBar,
|
||||
QTabWidget,
|
||||
@@ -193,6 +196,30 @@ class StudioMainWindow(QMainWindow):
|
||||
guide.setTextFormat(Qt.TextFormat.RichText)
|
||||
guide.setWordWrap(True)
|
||||
layout.addWidget(guide)
|
||||
|
||||
# AR Display Manager quick launch
|
||||
sep2 = QFrame()
|
||||
sep2.setFrameShape(QFrame.Shape.HLine)
|
||||
sep2.setStyleSheet(f"color:{ACCENT_MID}; margin: 10px 0;")
|
||||
layout.addWidget(sep2)
|
||||
|
||||
dm_row = QHBoxLayout()
|
||||
dm_label = QLabel(
|
||||
f"<b style='color:{ACCENT_MID}'>🖥 AR Display Manager</b><br/>"
|
||||
f"<span style='color:{TEXT_MUTED};font-size:11px;'>"
|
||||
"Gestiona cuál app aparece en cada monitor del J6412 "
|
||||
"(hasta 4 pantallas simultáneas).</span>"
|
||||
)
|
||||
dm_label.setTextFormat(Qt.TextFormat.RichText)
|
||||
dm_label.setWordWrap(True)
|
||||
dm_row.addWidget(dm_label, stretch=1)
|
||||
|
||||
dm_btn = QPushButton("Lanzar Display Manager")
|
||||
dm_btn.setMinimumWidth(200)
|
||||
dm_btn.clicked.connect(self._launch_display_manager)
|
||||
dm_row.addWidget(dm_btn)
|
||||
layout.addLayout(dm_row)
|
||||
|
||||
layout.addStretch(1)
|
||||
|
||||
footer = QLabel(
|
||||
@@ -204,3 +231,27 @@ class StudioMainWindow(QMainWindow):
|
||||
layout.addWidget(footer)
|
||||
|
||||
return w
|
||||
|
||||
# ── Display Manager launcher ──────────────────────────────────────────────
|
||||
|
||||
def _launch_display_manager(self) -> None:
|
||||
import subprocess
|
||||
import sys as _sys
|
||||
launcher = REPO_ROOT / "display_manager_main.py"
|
||||
if not launcher.exists():
|
||||
QMessageBox.warning(
|
||||
self,
|
||||
"Not found",
|
||||
f"display_manager_main.py not found at:\n{launcher}",
|
||||
)
|
||||
return
|
||||
try:
|
||||
subprocess.Popen(
|
||||
[_sys.executable, str(launcher)],
|
||||
creationflags=(
|
||||
subprocess.CREATE_NEW_PROCESS_GROUP
|
||||
if _sys.platform == "win32" else 0
|
||||
),
|
||||
)
|
||||
except Exception as exc:
|
||||
QMessageBox.critical(self, "Launch failed", str(exc))
|
||||
|
||||
Reference in New Issue
Block a user