Browse Source

UI update, mouse event tracking on all events, mouse leave, and mouse position tracking

tb-init-ui-render
Taylor Bockman 5 years ago
parent
commit
c0e9568c66
  1. 26
      CONTRIBUTING.md
  2. 92
      clusterview.ui
  3. 31
      clusterview/mode_handlers.py
  4. 10
      clusterview/opengl_widget.py
  5. 33
      clusterview_ui.py
  6. 22
      main_window.py

26
CONTRIBUTING.md

@ -78,3 +78,29 @@ If you are importing more than one thing from a module, alphabetize those as wel
should be should be
`from x import bar, baz, foo`. `from x import bar, baz, foo`.
### Prefer Private Methods
In Python, private methods don't exist in the way that they do in C++, Java, etc.
To declare a method private we must tell the compiler to garble the name. To do this
add two underscores to the prefix of the method name:
```python
# This method can be seen by anyone on import.
def hello_world():
print("Hello, world!")
# This method can only be seen by the module/class it is defined
# in.
def __hello_module():
print("Hello, module!")
```
We only want to expose the absolute bare minimum number of functions to the consumers of
our modules.

92
clusterview.ui

@ -59,6 +59,12 @@
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>200</width> <width>200</width>
@ -70,24 +76,104 @@
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QListWidget" name="point_list_widget"/> <widget class="QListWidget" name="point_list_widget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>
</item> </item>
<item> <item>
<spacer name="verticalSpacer"> <spacer name="verticalSpacer_2">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
</property> </property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>20</width> <width>20</width>
<height>40</height> <height>20</height>
</size> </size>
</property> </property>
</spacer> </spacer>
</item> </item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Canvas Information</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Mouse Position:</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="mouse_position_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>

31
clusterview/mode_handlers.py

