diff --git a/clusterview/mode.py b/clusterview/mode.py index 5f243ba..a825cdf 100644 --- a/clusterview/mode.py +++ b/clusterview/mode.py @@ -13,3 +13,5 @@ class Mode(Enum): MOVE = 3 DELETE = 4 LOADED = 5 + CHOOSE_CENTROIDS = 6 + GROUP = 7 diff --git a/clusterview/mode_handlers.py b/clusterview/mode_handlers.py index 30fa28c..6afc402 100644 --- a/clusterview/mode_handlers.py +++ b/clusterview/mode_handlers.py @@ -1,4 +1,4 @@ -from enum import Enum +import random from PyQt5.QtCore import QEvent, Qt from PyQt5.QtGui import QCursor @@ -54,6 +54,12 @@ __last_mouse_pos = None # Used to implement mouse dragging when clicked __left_click_down = False +# TODO: WHEN THE GROUPING ENDS AND THE USER CANCELS THE CENTROID COUNT +# SHOULD BE ZEROED AND REMAINING COLORS SHOULD BE REPOPULATED. +# Count of centroids for comparison with the spin widget +__centroid_count = 0 +__remaining_colors = [c for c in Color if c not in [Color.BLUE, Color.GREY]] + def refresh_point_list(ctx): """ @@ -294,6 +300,55 @@ def __handle_info_updates(ctx, event): ctx.mouse_position_label.setText(f"{event.x(), event.y()}") +def __handle_choose_centroids(ctx, event): + """ + Similar to move in terms of selecting points, however this + function assigns a random color up to the maximum number + of centroids, and after the maximum number has been selected it will + enable the group button. + """ + global __centroid_count + global __remaining_colors + + __handle_info_updates(ctx, event) + + if __centroid_count == ctx.number_of_centroids.value: + # We have specified the number of centroids required + return + + if (event.button() == Qt.LeftButton and + event.type() == QEvent.MouseButtonPress): + + point = None + + for test_point in PointManager.point_set.points: + if test_point.hit(event.x(), event.y()): + point = test_point + + if point is None: + # No point was found on the click, do nothing + return + + if point in PointManager.centroids: + # Centroids must be unique + return + + __centroid_count += 1 + + color = random.choice(__remaining_colors) + __remaining_colors.remove(color) + + point.color = color + + # Recolor the point and restash the point in centroids + PointManager.centroids.append(point) + + if __centroid_count == ctx.number_of_centroids.value: + ctx.group_button.setEnabled(True) + + ctx.opengl_widget.update() + + # Simple dispatcher to make it easy to dispatch the right mode # function when the OpenGL window is acted on. MODE_HANDLER_MAP = { @@ -302,5 +357,6 @@ MODE_HANDLER_MAP = { Mode.ADD: __handle_add_point, Mode.EDIT: __handle_edit_point, Mode.MOVE: __handle_move_points, - Mode.DELETE: __handle_delete_point + Mode.DELETE: __handle_delete_point, + Mode.CHOOSE_CENTROIDS: __handle_choose_centroids } diff --git a/clusterview/opengl_widget.py b/clusterview/opengl_widget.py index d558a18..2c14248 100644 --- a/clusterview/opengl_widget.py +++ b/clusterview/opengl_widget.py @@ -167,7 +167,9 @@ def paint_gl(): if (__current_context.mode is Mode.ADD or __current_context.mode is Mode.DELETE or - __current_context.mode is Mode.LOADED): + __current_context.mode is Mode.LOADED or + __current_context.mode is Mode.CHOOSE_CENTROIDS or + __current_context.mode is Mode.GROUP): draw_points(PointManager.point_set) diff --git a/clusterview/point_manager.py b/clusterview/point_manager.py index 30320a8..f15f20d 100644 --- a/clusterview/point_manager.py +++ b/clusterview/point_manager.py @@ -11,6 +11,7 @@ class PointManager(): """ point_set = None + centroids = [] @staticmethod def load(location): diff --git a/main_window.py b/main_window.py index 6eee515..91f5a1d 100644 --- a/main_window.py +++ b/main_window.py @@ -65,10 +65,12 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.point_list_widget.itemClicked.connect(partial(item_click_handler, self)) - #----------------------------------------------- + self.choose_centroids_button.clicked.connect(self.__choose_centroids) + + # ----------------------------------------------- # OpenGL Graphics Handlers are set # here and defined in clusterview.opengl_widget. - #----------------------------------------------- + # ----------------------------------------------- self.opengl_widget.initializeGL = initialize_gl self.opengl_widget.paintGL = paint_gl self.opengl_widget.resizeGL = resize_gl @@ -97,10 +99,10 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.opengl_widget.mouseMoveEvent = self.__ogl_click_dispatcher self.opengl_widget.mouseReleaseEvent = self.__ogl_click_dispatcher - #----------------------------------------------------------------- + # ----------------------------------------------------------------- # Mode changers - these will be used to signal the action in the # OpenGL Widget. - #----------------------------------------------------------------- + # ----------------------------------------------------------------- def __off_mode(self): self.opengl_widget.setCursor(QCursor(Qt.CursorShape.ArrowCursor)) self.status_bar.showMessage("") @@ -123,7 +125,8 @@ class MainWindow(QMainWindow, Ui_MainWindow): def __delete_points(self): self.__mode = Mode.DELETE - self.opengl_widget.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + self.opengl_widget.setCursor(QCursor( + Qt.CursorShape.PointingHandCursor)) self.status_bar.showMessage("DELETE MODE") clear_selection() self.opengl_widget.update() @@ -131,8 +134,16 @@ class MainWindow(QMainWindow, Ui_MainWindow): def __move_points(self): self.__mode = Mode.MOVE self.opengl_widget.setCursor(QCursor(Qt.CursorShape.SizeAllCursor)) - self.status_bar.showMessage("MOVE MODE - PRESS ESC OR SWITCH MODES TO "+ - "CANCEL SELECTION") + self.status_bar.showMessage("MOVE MODE - PRESS ESC OR SWITCH MODES" + + "TO CANCEL SELECTION") + clear_selection() + self.opengl_widget.update() + + def __choose_centroids(self): + self.__mode = Mode.CHOOSE_CENTROIDS + self.opengl_widget.setCursor(QCursor(Qt.CursorShape.CrossCursor)) + self.status_bar.showMessage("CHOOSE CENTROIDS") + clear_selection() self.opengl_widget.update() @@ -167,10 +178,11 @@ class MainWindow(QMainWindow, Ui_MainWindow): refresh_point_list(self) def __save_points_file(self): - file_name, _ = QFileDialog.getSaveFileName(self, - "Save Point Configuration", - "", - "JSON Files (*.json)") + file_name, _ = (QFileDialog. + getSaveFileName(self, + "Save Point Configuration", + "", + "JSON Files (*.json)")) if file_name: PointManager.save(file_name)