diff --git a/.gitignore b/.gitignore index 0698ebe..8b13789 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -mucapy_config.json + diff --git a/mucapy/main.py b/mucapy/main.py index 5e67bac..c2e2282 100644 --- a/mucapy/main.py +++ b/mucapy/main.py @@ -18,12 +18,22 @@ import time class Config: def __init__(self): - # Use JSON file in current working directory - self.config_file = os.path.join(os.getcwd(), 'mucapy_config.json') + # Use platform-specific user directory for config + if sys.platform.startswith('win'): + config_dir = os.path.join(os.environ.get('APPDATA', os.path.expanduser('~')), 'MuCaPy') + pictures_dir = os.path.join(os.environ.get('USERPROFILE', os.path.expanduser('~')), 'Pictures', 'MuCaPy') + else: + config_dir = os.path.join(os.path.expanduser('~'), '.config', 'mucapy') + pictures_dir = os.path.join(os.path.expanduser('~'), 'Pictures', 'MuCaPy') + + # Create config directory if it doesn't exist + os.makedirs(config_dir, exist_ok=True) + + self.config_file = os.path.join(config_dir, 'config.json') self.settings = { 'network_cameras': {}, # Store network cameras configuration 'last_model_dir': '', - 'last_screenshot_dir': os.path.expanduser('~/Pictures/MuCaPy'), + 'last_screenshot_dir': pictures_dir, 'last_layout': 0, 'last_fps': 10, 'last_selected_cameras': [], @@ -206,7 +216,7 @@ class MultiCamYOLODetector: """Check for available cameras including network cameras""" self.available_cameras = [] - # Try numeric indices first (this works more reliably) + # Try numeric indices first (this works on all platforms) for i in range(max_to_check): try: cap = cv2.VideoCapture(i) @@ -216,18 +226,19 @@ class MultiCamYOLODetector: except: continue - # Also check device paths as fallback - if os.path.exists('/dev'): - for i in range(max_to_check): - device_path = f"/dev/video{i}" - if os.path.exists(device_path) and device_path not in self.available_cameras: - try: - cap = cv2.VideoCapture(device_path) - if cap.isOpened(): - self.available_cameras.append(device_path) - cap.release() - except: - continue + # Platform-specific device path checks + if sys.platform.startswith('linux'): + if os.path.exists('/dev'): + for i in range(max_to_check): + device_path = f"/dev/video{i}" + if os.path.exists(device_path) and device_path not in self.available_cameras: + try: + cap = cv2.VideoCapture(device_path) + if cap.isOpened(): + self.available_cameras.append(device_path) + cap.release() + except: + continue # Add saved network cameras for name, camera_info in self.network_cameras.items(): @@ -476,20 +487,58 @@ class CameraDisplay(QLabel): self.fullscreen_window = QMainWindow(self.window()) self.fullscreen_window.setWindowTitle(f"Camera {self.cam_id} - Fullscreen") + self.fullscreen_window.setWindowFlags(Qt.Window | Qt.FramelessWindowHint) # Create central widget central_widget = QWidget() layout = QVBoxLayout(central_widget) + layout.setContentsMargins(0, 0, 0, 0) + + # Create title bar + title_bar = QWidget() + title_bar.setStyleSheet(""" + QWidget { + background-color: #1E1E1E; + color: #DDD; + } + """) + title_bar.setFixedHeight(30) + title_layout = QHBoxLayout(title_bar) + title_layout.setContentsMargins(10, 0, 10, 0) + + # Add title label + title_label = QLabel(f"Camera {self.cam_id} - Fullscreen") + title_layout.addWidget(title_label) + + # Add close button + close_btn = QPushButton("×") + close_btn.setFixedSize(20, 20) + close_btn.setStyleSheet(""" + QPushButton { + background-color: transparent; + color: #DDD; + border: none; + font-size: 16px; + } + QPushButton:hover { + background-color: #E81123; + color: white; + } + """) + close_btn.clicked.connect(self.close_fullscreen) + title_layout.addWidget(close_btn) + + layout.addWidget(title_bar) # Create fullscreen label - label = QLabel() - label.setAlignment(Qt.AlignCenter) - label.setPixmap(self.pixmap().scaled( + self.fullscreen_label = QLabel() + self.fullscreen_label.setAlignment(Qt.AlignCenter) + self.fullscreen_label.setPixmap(self.pixmap().scaled( QApplication.primaryScreen().size(), Qt.KeepAspectRatio, Qt.SmoothTransformation )) - layout.addWidget(label) + layout.addWidget(self.fullscreen_label) self.fullscreen_window.setCentralWidget(central_widget) @@ -501,15 +550,31 @@ class CameraDisplay(QLabel): screenshot_shortcut = QShortcut(QKeySequence("Ctrl+S"), self.fullscreen_window) screenshot_shortcut.activated.connect(self.take_screenshot) + # Make window draggable + title_bar.mousePressEvent = self.fullscreen_mousePressEvent + title_bar.mouseMoveEvent = self.fullscreen_mouseMoveEvent + # Update fullscreen image when main window updates self.fullscreen_timer = QTimer() self.fullscreen_timer.timeout.connect( - lambda: self.update_fullscreen(label) + lambda: self.update_fullscreen(self.fullscreen_label) ) self.fullscreen_timer.start(30) # Show fullscreen - self.fullscreen_window.showFullScreen() + self.fullscreen_window.showMaximized() + + def fullscreen_mousePressEvent(self, event): + """Handle mouse press events for dragging""" + if event.button() == Qt.LeftButton: + self.fullscreen_window.drag_position = event.globalPos() - self.fullscreen_window.frameGeometry().topLeft() + event.accept() + + def fullscreen_mouseMoveEvent(self, event): + """Handle mouse move events for dragging""" + if hasattr(self.fullscreen_window, 'drag_position'): + self.fullscreen_window.move(event.globalPos() - self.fullscreen_window.drag_position) + event.accept() def update_fullscreen(self, label): """Update the fullscreen display""" diff --git a/mucapy_config.json b/mucapy_config.json new file mode 100644 index 0000000..6317a28 --- /dev/null +++ b/mucapy_config.json @@ -0,0 +1,13 @@ +{ + "network_cameras": {}, + "last_model_dir": "", + "last_screenshot_dir": "/home/rattatwinko/Pictures/MuCaPy", + "last_layout": 0, + "last_fps": 10, + "last_selected_cameras": [], + "window_geometry": null, + "confidence_threshold": 0.35, + "model_dir": "/home/rattatwinko/Documents/mucapy/mucapy/mucapy/models", + "fps": 10, + "layout": 0 +} \ No newline at end of file