diff --git a/src/gui/app.py b/src/gui/app.py index 5fa2639..1592eea 100644 --- a/src/gui/app.py +++ b/src/gui/app.py @@ -63,6 +63,7 @@ def __init__(self, version="0.9.0", github_repo="ThreeHats/auto-wall"): # Set up the main layout and widgets self.initialize_state() self.setup_ui() + self.setup_shortcuts() # Load presets on startup self.preset_manager.load_presets_from_file() @@ -214,6 +215,52 @@ def setup_ui(self): self.setup_central_image_area() self.setup_right_properties_panel() + def setup_shortcuts(self): + """Set up keyboard shortcuts for quick access to drawing and wall editing modes.""" + + # Drawing mode shortcuts (D/E) + self.draw_mode_shortcut = QShortcut(QKeySequence(Qt.Key.Key_D), self) + self.draw_mode_shortcut.activated.connect(self.select_draw_mode) + + self.erase_mode_shortcut = QShortcut(QKeySequence(Qt.Key.Key_E), self) + self.erase_mode_shortcut.activated.connect(self.select_erase_mode) + + # Drawing tool shortcuts (1-5) + self.brush_tool_shortcut = QShortcut(QKeySequence(Qt.Key.Key_1), self) + self.brush_tool_shortcut.activated.connect(lambda: self.select_tool('brush')) + + self.line_tool_shortcut = QShortcut(QKeySequence(Qt.Key.Key_2), self) + self.line_tool_shortcut.activated.connect(lambda: self.select_tool('line')) + + self.rectangle_tool_shortcut = QShortcut(QKeySequence(Qt.Key.Key_3), self) + self.rectangle_tool_shortcut.activated.connect(lambda: self.select_tool('rectangle')) + + self.circle_tool_shortcut = QShortcut(QKeySequence(Qt.Key.Key_4), self) + self.circle_tool_shortcut.activated.connect(lambda: self.select_tool('circle')) + + self.ellipse_tool_shortcut = QShortcut(QKeySequence(Qt.Key.Key_5), self) + self.ellipse_tool_shortcut.activated.connect(lambda: self.select_tool('ellipse')) + + # Wall editing mode shortcuts (W/I/X/P) + self.wall_draw_shortcut = QShortcut(QKeySequence(Qt.Key.Key_W), self) + self.wall_draw_shortcut.activated.connect(lambda: self.select_wall_mode('draw')) + + self.wall_edit_shortcut = QShortcut(QKeySequence(Qt.Key.Key_I), self) + self.wall_edit_shortcut.activated.connect(lambda: self.select_wall_mode('edit')) + + self.wall_delete_shortcut = QShortcut(QKeySequence(Qt.Key.Key_X), self) + self.wall_delete_shortcut.activated.connect(lambda: self.select_wall_mode('delete')) + + self.wall_portal_shortcut = QShortcut(QKeySequence(Qt.Key.Key_P), self) + self.wall_portal_shortcut.activated.connect(lambda: self.select_wall_mode('portal')) + + # Universal shortcuts (Esc/Delete) + self.cancel_shortcut = QShortcut(QKeySequence(Qt.Key.Key_Escape), self) + self.cancel_shortcut.activated.connect(self.cancel_current_action) + + self.delete_shortcut = QShortcut(QKeySequence(Qt.Key.Key_Delete), self) + self.delete_shortcut.activated.connect(self.delete_selected_wall) + def setup_menu_bar(self): """Create the menu bar with File, Edit, View, and Help menus.""" menubar = self.menuBar() @@ -347,12 +394,12 @@ def setup_left_tools_panel(self): self.left_layout.addWidget(self.detect_tool_btn) # Paint/Edit tool - self.paint_tool_btn = QPushButton(" Draw") + self.paint_tool_btn = QPushButton(" &Draw") draw_icon = QIcon(os.path.join(resources_dir, 'pen-tool-vector-design-icon.svg')) self.paint_tool_btn.setIcon(draw_icon) self.paint_tool_btn.setIconSize(QSize(24, 24)) self.paint_tool_btn.setCheckable(True) - self.paint_tool_btn.setToolTip("Draw/Edit Mask Tool") + self.paint_tool_btn.setToolTip("Draw/Edit Mask Tool (D)") self.tool_group.addButton(self.paint_tool_btn, 1) self.left_layout.addWidget(self.paint_tool_btn) @@ -1155,8 +1202,10 @@ def setup_paint_properties(self): # Draw/Erase mode mode_layout = QHBoxLayout() - self.draw_radio = QRadioButton("Draw") - self.erase_radio = QRadioButton("Erase") + self.draw_radio = QRadioButton("&Draw") + self.draw_radio.setToolTip("Draw on mask (D)") + self.erase_radio = QRadioButton("&Erase") + self.erase_radio.setToolTip("Erase from mask (E)") self.draw_radio.setChecked(True) self.draw_mode_group = QButtonGroup() @@ -1992,6 +2041,82 @@ def unified_undo(self): self.setStatusTip("Nothing to undo") QMessageBox.information(self, "Undo", "Nothing to undo") + def _reset_uvtt_temporary_state(self): + """Reset temporary UVTT editing/drawing state without changing the active mode.""" + self.drawing_new_wall = False + self.drawing_new_portal = False + self.new_wall_start = None + self.new_wall_end = None + self.new_portal_start = None + self.new_portal_end = None + self.selecting_walls = False + self.wall_selection_start = None + self.wall_selection_current = None + self.multi_wall_drag = False + self.multi_wall_drag_start = None + self.dragging_from_line = False + self.dragging_from_portal_line = False + self.selected_wall_index = -1 + self.selected_point_index = -1 + self.selected_portal_index = -1 + + def select_draw_mode(self): + """Select draw mode for mask editing and sync UI state.""" + if hasattr(self, 'draw_radio'): + self.draw_radio.setChecked(True) + if hasattr(self, 'erase_radio'): + self.erase_radio.setChecked(False) + self.setStatusTip("Paint Mode: Draw on the mask layer") + + def select_erase_mode(self): + """Select erase mode for mask editing and sync UI state.""" + if hasattr(self, 'erase_radio'): + self.erase_radio.setChecked(True) + if hasattr(self, 'draw_radio'): + self.draw_radio.setChecked(False) + self.setStatusTip("Paint Mode: Erase from the mask layer") + + def select_tool(self, tool_name): + """Select a drawing tool and sync the corresponding radio button.""" + tools = { + 'brush': 'brush_tool_radio', + 'line': 'line_tool_radio', + 'rectangle': 'rectangle_tool_radio', + 'circle': 'circle_tool_radio', + 'ellipse': 'ellipse_tool_radio' + } + radio_name = tools.get(tool_name) + if radio_name and hasattr(self, radio_name): + getattr(self, radio_name).setChecked(True) + + def select_wall_mode(self, mode): + """Select a UVTT wall editing mode and keep radio buttons and flags in sync.""" + if hasattr(self, 'draw_mode_radio') and hasattr(self, 'edit_mode_radio'): + if mode == 'draw' and hasattr(self, 'draw_mode_radio'): + self.draw_mode_radio.setChecked(True) + elif mode == 'edit' and hasattr(self, 'edit_mode_radio'): + self.edit_mode_radio.setChecked(True) + elif mode == 'delete' and hasattr(self, 'delete_mode_radio'): + self.delete_mode_radio.setChecked(True) + elif mode == 'portal' and hasattr(self, 'portal_mode_radio'): + self.portal_mode_radio.setChecked(True) + elif hasattr(self.export_panel, 'toggle_wall_edit_mode'): + self.export_panel.toggle_wall_edit_mode(mode, True) + + def cancel_current_action(self): + """Cancel the current action by clearing temporary drawing and selection state.""" + self._reset_uvtt_temporary_state() + if hasattr(self, 'uvtt_preview_active') and self.uvtt_preview_active: + if hasattr(self.export_panel, 'display_uvtt_preview'): + self.export_panel.display_uvtt_preview() + self.setStatusTip("Action canceled") + + def delete_selected_wall(self): + """Delete selected wall/portal if a selection exists.""" + if hasattr(self.export_panel, 'delete_selected_wall'): + self.export_panel.delete_selected_wall() + + if __name__ == "__main__": app = QApplication(sys.argv) window = WallDetectionApp() diff --git a/src/gui/export_panel.py b/src/gui/export_panel.py index 99e053a..cd8c04d 100644 --- a/src/gui/export_panel.py +++ b/src/gui/export_panel.py @@ -1551,27 +1551,27 @@ def setup_wall_editing_controls(self): edit_mode_group = QButtonGroup(self.app.wall_edit_frame) # Draw mode - draw_mode_radio = QRadioButton("Draw Walls") - draw_mode_radio.setToolTip("Click and drag to draw new wall segments") + draw_mode_radio = QRadioButton("Draw Walls (&W)") + draw_mode_radio.setToolTip("Click and drag to draw new wall segments (W)") draw_mode_radio.setChecked(True) # Default mode edit_mode_group.addButton(draw_mode_radio) wall_edit_layout.addWidget(draw_mode_radio) # Portal mode - portal_mode_radio = QRadioButton("Draw Doors") - portal_mode_radio.setToolTip("Click and drag to draw doors and portals") + portal_mode_radio = QRadioButton("Draw Portals (&P)") + portal_mode_radio.setToolTip("Click and drag to draw doors and portals (P)") edit_mode_group.addButton(portal_mode_radio) wall_edit_layout.addWidget(portal_mode_radio) # Edit mode - edit_mode_radio = QRadioButton("Edit Mode") - edit_mode_radio.setToolTip("Click and drag wall endpoints to move them") + edit_mode_radio = QRadioButton("Edit Mode (&I)") + edit_mode_radio.setToolTip("Click and drag wall endpoints to move them (I)") edit_mode_group.addButton(edit_mode_radio) wall_edit_layout.addWidget(edit_mode_radio) # Delete mode - delete_mode_radio = QRadioButton("Delete Mode") - delete_mode_radio.setToolTip("Click on walls to delete them") + delete_mode_radio = QRadioButton("Delete Mode (&X)") + delete_mode_radio.setToolTip("Click on walls to delete them (X)") edit_mode_group.addButton(delete_mode_radio) wall_edit_layout.addWidget(delete_mode_radio)