@ -33,6 +33,9 @@ class __ClickFlag:
# Size of point for drawing # Size of point for drawing
__POINT_SIZE = 8 __POINT_SIZE = 8
# Canvas pixel border - empirical, not sure where this is stored officially
__CANVAS_BORDER = 1
# PointManager is a class that is filled with static methods # PointManager is a class that is filled with static methods
# designed for managing state. # designed for managing state.
PointManager.point_set = PointSet(__POINT_SIZE, viewport_height(), PointManager.point_set = PointSet(__POINT_SIZE, viewport_height(),
@ -73,6 +76,10 @@ def __handle_add_point(ctx, event):
@param ctx A context handle to the main window. @param ctx A context handle to the main window.
@param event The click event. @param event The click event.
""" """
# Update information as needed
__handle_info_updates(ctx, event)
if (event.button() == Qt.LeftButton and if (event.button() == Qt.LeftButton and
event.type() == QEvent.MouseButtonPress): event.type() == QEvent.MouseButtonPress):
@ -112,6 +119,8 @@ def __handle_edit_point(ctx, event):
# #
# Should move the associated point in the list to the new location if # Should move the associated point in the list to the new location if
# applicable. # applicable.
__handle_info_updates(ctx, event)
PointManager.point_set.clear_selection() PointManager.point_set.clear_selection()
# Store old x, y from event # Store old x, y from event
@ -168,6 +177,8 @@ def __handle_move_points(ctx, event):
set_drawing_event(event) set_drawing_event(event)
__handle_info_updates(ctx, event)
# Necessary to capture keyboard events # Necessary to capture keyboard events
ctx.opengl_widget.setFocusPolicy(Qt.StrongFocus) ctx.opengl_widget.setFocusPolicy(Qt.StrongFocus)
@ -235,6 +246,9 @@ def __handle_move_points(ctx, event):
ctx.opengl_widget.update() ctx.opengl_widget.update()
def __handle_delete_point(ctx, event): def __handle_delete_point(ctx, event):
__handle_info_updates(ctx, event)
if (event.button() == Qt.LeftButton and if (event.button() == Qt.LeftButton and
event.type() == QEvent.MouseButtonPress): event.type() == QEvent.MouseButtonPress):
@ -247,10 +261,23 @@ def __handle_delete_point(ctx, event):
ctx.opengl_widget.update() ctx.opengl_widget.update()
ctx.point_list_widget.update() ctx.point_list_widget.update()
def __handle_info_updates(ctx, event):
"""
Updates data under the "information" header.
@param ctx The context to the main window.
@param event The event.
"""
if event.type() == QEvent.MouseMove:
ctx.mouse_position_label.setText(f"{event.x(), event.y()}")
# Simple dispatcher to make it easy to dispatch the right mode # Simple dispatcher to make it easy to dispatch the right mode
# function when the OpenGL window is clicked. # function when the OpenGL window is acted on.
MODE_HANDLER_MAP = { MODE_HANDLER_MAP = {
Mode.OFF: lambda: None, Mode.OFF: __handle_info_updates,
Mode.LOADED: __handle_info_updates,
Mode.ADD: __handle_add_point, Mode.ADD: __handle_add_point,
Mode.EDIT: __handle_edit_point, Mode.EDIT: __handle_edit_point,
Mode.MOVE: __handle_move_points, Mode.MOVE: __handle_move_points,

10
clusterview/opengl_widget.py

@ -105,6 +105,16 @@ def set_drawing_event(event):
if event is not None: if event is not None:
__current_event = event __current_event = event
def mouse_leave(ctx, event):
"""
The leave event for the OpenGL widget to properly reset the mouse
position label.
@param ctx The context.
@param event The event.
"""
ctx.mouse_position_label.setText('')
def set_move_bb_top_left(x, y): def set_move_bb_top_left(x, y):
""" """
Called to set the move bounding box's top left corner. Called to set the move bounding box's top left corner.

33
clusterview_ui.py

@ -42,16 +42,45 @@ class Ui_MainWindow(object):
sizePolicy.setVerticalStretch(0) sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.groupBox.sizePolicy().hasHeightForWidth()) sizePolicy.setHeightForWidth(self.groupBox.sizePolicy().hasHeightForWidth())
self.groupBox.setSizePolicy(sizePolicy) self.groupBox.setSizePolicy(sizePolicy)
self.groupBox.setMinimumSize(QtCore.QSize(100, 0))
self.groupBox.setMaximumSize(QtCore.QSize(200, 200)) self.groupBox.setMaximumSize(QtCore.QSize(200, 200))
self.groupBox.setObjectName("groupBox") self.groupBox.setObjectName("groupBox")
self.gridLayout = QtWidgets.QGridLayout(self.groupBox) self.gridLayout = QtWidgets.QGridLayout(self.groupBox)
self.gridLayout.setObjectName("gridLayout") self.gridLayout.setObjectName("gridLayout")
self.point_list_widget = QtWidgets.QListWidget(self.groupBox) self.point_list_widget = QtWidgets.QListWidget(self.groupBox)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.point_list_widget.sizePolicy().hasHeightForWidth())
self.point_list_widget.setSizePolicy(sizePolicy)
self.point_list_widget.setMinimumSize(QtCore.QSize(100, 0))
self.point_list_widget.setObjectName("point_list_widget") self.point_list_widget.setObjectName("point_list_widget")
self.gridLayout.addWidget(self.point_list_widget, 0, 0, 1, 1) self.gridLayout.addWidget(self.point_list_widget, 0, 0, 1, 1)
self.verticalLayout.addWidget(self.groupBox) self.verticalLayout.addWidget(self.groupBox)
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) spacerItem = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
self.verticalLayout.addItem(spacerItem) self.verticalLayout.addItem(spacerItem)
self.groupBox_2 = QtWidgets.QGroupBox(self.centralwidget)
self.groupBox_2.setObjectName("groupBox_2")
self.gridLayout_2 = QtWidgets.QGridLayout(self.groupBox_2)
self.gridLayout_2.setObjectName("gridLayout_2")
spacerItem1 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
self.gridLayout_2.addItem(spacerItem1, 0, 2, 1, 1)
self.label = QtWidgets.QLabel(self.groupBox_2)
self.label.setObjectName("label")
self.gridLayout_2.addWidget(self.label, 0, 0, 1, 1)
self.mouse_position_label = QtWidgets.QLabel(self.groupBox_2)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.mouse_position_label.sizePolicy().hasHeightForWidth())
self.mouse_position_label.setSizePolicy(sizePolicy)
self.mouse_position_label.setMinimumSize(QtCore.QSize(100, 0))
self.mouse_position_label.setText("")
self.mouse_position_label.setObjectName("mouse_position_label")
self.gridLayout_2.addWidget(self.mouse_position_label, 0, 3, 1, 1)
spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout_2.addItem(spacerItem2, 1, 0, 1, 1)
self.verticalLayout.addWidget(self.groupBox_2)
self.horizontalLayout.addLayout(self.verticalLayout) self.horizontalLayout.addLayout(self.verticalLayout)
MainWindow.setCentralWidget(self.centralwidget) MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar = QtWidgets.QMenuBar(MainWindow)
@ -108,6 +137,8 @@ class Ui_MainWindow(object):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "ClusterView")) MainWindow.setWindowTitle(_translate("MainWindow", "ClusterView"))
self.groupBox.setTitle(_translate("MainWindow", "Point List")) self.groupBox.setTitle(_translate("MainWindow", "Point List"))
self.groupBox_2.setTitle(_translate("MainWindow", "Canvas Information"))
self.label.setText(_translate("MainWindow", "Mouse Position:"))
self.menu_file.setTitle(_translate("MainWindow", "File")) self.menu_file.setTitle(_translate("MainWindow", "File"))
self.menu_help.setTitle(_translate("MainWindow", "Help")) self.menu_help.setTitle(_translate("MainWindow", "Help"))
self.tool_bar.setWindowTitle(_translate("MainWindow", "toolBar")) self.tool_bar.setWindowTitle(_translate("MainWindow", "toolBar"))

