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
`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>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>200</width>
@ -70,24 +76,104 @@
</property>
<layout class="QGridLayout" name="gridLayout">
<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>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
<height>20</height>
</size>
</property>
</spacer>
</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>
</item>
</layout>

31
clusterview/mode_handlers.py

@ -33,6 +33,9 @@ class __ClickFlag:
# Size of point for drawing
__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
# designed for managing state.
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 event The click event.
"""
# Update information as needed
__handle_info_updates(ctx, event)
if (event.button() == Qt.LeftButton and
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
# applicable.
__handle_info_updates(ctx, event)
PointManager.point_set.clear_selection()
# Store old x, y from event
@ -168,6 +177,8 @@ def __handle_move_points(ctx, event):
set_drawing_event(event)
__handle_info_updates(ctx, event)
# Necessary to capture keyboard events
ctx.opengl_widget.setFocusPolicy(Qt.StrongFocus)
@ -235,6 +246,9 @@ def __handle_move_points(ctx, event):
ctx.opengl_widget.update()
def __handle_delete_point(ctx, event):
__handle_info_updates(ctx, event)
if (event.button() == Qt.LeftButton and
event.type() == QEvent.MouseButtonPress):
@ -247,10 +261,23 @@ def __handle_delete_point(ctx, event):
ctx.opengl_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
# function when the OpenGL window is clicked.
# function when the OpenGL window is acted on.
MODE_HANDLER_MAP = {
Mode.OFF: lambda: None,
Mode.OFF: __handle_info_updates,
Mode.LOADED: __handle_info_updates,
Mode.ADD: __handle_add_point,
Mode.EDIT: __handle_edit_point,
Mode.MOVE: __handle_move_points,

10
clusterview/opengl_widget.py

@ -105,6 +105,16 @@ def set_drawing_event(event):
if event is not None:
__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):
"""
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.setHeightForWidth(self.groupBox.sizePolicy().hasHeightForWidth())
self.groupBox.setSizePolicy(sizePolicy)
self.groupBox.setMinimumSize(QtCore.QSize(100, 0))
self.groupBox.setMaximumSize(QtCore.QSize(200, 200))
self.groupBox.setObjectName("groupBox")
self.gridLayout = QtWidgets.QGridLayout(self.groupBox)
self.gridLayout.setObjectName("gridLayout")
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.gridLayout.addWidget(self.point_list_widget, 0, 0, 1, 1)
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.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)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
@ -108,6 +137,8 @@ class Ui_MainWindow(object):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "ClusterView"))
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_help.setTitle(_translate("MainWindow", "Help"))
self.tool_bar.setWindowTitle(_translate("MainWindow", "toolBar"))

22
main_window.py

@ -3,7 +3,7 @@ from functools import partial
import os
from PyQt5 import uic
from PyQt5.QtCore import Qt
from PyQt5.QtCore import QEvent, Qt
from PyQt5.QtGui import QCursor
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,
refresh_point_list)
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)
from clusterview.point_manager import PointManager
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.paintGL = paint_gl
self.opengl_widget.resizeGL = resize_gl
self.opengl_widget.leaveEvent = partial(mouse_leave, self)
# -------------------------------------
# UI Handlers
@ -177,14 +178,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
"""
Mode dispatcher for click actions on the OpenGL widget.
"""
if self.__mode not in [Mode.OFF, Mode.LOADED]:
# 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)
else:
# Go back to the base state
self.__off_mode()
# 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