diff --git a/clusterview/mode_handlers.py b/clusterview/mode_handlers.py index b5b8028..1801ee0 100644 --- a/clusterview/mode_handlers.py +++ b/clusterview/mode_handlers.py @@ -83,6 +83,7 @@ def __handle_add_point(ctx, event): __refresh_point_list(ctx) set_drawing_event(event) + set_current_points(__point_set) ctx.opengl_widget.update() @@ -111,6 +112,30 @@ def __handle_edit_point(ctx, event): # after this remove the point from the list +def ogl_keypress_handler(ctx, event): + """ + A keypress handler attached to the OpenGL widget. + + It primarily exists to allow the user to cancel + selection with ESC. + + @param ctx A handle to the window context. + @param event The event associated with this handler. + """ + global __left_click_flag + global __mouse_start + + if (__left_click_flag is not __ClickFlag.NONE + and event.key() == Qt.Key_Escape): + + __mouse_start = None + + __left_click_flag = __ClickFlag.NONE + __point_set.clear_selection() + reset_move_bbs() + ctx.opengl_widget.update() + + def __handle_move_points(ctx, event): """ A relatively complicated state machine that handles the process of @@ -126,7 +151,8 @@ def __handle_move_points(ctx, event): set_drawing_event(event) - print(event.type()) + # Necessary to capture keyboard events + ctx.opengl_widget.setFocusPolicy(Qt.StrongFocus) # This if statement block is used to set the bounding box for # drawing and call the selection procedure. @@ -142,8 +168,6 @@ def __handle_move_points(ctx, event): # tracking and translation __left_click_flag = __ClickFlag.SELECTION_MOVE __mouse_start = (event.x(), event.y()) - else: - __left_click_flag = __ClickFlag.NONE elif (__left_click_flag is __ClickFlag.SELECTION_BOX and event.type() == QEvent.MouseMove): @@ -191,20 +215,7 @@ def __handle_move_points(ctx, event): # Satisfy the post condition by resetting the bounding box reset_move_bbs() - elif (__left_click_flag is not __ClickFlag.NONE - and event.type() == QEvent.KeyPress - and event.key() == Qt.Key_Escape): - - # TODO: THIS KEY PRESS IS BROKEN AND THE CLICK TO CANCEL BEHAVIOR - # NEED TO BE REMOVED. YOU NEED TO OVERWRITE THE KEY PRESS - # EVENT ON THE OPENGL WIDGET. IF MODE IS MOVE AND ESCAPE IS - # PRESSED CANCEL ALL SELECTIONS!! - - if __left_click_flag is __ClickFlag.SELECTION_MOVE: - __mouse_start = None - __left_click_flag = __ClickFlag.NONE - __point_set.clear_selection() ctx.point_list_widget.update() ctx.opengl_widget.update() diff --git a/clusterview/opengl_widget.py b/clusterview/opengl_widget.py index 6227427..90d2984 100644 --- a/clusterview/opengl_widget.py +++ b/clusterview/opengl_widget.py @@ -201,8 +201,7 @@ def paint_gl(): """ if (__current_mode in [Mode.ADD, Mode.EDIT, Mode.MOVE, Mode.DELETE] and __current_event is None): - raise InvalidStateError("Event must exist for ADD, EDIT, MOVE, " + - "and DELETE") + return if (__current_mode in [Mode.ADD, Mode.EDIT, Mode.DELETE] and __current_points is None): @@ -235,19 +234,6 @@ def paint_gl(): highlight_selection() draw_points(__current_points, Color.GREY) - if __move_bb_top_left is None and __move_bb_bottom_right is None: - # Currently this fires all the time - not great. Needs to only fire - # when, additionally, we have a selection chosen based on the box - # calculated in the mode handlers. - None - - # Once the selection boxes go to None begin the highlight selected - # points procedure. This will store a point list of selected points - # highlight them, etc. - # Once thats done moving points will be difficult but do-able. - - elif __current_mode is Mode.DELETE: - raise NotImplementedError("Drawing for DELETE not implemented.") def __clamp_x(x): """ @@ -368,6 +354,19 @@ def draw_selection_box(color): glEnd() + +def clear_selection(): + """ + A helper designed to be called from the main window + in order to clear the selection internal to the graphics + and mode files. This way you dont have to do something + before the selection clears. + """ + global __current_points + + if __current_points is not None: + __current_points.clear_selection() + def draw_points(point_set, color): """ Simple point drawing function. diff --git a/main_window.py b/main_window.py index ee86281..fcf4472 100644 --- a/main_window.py +++ b/main_window.py @@ -1,5 +1,6 @@ -import os from enum import Enum +from functools import partial +import os from PyQt5.QtCore import Qt from PyQt5.QtGui import QCursor @@ -7,8 +8,9 @@ from PyQt5 import QtWidgets, uic from clusterview.exceptions import handle_exceptions, InvalidModeError from clusterview.mode import Mode -from clusterview.mode_handlers import MODE_HANDLER_MAP -from clusterview.opengl_widget import (initialize_gl, paint_gl, resize_gl, +from clusterview.mode_handlers import MODE_HANDLER_MAP, ogl_keypress_handler +from clusterview.opengl_widget import (clear_selection, initialize_gl, + paint_gl, resize_gl, set_drawing_mode, set_drawing_context) from clusterview_ui import Ui_MainWindow @@ -36,6 +38,14 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): # tracked and fired properly. self.opengl_widget.setMouseTracking(True) + # Enables us to handle key press events (used for checking + # for and handling terminating selections with ESC). + # Here we partially apply the key press handler with self to + # create a new function that only expects the event `keyPressEvent` + # expects. In this way, we've snuck the state of the opengl_widget + # into the function so that we can modify it as we please. + self.opengl_widget.keyPressEvent = partial(ogl_keypress_handler, self) + #----------------------------------------------- # OpenGL Graphics Handlers are set # here and defined in clusterview.opengl_widget. @@ -68,24 +78,32 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): set_drawing_mode(self.__mode) self.opengl_widget.setCursor(QCursor(Qt.CursorShape.CrossCursor)) self.status_bar.showMessage("ADD MODE") + clear_selection() + self.opengl_widget.update() def __edit_points(self): self.__mode = Mode.EDIT set_drawing_mode(self.__mode) self.opengl_widget.setCursor(QCursor(Qt.CursorShape.CrossCursor)) self.status_bar.showMessage("EDIT MODE") + clear_selection() + self.opengl_widget.update() def __delete_points(self): self.__mode = Mode.DELETE set_drawing_mode(self.__mode) self.opengl_widget.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) self.status_bar.showMessage("DELETE MODE") + clear_selection() + self.opengl_widget.update() def __move_points(self): self.__mode = Mode.MOVE set_drawing_mode(self.__mode) self.opengl_widget.setCursor(QCursor(Qt.CursorShape.SizeAllCursor)) self.status_bar.showMessage("MOVE MODE") + clear_selection() + self.opengl_widget.update() @handle_exceptions def __solve_launcher(self):