22
main_window.py

@ -3,7 +3,7 @@ from functools import partial
import os import os
from PyQt5 import uic from PyQt5 import uic
from PyQt5.QtCore import Qt from PyQt5.QtCore import QEvent, Qt
from PyQt5.QtGui import QCursor from PyQt5.QtGui import QCursor
from PyQt5.QtWidgets import QFileDialog, QMainWindow from PyQt5.QtWidgets import QFileDialog, QMainWindow
@ -12,7 +12,7 @@ from clusterview.mode import Mode
from clusterview.mode_handlers import (MODE_HANDLER_MAP, ogl_keypress_handler, from clusterview.mode_handlers import (MODE_HANDLER_MAP, ogl_keypress_handler,
refresh_point_list) refresh_point_list)
from clusterview.opengl_widget import (clear_selection, initialize_gl, from clusterview.opengl_widget import (clear_selection, initialize_gl,
paint_gl, resize_gl, mouse_leave, paint_gl, resize_gl,
set_drawing_mode, set_drawing_context) set_drawing_mode, set_drawing_context)
from clusterview.point_manager import PointManager from clusterview.point_manager import PointManager
from clusterview.point_list_widget import item_click_handler from clusterview.point_list_widget import item_click_handler
@ -61,6 +61,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.opengl_widget.initializeGL = initialize_gl self.opengl_widget.initializeGL = initialize_gl
self.opengl_widget.paintGL = paint_gl self.opengl_widget.paintGL = paint_gl
self.opengl_widget.resizeGL = resize_gl self.opengl_widget.resizeGL = resize_gl
self.opengl_widget.leaveEvent = partial(mouse_leave, self)
# ------------------------------------- # -------------------------------------
# UI Handlers # UI Handlers
@ -177,14 +178,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
""" """
Mode dispatcher for click actions on the OpenGL widget. Mode dispatcher for click actions on the OpenGL widget.
""" """
# Map from Mode -> function
if self.__mode not in [Mode.OFF, Mode.LOADED]: # where the function is a handler for the
# Map from Mode -> function # OpenGL event. The context passed to these functions allows
# where the function is a handler for the # them to modify on screen widgets such as the QOpenGLWidget and
# OpenGL event. The context passed to these functions allows # QListWidget.
# them to modify on screen widgets such as the QOpenGLWidget and MODE_HANDLER_MAP[self.__mode](self, event)
# QListWidget.
MODE_HANDLER_MAP[self.__mode](self, event)
else:
# Go back to the base state
self.__off_mode()

Loading…
Cancel
Save