2019-10-13 15:13:39 +00:00
|
|
|
# ##########################################################
|
2019-01-03 19:25:08 +00:00
|
|
|
# FlatCAM: 2D Post-processing for Manufacturing #
|
2019-10-13 15:13:39 +00:00
|
|
|
# Author: Dennis Hayrullin (c) #
|
|
|
|
# Date: 2016 #
|
2019-01-03 19:25:08 +00:00
|
|
|
# MIT Licence #
|
2019-10-13 15:13:39 +00:00
|
|
|
# ##########################################################
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
from PyQt5 import QtCore
|
|
|
|
|
|
|
|
import logging
|
2020-04-27 11:05:40 +00:00
|
|
|
from flatcamGUI.VisPyCanvas import VisPyCanvas, Color
|
2019-03-11 10:23:26 +00:00
|
|
|
from flatcamGUI.VisPyVisuals import ShapeGroup, ShapeCollection, TextCollection, TextGroup, Cursor
|
2019-01-03 19:25:08 +00:00
|
|
|
from vispy.scene.visuals import InfiniteLine, Line
|
2019-10-12 13:31:44 +00:00
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
import numpy as np
|
|
|
|
from vispy.geometry import Rect
|
|
|
|
|
|
|
|
log = logging.getLogger('base')
|
|
|
|
|
|
|
|
|
2019-08-24 01:45:25 +00:00
|
|
|
class PlotCanvas(QtCore.QObject, VisPyCanvas):
|
2019-01-03 19:25:08 +00:00
|
|
|
"""
|
|
|
|
Class handling the plotting area in the application.
|
|
|
|
"""
|
|
|
|
|
2019-08-24 01:45:25 +00:00
|
|
|
def __init__(self, container, fcapp):
|
2019-01-03 19:25:08 +00:00
|
|
|
"""
|
|
|
|
The constructor configures the VisPy figure that
|
|
|
|
will contain all plots, creates the base axes and connects
|
|
|
|
events to the plotting area.
|
|
|
|
|
|
|
|
:param container: The parent container in which to draw plots.
|
|
|
|
:rtype: PlotCanvas
|
|
|
|
"""
|
|
|
|
|
2020-01-10 11:00:47 +00:00
|
|
|
# super(PlotCanvas, self).__init__()
|
|
|
|
# QtCore.QObject.__init__(self)
|
2019-09-02 10:24:04 +00:00
|
|
|
# VisPyCanvas.__init__(self)
|
2020-01-10 11:00:47 +00:00
|
|
|
super().__init__()
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-08-24 01:45:25 +00:00
|
|
|
# VisPyCanvas does not allow new attributes. Override.
|
|
|
|
self.unfreeze()
|
|
|
|
|
|
|
|
self.fcapp = fcapp
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
# Parent container
|
|
|
|
self.container = container
|
|
|
|
|
2019-10-07 01:06:00 +00:00
|
|
|
settings = QtCore.QSettings("Open Source", "FlatCAM")
|
|
|
|
if settings.contains("theme"):
|
|
|
|
theme = settings.value('theme', type=str)
|
|
|
|
else:
|
|
|
|
theme = 'white'
|
|
|
|
|
|
|
|
if theme == 'white':
|
|
|
|
self.line_color = (0.3, 0.0, 0.0, 1.0)
|
|
|
|
else:
|
|
|
|
self.line_color = (0.4, 0.4, 0.4, 1.0)
|
|
|
|
|
2019-01-03 19:25:08 +00:00
|
|
|
# workspace lines; I didn't use the rectangle because I didn't want to add another VisPy Node,
|
|
|
|
# which might decrease performance
|
2019-11-27 13:55:31 +00:00
|
|
|
# self.b_line, self.r_line, self.t_line, self.l_line = None, None, None, None
|
|
|
|
self.workspace_line = None
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2020-02-29 22:52:24 +00:00
|
|
|
self.pagesize_dict = {}
|
2019-11-27 13:55:31 +00:00
|
|
|
self.pagesize_dict.update(
|
2019-11-27 01:44:28 +00:00
|
|
|
{
|
|
|
|
'A0': (841, 1189),
|
|
|
|
'A1': (594, 841),
|
|
|
|
'A2': (420, 594),
|
|
|
|
'A3': (297, 420),
|
|
|
|
'A4': (210, 297),
|
|
|
|
'A5': (148, 210),
|
|
|
|
'A6': (105, 148),
|
|
|
|
'A7': (74, 105),
|
|
|
|
'A8': (52, 74),
|
|
|
|
'A9': (37, 52),
|
|
|
|
'A10': (26, 37),
|
|
|
|
|
|
|
|
'B0': (1000, 1414),
|
|
|
|
'B1': (707, 1000),
|
|
|
|
'B2': (500, 707),
|
|
|
|
'B3': (353, 500),
|
|
|
|
'B4': (250, 353),
|
|
|
|
'B5': (176, 250),
|
|
|
|
'B6': (125, 176),
|
|
|
|
'B7': (88, 125),
|
|
|
|
'B8': (62, 88),
|
|
|
|
'B9': (44, 62),
|
|
|
|
'B10': (31, 44),
|
|
|
|
|
|
|
|
'C0': (917, 1297),
|
|
|
|
'C1': (648, 917),
|
|
|
|
'C2': (458, 648),
|
|
|
|
'C3': (324, 458),
|
|
|
|
'C4': (229, 324),
|
|
|
|
'C5': (162, 229),
|
|
|
|
'C6': (114, 162),
|
|
|
|
'C7': (81, 114),
|
|
|
|
'C8': (57, 81),
|
|
|
|
'C9': (40, 57),
|
|
|
|
'C10': (28, 40),
|
|
|
|
|
|
|
|
# American paper sizes
|
|
|
|
'LETTER': (8.5*25.4, 11*25.4),
|
|
|
|
'LEGAL': (8.5*25.4, 14*25.4),
|
|
|
|
'ELEVENSEVENTEEN': (11*25.4, 17*25.4),
|
|
|
|
|
|
|
|
# From https://en.wikipedia.org/wiki/Paper_size
|
|
|
|
'JUNIOR_LEGAL': (5*25.4, 8*25.4),
|
|
|
|
'HALF_LETTER': (5.5*25.4, 8*25.4),
|
|
|
|
'GOV_LETTER': (8*25.4, 10.5*25.4),
|
|
|
|
'GOV_LEGAL': (8.5*25.4, 13*25.4),
|
|
|
|
'LEDGER': (17*25.4, 11*25.4),
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2019-11-27 13:55:31 +00:00
|
|
|
# <VisPyCanvas>
|
|
|
|
self.create_native()
|
|
|
|
self.native.setParent(self.fcapp.ui)
|
|
|
|
|
|
|
|
# <QtCore.QObject>
|
|
|
|
self.container.addWidget(self.native)
|
|
|
|
|
|
|
|
# ## AXIS # ##
|
2019-11-27 19:40:39 +00:00
|
|
|
self.v_line = InfiniteLine(pos=0, color=(0.70, 0.3, 0.3, 0.8), vertical=True,
|
2019-11-27 13:55:31 +00:00
|
|
|
parent=self.view.scene)
|
|
|
|
|
2019-11-27 19:40:39 +00:00
|
|
|
self.h_line = InfiniteLine(pos=0, color=(0.70, 0.3, 0.3, 0.8), vertical=False,
|
2019-11-27 13:55:31 +00:00
|
|
|
parent=self.view.scene)
|
|
|
|
|
|
|
|
# draw a rectangle made out of 4 lines on the canvas to serve as a hint for the work area
|
|
|
|
# all CNC have a limited workspace
|
|
|
|
if self.fcapp.defaults['global_workspace'] is True:
|
|
|
|
self.draw_workspace(workspace_size=self.fcapp.defaults["global_workspaceT"])
|
|
|
|
|
|
|
|
self.line_parent = None
|
2019-12-28 01:59:05 +00:00
|
|
|
if self.fcapp.defaults["global_cursor_color_enabled"]:
|
|
|
|
c_color = Color(self.fcapp.defaults["global_cursor_color"]).rgba
|
|
|
|
else:
|
|
|
|
c_color = self.line_color
|
2020-01-09 10:44:24 +00:00
|
|
|
|
2019-12-28 01:59:05 +00:00
|
|
|
self.cursor_v_line = InfiniteLine(pos=None, color=c_color, vertical=True,
|
2019-11-27 13:55:31 +00:00
|
|
|
parent=self.line_parent)
|
|
|
|
|
2019-12-28 01:59:05 +00:00
|
|
|
self.cursor_h_line = InfiniteLine(pos=None, color=c_color, vertical=False,
|
2019-11-27 13:55:31 +00:00
|
|
|
parent=self.line_parent)
|
|
|
|
|
|
|
|
self.shape_collections = []
|
|
|
|
|
|
|
|
self.shape_collection = self.new_shape_collection()
|
|
|
|
self.fcapp.pool_recreated.connect(self.on_pool_recreated)
|
|
|
|
self.text_collection = self.new_text_collection()
|
|
|
|
|
|
|
|
# TODO: Should be setting to show/hide CNC job annotations (global or per object)
|
|
|
|
self.text_collection.enabled = True
|
|
|
|
|
|
|
|
self.c = None
|
|
|
|
self.big_cursor = None
|
|
|
|
# Keep VisPy canvas happy by letting it be "frozen" again.
|
|
|
|
self.freeze()
|
2019-12-10 15:24:28 +00:00
|
|
|
self.fit_view()
|
2020-01-09 10:44:24 +00:00
|
|
|
|
2019-11-27 13:55:31 +00:00
|
|
|
self.graph_event_connect('mouse_wheel', self.on_mouse_scroll)
|
|
|
|
|
|
|
|
def draw_workspace(self, workspace_size):
|
|
|
|
"""
|
|
|
|
Draw a rectangular shape on canvas to specify our valid workspace.
|
|
|
|
:param workspace_size: the workspace size; tuple
|
|
|
|
:return:
|
|
|
|
"""
|
2019-11-27 01:44:28 +00:00
|
|
|
try:
|
|
|
|
if self.fcapp.defaults['units'].upper() == 'MM':
|
2019-11-27 13:55:31 +00:00
|
|
|
dims = self.pagesize_dict[workspace_size]
|
2019-11-27 01:44:28 +00:00
|
|
|
else:
|
2019-11-27 13:55:31 +00:00
|
|
|
dims = (self.pagesize_dict[workspace_size][0]/25.4, self.pagesize_dict[workspace_size][1]/25.4)
|
2019-11-27 01:44:28 +00:00
|
|
|
except Exception as e:
|
|
|
|
log.debug("PlotCanvas.draw_workspace() --> %s" % str(e))
|
|
|
|
return
|
|
|
|
|
|
|
|
if self.fcapp.defaults['global_workspace_orientation'] == 'l':
|
|
|
|
dims = (dims[1], dims[0])
|
|
|
|
|
|
|
|
a = np.array([(0, 0), (dims[0], 0), (dims[0], dims[1]), (0, dims[1])])
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-11-27 13:55:31 +00:00
|
|
|
if not self.workspace_line:
|
2019-11-27 19:40:39 +00:00
|
|
|
self.workspace_line = Line(pos=np.array((a[0], a[1], a[2], a[3], a[0])), color=(0.70, 0.3, 0.3, 0.7),
|
2019-11-27 13:55:31 +00:00
|
|
|
antialias=True, method='agg', parent=self.view.scene)
|
|
|
|
else:
|
|
|
|
self.workspace_line.parent = self.view.scene
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
def delete_workspace(self):
|
|
|
|
try:
|
2019-11-27 13:55:31 +00:00
|
|
|
self.workspace_line.parent = None
|
2019-11-11 00:35:42 +00:00
|
|
|
except Exception:
|
2019-01-03 19:25:08 +00:00
|
|
|
pass
|
|
|
|
|
2019-11-27 13:55:31 +00:00
|
|
|
# redraw the workspace lines on the plot by re adding them to the parent view.scene
|
2019-01-03 19:25:08 +00:00
|
|
|
def restore_workspace(self):
|
|
|
|
try:
|
2019-11-27 13:55:31 +00:00
|
|
|
self.workspace_line.parent = self.view.scene
|
2019-11-11 00:35:42 +00:00
|
|
|
except Exception:
|
2019-01-03 19:25:08 +00:00
|
|
|
pass
|
|
|
|
|
2019-09-20 14:25:32 +00:00
|
|
|
def graph_event_connect(self, event_name, callback):
|
2019-08-24 01:45:25 +00:00
|
|
|
return getattr(self.events, event_name).connect(callback)
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-09-20 14:25:32 +00:00
|
|
|
def graph_event_disconnect(self, event_name, callback=None):
|
2019-04-10 00:56:56 +00:00
|
|
|
if callback is None:
|
2019-08-24 01:45:25 +00:00
|
|
|
getattr(self.events, event_name).disconnect()
|
2019-04-10 00:56:56 +00:00
|
|
|
else:
|
2019-08-24 01:45:25 +00:00
|
|
|
getattr(self.events, event_name).disconnect(callback)
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
def zoom(self, factor, center=None):
|
|
|
|
"""
|
|
|
|
Zooms the plot by factor around a given
|
|
|
|
center point. Takes care of re-drawing.
|
|
|
|
|
|
|
|
:param factor: Number by which to scale the plot.
|
|
|
|
:type factor: float
|
|
|
|
:param center: Coordinates [x, y] of the point around which to scale the plot.
|
|
|
|
:type center: list
|
|
|
|
:return: None
|
|
|
|
"""
|
2019-08-24 01:45:25 +00:00
|
|
|
self.view.camera.zoom(factor, center)
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-02-25 14:28:32 +00:00
|
|
|
def new_shape_group(self, shape_collection=None):
|
|
|
|
if shape_collection:
|
|
|
|
return ShapeGroup(shape_collection)
|
2019-01-03 19:25:08 +00:00
|
|
|
return ShapeGroup(self.shape_collection)
|
|
|
|
|
|
|
|
def new_shape_collection(self, **kwargs):
|
2019-08-24 01:45:25 +00:00
|
|
|
# sc = ShapeCollection(parent=self.view.scene, pool=self.app.pool, **kwargs)
|
2019-01-03 19:25:08 +00:00
|
|
|
# self.shape_collections.append(sc)
|
|
|
|
# return sc
|
2019-08-24 01:45:25 +00:00
|
|
|
return ShapeCollection(parent=self.view.scene, pool=self.fcapp.pool, **kwargs)
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-09-27 01:42:28 +00:00
|
|
|
def new_cursor(self, big=None):
|
2019-09-27 14:19:44 +00:00
|
|
|
"""
|
|
|
|
Will create a mouse cursor pointer on canvas
|
|
|
|
|
|
|
|
:param big: if True will create a mouse cursor made out of infinite lines
|
|
|
|
:return: the mouse cursor object
|
|
|
|
"""
|
2019-09-27 01:42:28 +00:00
|
|
|
if big is True:
|
2019-09-28 18:29:23 +00:00
|
|
|
self.big_cursor = True
|
2020-04-27 11:05:40 +00:00
|
|
|
self.c = CursorBig(app=self.fcapp)
|
2019-09-27 14:19:44 +00:00
|
|
|
|
|
|
|
# in case there are multiple new_cursor calls, best to disconnect first the signals
|
|
|
|
try:
|
|
|
|
self.c.mouse_state_updated.disconnect(self.on_mouse_state)
|
|
|
|
except (TypeError, AttributeError):
|
|
|
|
pass
|
|
|
|
try:
|
|
|
|
self.c.mouse_position_updated.disconnect(self.on_mouse_position)
|
|
|
|
except (TypeError, AttributeError):
|
|
|
|
pass
|
|
|
|
|
2019-09-27 01:42:28 +00:00
|
|
|
self.c.mouse_state_updated.connect(self.on_mouse_state)
|
|
|
|
self.c.mouse_position_updated.connect(self.on_mouse_position)
|
|
|
|
else:
|
2019-09-28 18:29:23 +00:00
|
|
|
self.big_cursor = False
|
2019-09-27 01:42:28 +00:00
|
|
|
self.c = Cursor(pos=np.empty((0, 2)), parent=self.view.scene)
|
|
|
|
self.c.antialias = 0
|
2019-09-27 14:19:44 +00:00
|
|
|
|
2019-09-27 01:42:28 +00:00
|
|
|
return self.c
|
|
|
|
|
|
|
|
def on_mouse_state(self, state):
|
|
|
|
if state:
|
|
|
|
self.cursor_h_line.parent = self.view.scene
|
|
|
|
self.cursor_v_line.parent = self.view.scene
|
|
|
|
else:
|
|
|
|
self.cursor_h_line.parent = None
|
|
|
|
self.cursor_v_line.parent = None
|
|
|
|
|
|
|
|
def on_mouse_position(self, pos):
|
|
|
|
|
2019-12-28 01:59:05 +00:00
|
|
|
if self.fcapp.defaults['global_cursor_color_enabled']:
|
|
|
|
color = Color(self.fcapp.defaults['global_cursor_color']).rgba
|
|
|
|
else:
|
|
|
|
color = self.line_color
|
|
|
|
|
|
|
|
self.cursor_h_line.set_data(pos=pos[1], color=color)
|
|
|
|
self.cursor_v_line.set_data(pos=pos[0], color=color)
|
2019-09-27 01:42:28 +00:00
|
|
|
self.view.scene.update()
|
2019-01-03 19:25:08 +00:00
|
|
|
|
2019-10-12 13:31:44 +00:00
|
|
|
def on_mouse_scroll(self, event):
|
|
|
|
# key modifiers
|
|
|
|
modifiers = event.modifiers
|
|
|
|
pan_delta_x = self.fcapp.defaults["global_gridx"]
|
|
|
|
pan_delta_y = self.fcapp.defaults["global_gridy"]
|
|
|
|
curr_pos = event.pos
|
|
|
|
|
|
|
|
# Controlled pan by mouse wheel
|
|
|
|
if 'Shift' in modifiers:
|
|
|
|
p1 = np.array(curr_pos)[:2]
|
|
|
|
|
|
|
|
if event.delta[1] > 0:
|
|
|
|
curr_pos[0] -= pan_delta_x
|
|
|
|
else:
|
|
|
|
curr_pos[0] += pan_delta_x
|
|
|
|
p2 = np.array(curr_pos)[:2]
|
|
|
|
self.view.camera.pan(p2 - p1)
|
|
|
|
elif 'Control' in modifiers:
|
|
|
|
p1 = np.array(curr_pos)[:2]
|
|
|
|
|
|
|
|
if event.delta[1] > 0:
|
|
|
|
curr_pos[1] += pan_delta_y
|
|
|
|
else:
|
|
|
|
curr_pos[1] -= pan_delta_y
|
|
|
|
p2 = np.array(curr_pos)[:2]
|
|
|
|
self.view.camera.pan(p2 - p1)
|
|
|
|
|
2019-12-10 13:26:51 +00:00
|
|
|
if self.fcapp.grid_status():
|
2019-10-12 13:31:44 +00:00
|
|
|
pos_canvas = self.translate_coords(curr_pos)
|
|
|
|
pos = self.fcapp.geo_editor.snap(pos_canvas[0], pos_canvas[1])
|
|
|
|
|
|
|
|
# Update cursor
|
|
|
|
self.fcapp.app_cursor.set_data(np.asarray([(pos[0], pos[1])]),
|
|
|
|
symbol='++', edge_color=self.fcapp.cursor_color_3D,
|
2019-12-25 15:51:37 +00:00
|
|
|
edge_width=self.fcapp.defaults["global_cursor_width"],
|
2019-10-12 13:31:44 +00:00
|
|
|
size=self.fcapp.defaults["global_cursor_size"])
|
|
|
|
|
2019-08-16 14:21:31 +00:00
|
|
|
def new_text_group(self, collection=None):
|
|
|
|
if collection:
|
|
|
|
return TextGroup(collection)
|
|
|
|
else:
|
|
|
|
return TextGroup(self.text_collection)
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
def new_text_collection(self, **kwargs):
|
2019-08-24 01:45:25 +00:00
|
|
|
return TextCollection(parent=self.view.scene, **kwargs)
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
def fit_view(self, rect=None):
|
|
|
|
|
|
|
|
# Lock updates in other threads
|
|
|
|
self.shape_collection.lock_updates()
|
|
|
|
|
|
|
|
if not rect:
|
|
|
|
rect = Rect(-1, -1, 20, 20)
|
|
|
|
try:
|
|
|
|
rect.left, rect.right = self.shape_collection.bounds(axis=0)
|
|
|
|
rect.bottom, rect.top = self.shape_collection.bounds(axis=1)
|
|
|
|
except TypeError:
|
|
|
|
pass
|
|
|
|
|
2019-12-08 23:56:45 +00:00
|
|
|
# adjust the view camera to be slightly bigger than the bounds so the shape collection can be seen clearly
|
2019-02-18 17:35:18 +00:00
|
|
|
# otherwise the shape collection boundary will have no border
|
2019-12-08 23:56:45 +00:00
|
|
|
dx = rect.right - rect.left
|
|
|
|
dy = rect.top - rect.bottom
|
|
|
|
x_factor = dx * 0.02
|
|
|
|
y_factor = dy * 0.02
|
|
|
|
|
|
|
|
rect.left -= x_factor
|
|
|
|
rect.bottom -= y_factor
|
|
|
|
rect.right += x_factor
|
|
|
|
rect.top += y_factor
|
|
|
|
|
|
|
|
# rect.left *= 0.96
|
|
|
|
# rect.bottom *= 0.96
|
|
|
|
# rect.right *= 1.04
|
|
|
|
# rect.top *= 1.04
|
|
|
|
|
|
|
|
# units = self.fcapp.defaults['units'].upper()
|
|
|
|
# if units == 'MM':
|
|
|
|
# compensation = 0.5
|
|
|
|
# else:
|
|
|
|
# compensation = 0.5 / 25.4
|
|
|
|
# rect.left -= compensation
|
|
|
|
# rect.bottom -= compensation
|
|
|
|
# rect.right += compensation
|
|
|
|
# rect.top += compensation
|
2019-02-18 17:35:18 +00:00
|
|
|
|
2019-08-24 01:45:25 +00:00
|
|
|
self.view.camera.rect = rect
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
self.shape_collection.unlock_updates()
|
|
|
|
|
|
|
|
def fit_center(self, loc, rect=None):
|
|
|
|
|
|
|
|
# Lock updates in other threads
|
|
|
|
self.shape_collection.lock_updates()
|
|
|
|
|
|
|
|
if not rect:
|
|
|
|
try:
|
|
|
|
rect = Rect(loc[0]-20, loc[1]-20, 40, 40)
|
|
|
|
except TypeError:
|
|
|
|
pass
|
|
|
|
|
2019-08-24 01:45:25 +00:00
|
|
|
self.view.camera.rect = rect
|
2019-01-03 19:25:08 +00:00
|
|
|
|
|
|
|
self.shape_collection.unlock_updates()
|
|
|
|
|
|
|
|
def clear(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def redraw(self):
|
|
|
|
self.shape_collection.redraw([])
|
|
|
|
self.text_collection.redraw()
|
|
|
|
|
|
|
|
def on_pool_recreated(self, pool):
|
|
|
|
self.shape_collection.pool = pool
|
2019-09-27 01:42:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
class CursorBig(QtCore.QObject):
|
|
|
|
"""
|
|
|
|
This is a fake cursor to ensure compatibility with the OpenGL engine (VisPy).
|
|
|
|
This way I don't have to chane (disable) things related to the cursor all over when
|
|
|
|
using the low performance Matplotlib 2D graphic engine.
|
|
|
|
"""
|
|
|
|
|
|
|
|
mouse_state_updated = QtCore.pyqtSignal(bool)
|
|
|
|
mouse_position_updated = QtCore.pyqtSignal(list)
|
|
|
|
|
2020-04-27 11:05:40 +00:00
|
|
|
def __init__(self, app):
|
2019-09-27 01:42:28 +00:00
|
|
|
super().__init__()
|
2020-04-27 11:05:40 +00:00
|
|
|
self.app = app
|
2019-09-27 01:42:28 +00:00
|
|
|
self._enabled = None
|
|
|
|
|
|
|
|
@property
|
|
|
|
def enabled(self):
|
|
|
|
return True if self._enabled else False
|
|
|
|
|
|
|
|
@enabled.setter
|
|
|
|
def enabled(self, value):
|
|
|
|
self._enabled = value
|
|
|
|
self.mouse_state_updated.emit(value)
|
|
|
|
|
|
|
|
def set_data(self, pos, **kwargs):
|
|
|
|
"""Internal event handler to draw the cursor when the mouse moves."""
|
|
|
|
if 'edge_color' in kwargs:
|
|
|
|
color = kwargs['edge_color']
|
|
|
|
else:
|
2019-10-07 01:06:00 +00:00
|
|
|
if self.app.defaults['global_theme'] == 'white':
|
|
|
|
color = '#000000FF'
|
|
|
|
else:
|
|
|
|
color = '#FFFFFFFF'
|
2019-09-27 01:42:28 +00:00
|
|
|
|
|
|
|
position = [pos[0][0], pos[0][1]]
|
|
|
|
self.mouse_position_updated.emit(position)
|