Browse Source

bounding box for move

tb-init-ui-render
Taylor Bockman 5 years ago
parent
commit
f538fc648b
  1. 4
      clusterview/exceptions.py
  2. 77
      clusterview/mode_handlers.py
  3. 129
      clusterview/opengl_widget.py
  4. 23
      main_window.py

4
clusterview/exceptions.py

@ -42,9 +42,9 @@ def handle_exceptions(func):
def my_qt_func():
raises SomeException
"""
def wrapped(self, *args, **kwargs):
def wrapped(*args, **kwargs):
try:
return func(self, *args, **kwargs)
return func(*args, **kwargs)
except Exception as e:
error_dialog = QErrorMessage()
error_dialog.showMessage(str(e))

77
clusterview/mode_handlers.py

@ -1,5 +1,9 @@
from PyQt5.QtCore import QEvent, Qt
from .mode import Mode
from .opengl_widget import set_current_points, set_drawing_event
from .opengl_widget import (set_current_points, set_drawing_event,
set_move_bb_top_left, set_move_bb_bottom_right,
reset_move_bbs)
from .points import PointSet
# Size of point for drawing
@ -9,6 +13,11 @@ __POINT_SIZE = 8
# nature of state management in OpenGL.
__point_set = PointSet(__POINT_SIZE)
# Module level flag for left click events (used to detect a left
# click hold drag)
__left_click_flag = False
def __refresh_point_list(ctx):
"""
Refreshes the point list display.
@ -37,16 +46,19 @@ def __handle_add_point(ctx, event):
"""
global __point_set
# No attribute at the moment.
__point_set.add_point(event.x(), event.y())
if (event.button() == Qt.LeftButton and
event.type() == QEvent.MouseButtonPress):
__refresh_point_list(ctx)
# No attribute at the moment.
__point_set.add_point(event.x(), event.y())
set_drawing_event(event)
set_current_points(__point_set)
__refresh_point_list(ctx)
ctx.opengl_widget.update()
ctx.point_list_widget.update()
set_drawing_event(event)
set_current_points(__point_set)
ctx.opengl_widget.update()
ctx.point_list_widget.update()
def __handle_edit_point(ctx, event):
@ -67,23 +79,56 @@ def __handle_edit_point(ctx, event):
ctx.update()
# after this remove the point from the list
def __handle_move_points(ctx, event):
# TODO: Should move the associated points in the list to the new location.
# Store list of old points that are captured
global __left_click_flag
set_drawing_event(event)
ctx.update()
if event.button() == Qt.LeftButton:
__left_click_flag = True
# This if statement block is used to set the bounding box for
# drawing and call the selection procedure.
if __left_click_flag and event.type() == QEvent.MouseButtonPress:
set_move_bb_top_left(event.x(), event.y())
elif __left_click_flag and event.type() == QEvent.MouseMove:
set_move_bb_bottom_right(event.x(), event.y())
elif __left_click_flag and event.type() == QEvent.MouseButtonRelease:
__left_click_flag = False
# Final bottom right corner point
set_move_bb_bottom_right(event.x(), event.y())
# Call the selection procedure
# TODO
# Satisfy the post condition by resetting the bounding box
reset_move_bbs()
# Find and move all points from the old list to their new locations
ctx.opengl_widget.update()
def __handle_delete_point(ctx, event):
set_drawing_event(event)
if (event.button() == Qt.LeftButton and
event.type() == QEvent.MouseButtonPress):
__point_set.remove_point(event.x(), event.y())
set_drawing_event(event)
__refresh_point_list(ctx)
__point_set.remove_point(event.x(), event.y())
ctx.opengl_widget.update()
ctx.point_list_widget.update()
__refresh_point_list(ctx)
ctx.opengl_widget.update()
ctx.point_list_widget.update()
# Simple dispatcher to make it easy to dispatch the right mode
# function when the OpenGL window is clicked.

129
clusterview/opengl_widget.py

@ -8,26 +8,31 @@ To be clear, the actual widget is defined in the UI
generated code - `clusterview_ui.py`. The functions
here are imported as overrides to the OpenGL functions of
that widget.
It should be split up into a few more separate files eventually...
Probably even into it's own module folder.
"""
from enum import Enum
from OpenGL.GL import (glBegin, glClearColor, glColor4f, glEnable,
glEnd, GL_LIGHT0, GL_LIGHTING, GL_POINTS,
glEnd, GL_LIGHT0, GL_LIGHTING, GL_LINE_LOOP, GL_POINTS,
glPointSize, glVertex3f, glViewport)
from .exceptions import InvalidModeError, InvalidStateError
from .exceptions import handle_exceptions, InvalidModeError, InvalidStateError
from .mode import Mode
from .points import PointSet
class Color(Enum):
BLUE = 0
BLACK = 1
# A simple map from Color -> RGBA 4-Tuple
# Note: The color values in the tuple are not RGB, but
# rather OpenGL percentage values for RGB.
COLOR_TO_RGBA = {
Color.BLUE: (0, 0.5, 1.0, 0.0)
Color.BLUE: (0, 0.5, 1.0, 0.0),
Color.BLACK: (0.0, 0.0, 0.0, 0.0)
}
# Constants set based on the size of the window.
@ -35,6 +40,11 @@ __BOTTOM_LEFT = (0, 0)
__WIDTH = None
__HEIGHT = None
# State variables for a move selection bounding box.
# There are always reset to None after a selection has been made.
__move_bb_top_left = None
__move_bb_bottom_right = None
# Module-global state variables for our drawing
# state machine.
#
@ -117,6 +127,38 @@ def set_drawing_event(event):
__current_event = event
def set_move_bb_top_left(x, y):
"""
Called to set the move bounding box's top left corner.
@param x The x-coordinate.
@param y The y-coordinate.
"""
global __move_bb_top_left
__move_bb_top_left = (x, y)
def set_move_bb_bottom_right(x, y):
"""
Called to set the move bounding box's bottom right corner.
@param x The x-coordinate.
@param y The y-coordinate.
"""
global __move_bb_bottom_right
__move_bb_bottom_right = (x, y)
def reset_move_bbs():
global __move_bb_top_left
global __move_bb_bottom_right
__move_bb_top_left = None
__move_bb_bottom_right = None
def initialize_gl():
"""
Initializes the OpenGL context on the Window.
@ -144,6 +186,7 @@ def resize_gl(w, h):
__HEIGHT = __current_context.height()
@handle_exceptions
def paint_gl():
"""
Stock PaintGL function from OpenGL that switches
@ -155,10 +198,9 @@ def paint_gl():
raise InvalidStateError("Event must exist for ADD, EDIT, MOVE, " +
"and DELETE")
if (__current_mode in [Mode.ADD, Mode.EDIT, Mode.MOVE, Mode.DELETE] and
if (__current_mode in [Mode.ADD, Mode.EDIT, Mode.DELETE] and
__current_points is None):
raise InvalidStateError("Points must exist for ADD, EDIT, MOVE, " +
"and DELETE")
return
if __current_mode is Mode.ADD or __current_mode is Mode.DELETE:
# Note that drawing the points doesn't require a bounding box or
@ -167,10 +209,29 @@ def paint_gl():
# is the same as adding a point since we just draw what is in
# the point set.
draw_points(__current_points, Color.BLUE)
elif __current_mode is Mode.EDIT:
raise NotImplementedError("Drawing for EDIT not implemented.")
elif __current_mode is Mode.MOVE:
raise NotImplementedError("Drawing for MOVE not implemented.")
# We have to repeatedly draw the points while we are showing the
# move box.
if __current_points is not None:
draw_points(__current_points, Color.BLUE)
draw_selection_box(Color.BLACK)
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.
print("FIRE THE MOVE STUFF")
# 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.")
@ -199,6 +260,60 @@ def __clamp_y(y):
return y_w
def draw_selection_box(color):
"""
When the move bounding box state is populated and the mode is set
to MODE.Move this function will draw the selection bounding box.
@param color The color Enum.
"""
global __current_context
if __current_context is None:
raise InvalidStateError("Drawing context must be set before setting " +
"drawing mode")
if not isinstance(color, Color):
raise ValueError("Color must exist in the Color enumeration")
if __move_bb_top_left is None or __move_bb_bottom_right is None:
# Nothing to draw.
return
ct = COLOR_TO_RGBA[color]
glViewport(0, 0, __WIDTH, __HEIGHT)
# Top right corner has the same x as the bottom right
# and same y as the top left.
top_right_corner = (__move_bb_bottom_right[0], __move_bb_top_left[1])
# Bottom left corner has the same x as the top left and
# same y as the bottom right.
bottom_left_corner = (__move_bb_top_left[0], __move_bb_bottom_right[1])
glBegin(GL_LINE_LOOP)
glColor4f(ct[0], ct[1], ct[2], ct[3])
glVertex3f(__clamp_x(__move_bb_top_left[0]),
__clamp_y(__move_bb_top_left[1]),
0.0)
glVertex3f(__clamp_x(top_right_corner[0]),
__clamp_y(top_right_corner[1]),
0.0)
glVertex3f(__clamp_x(__move_bb_bottom_right[0]),
__clamp_y(__move_bb_bottom_right[1]),
0.0)
glVertex3f(__clamp_x(bottom_left_corner[0]),
__clamp_y(bottom_left_corner[1]),
0.0)
glEnd()
def draw_points(point_set, color):
"""
Simple point drawing function.

23
main_window.py

@ -32,6 +32,10 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
# to OpenGL coordinates properly.
set_drawing_context(self.opengl_widget)
# Enables mouse tracking on the viewport so mouseMoveEvents are
# tracked and fired properly.
self.opengl_widget.setMouseTracking(True)
#-----------------------------------------------
# OpenGL Graphics Handlers are set
# here and defined in clusterview.opengl_widget.
@ -52,6 +56,8 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
# Override handler for mouse press so we can draw points based on
# the OpenGL coordinate system inside of the OpenGL Widget.
self.opengl_widget.mousePressEvent = self.__ogl_click_dispatcher
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
@ -98,12 +104,11 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
"""
Mode dispatcher for click actions on the OpenGL widget.
"""
if self.__mode is Mode.OFF:
raise InvalidModeError(Mode.OFF)
# Map from Mode -> function
# where the function is a handler for the
# OpenGL event. The context passed to these functions allows
# them to modify on screen widgets such as the QOpenGLWidget and
# QListWidget.
MODE_HANDLER_MAP[self.__mode](self, event)
if self.__mode is not Mode.OFF:
# Map from Mode -> function
# where the function is a handler for the
# OpenGL event. The context passed to these functions allows
# them to modify on screen widgets such as the QOpenGLWidget and
# QListWidget.
MODE_HANDLER_MAP[self.__mode](self, event)

Loading…
Cancel
Save