author | Andrey Skvortsov <andrej.skvortzov@gmail.com> |
Thu, 01 Jun 2017 14:37:14 +0300 | |
changeset 1686 | 85fdcc04da25 |
parent 1631 | 940e20a8865b |
child 1730 | 64d8f52bc8c8 |
permissions | -rw-r--r-- |
814 | 1 |
#!/usr/bin/env python |
2 |
# -*- coding: utf-8 -*- |
|
3 |
||
1571
486f94a8032c
fix license notices in source files and license files under GPLv2+
Andrey Skvortsov <andrej.skvortzov@gmail.com>
parents:
1544
diff
changeset
|
4 |
# This file is part of Beremiz, a Integrated Development Environment for |
486f94a8032c
fix license notices in source files and license files under GPLv2+
Andrey Skvortsov <andrej.skvortzov@gmail.com>
parents:
1544
diff
changeset
|
5 |
# programming IEC 61131-3 automates supporting plcopen standard and CanFestival. |
814 | 6 |
# |
1571
486f94a8032c
fix license notices in source files and license files under GPLv2+
Andrey Skvortsov <andrej.skvortzov@gmail.com>
parents:
1544
diff
changeset
|
7 |
# Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD |
814 | 8 |
# |
1571
486f94a8032c
fix license notices in source files and license files under GPLv2+
Andrey Skvortsov <andrej.skvortzov@gmail.com>
parents:
1544
diff
changeset
|
9 |
# See COPYING file for copyrights details. |
814 | 10 |
# |
1571
486f94a8032c
fix license notices in source files and license files under GPLv2+
Andrey Skvortsov <andrej.skvortzov@gmail.com>
parents:
1544
diff
changeset
|
11 |
# This program is free software; you can redistribute it and/or |
486f94a8032c
fix license notices in source files and license files under GPLv2+
Andrey Skvortsov <andrej.skvortzov@gmail.com>
parents:
1544
diff
changeset
|
12 |
# modify it under the terms of the GNU General Public License |
486f94a8032c
fix license notices in source files and license files under GPLv2+
Andrey Skvortsov <andrej.skvortzov@gmail.com>
parents:
1544
diff
changeset
|
13 |
# as published by the Free Software Foundation; either version 2 |
486f94a8032c
fix license notices in source files and license files under GPLv2+
Andrey Skvortsov <andrej.skvortzov@gmail.com>
parents:
1544
diff
changeset
|
14 |
# of the License, or (at your option) any later version. |
814 | 15 |
# |
1571
486f94a8032c
fix license notices in source files and license files under GPLv2+
Andrey Skvortsov <andrej.skvortzov@gmail.com>
parents:
1544
diff
changeset
|
16 |
# This program is distributed in the hope that it will be useful, |
486f94a8032c
fix license notices in source files and license files under GPLv2+
Andrey Skvortsov <andrej.skvortzov@gmail.com>
parents:
1544
diff
changeset
|
17 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
486f94a8032c
fix license notices in source files and license files under GPLv2+
Andrey Skvortsov <andrej.skvortzov@gmail.com>
parents:
1544
diff
changeset
|
18 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
486f94a8032c
fix license notices in source files and license files under GPLv2+
Andrey Skvortsov <andrej.skvortzov@gmail.com>
parents:
1544
diff
changeset
|
19 |
# GNU General Public License for more details. |
814 | 20 |
# |
1571
486f94a8032c
fix license notices in source files and license files under GPLv2+
Andrey Skvortsov <andrej.skvortzov@gmail.com>
parents:
1544
diff
changeset
|
21 |
# You should have received a copy of the GNU General Public License |
486f94a8032c
fix license notices in source files and license files under GPLv2+
Andrey Skvortsov <andrej.skvortzov@gmail.com>
parents:
1544
diff
changeset
|
22 |
# along with this program; if not, write to the Free Software |
486f94a8032c
fix license notices in source files and license files under GPLv2+
Andrey Skvortsov <andrej.skvortzov@gmail.com>
parents:
1544
diff
changeset
|
23 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
814 | 24 |
|
25 |
import wx |
|
26 |
from math import * |
|
27 |
from types import * |
|
28 |
import datetime |
|
875
a8952b79caec
Fix bug in Debug refresh lock that, with too much data to debug, flooded GUI and blocked it
Laurent Bessard
parents:
857
diff
changeset
|
29 |
from threading import Lock,Timer |
814 | 30 |
|
1170
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
31 |
from graphics.ToolTipProducer import ToolTipProducer |
1176
f4b434672204
Moved and rewrote DebugViewer and DebusDataConsumer classes
Laurent Bessard
parents:
1173
diff
changeset
|
32 |
from graphics.DebugDataConsumer import DebugDataConsumer |
1169
53e4a2b775a7
Move CustomToolTip from GraphicCommons to controls
Laurent Bessard
parents:
1166
diff
changeset
|
33 |
|
814 | 34 |
#------------------------------------------------------------------------------- |
35 |
# Common constants |
|
36 |
#------------------------------------------------------------------------------- |
|
37 |
||
38 |
""" |
|
39 |
Definition of constants for dimensions of graphic elements |
|
40 |
""" |
|
41 |
||
42 |
# FBD and SFC constants |
|
43 |
MIN_MOVE = 5 # Minimum move before starting a element dragging |
|
44 |
CONNECTOR_SIZE = 8 # Size of connectors |
|
45 |
BLOCK_LINE_SIZE = 20 # Minimum size of each line in a block |
|
46 |
HANDLE_SIZE = 6 # Size of the squares for handles |
|
47 |
ANCHOR_DISTANCE = 5 # Distance where wire is automativally attached to a connector |
|
48 |
POINT_RADIUS = 2 # Radius of the point of wire ends |
|
49 |
MIN_SEGMENT_SIZE = 2 # Minimum size of the endling segments of a wire |
|
50 |
||
51 |
# LD constants |
|
52 |
LD_LINE_SIZE = 40 # Distance between two lines in a ladder rung |
|
53 |
LD_ELEMENT_SIZE = (21, 15) # Size (width, height) of a ladder element (contact or coil) |
|
54 |
LD_WIRE_SIZE = 30 # Size of a wire between two contact |
|
55 |
LD_WIRECOIL_SIZE = 70 # Size of a wire between a coil and a contact |
|
56 |
LD_POWERRAIL_WIDTH = 3 # Width of a Powerrail |
|
57 |
LD_OFFSET = (10, 10) # Distance (x, y) between each comment and rung of the ladder |
|
58 |
LD_COMMENT_DEFAULTSIZE = (600, 40) # Size (width, height) of a comment box |
|
59 |
||
60 |
# SFC constants |
|
61 |
SFC_STEP_DEFAULT_SIZE = (40, 30) # Default size of a SFC step |
|
62 |
SFC_TRANSITION_SIZE = (20, 2) # Size of a SFC transition |
|
63 |
SFC_DEFAULT_SEQUENCE_INTERVAL = 40 # Default size of the interval between two divergence branches |
|
64 |
SFC_SIMULTANEOUS_SEQUENCE_EXTRA = 20 # Size of extra lines for simultaneous divergence and convergence |
|
65 |
SFC_JUMP_SIZE = (12, 13) # Size of a SFC jump to step |
|
66 |
SFC_WIRE_MIN_SIZE = 25 # Size of a wire between two elements |
|
67 |
SFC_ACTION_MIN_SIZE = (100, 30) # Minimum size of an action block line |
|
68 |
||
69 |
# Type definition constants for graphic elements |
|
70 |
[INPUT, OUTPUT, INOUT] = range(3) |
|
71 |
[CONNECTOR, CONTINUATION] = range(2) |
|
72 |
[LEFTRAIL, RIGHTRAIL] = range(2) |
|
73 |
[CONTACT_NORMAL, CONTACT_REVERSE, CONTACT_RISING, CONTACT_FALLING] = range(4) |
|
74 |
[COIL_NORMAL, COIL_REVERSE, COIL_SET, COIL_RESET, COIL_RISING, COIL_FALLING] = range(6) |
|
75 |
[SELECTION_DIVERGENCE, SELECTION_CONVERGENCE, SIMULTANEOUS_DIVERGENCE, SIMULTANEOUS_CONVERGENCE] = range(4) |
|
76 |
||
77 |
# Constants for defining the type of dragging that has been selected |
|
78 |
[HANDLE_MOVE, HANDLE_RESIZE, HANDLE_POINT, HANDLE_SEGMENT, HANDLE_CONNECTOR] = range(5) |
|
79 |
||
80 |
# List of value for resize handle that are valid |
|
81 |
VALID_HANDLES = [(1,1), (1,2), (1,3), (2,3), (3,3), (3,2), (3,1), (2,1)] |
|
82 |
||
83 |
# Contants for defining the direction of a connector |
|
84 |
[EAST, NORTH, WEST, SOUTH] = [(1,0), (0,-1), (-1,0), (0,1)] |
|
85 |
||
86 |
# Contants for defining which mode is selected for each view |
|
87 |
[MODE_SELECTION, MODE_BLOCK, MODE_VARIABLE, MODE_CONNECTION, MODE_COMMENT, |
|
88 |
MODE_COIL, MODE_CONTACT, MODE_POWERRAIL, MODE_INITIALSTEP, MODE_STEP, |
|
89 |
MODE_TRANSITION, MODE_DIVERGENCE, MODE_JUMP, MODE_ACTION, MODE_MOTION] = range(15) |
|
90 |
||
91 |
# Contants for defining alignment types for graphic group |
|
92 |
[ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT, ALIGN_TOP, ALIGN_MIDDLE, ALIGN_BOTTOM] = range(6) |
|
93 |
||
94 |
# Contants for defining which drawing mode is selected for app |
|
95 |
[FREEDRAWING_MODE, DRIVENDRAWING_MODE] = [1, 2] |
|
96 |
||
97 |
# Color for Highlighting |
|
98 |
HIGHLIGHTCOLOR = wx.CYAN |
|
99 |
||
100 |
# Define highlight types |
|
101 |
ERROR_HIGHLIGHT = (wx.Colour(255, 255, 0), wx.RED) |
|
102 |
SEARCH_RESULT_HIGHLIGHT = (wx.Colour(255, 165, 0), wx.WHITE) |
|
103 |
||
104 |
# Define highlight refresh inhibition period in second |
|
105 |
REFRESH_HIGHLIGHT_PERIOD = 0.1 |
|
106 |
||
107 |
HANDLE_CURSORS = { |
|
108 |
(1, 1) : 2, |
|
109 |
(3, 3) : 2, |
|
110 |
(1, 3) : 3, |
|
111 |
(3, 1) : 3, |
|
112 |
(1, 2) : 4, |
|
113 |
(3, 2) : 4, |
|
114 |
(2, 1) : 5, |
|
115 |
(2, 3) : 5 |
|
116 |
} |
|
117 |
||
118 |
def round_scaling(x, n, constraint=0): |
|
119 |
fraction = float(x) / float(n) |
|
852
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
120 |
if constraint == -1: |
814 | 121 |
xround = int(fraction) |
122 |
else: |
|
123 |
xround = round(fraction) |
|
852
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
124 |
if constraint == 1 and xround < fraction: |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
125 |
xround += 1 |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
126 |
return int(xround * n) |
814 | 127 |
|
128 |
""" |
|
129 |
Basic vector operations for calculate wire points |
|
130 |
""" |
|
131 |
||
132 |
# Create a vector from two points and define if vector must be normal |
|
133 |
def vector(p1, p2, normal = True): |
|
134 |
vector = (p2.x - p1.x, p2.y - p1.y) |
|
135 |
if normal: |
|
136 |
return normalize(vector) |
|
137 |
return vector |
|
138 |
||
139 |
# Calculate the norm of a given vector |
|
140 |
def norm(v): |
|
141 |
return sqrt(v[0] * v[0] + v[1] * v[1]) |
|
142 |
||
143 |
# Normalize a given vector |
|
144 |
def normalize(v): |
|
145 |
v_norm = norm(v) |
|
146 |
# Verifie if it is not a null vector |
|
147 |
if v_norm > 0: |
|
148 |
return (v[0] / v_norm, v[1] / v_norm) |
|
149 |
else: |
|
150 |
return v |
|
151 |
||
152 |
# Calculate the scalar product of two vectors |
|
153 |
def is_null_vector(v): |
|
154 |
return v == (0, 0) |
|
155 |
||
156 |
# Calculate the scalar product of two vectors |
|
157 |
def add_vectors(v1, v2): |
|
158 |
return (v1[0] + v2[0], v1[1] + v2[1]) |
|
159 |
||
160 |
# Calculate the scalar product of two vectors |
|
161 |
def product(v1, v2): |
|
162 |
return v1[0] * v2[0] + v1[1] * v2[1] |
|
163 |
||
164 |
||
165 |
""" |
|
166 |
Function that calculates the nearest point of the grid defined by scaling for the given point |
|
167 |
""" |
|
168 |
||
169 |
def GetScaledEventPosition(event, dc, scaling): |
|
170 |
pos = event.GetLogicalPosition(dc) |
|
171 |
if scaling: |
|
172 |
pos.x = round(float(pos.x) / float(scaling[0])) * scaling[0] |
|
173 |
pos.y = round(float(pos.y) / float(scaling[1])) * scaling[1] |
|
174 |
return pos |
|
175 |
||
176 |
||
177 |
""" |
|
178 |
Function that choose a direction during the wire points generation |
|
179 |
""" |
|
180 |
||
181 |
def DirectionChoice(v_base, v_target, dir_target): |
|
182 |
dir_product = product(v_base, v_target) |
|
183 |
if dir_product < 0: |
|
184 |
return (-v_base[0], -v_base[1]) |
|
185 |
elif dir_product == 0 and product(v_base, dir_target) != 0: |
|
186 |
return dir_target |
|
187 |
return v_base |
|
188 |
||
189 |
def MiterPen(colour, width=1, style=wx.SOLID): |
|
190 |
pen = wx.Pen(colour, width, style) |
|
191 |
pen.SetJoin(wx.JOIN_MITER) |
|
192 |
pen.SetCap(wx.CAP_PROJECTING) |
|
193 |
return pen |
|
194 |
||
195 |
#------------------------------------------------------------------------------- |
|
196 |
# Helpers for highlighting text |
|
197 |
#------------------------------------------------------------------------------- |
|
198 |
||
199 |
def AddHighlight(highlights, infos): |
|
200 |
RemoveHighlight(highlights, infos) |
|
201 |
highlights.append(infos) |
|
202 |
||
203 |
def RemoveHighlight(highlights, infos): |
|
204 |
if infos in highlights: |
|
205 |
highlights.remove(infos) |
|
206 |
return True |
|
207 |
return False |
|
208 |
||
209 |
def ClearHighlight(highlights, highlight_type=None): |
|
210 |
if highlight_type is not None: |
|
211 |
return [highlight for highlight in highlights if highlight[2] != highlight_type] |
|
212 |
return [] |
|
213 |
||
214 |
def DrawHighlightedText(dc, text, highlights, x, y): |
|
215 |
current_pen = dc.GetPen() |
|
216 |
dc.SetPen(wx.TRANSPARENT_PEN) |
|
217 |
for start, end, highlight_type in highlights: |
|
218 |
dc.SetBrush(wx.Brush(highlight_type[0])) |
|
219 |
offset_width, offset_height = dc.GetTextExtent(text[:start[1]]) |
|
220 |
part = text[start[1]:end[1] + 1] |
|
221 |
part_width, part_height = dc.GetTextExtent(part) |
|
222 |
dc.DrawRectangle(x + offset_width, y, part_width, part_height) |
|
223 |
dc.SetTextForeground(highlight_type[1]) |
|
224 |
dc.DrawText(part, x + offset_width, y) |
|
225 |
dc.SetPen(current_pen) |
|
226 |
dc.SetTextForeground(wx.BLACK) |
|
227 |
||
228 |
#------------------------------------------------------------------------------- |
|
229 |
# Graphic element base class |
|
230 |
#------------------------------------------------------------------------------- |
|
231 |
||
232 |
""" |
|
233 |
Class that implements a generic graphic element |
|
234 |
""" |
|
235 |
||
1170
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
236 |
class Graphic_Element(ToolTipProducer): |
814 | 237 |
|
238 |
# Create a new graphic element |
|
239 |
def __init__(self, parent, id = None): |
|
1170
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
240 |
ToolTipProducer.__init__(self, parent) |
814 | 241 |
self.Parent = parent |
242 |
self.Id = id |
|
243 |
self.oldPos = None |
|
244 |
self.StartPos = None |
|
245 |
self.CurrentDrag = None |
|
246 |
self.Handle = (None,None) |
|
247 |
self.Dragging = False |
|
248 |
self.Selected = False |
|
249 |
self.Highlighted = False |
|
250 |
self.Pos = wx.Point(0, 0) |
|
251 |
self.Size = wx.Size(0, 0) |
|
252 |
self.BoundingBox = wx.Rect(0, 0, 0, 0) |
|
253 |
self.Visible = False |
|
254 |
||
255 |
def GetDefinition(self): |
|
256 |
return [self.Id], [] |
|
257 |
||
258 |
def TestVisible(self, screen): |
|
852
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
259 |
self.Visible = self.Selected or self.GetRedrawRect().Intersects(screen) |
814 | 260 |
|
261 |
def IsVisible(self): |
|
262 |
return self.Visible |
|
263 |
||
264 |
def SpreadCurrent(self): |
|
265 |
pass |
|
266 |
||
267 |
def GetConnectorTranslation(self, element): |
|
268 |
return {} |
|
269 |
||
270 |
def FindNearestConnector(self, position, connectors): |
|
271 |
distances = [] |
|
272 |
for connector in connectors: |
|
273 |
connector_pos = connector.GetRelPosition() |
|
274 |
distances.append((sqrt((self.Pos.x + connector_pos.x - position.x) ** 2 + |
|
275 |
(self.Pos.y + connector_pos.y - position.y) ** 2), |
|
276 |
connector)) |
|
277 |
distances.sort() |
|
278 |
if len(distances) > 0: |
|
279 |
return distances[0][1] |
|
280 |
return None |
|
281 |
||
282 |
def IsOfType(self, type, reference): |
|
283 |
return self.Parent.IsOfType(type, reference) |
|
284 |
||
285 |
def IsEndType(self, type): |
|
286 |
return self.Parent.IsEndType(type) |
|
287 |
||
288 |
def GetDragging(self): |
|
289 |
return self.Dragging |
|
290 |
||
291 |
# Make a clone of this element |
|
292 |
def Clone(self, parent): |
|
293 |
return Graphic_Element(parent, self.Id) |
|
294 |
||
295 |
# Changes the block position |
|
296 |
def SetPosition(self, x, y): |
|
297 |
self.Pos.x = x |
|
298 |
self.Pos.y = y |
|
299 |
self.RefreshConnected() |
|
300 |
self.RefreshBoundingBox() |
|
301 |
||
302 |
# Returns the block position |
|
303 |
def GetPosition(self): |
|
304 |
return self.Pos.x, self.Pos.y |
|
305 |
||
306 |
# Changes the element size |
|
307 |
def SetSize(self, width, height): |
|
308 |
self.Size.SetWidth(width) |
|
309 |
self.Size.SetHeight(height) |
|
310 |
self.RefreshConnectors() |
|
311 |
self.RefreshBoundingBox() |
|
312 |
||
313 |
# Returns the element size |
|
314 |
def GetSize(self): |
|
315 |
return self.Size.GetWidth(), self.Size.GetHeight() |
|
316 |
||
317 |
# Returns the minimum element size |
|
318 |
def GetMinSize(self): |
|
319 |
return 0, 0 |
|
320 |
||
852
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
321 |
# Set size of the element to the minimum size |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
322 |
def SetBestSize(self, scaling, x_factor=0.5, y_factor=0.5): |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
323 |
width, height = self.GetSize() |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
324 |
posx, posy = self.GetPosition() |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
325 |
min_width, min_height = self.GetMinSize() |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
326 |
if width < min_width: |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
327 |
self.Pos.x = max(0, self.Pos.x - (width - min_width) * x_factor) |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
328 |
width = min_width |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
329 |
if height < min_height: |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
330 |
self.Pos.y = max(0, self.Pos.y - (height - min_height) * y_factor) |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
331 |
height = min_height |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
332 |
if scaling is not None: |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
333 |
self.Pos.x = round_scaling(self.Pos.x, scaling[0]) |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
334 |
self.Pos.y = round_scaling(self.Pos.y, scaling[1]) |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
335 |
width = round_scaling(width, scaling[0], 1) |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
336 |
height = round_scaling(height, scaling[1], 1) |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
337 |
self.SetSize(width, height) |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
338 |
return self.Pos.x - posx, self.Pos.y - posy |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
339 |
|
814 | 340 |
# Refresh the element Bounding Box |
341 |
def RefreshBoundingBox(self): |
|
342 |
self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0], self.Size[1]) |
|
343 |
||
344 |
# Refresh the element connectors position |
|
345 |
def RefreshConnectors(self): |
|
346 |
pass |
|
347 |
||
348 |
# Refresh the position of wires connected to element inputs and outputs |
|
349 |
def RefreshConnected(self): |
|
350 |
pass |
|
351 |
||
352 |
# Change the parent |
|
353 |
def SetParent(self, parent): |
|
354 |
self.Parent = parent |
|
355 |
||
356 |
# Override this method for defining the method to call for deleting this element |
|
357 |
def Delete(self): |
|
358 |
pass |
|
359 |
||
360 |
# Returns the Id |
|
361 |
def GetId(self): |
|
362 |
return self.Id |
|
363 |
||
364 |
# Returns if the point given is in the bounding box |
|
365 |
def HitTest(self, pt, connectors=True): |
|
366 |
if connectors: |
|
367 |
rect = self.BoundingBox |
|
368 |
else: |
|
369 |
rect = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0], self.Size[1]) |
|
370 |
return rect.InsideXY(pt.x, pt.y) |
|
371 |
||
372 |
# Returns if the point given is in the bounding box |
|
373 |
def IsInSelection(self, rect): |
|
374 |
return rect.InsideXY(self.BoundingBox.x, self.BoundingBox.y) and rect.InsideXY(self.BoundingBox.x + self.BoundingBox.width, self.BoundingBox.y + self.BoundingBox.height) |
|
375 |
||
376 |
# Override this method for refreshing the bounding box |
|
377 |
def RefreshBoundingBox(self): |
|
378 |
pass |
|
379 |
||
380 |
# Returns the bounding box |
|
381 |
def GetBoundingBox(self): |
|
382 |
return self.BoundingBox |
|
383 |
||
384 |
# Returns the RedrawRect |
|
385 |
def GetRedrawRect(self, movex = 0, movey = 0): |
|
386 |
scalex, scaley = self.Parent.GetViewScale() |
|
387 |
rect = wx.Rect() |
|
388 |
rect.x = self.BoundingBox.x - int(HANDLE_SIZE / scalex) - 3 - abs(movex) |
|
389 |
rect.y = self.BoundingBox.y - int(HANDLE_SIZE / scaley) - 3 - abs(movey) |
|
390 |
rect.width = self.BoundingBox.width + 2 * (int(HANDLE_SIZE / scalex) + abs(movex) + 1) + 4 |
|
391 |
rect.height = self.BoundingBox.height + 2 * (int(HANDLE_SIZE / scaley) + abs(movey) + 1) + 4 |
|
392 |
return rect |
|
393 |
||
394 |
def Refresh(self, rect = None): |
|
395 |
if self.Visible: |
|
396 |
if rect is not None: |
|
397 |
self.Parent.RefreshRect(self.Parent.GetScrolledRect(rect), False) |
|
398 |
else: |
|
399 |
self.Parent.RefreshRect(self.Parent.GetScrolledRect(self.GetRedrawRect()), False) |
|
400 |
||
401 |
# Change the variable that indicates if this element is selected |
|
402 |
def SetSelected(self, selected): |
|
403 |
self.Selected = selected |
|
404 |
self.Refresh() |
|
405 |
||
406 |
# Change the variable that indicates if this element is highlighted |
|
407 |
def SetHighlighted(self, highlighted): |
|
408 |
self.Highlighted = highlighted |
|
409 |
self.Refresh() |
|
410 |
||
411 |
# Test if the point is on a handle of this element |
|
412 |
def TestHandle(self, event): |
|
413 |
dc = self.Parent.GetLogicalDC() |
|
414 |
scalex, scaley = dc.GetUserScale() |
|
415 |
pos = event.GetPosition() |
|
416 |
pt = wx.Point(*self.Parent.CalcUnscrolledPosition(pos.x, pos.y)) |
|
417 |
||
418 |
left = (self.BoundingBox.x - 2) * scalex - HANDLE_SIZE |
|
419 |
center = (self.BoundingBox.x + self.BoundingBox.width / 2) * scalex - HANDLE_SIZE / 2 |
|
420 |
right = (self.BoundingBox.x + self.BoundingBox.width + 2) * scalex |
|
421 |
||
422 |
top = (self.BoundingBox.y - 2) * scaley - HANDLE_SIZE |
|
423 |
middle = (self.BoundingBox.y + self.BoundingBox.height / 2) * scaley - HANDLE_SIZE / 2 |
|
424 |
bottom = (self.BoundingBox.y + self.BoundingBox.height + 2) * scaley |
|
425 |
||
426 |
extern_rect = wx.Rect(left, top, right + HANDLE_SIZE - left, bottom + HANDLE_SIZE - top) |
|
427 |
intern_rect = wx.Rect(left + HANDLE_SIZE, top + HANDLE_SIZE, right - left - HANDLE_SIZE, bottom - top - HANDLE_SIZE) |
|
428 |
||
429 |
# Verify that this element is selected |
|
430 |
if self.Selected and extern_rect.InsideXY(pt.x, pt.y) and not intern_rect.InsideXY(pt.x, pt.y): |
|
431 |
# Find if point is on a handle horizontally |
|
432 |
if left <= pt.x < left + HANDLE_SIZE: |
|
433 |
handle_x = 1 |
|
434 |
elif center <= pt.x < center + HANDLE_SIZE: |
|
435 |
handle_x = 2 |
|
436 |
elif right <= pt.x < right + HANDLE_SIZE: |
|
437 |
handle_x = 3 |
|
438 |
else: |
|
439 |
handle_x = 0 |
|
440 |
# Find if point is on a handle vertically |
|
441 |
if top <= pt.y < top + HANDLE_SIZE: |
|
442 |
handle_y = 1 |
|
443 |
elif middle <= pt.y < middle + HANDLE_SIZE: |
|
444 |
handle_y = 2 |
|
445 |
elif bottom <= pt.y < bottom + HANDLE_SIZE: |
|
446 |
handle_y = 3 |
|
447 |
else: |
|
448 |
handle_y = 0 |
|
449 |
# Verify that the result is valid |
|
450 |
if (handle_x, handle_y) in VALID_HANDLES: |
|
451 |
return handle_x, handle_y |
|
452 |
return 0, 0 |
|
453 |
||
454 |
# Method called when a LeftDown event have been generated |
|
455 |
def OnLeftDown(self, event, dc, scaling): |
|
456 |
pos = event.GetLogicalPosition(dc) |
|
457 |
# Test if an handle have been clicked |
|
458 |
handle = self.TestHandle(event) |
|
459 |
# Find which type of handle have been clicked, |
|
460 |
# Save a resize event and change the cursor |
|
461 |
cursor = HANDLE_CURSORS.get(handle, 1) |
|
462 |
wx.CallAfter(self.Parent.SetCurrentCursor, cursor) |
|
463 |
if cursor > 1: |
|
464 |
self.Handle = (HANDLE_RESIZE, handle) |
|
465 |
else: |
|
466 |
self.Handle = (HANDLE_MOVE, None) |
|
467 |
self.SetSelected(False) |
|
468 |
# Initializes the last position |
|
469 |
self.oldPos = GetScaledEventPosition(event, dc, scaling) |
|
470 |
self.StartPos = wx.Point(self.Pos.x, self.Pos.y) |
|
471 |
self.CurrentDrag = wx.Point(0, 0) |
|
472 |
||
473 |
# Method called when a LeftUp event have been generated |
|
474 |
def OnLeftUp(self, event, dc, scaling): |
|
475 |
# If a dragging have been initiated |
|
476 |
if self.Dragging and self.oldPos: |
|
477 |
self.RefreshModel() |
|
478 |
self.Parent.RefreshBuffer() |
|
479 |
wx.CallAfter(self.Parent.SetCurrentCursor, 0) |
|
480 |
self.SetSelected(True) |
|
481 |
self.oldPos = None |
|
482 |
||
483 |
# Method called when a RightDown event have been generated |
|
484 |
def OnRightDown(self, event, dc, scaling): |
|
485 |
pass |
|
486 |
||
487 |
# Method called when a RightUp event have been generated |
|
488 |
def OnRightUp(self, event, dc, scaling): |
|
489 |
if self.Dragging and self.oldPos: |
|
490 |
self.RefreshModel() |
|
491 |
self.Parent.RefreshBuffer() |
|
492 |
wx.CallAfter(self.Parent.SetCurrentCursor, 0) |
|
493 |
self.SetSelected(True) |
|
494 |
self.oldPos = None |
|
495 |
if self.Parent.Debug: |
|
496 |
self.Parent.PopupForceMenu() |
|
497 |
||
498 |
# Method called when a LeftDClick event have been generated |
|
499 |
def OnLeftDClick(self, event, dc, scaling): |
|
500 |
pass |
|
501 |
||
502 |
# Method called when a Motion event have been generated |
|
503 |
def OnMotion(self, event, dc, scaling): |
|
504 |
# If the cursor is dragging and the element have been clicked |
|
505 |
if event.Dragging() and self.oldPos: |
|
506 |
# Calculate the movement of cursor |
|
1258
441f31474b50
Fixed move of LD_PowerRail and SFC_Divergence connectors using Right button
Laurent Bessard
parents:
1226
diff
changeset
|
507 |
pos = GetScaledEventPosition(event, dc, scaling) |
814 | 508 |
movex = pos.x - self.oldPos.x |
509 |
movey = pos.y - self.oldPos.y |
|
510 |
# If movement is greater than MIN_MOVE then a dragging is initiated |
|
511 |
if not self.Dragging and (abs(movex) > MIN_MOVE or abs(movey) > MIN_MOVE): |
|
512 |
self.Dragging = True |
|
513 |
# If a dragging have been initiated, refreshes the element state |
|
514 |
if self.Dragging: |
|
515 |
dragx, dragy = self.ProcessDragging(movex, movey, event, scaling) |
|
516 |
if event.ControlDown() and self.Handle[0] == HANDLE_MOVE: |
|
517 |
self.oldPos.x = self.StartPos.x + self.CurrentDrag.x |
|
518 |
self.oldPos.y = self.StartPos.y + self.CurrentDrag.y |
|
519 |
else: |
|
520 |
self.oldPos.x += dragx |
|
521 |
self.oldPos.y += dragy |
|
522 |
return dragx, dragy |
|
523 |
return movex, movey |
|
524 |
# If cursor just pass over the element, changes the cursor if it is on a handle |
|
525 |
else: |
|
526 |
pos = event.GetLogicalPosition(dc) |
|
527 |
handle = self.TestHandle(event) |
|
528 |
# Find which type of handle have been clicked, |
|
529 |
# Save a resize event and change the cursor |
|
530 |
cursor = HANDLE_CURSORS.get(handle, 0) |
|
531 |
wx.CallAfter(self.Parent.SetCurrentCursor, cursor) |
|
532 |
return 0, 0 |
|
533 |
||
534 |
# Moves the element |
|
535 |
def Move(self, dx, dy, exclude = []): |
|
536 |
self.Pos.x += max(-self.BoundingBox.x, dx) |
|
537 |
self.Pos.y += max(-self.BoundingBox.y, dy) |
|
538 |
self.RefreshConnected(exclude) |
|
539 |
self.RefreshBoundingBox() |
|
540 |
||
541 |
# Resizes the element from position and size given |
|
542 |
def Resize(self, x, y, width, height): |
|
543 |
self.Move(x, y) |
|
544 |
self.SetSize(width, height) |
|
545 |
||
546 |
# Refreshes the element state according to move defined and handle selected |
|
547 |
def ProcessDragging(self, movex, movey, event, scaling, width_fac = 1, height_fac = 1): |
|
548 |
handle_type, handle = self.Handle |
|
549 |
# If it is a resize handle, calculate the values from resizing |
|
550 |
if handle_type == HANDLE_RESIZE: |
|
551 |
if scaling is not None: |
|
552 |
scaling = (scaling[0] * width_fac, scaling[1] * height_fac) |
|
553 |
x = y = start_x = start_y = 0 |
|
554 |
width, height = start_width, start_height = self.GetSize() |
|
555 |
if handle[0] == 1: |
|
556 |
movex = max(-self.BoundingBox.x, movex) |
|
557 |
if scaling is not None: |
|
558 |
movex = -(round_scaling(width - movex, scaling[0]) - width) |
|
559 |
x = movex |
|
560 |
if event.ShiftDown(): |
|
561 |
width -= 2 * movex |
|
562 |
else: |
|
563 |
width -= movex |
|
564 |
elif handle[0] == 3: |
|
565 |
if scaling is not None: |
|
566 |
movex = round_scaling(width + movex, scaling[0]) - width |
|
567 |
if event.ShiftDown(): |
|
568 |
movex = min(self.BoundingBox.x, movex) |
|
569 |
x = -movex |
|
570 |
width += 2 * movex |
|
571 |
else: |
|
572 |
width += movex |
|
573 |
if handle[1] == 1: |
|
574 |
movey = max(-self.BoundingBox.y, movey) |
|
575 |
if scaling is not None: |
|
576 |
movey = -(round_scaling(height - movey, scaling[1]) - height) |
|
577 |
y = movey |
|
578 |
if event.ShiftDown(): |
|
579 |
height -= 2 * movey |
|
580 |
else: |
|
581 |
height -= movey |
|
582 |
elif handle[1] == 3: |
|
583 |
if scaling is not None: |
|
584 |
movey = round_scaling(height + movey, scaling[1]) - height |
|
585 |
if event.ShiftDown(): |
|
586 |
movey = min(self.BoundingBox.y, movey) |
|
587 |
y = -movey |
|
588 |
height += 2 * movey |
|
589 |
else: |
|
590 |
height += movey |
|
591 |
# Verify that new size is not lesser than minimum |
|
592 |
min_width, min_height = self.GetMinSize() |
|
593 |
if handle[0] != 2 and (width >= min_width or width > self.Size[0]): |
|
594 |
start_x = x |
|
595 |
start_width = width |
|
596 |
else: |
|
597 |
movex = 0 |
|
598 |
if handle[1] != 2 and (height >= min_height or height > self.Size[1]): |
|
599 |
start_y = y |
|
600 |
start_height = height |
|
601 |
else: |
|
602 |
movey = 0 |
|
603 |
if movex != 0 or movey != 0: |
|
604 |
self.Resize(start_x, start_y, start_width, start_height) |
|
605 |
return movex, movey |
|
606 |
# If it is a move handle, Move this element |
|
607 |
elif handle_type == HANDLE_MOVE: |
|
608 |
movex = max(-self.BoundingBox.x, movex) |
|
609 |
movey = max(-self.BoundingBox.y, movey) |
|
610 |
if scaling is not None: |
|
611 |
movex = round_scaling(self.Pos.x + movex, scaling[0]) - self.Pos.x |
|
612 |
movey = round_scaling(self.Pos.y + movey, scaling[1]) - self.Pos.y |
|
613 |
if event.ControlDown(): |
|
614 |
self.CurrentDrag.x = self.CurrentDrag.x + movex |
|
615 |
self.CurrentDrag.y = self.CurrentDrag.y + movey |
|
616 |
if abs(self.CurrentDrag.x) > abs(self.CurrentDrag.y): |
|
617 |
movex = self.StartPos.x + self.CurrentDrag.x - self.Pos.x |
|
618 |
movey = self.StartPos.y - self.Pos.y |
|
619 |
else: |
|
620 |
movex = self.StartPos.x - self.Pos.x |
|
621 |
movey = self.StartPos.y + self.CurrentDrag.y - self.Pos.y |
|
622 |
self.Move(movex, movey) |
|
623 |
return movex, movey |
|
624 |
return 0, 0 |
|
625 |
||
626 |
# Override this method for defining the method to call for adding an highlight to this element |
|
627 |
def AddHighlight(self, infos, start, end, highlight_type): |
|
628 |
pass |
|
629 |
||
630 |
# Override this method for defining the method to call for removing an highlight from this element |
|
631 |
def RemoveHighlight(self, infos, start, end, highlight_type): |
|
632 |
pass |
|
633 |
||
634 |
# Override this method for defining the method to call for removing all the highlights of one particular type from this element |
|
635 |
def ClearHighlight(self, highlight_type=None): |
|
636 |
pass |
|
637 |
||
638 |
# Override this method for defining the method to call for refreshing the model of this element |
|
639 |
def RefreshModel(self, move=True): |
|
640 |
pass |
|
641 |
||
642 |
# Draws the highlightment of this element if it is highlighted (can be overwritten) |
|
643 |
def DrawHighlightment(self, dc): |
|
644 |
scalex, scaley = dc.GetUserScale() |
|
645 |
dc.SetUserScale(1, 1) |
|
646 |
dc.SetPen(MiterPen(HIGHLIGHTCOLOR)) |
|
647 |
dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR)) |
|
648 |
dc.SetLogicalFunction(wx.AND) |
|
649 |
dc.DrawRectangle(int(round((self.Pos.x - 1) * scalex)) - 2, |
|
650 |
int(round((self.Pos.y - 1) * scaley)) - 2, |
|
651 |
int(round((self.Size.width + 3) * scalex)) + 5, |
|
652 |
int(round((self.Size.height + 3) * scaley)) + 5) |
|
653 |
dc.SetLogicalFunction(wx.COPY) |
|
654 |
dc.SetUserScale(scalex, scaley) |
|
655 |
||
656 |
# Draws the handles of this element if it is selected |
|
657 |
def Draw(self, dc): |
|
658 |
if not getattr(dc, "printing", False): |
|
659 |
if self.Highlighted: |
|
660 |
self.DrawHighlightment(dc) |
|
661 |
if self.Selected: |
|
662 |
scalex, scaley = dc.GetUserScale() |
|
663 |
dc.SetUserScale(1, 1) |
|
664 |
dc.SetPen(MiterPen(wx.BLACK)) |
|
665 |
dc.SetBrush(wx.BLACK_BRUSH) |
|
666 |
||
667 |
left = (self.BoundingBox.x - 2) * scalex - HANDLE_SIZE |
|
668 |
center = (self.BoundingBox.x + self.BoundingBox.width / 2) * scalex - HANDLE_SIZE / 2 |
|
669 |
right = (self.BoundingBox.x + self.BoundingBox.width + 2) * scalex |
|
670 |
||
671 |
top = (self.BoundingBox.y - 2) * scaley - HANDLE_SIZE |
|
672 |
middle = (self.BoundingBox.y + self.BoundingBox.height / 2) * scaley - HANDLE_SIZE / 2 |
|
673 |
bottom = (self.BoundingBox.y + self.BoundingBox.height + 2) * scaley |
|
674 |
||
675 |
for x, y in [(left, top), (center, top), (right, top), |
|
676 |
(left, middle), (right, middle), |
|
677 |
(left, bottom), (center, bottom), (right, bottom)]: |
|
678 |
dc.DrawRectangle(x, y, HANDLE_SIZE, HANDLE_SIZE) |
|
679 |
||
680 |
dc.SetUserScale(scalex, scaley) |
|
681 |
||
682 |
||
683 |
#------------------------------------------------------------------------------- |
|
684 |
# Group of graphic elements |
|
685 |
#------------------------------------------------------------------------------- |
|
686 |
||
687 |
""" |
|
688 |
Class that implements a group of graphic elements |
|
689 |
""" |
|
690 |
||
691 |
class Graphic_Group(Graphic_Element): |
|
692 |
||
693 |
# Create a new group of graphic elements |
|
694 |
def __init__(self, parent): |
|
695 |
Graphic_Element.__init__(self, parent) |
|
696 |
self.Elements = [] |
|
697 |
self.RefreshWireExclusion() |
|
698 |
self.RefreshBoundingBox() |
|
699 |
||
700 |
# Destructor |
|
701 |
def __del__(self): |
|
702 |
self.Elements = [] |
|
703 |
||
704 |
def GetDefinition(self): |
|
705 |
blocks = [] |
|
706 |
wires = [] |
|
707 |
for element in self.Elements: |
|
708 |
block, wire = element.GetDefinition() |
|
709 |
blocks.extend(block) |
|
710 |
wires.extend(wire) |
|
711 |
return blocks, wires |
|
712 |
||
713 |
# Make a clone of this element |
|
714 |
def Clone(self, parent, pos = None): |
|
715 |
group = Graphic_Group(parent) |
|
716 |
connectors = {} |
|
717 |
exclude_names = {} |
|
718 |
wires = [] |
|
719 |
if pos is not None: |
|
720 |
dx, dy = pos.x - self.BoundingBox.x, pos.y - self.BoundingBox.y |
|
721 |
for element in self.Elements: |
|
722 |
if isinstance(element, Wire): |
|
723 |
wires.append(element) |
|
724 |
else: |
|
725 |
if pos is not None: |
|
726 |
x, y = element.GetPosition() |
|
727 |
new_pos = wx.Point(x + dx, y + dy) |
|
728 |
newid = parent.GetNewId() |
|
729 |
if parent.IsNamedElement(element): |
|
730 |
name = parent.GenerateNewName(element, exclude_names) |
|
731 |
exclude_names[name.upper()] = True |
|
732 |
new_element = element.Clone(parent, newid, name, pos = new_pos) |
|
733 |
else: |
|
734 |
new_element = element.Clone(parent, newid, pos = new_pos) |
|
852
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
735 |
new_element.SetBestSize(parent.Scaling) |
814 | 736 |
else: |
737 |
new_element = element.Clone(parent) |
|
738 |
connectors.update(element.GetConnectorTranslation(new_element)) |
|
739 |
group.SelectElement(new_element) |
|
740 |
for element in wires: |
|
741 |
if pos is not None: |
|
742 |
new_wire = element.Clone(parent, connectors, dx, dy) |
|
743 |
else: |
|
744 |
new_wire = element.Clone(parent, connectors) |
|
745 |
if new_wire is not None: |
|
746 |
if pos is not None: |
|
747 |
parent.AddWire(new_wire) |
|
748 |
group.SelectElement(new_wire) |
|
749 |
if pos is not None: |
|
750 |
for element in group.Elements: |
|
751 |
if not isinstance(element, Wire): |
|
752 |
parent.AddBlockInModel(element) |
|
753 |
return group |
|
754 |
||
755 |
def CanAddBlocks(self, parent): |
|
756 |
valid = True |
|
757 |
for element in self.Elements: |
|
758 |
if not isinstance(element, Wire): |
|
759 |
valid &= parent.CanAddElement(element) |
|
760 |
return valid |
|
761 |
||
762 |
def IsVisible(self): |
|
763 |
for element in self.Elements: |
|
764 |
if element.IsVisible(): |
|
765 |
return True |
|
766 |
return False |
|
767 |
||
768 |
# Refresh the list of wire excluded |
|
769 |
def RefreshWireExclusion(self): |
|
770 |
self.WireExcluded = [] |
|
771 |
for element in self.Elements: |
|
772 |
if isinstance(element, Wire): |
|
773 |
startblock = element.StartConnected.GetParentBlock() |
|
774 |
endblock = element.EndConnected.GetParentBlock() |
|
775 |
if startblock in self.Elements and endblock in self.Elements: |
|
776 |
self.WireExcluded.append(element) |
|
777 |
||
778 |
# Returns the RedrawRect |
|
779 |
def GetRedrawRect(self, movex = 0, movey = 0): |
|
780 |
rect = None |
|
781 |
for element in self.Elements: |
|
782 |
if rect is None: |
|
783 |
rect = element.GetRedrawRect(movex, movey) |
|
784 |
else: |
|
785 |
rect = rect.Union(element.GetRedrawRect(movex, movey)) |
|
786 |
return rect |
|
787 |
||
788 |
# Clean this group of elements |
|
789 |
def Clean(self): |
|
790 |
# Clean all the elements of the group |
|
791 |
for element in self.Elements: |
|
792 |
element.Clean() |
|
793 |
||
794 |
# Delete this group of elements |
|
795 |
def Delete(self): |
|
796 |
# Delete all the elements of the group |
|
797 |
for element in self.Elements: |
|
798 |
element.Delete() |
|
799 |
self.WireExcluded = [] |
|
800 |
||
801 |
# Returns if the point given is in the bounding box of one of the elements of this group |
|
802 |
def HitTest(self, pt, connectors=True): |
|
803 |
result = False |
|
804 |
for element in self.Elements: |
|
805 |
result |= element.HitTest(pt, connectors) |
|
806 |
return result |
|
807 |
||
808 |
# Returns if the element given is in this group |
|
809 |
def IsElementIn(self, element): |
|
810 |
return element in self.Elements |
|
811 |
||
812 |
# Change the elements of the group |
|
813 |
def SetElements(self, elements): |
|
814 |
self.Elements = elements |
|
815 |
self.RefreshWireExclusion() |
|
816 |
self.RefreshBoundingBox() |
|
817 |
||
818 |
# Returns the elements of the group |
|
819 |
def GetElements(self): |
|
820 |
return self.Elements |
|
821 |
||
822 |
# Align the group elements |
|
823 |
def AlignElements(self, horizontally, vertically): |
|
824 |
minx = self.BoundingBox.x + self.BoundingBox.width |
|
825 |
miny = self.BoundingBox.y + self.BoundingBox.height |
|
826 |
maxx = self.BoundingBox.x |
|
827 |
maxy = self.BoundingBox.y |
|
828 |
for element in self.Elements: |
|
829 |
if not isinstance(element, Wire): |
|
830 |
posx, posy = element.GetPosition() |
|
831 |
width, height = element.GetSize() |
|
832 |
minx = min(minx, posx) |
|
833 |
miny = min(miny, posy) |
|
834 |
maxx = max(maxx, posx + width) |
|
835 |
maxy = max(maxy, posy + height) |
|
836 |
for element in self.Elements: |
|
837 |
if not isinstance(element, Wire): |
|
838 |
posx, posy = element.GetPosition() |
|
839 |
width, height = element.GetSize() |
|
840 |
movex = movey = 0 |
|
841 |
if horizontally == ALIGN_LEFT: |
|
842 |
movex = minx - posx |
|
843 |
elif horizontally == ALIGN_CENTER: |
|
844 |
movex = (maxx + minx - width) / 2 - posx |
|
845 |
elif horizontally == ALIGN_RIGHT: |
|
846 |
movex = maxx - width - posx |
|
847 |
if vertically == ALIGN_TOP: |
|
848 |
movey = miny - posy |
|
849 |
elif vertically == ALIGN_MIDDLE: |
|
850 |
movey = (maxy + miny - height) / 2 - posy |
|
851 |
elif vertically == ALIGN_BOTTOM: |
|
852 |
movey = maxy - height - posy |
|
853 |
if movex != 0 or movey != 0: |
|
854 |
element.Move(movex, movey) |
|
855 |
element.RefreshModel() |
|
856 |
self.RefreshBoundingBox() |
|
857 |
||
1226
93e7a8abce5e
Fixed lag when selecting all elements using CTRL+A or after paste a lot of blocks
Laurent Bessard
parents:
1176
diff
changeset
|
858 |
# Add the given element to the group of elements |
93e7a8abce5e
Fixed lag when selecting all elements using CTRL+A or after paste a lot of blocks
Laurent Bessard
parents:
1176
diff
changeset
|
859 |
def AddElement(self, element): |
93e7a8abce5e
Fixed lag when selecting all elements using CTRL+A or after paste a lot of blocks
Laurent Bessard
parents:
1176
diff
changeset
|
860 |
self.Elements.append(element) |
93e7a8abce5e
Fixed lag when selecting all elements using CTRL+A or after paste a lot of blocks
Laurent Bessard
parents:
1176
diff
changeset
|
861 |
|
814 | 862 |
# Remove or select the given element if it is or not in the group |
863 |
def SelectElement(self, element): |
|
864 |
if element in self.Elements: |
|
865 |
self.Elements.remove(element) |
|
866 |
else: |
|
867 |
self.Elements.append(element) |
|
868 |
self.RefreshWireExclusion() |
|
869 |
self.RefreshBoundingBox() |
|
870 |
||
871 |
# Move this group of elements |
|
872 |
def Move(self, movex, movey): |
|
873 |
movex = max(-self.BoundingBox.x, movex) |
|
874 |
movey = max(-self.BoundingBox.y, movey) |
|
875 |
# Move all the elements of the group |
|
876 |
for element in self.Elements: |
|
877 |
if not isinstance(element, Wire): |
|
878 |
element.Move(movex, movey, self.WireExcluded) |
|
879 |
elif element in self.WireExcluded: |
|
880 |
element.Move(movex, movey, True) |
|
881 |
self.RefreshBoundingBox() |
|
882 |
||
883 |
# Refreshes the bounding box of this group of elements |
|
884 |
def RefreshBoundingBox(self): |
|
885 |
if len(self.Elements) > 0: |
|
886 |
bbox = self.Elements[0].GetBoundingBox() |
|
887 |
minx, miny = bbox.x, bbox.y |
|
888 |
maxx = bbox.x + bbox.width |
|
889 |
maxy = bbox.y + bbox.height |
|
890 |
for element in self.Elements[1:]: |
|
891 |
bbox = element.GetBoundingBox() |
|
892 |
minx = min(minx, bbox.x) |
|
893 |
miny = min(miny, bbox.y) |
|
894 |
maxx = max(maxx, bbox.x + bbox.width) |
|
895 |
maxy = max(maxy, bbox.y + bbox.height) |
|
896 |
self.BoundingBox = wx.Rect(minx, miny, maxx - minx, maxy - miny) |
|
897 |
else: |
|
898 |
self.BoundingBox = wx.Rect(0, 0, 0, 0) |
|
899 |
self.Pos = wx.Point(self.BoundingBox.x, self.BoundingBox.y) |
|
900 |
self.Size = wx.Size(self.BoundingBox.width, self.BoundingBox.height) |
|
901 |
||
902 |
# Forbids to change the group position |
|
903 |
def SetPosition(x, y): |
|
904 |
pass |
|
905 |
||
906 |
# Returns the position of this group |
|
825
0623820aa14a
Fix bug in Viewer when dragging element group with control down and group contains wires connected to blocks not in group
laurent
parents:
814
diff
changeset
|
907 |
def GetPosition(self, exclude_wires=False): |
0623820aa14a
Fix bug in Viewer when dragging element group with control down and group contains wires connected to blocks not in group
laurent
parents:
814
diff
changeset
|
908 |
if exclude_wires: |
0623820aa14a
Fix bug in Viewer when dragging element group with control down and group contains wires connected to blocks not in group
laurent
parents:
814
diff
changeset
|
909 |
posx = posy = None |
0623820aa14a
Fix bug in Viewer when dragging element group with control down and group contains wires connected to blocks not in group
laurent
parents:
814
diff
changeset
|
910 |
for element in self.Elements: |
0623820aa14a
Fix bug in Viewer when dragging element group with control down and group contains wires connected to blocks not in group
laurent
parents:
814
diff
changeset
|
911 |
if not isinstance(element, Wire) or element in self.WireExcluded: |
0623820aa14a
Fix bug in Viewer when dragging element group with control down and group contains wires connected to blocks not in group
laurent
parents:
814
diff
changeset
|
912 |
bbox = element.GetBoundingBox() |
0623820aa14a
Fix bug in Viewer when dragging element group with control down and group contains wires connected to blocks not in group
laurent
parents:
814
diff
changeset
|
913 |
if posx is None and posy is None: |
0623820aa14a
Fix bug in Viewer when dragging element group with control down and group contains wires connected to blocks not in group
laurent
parents:
814
diff
changeset
|
914 |
posx, posy = bbox.x, bbox.y |
0623820aa14a
Fix bug in Viewer when dragging element group with control down and group contains wires connected to blocks not in group
laurent
parents:
814
diff
changeset
|
915 |
else: |
0623820aa14a
Fix bug in Viewer when dragging element group with control down and group contains wires connected to blocks not in group
laurent
parents:
814
diff
changeset
|
916 |
posx = min(posx, bbox.x) |
0623820aa14a
Fix bug in Viewer when dragging element group with control down and group contains wires connected to blocks not in group
laurent
parents:
814
diff
changeset
|
917 |
posy = min(posy, bbox.y) |
0623820aa14a
Fix bug in Viewer when dragging element group with control down and group contains wires connected to blocks not in group
laurent
parents:
814
diff
changeset
|
918 |
if posx is None and posy is None: |
0623820aa14a
Fix bug in Viewer when dragging element group with control down and group contains wires connected to blocks not in group
laurent
parents:
814
diff
changeset
|
919 |
return 0, 0 |
0623820aa14a
Fix bug in Viewer when dragging element group with control down and group contains wires connected to blocks not in group
laurent
parents:
814
diff
changeset
|
920 |
return posx, posy |
814 | 921 |
return self.BoundingBox.x, self.BoundingBox.y |
922 |
||
923 |
# Forbids to change the group size |
|
924 |
def SetSize(width, height): |
|
925 |
pass |
|
926 |
||
927 |
# Returns the size of this group |
|
928 |
def GetSize(self): |
|
929 |
return self.BoundingBox.width, self.BoundingBox.height |
|
852
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
930 |
|
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
931 |
# Set size of the group elements to their minimum size |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
932 |
def SetBestSize(self, scaling): |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
933 |
max_movex = max_movey = 0 |
814 | 934 |
for element in self.Elements: |
852
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
935 |
movex, movey = element.SetBestSize(scaling) |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
936 |
max_movex = max(max_movex, movex) |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
937 |
max_movey = max(max_movey, movey) |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
938 |
return max_movex, max_movey |
814 | 939 |
|
940 |
# Refreshes the group elements to move defined and handle selected |
|
941 |
def ProcessDragging(self, movex, movey, event, scaling): |
|
942 |
handle_type, handle = self.Handle |
|
943 |
# If it is a move handle, Move this group elements |
|
944 |
if handle_type == HANDLE_MOVE: |
|
945 |
movex = max(-self.BoundingBox.x, movex) |
|
946 |
movey = max(-self.BoundingBox.y, movey) |
|
947 |
if scaling is not None: |
|
948 |
movex = round_scaling(movex, scaling[0]) |
|
949 |
movey = round_scaling(movey, scaling[1]) |
|
950 |
if event.ControlDown(): |
|
951 |
self.CurrentDrag.x = self.CurrentDrag.x + movex |
|
952 |
self.CurrentDrag.y = self.CurrentDrag.y + movey |
|
825
0623820aa14a
Fix bug in Viewer when dragging element group with control down and group contains wires connected to blocks not in group
laurent
parents:
814
diff
changeset
|
953 |
posx, posy = self.GetPosition(True) |
814 | 954 |
if abs(self.CurrentDrag.x) > abs(self.CurrentDrag.y): |
825
0623820aa14a
Fix bug in Viewer when dragging element group with control down and group contains wires connected to blocks not in group
laurent
parents:
814
diff
changeset
|
955 |
movex = self.StartPos.x + self.CurrentDrag.x - posx |
0623820aa14a
Fix bug in Viewer when dragging element group with control down and group contains wires connected to blocks not in group
laurent
parents:
814
diff
changeset
|
956 |
movey = self.StartPos.y - posy |
814 | 957 |
else: |
825
0623820aa14a
Fix bug in Viewer when dragging element group with control down and group contains wires connected to blocks not in group
laurent
parents:
814
diff
changeset
|
958 |
movex = self.StartPos.x - posx |
0623820aa14a
Fix bug in Viewer when dragging element group with control down and group contains wires connected to blocks not in group
laurent
parents:
814
diff
changeset
|
959 |
movey = self.StartPos.y + self.CurrentDrag.y - posy |
814 | 960 |
self.Move(movex, movey) |
961 |
return movex, movey |
|
962 |
return 0, 0 |
|
963 |
||
964 |
# Change the variable that indicates if this element is highlighted |
|
965 |
def SetHighlighted(self, highlighted): |
|
966 |
for element in self.Elements: |
|
967 |
element.SetHighlighted(highlighted) |
|
968 |
||
969 |
def HighlightPoint(self, pos): |
|
970 |
for element in self.Elements: |
|
971 |
if isinstance(element, Wire): |
|
972 |
element.HighlightPoint(pos) |
|
973 |
||
974 |
# Method called when a LeftDown event have been generated |
|
975 |
def OnLeftDown(self, event, dc, scaling): |
|
976 |
Graphic_Element.OnLeftDown(self, event, dc, scaling) |
|
825
0623820aa14a
Fix bug in Viewer when dragging element group with control down and group contains wires connected to blocks not in group
laurent
parents:
814
diff
changeset
|
977 |
self.StartPos = wx.Point(*self.GetPosition(True)) |
814 | 978 |
for element in self.Elements: |
979 |
element.Handle = self.Handle |
|
980 |
||
981 |
# Change the variable that indicates if the elemente is selected |
|
982 |
def SetSelected(self, selected): |
|
983 |
for element in self.Elements: |
|
984 |
element.SetSelected(selected) |
|
985 |
||
986 |
# Method called when a RightUp event has been generated |
|
987 |
def OnRightUp(self, event, dc, scaling): |
|
988 |
# Popup the menu with special items for a group |
|
989 |
self.Parent.PopupGroupMenu() |
|
990 |
||
991 |
# Refreshes the model of all the elements of this group |
|
1047
efcc2283dd77
Fixed bug when using 'Adjust Block Size' contextual menu item on a group of selected elements
Laurent Bessard
parents:
993
diff
changeset
|
992 |
def RefreshModel(self, move=True): |
814 | 993 |
for element in self.Elements: |
1047
efcc2283dd77
Fixed bug when using 'Adjust Block Size' contextual menu item on a group of selected elements
Laurent Bessard
parents:
993
diff
changeset
|
994 |
element.RefreshModel(move) |
814 | 995 |
|
1069
880ec628d490
Fixed refresh bugs when drag'n dropping of group of elements
Laurent Bessard
parents:
1054
diff
changeset
|
996 |
# Draws the handles of this element if it is selected |
880ec628d490
Fixed refresh bugs when drag'n dropping of group of elements
Laurent Bessard
parents:
1054
diff
changeset
|
997 |
def Draw(self, dc): |
880ec628d490
Fixed refresh bugs when drag'n dropping of group of elements
Laurent Bessard
parents:
1054
diff
changeset
|
998 |
for element in self.Elements: |
880ec628d490
Fixed refresh bugs when drag'n dropping of group of elements
Laurent Bessard
parents:
1054
diff
changeset
|
999 |
element.Draw(dc) |
814 | 1000 |
|
1001 |
#------------------------------------------------------------------------------- |
|
1002 |
# Connector for all types of blocks |
|
1003 |
#------------------------------------------------------------------------------- |
|
1004 |
||
1005 |
""" |
|
1006 |
Class that implements a connector for any type of block |
|
1007 |
""" |
|
1008 |
||
1170
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1009 |
class Connector(DebugDataConsumer, ToolTipProducer): |
814 | 1010 |
|
1011 |
# Create a new connector |
|
1012 |
def __init__(self, parent, name, type, position, direction, negated = False, edge = "none", onlyone = False): |
|
1166
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1013 |
DebugDataConsumer.__init__(self) |
1170
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1014 |
ToolTipProducer.__init__(self, parent.Parent) |
814 | 1015 |
self.ParentBlock = parent |
1016 |
self.Name = name |
|
1017 |
self.Type = type |
|
1018 |
self.Pos = position |
|
1019 |
self.Direction = direction |
|
1020 |
self.Wires = [] |
|
1021 |
if self.ParentBlock.IsOfType("BOOL", type): |
|
1022 |
self.Negated = negated |
|
1023 |
self.Edge = edge |
|
1024 |
else: |
|
1025 |
self.Negated = False |
|
1026 |
self.Edge = "none" |
|
1027 |
self.OneConnected = onlyone |
|
1028 |
self.Valid = True |
|
1029 |
self.Value = None |
|
1030 |
self.Forced = False |
|
1166
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1031 |
self.ValueSize = None |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1032 |
self.ComputedValue = None |
814 | 1033 |
self.Selected = False |
1034 |
self.Highlights = [] |
|
1035 |
self.RefreshNameSize() |
|
1036 |
||
1037 |
def Flush(self): |
|
1038 |
self.ParentBlock = None |
|
1039 |
for wire, handle in self.Wires: |
|
1040 |
wire.Flush() |
|
1041 |
self.Wires = [] |
|
1042 |
||
1043 |
# Returns the RedrawRect |
|
1044 |
def GetRedrawRect(self, movex = 0, movey = 0): |
|
1045 |
parent_pos = self.ParentBlock.GetPosition() |
|
1046 |
x = min(parent_pos[0] + self.Pos.x, parent_pos[0] + self.Pos.x + self.Direction[0] * CONNECTOR_SIZE) |
|
1047 |
y = min(parent_pos[1] + self.Pos.y, parent_pos[1] + self.Pos.y + self.Direction[1] * CONNECTOR_SIZE) |
|
1377
cc8f9177d41c
Fixed bug when debugging wire connected to output connector with modifiers even if connector/continuation is used to replace long wires
Laurent Bessard
parents:
1258
diff
changeset
|
1048 |
has_modifier = self.Negated or self.Edge != "none" |
814 | 1049 |
if self.Direction[0] == 0: |
1377
cc8f9177d41c
Fixed bug when debugging wire connected to output connector with modifiers even if connector/continuation is used to replace long wires
Laurent Bessard
parents:
1258
diff
changeset
|
1050 |
width = 10 if has_modifier else 5 |
814 | 1051 |
else: |
1052 |
width = CONNECTOR_SIZE |
|
1377
cc8f9177d41c
Fixed bug when debugging wire connected to output connector with modifiers even if connector/continuation is used to replace long wires
Laurent Bessard
parents:
1258
diff
changeset
|
1053 |
if self.Edge == "rising" and self.Direction[0] == 1: |
cc8f9177d41c
Fixed bug when debugging wire connected to output connector with modifiers even if connector/continuation is used to replace long wires
Laurent Bessard
parents:
1258
diff
changeset
|
1054 |
x -= 5 |
cc8f9177d41c
Fixed bug when debugging wire connected to output connector with modifiers even if connector/continuation is used to replace long wires
Laurent Bessard
parents:
1258
diff
changeset
|
1055 |
width += 5 |
814 | 1056 |
if self.Direction[1] == 0: |
1377
cc8f9177d41c
Fixed bug when debugging wire connected to output connector with modifiers even if connector/continuation is used to replace long wires
Laurent Bessard
parents:
1258
diff
changeset
|
1057 |
height = 10 if has_modifier else 5 |
814 | 1058 |
else: |
1059 |
height = CONNECTOR_SIZE |
|
1377
cc8f9177d41c
Fixed bug when debugging wire connected to output connector with modifiers even if connector/continuation is used to replace long wires
Laurent Bessard
parents:
1258
diff
changeset
|
1060 |
if self.Edge == "rising" and self.Direction[1] == 1: |
cc8f9177d41c
Fixed bug when debugging wire connected to output connector with modifiers even if connector/continuation is used to replace long wires
Laurent Bessard
parents:
1258
diff
changeset
|
1061 |
y -= 5 |
cc8f9177d41c
Fixed bug when debugging wire connected to output connector with modifiers even if connector/continuation is used to replace long wires
Laurent Bessard
parents:
1258
diff
changeset
|
1062 |
height += 5 |
1166
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1063 |
rect = wx.Rect(x - abs(movex), y - abs(movey), width + 2 * abs(movex), height + 2 * abs(movey)) |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1064 |
if self.ValueSize is None and isinstance(self.ComputedValue, (StringType, UnicodeType)): |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1065 |
self.ValueSize = self.ParentBlock.Parent.GetMiniTextExtent(self.ComputedValue) |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1066 |
if self.ValueSize is not None: |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1067 |
width, height = self.ValueSize |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1068 |
rect = rect.Union(wx.Rect( |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1069 |
parent_pos[0] + self.Pos.x + CONNECTOR_SIZE * self.Direction[0] + \ |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1070 |
width * (self.Direction[0] - 1) / 2, |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1071 |
parent_pos[1] + self.Pos.y + CONNECTOR_SIZE * self.Direction[1] + \ |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1072 |
height * (self.Direction[1] - 1), |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1073 |
width, height)) |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1074 |
return rect |
814 | 1075 |
|
1076 |
# Change the connector selection |
|
1077 |
def SetSelected(self, selected): |
|
1078 |
self.Selected = selected |
|
1079 |
||
1080 |
# Make a clone of the connector |
|
1081 |
def Clone(self, parent = None): |
|
1082 |
if parent is None: |
|
1083 |
parent = self.ParentBlock |
|
1084 |
return Connector(parent, self.Name, self.Type, wx.Point(self.Pos[0], self.Pos[1]), |
|
1085 |
self.Direction, self.Negated) |
|
1086 |
||
1087 |
# Returns the connector parent block |
|
1088 |
def GetParentBlock(self): |
|
1089 |
return self.ParentBlock |
|
1090 |
||
1091 |
# Returns the connector type |
|
1092 |
def GetType(self, raw = False): |
|
1093 |
if self.ParentBlock.IsEndType(self.Type) or raw: |
|
1094 |
return self.Type |
|
1095 |
elif (self.Negated or self.Edge != "none") and self.ParentBlock.IsOfType("BOOL", self.Type): |
|
1096 |
return "BOOL" |
|
1097 |
else: |
|
1098 |
return self.ParentBlock.GetConnectionResultType(self, self.Type) |
|
1099 |
||
1100 |
# Returns the connector type |
|
1101 |
def GetConnectedType(self): |
|
1102 |
if self.ParentBlock.IsEndType(self.Type): |
|
1103 |
return self.Type |
|
1104 |
elif len(self.Wires) == 1: |
|
1105 |
return self.Wires[0][0].GetOtherConnectedType(self.Wires[0][1]) |
|
1106 |
return self.Type |
|
1107 |
||
1108 |
# Returns the connector type |
|
1109 |
def GetConnectedRedrawRect(self, movex, movey): |
|
1110 |
rect = None |
|
1111 |
for wire, handle in self.Wires: |
|
1112 |
if rect is None: |
|
1113 |
rect = wire.GetRedrawRect() |
|
1114 |
else: |
|
1115 |
rect = rect.Union(wire.GetRedrawRect()) |
|
1116 |
return rect |
|
1117 |
||
1118 |
# Returns if connector type is compatible with type given |
|
1119 |
def IsCompatible(self, type): |
|
1120 |
reference = self.GetType() |
|
1121 |
return self.ParentBlock.IsOfType(type, reference) or self.ParentBlock.IsOfType(reference, type) |
|
1122 |
||
1123 |
# Changes the connector name |
|
1124 |
def SetType(self, type): |
|
1125 |
self.Type = type |
|
1126 |
for wire, handle in self.Wires: |
|
1127 |
wire.SetValid(wire.IsConnectedCompatible()) |
|
1128 |
||
1129 |
# Returns the connector name |
|
1130 |
def GetName(self): |
|
1131 |
return self.Name |
|
1132 |
||
1133 |
# Changes the connector name |
|
1134 |
def SetName(self, name): |
|
1135 |
self.Name = name |
|
1136 |
self.RefreshNameSize() |
|
1137 |
||
1166
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1138 |
def SetForced(self, forced): |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1139 |
if self.Forced != forced: |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1140 |
self.Forced = forced |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1141 |
if self.Visible: |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1142 |
self.Parent.ElementNeedRefresh(self) |
1170
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1143 |
|
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1144 |
def GetComputedValue(self): |
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1145 |
if self.Value is not None and self.Value != "undefined" and not isinstance(self.Value, BooleanType): |
1176
f4b434672204
Moved and rewrote DebugViewer and DebusDataConsumer classes
Laurent Bessard
parents:
1173
diff
changeset
|
1146 |
return self.Value |
1170
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1147 |
return None |
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1148 |
|
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1149 |
def GetToolTipValue(self): |
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1150 |
return self.GetComputedValue() |
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1151 |
|
1166
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1152 |
def SetValue(self, value): |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1153 |
if self.Value != value: |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1154 |
self.Value = value |
1170
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1155 |
computed_value = self.GetComputedValue() |
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1156 |
if computed_value is not None: |
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1157 |
self.ComputedValue = computed_value |
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1158 |
self.SetToolTipText(self.ComputedValue) |
1166
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1159 |
if len(self.ComputedValue) > 4: |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1160 |
self.ComputedValue = self.ComputedValue[:4] + "..." |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1161 |
self.ValueSize = None |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1162 |
if self.ParentBlock.Visible: |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1163 |
self.ParentBlock.Parent.ElementNeedRefresh(self) |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1164 |
|
814 | 1165 |
def RefreshForced(self): |
1166 |
self.Forced = False |
|
1167 |
for wire, handle in self.Wires: |
|
1168 |
self.Forced |= wire.IsForced() |
|
1169 |
||
1170 |
def RefreshValue(self): |
|
1171 |
self.Value = self.ReceivingCurrent() |
|
1172 |
||
1173 |
def RefreshValid(self): |
|
1174 |
self.Valid = True |
|
1175 |
for wire, handle in self.Wires: |
|
1176 |
self.Valid &= wire.GetValid() |
|
1177 |
||
1178 |
def ReceivingCurrent(self): |
|
1179 |
current = False |
|
1180 |
for wire, handle in self.Wires: |
|
1181 |
value = wire.GetValue() |
|
1182 |
if current != "undefined" and isinstance(value, BooleanType): |
|
1183 |
current |= wire.GetValue() |
|
1184 |
elif value == "undefined": |
|
1185 |
current = "undefined" |
|
1186 |
return current |
|
1187 |
||
1188 |
def SpreadCurrent(self, spreading): |
|
1189 |
for wire, handle in self.Wires: |
|
1190 |
wire.SetValue(spreading) |
|
1191 |
||
1192 |
# Changes the connector name size |
|
1193 |
def RefreshNameSize(self): |
|
1194 |
if self.Name != "": |
|
1195 |
self.NameSize = self.ParentBlock.Parent.GetTextExtent(self.Name) |
|
1196 |
else: |
|
1197 |
self.NameSize = 0, 0 |
|
1198 |
||
1199 |
# Returns the connector name size |
|
1200 |
def GetNameSize(self): |
|
1201 |
return self.NameSize |
|
1202 |
||
1203 |
# Returns the wires connected to the connector |
|
1204 |
def GetWires(self): |
|
1205 |
return self.Wires |
|
1206 |
||
1207 |
# Returns the parent block Id |
|
1208 |
def GetBlockId(self): |
|
1209 |
return self.ParentBlock.GetId() |
|
1210 |
||
1211 |
# Returns the connector relative position |
|
1212 |
def GetRelPosition(self): |
|
1213 |
return self.Pos |
|
1214 |
||
1215 |
# Returns the connector absolute position |
|
1216 |
def GetPosition(self, size = True): |
|
1217 |
parent_pos = self.ParentBlock.GetPosition() |
|
1218 |
# If the position of the end of the connector is asked |
|
1219 |
if size: |
|
1220 |
x = parent_pos[0] + self.Pos.x + self.Direction[0] * CONNECTOR_SIZE |
|
1221 |
y = parent_pos[1] + self.Pos.y + self.Direction[1] * CONNECTOR_SIZE |
|
1222 |
else: |
|
1223 |
x = parent_pos[0] + self.Pos.x |
|
1224 |
y = parent_pos[1] + self.Pos.y |
|
1225 |
return wx.Point(x, y) |
|
1226 |
||
1227 |
# Change the connector relative position |
|
1228 |
def SetPosition(self, pos): |
|
1229 |
self.Pos = pos |
|
1230 |
||
1231 |
# Returns the connector direction |
|
1232 |
def GetDirection(self): |
|
1233 |
return self.Direction |
|
1234 |
||
1235 |
# Change the connector direction |
|
1236 |
def SetDirection(self, direction): |
|
1237 |
self.Direction = direction |
|
1238 |
||
1239 |
# Connect a wire to this connector at the last place |
|
1240 |
def Connect(self, wire, refresh = True): |
|
1241 |
self.InsertConnect(len(self.Wires), wire, refresh) |
|
1242 |
||
1243 |
# Connect a wire to this connector at the place given |
|
1244 |
def InsertConnect(self, idx, wire, refresh = True): |
|
1245 |
if wire not in self.Wires: |
|
1246 |
self.Wires.insert(idx, wire) |
|
1054
ef514eaacd8c
Fixed connections of block when changing block type
Laurent Bessard
parents:
1047
diff
changeset
|
1247 |
if wire[1] == 0: |
ef514eaacd8c
Fixed connections of block when changing block type
Laurent Bessard
parents:
1047
diff
changeset
|
1248 |
wire[0].ConnectStartPoint(None, self) |
ef514eaacd8c
Fixed connections of block when changing block type
Laurent Bessard
parents:
1047
diff
changeset
|
1249 |
else: |
ef514eaacd8c
Fixed connections of block when changing block type
Laurent Bessard
parents:
1047
diff
changeset
|
1250 |
wire[0].ConnectEndPoint(None, self) |
814 | 1251 |
if refresh: |
1252 |
self.ParentBlock.RefreshModel(False) |
|
1253 |
||
1254 |
# Returns the index of the wire given in the list of connected |
|
1255 |
def GetWireIndex(self, wire): |
|
1256 |
for i, (tmp_wire, handle) in enumerate(self.Wires): |
|
1257 |
if tmp_wire == wire: |
|
1258 |
return i |
|
1259 |
return None |
|
1260 |
||
1261 |
# Unconnect a wire or all wires connected to the connector |
|
1262 |
def UnConnect(self, wire = None, unconnect = True, delete = False): |
|
1263 |
i = 0 |
|
1264 |
found = False |
|
1265 |
while i < len(self.Wires) and not found: |
|
1266 |
if not wire or self.Wires[i][0] == wire: |
|
1267 |
# If Unconnect haven't been called from a wire, disconnect the connector in the wire |
|
1268 |
if unconnect: |
|
1269 |
if self.Wires[i][1] == 0: |
|
1270 |
self.Wires[i][0].UnConnectStartPoint(delete) |
|
1271 |
else: |
|
1272 |
self.Wires[i][0].UnConnectEndPoint(delete) |
|
1273 |
# Remove wire from connected |
|
1274 |
if wire: |
|
1275 |
self.Wires.pop(i) |
|
1276 |
found = True |
|
1277 |
i += 1 |
|
1278 |
# If no wire defined, unconnect all wires |
|
1279 |
if not wire: |
|
1280 |
self.Wires = [] |
|
857
9695969796d0
Adding support for quickly changing variable and connection type
Laurent Bessard
parents:
852
diff
changeset
|
1281 |
if not delete: |
9695969796d0
Adding support for quickly changing variable and connection type
Laurent Bessard
parents:
852
diff
changeset
|
1282 |
self.RefreshValid() |
9695969796d0
Adding support for quickly changing variable and connection type
Laurent Bessard
parents:
852
diff
changeset
|
1283 |
self.ParentBlock.RefreshModel(False) |
814 | 1284 |
|
1285 |
# Returns if connector has one or more wire connected |
|
1286 |
def IsConnected(self): |
|
1287 |
return len(self.Wires) > 0 |
|
1288 |
||
1289 |
# Move the wires connected |
|
1290 |
def MoveConnected(self, exclude = []): |
|
1291 |
if len(self.Wires) > 0: |
|
1292 |
# Calculate the new position of the end point |
|
1293 |
parent_pos = self.ParentBlock.GetPosition() |
|
1294 |
x = parent_pos[0] + self.Pos.x + self.Direction[0] * CONNECTOR_SIZE |
|
1295 |
y = parent_pos[1] + self.Pos.y + self.Direction[1] * CONNECTOR_SIZE |
|
1296 |
# Move the corresponding point on all the wires connected |
|
1297 |
for wire, index in self.Wires: |
|
1298 |
if wire not in exclude: |
|
1299 |
if index == 0: |
|
1300 |
wire.MoveStartPoint(wx.Point(x, y)) |
|
1301 |
else: |
|
1302 |
wire.MoveEndPoint(wx.Point(x, y)) |
|
1303 |
||
1304 |
# Refreshes the model of all the wires connected |
|
1305 |
def RefreshWires(self): |
|
1306 |
for wire in self.Wires: |
|
1307 |
wire[0].RefreshModel() |
|
1308 |
||
1309 |
# Refreshes the parent block model |
|
1310 |
def RefreshParentBlock(self): |
|
1311 |
self.ParentBlock.RefreshModel(False) |
|
1312 |
||
1313 |
# Highlight the parent block |
|
1314 |
def HighlightParentBlock(self, highlight): |
|
1315 |
self.ParentBlock.SetHighlighted(highlight) |
|
1316 |
self.ParentBlock.Refresh() |
|
1317 |
||
1318 |
# Returns all the blocks connected to this connector |
|
1319 |
def GetConnectedBlocks(self): |
|
1320 |
blocks = [] |
|
1321 |
for wire, handle in self.Wires: |
|
1322 |
# Get other connector connected to each wire |
|
1323 |
if handle == 0: |
|
1324 |
connector = wire.GetEndConnected() |
|
1325 |
else: |
|
1326 |
connector = wire.GetStartConnected() |
|
1327 |
# Get parent block for this connector |
|
1328 |
if connector: |
|
1329 |
block = connector.GetParentBlock() |
|
1330 |
if block not in blocks: |
|
1331 |
blocks.append(block) |
|
1332 |
return blocks |
|
1333 |
||
1334 |
# Returns the connector negated property |
|
1335 |
def IsNegated(self): |
|
1336 |
return self.Negated |
|
1337 |
||
1338 |
# Changes the connector negated property |
|
1339 |
def SetNegated(self, negated): |
|
1340 |
if self.ParentBlock.IsOfType("BOOL", self.Type): |
|
1341 |
self.Negated = negated |
|
1342 |
self.Edge = "none" |
|
1343 |
||
1344 |
# Returns the connector edge property |
|
1345 |
def GetEdge(self): |
|
1346 |
return self.Edge |
|
1347 |
||
1348 |
# Changes the connector edge property |
|
1349 |
def SetEdge(self, edge): |
|
1350 |
if self.ParentBlock.IsOfType("BOOL", self.Type): |
|
1351 |
self.Edge = edge |
|
1352 |
self.Negated = False |
|
1353 |
||
1544
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1354 |
# assume that pointer is already inside of this connector |
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1355 |
def ConnectionAvailable(self, direction=None, exclude=True): |
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1356 |
wire_nums = len(self.Wires) |
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1357 |
|
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1358 |
connector_free = (wire_nums<= 0) |
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1359 |
connector_max_used = ((wire_nums > 0) and self.OneConnected) |
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1360 |
if (self.Parent.CurrentLanguage in ["SFC", "LD"]) and (self.Type == "BOOL"): |
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1361 |
connector_max_used = False; |
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1362 |
|
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1363 |
# connector is available for new connection |
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1364 |
connect = connector_free or not connector_max_used |
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1365 |
return connect, connector_max_used |
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1366 |
|
814 | 1367 |
# Tests if the point given is near from the end point of this connector |
1544
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1368 |
def TestPoint(self, pt, direction=None, exclude=True): |
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1369 |
inside = False; |
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1370 |
check_point = (not exclude) and (direction is None or self.Direction == direction); |
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1371 |
|
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1372 |
if check_point: |
814 | 1373 |
# Calculate a square around the end point of this connector |
1544
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1374 |
parent_pos = self.ParentBlock.GetPosition() |
814 | 1375 |
x = parent_pos[0] + self.Pos.x + self.Direction[0] * CONNECTOR_SIZE - ANCHOR_DISTANCE |
1376 |
y = parent_pos[1] + self.Pos.y + self.Direction[1] * CONNECTOR_SIZE - ANCHOR_DISTANCE |
|
1377 |
width = ANCHOR_DISTANCE * 2 + abs(self.Direction[0]) * CONNECTOR_SIZE |
|
1378 |
height = ANCHOR_DISTANCE * 2 + abs(self.Direction[1]) * CONNECTOR_SIZE |
|
1379 |
rect = wx.Rect(x, y, width, height) |
|
1544
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1380 |
inside = rect.InsideXY(pt.x, pt.y); |
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1381 |
|
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1382 |
return inside |
814 | 1383 |
|
1384 |
# Draws the highlightment of this element if it is highlighted |
|
1385 |
def DrawHighlightment(self, dc): |
|
1386 |
scalex, scaley = dc.GetUserScale() |
|
1387 |
dc.SetUserScale(1, 1) |
|
1388 |
pen = MiterPen(HIGHLIGHTCOLOR, 2 * scalex + 5) |
|
1389 |
pen.SetCap(wx.CAP_BUTT) |
|
1390 |
dc.SetPen(pen) |
|
1391 |
dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR)) |
|
1392 |
dc.SetLogicalFunction(wx.AND) |
|
1393 |
parent_pos = self.ParentBlock.GetPosition() |
|
1394 |
posx = parent_pos[0] + self.Pos.x |
|
1395 |
posy = parent_pos[1] + self.Pos.y |
|
1396 |
xstart = parent_pos[0] + self.Pos.x |
|
1397 |
ystart = parent_pos[1] + self.Pos.y |
|
1398 |
if self.Direction[0] < 0: |
|
1399 |
xstart += 1 |
|
1400 |
if self.Direction[1] < 0: |
|
1401 |
ystart += 1 |
|
1402 |
xend = xstart + CONNECTOR_SIZE * self.Direction[0] |
|
1403 |
yend = ystart + CONNECTOR_SIZE * self.Direction[1] |
|
1404 |
dc.DrawLine(round((xstart + self.Direction[0]) * scalex), round((ystart + self.Direction[1]) * scaley), |
|
1405 |
round(xend * scalex), round(yend * scaley)) |
|
1406 |
dc.SetLogicalFunction(wx.COPY) |
|
1407 |
dc.SetUserScale(scalex, scaley) |
|
1408 |
||
1409 |
# Adds an highlight to the connector |
|
1410 |
def AddHighlight(self, infos, start, end, highlight_type): |
|
1411 |
if highlight_type == ERROR_HIGHLIGHT: |
|
1412 |
for wire, handle in self.Wires: |
|
1413 |
wire.SetValid(False) |
|
1414 |
AddHighlight(self.Highlights, (start, end, highlight_type)) |
|
1415 |
||
1416 |
# Removes an highlight from the connector |
|
1417 |
def RemoveHighlight(self, infos, start, end, highlight_type): |
|
1418 |
error = False |
|
1419 |
highlights = [] |
|
1420 |
for highlight in self.Highlights: |
|
1421 |
if highlight != (start, end, highlight_type): |
|
1422 |
highlights.append(highlight) |
|
1423 |
error |= highlight == ERROR_HIGHLIGHT |
|
1424 |
self.Highlights = highlights |
|
1425 |
if not error: |
|
1426 |
for wire, handle in self.Wires: |
|
1427 |
wire.SetValid(wire.IsConnectedCompatible()) |
|
1428 |
||
1429 |
# Removes all the highlights of one particular type from the connector |
|
1430 |
def ClearHighlight(self, highlight_type=None): |
|
1431 |
error = False |
|
1432 |
if highlight_type is None: |
|
1433 |
self.Highlights = [] |
|
1434 |
else: |
|
1435 |
highlights = [] |
|
1436 |
for highlight in self.Highlights: |
|
1437 |
if highlight[2] != highlight_type: |
|
1438 |
highlights.append(highlight) |
|
1439 |
error |= highlight == ERROR_HIGHLIGHT |
|
1440 |
self.Highlights = highlights |
|
1441 |
if not error: |
|
1442 |
for wire, handle in self.Wires: |
|
1443 |
wire.SetValid(wire.IsConnectedCompatible()) |
|
1444 |
||
1445 |
# Draws the connector |
|
1446 |
def Draw(self, dc): |
|
1447 |
if self.Selected: |
|
1448 |
dc.SetPen(MiterPen(wx.BLUE, 3)) |
|
1449 |
dc.SetBrush(wx.WHITE_BRUSH) |
|
1450 |
#elif len(self.Highlights) > 0: |
|
1451 |
# dc.SetPen(MiterPen(self.Highlights[-1][1])) |
|
1452 |
# dc.SetBrush(wx.Brush(self.Highlights[-1][0])) |
|
1453 |
else: |
|
1454 |
if not self.Valid: |
|
1455 |
dc.SetPen(MiterPen(wx.RED)) |
|
1456 |
elif isinstance(self.Value, BooleanType) and self.Value: |
|
1457 |
if self.Forced: |
|
1458 |
dc.SetPen(MiterPen(wx.CYAN)) |
|
1459 |
else: |
|
1460 |
dc.SetPen(MiterPen(wx.GREEN)) |
|
1461 |
elif self.Value == "undefined": |
|
1462 |
dc.SetPen(MiterPen(wx.NamedColour("orange"))) |
|
1463 |
elif self.Forced: |
|
1464 |
dc.SetPen(MiterPen(wx.BLUE)) |
|
1465 |
else: |
|
1466 |
dc.SetPen(MiterPen(wx.BLACK)) |
|
1467 |
dc.SetBrush(wx.WHITE_BRUSH) |
|
1468 |
parent_pos = self.ParentBlock.GetPosition() |
|
1469 |
||
1470 |
if getattr(dc, "printing", False): |
|
1471 |
name_size = dc.GetTextExtent(self.Name) |
|
1472 |
else: |
|
1473 |
name_size = self.NameSize |
|
1474 |
||
1475 |
if self.Negated: |
|
1476 |
# If connector is negated, draw a circle |
|
1477 |
xcenter = parent_pos[0] + self.Pos.x + (CONNECTOR_SIZE * self.Direction[0]) / 2 |
|
1478 |
ycenter = parent_pos[1] + self.Pos.y + (CONNECTOR_SIZE * self.Direction[1]) / 2 |
|
1479 |
dc.DrawCircle(xcenter, ycenter, CONNECTOR_SIZE / 2) |
|
1480 |
else: |
|
1481 |
xstart = parent_pos[0] + self.Pos.x |
|
1482 |
ystart = parent_pos[1] + self.Pos.y |
|
1483 |
if self.Edge == "rising": |
|
1484 |
# If connector has a rising edge, draw a right arrow |
|
1485 |
dc.DrawLine(xstart, ystart, xstart - 4, ystart - 4) |
|
1486 |
dc.DrawLine(xstart, ystart, xstart - 4, ystart + 4) |
|
1487 |
elif self.Edge == "falling": |
|
1488 |
# If connector has a falling edge, draw a left arrow |
|
1489 |
dc.DrawLine(xstart, ystart, xstart + 4, ystart - 4) |
|
1490 |
dc.DrawLine(xstart, ystart, xstart + 4, ystart + 4) |
|
1491 |
if self.Direction[0] < 0: |
|
1492 |
xstart += 1 |
|
1493 |
if self.Direction[1] < 0: |
|
1494 |
ystart += 1 |
|
1495 |
if self.Selected: |
|
1496 |
xend = xstart + (CONNECTOR_SIZE - 2) * self.Direction[0] |
|
1497 |
yend = ystart + (CONNECTOR_SIZE - 2) * self.Direction[1] |
|
1498 |
dc.DrawLine(xstart + 2 * self.Direction[0], ystart + 2 * self.Direction[1], xend, yend) |
|
1499 |
else: |
|
1500 |
xend = xstart + CONNECTOR_SIZE * self.Direction[0] |
|
1501 |
yend = ystart + CONNECTOR_SIZE * self.Direction[1] |
|
1502 |
dc.DrawLine(xstart + self.Direction[0], ystart + self.Direction[1], xend, yend) |
|
1503 |
if self.Direction[0] != 0: |
|
1504 |
ytext = parent_pos[1] + self.Pos.y - name_size[1] / 2 |
|
1505 |
if self.Direction[0] < 0: |
|
1506 |
xtext = parent_pos[0] + self.Pos.x + 5 |
|
1507 |
else: |
|
1508 |
xtext = parent_pos[0] + self.Pos.x - (name_size[0] + 5) |
|
1509 |
if self.Direction[1] != 0: |
|
1510 |
xtext = parent_pos[0] + self.Pos.x - name_size[0] / 2 |
|
1511 |
if self.Direction[1] < 0: |
|
1512 |
ytext = parent_pos[1] + self.Pos.y + 5 |
|
1513 |
else: |
|
1514 |
ytext = parent_pos[1] + self.Pos.y - (name_size[1] + 5) |
|
1515 |
# Draw the text |
|
1516 |
dc.DrawText(self.Name, xtext, ytext) |
|
1517 |
if not getattr(dc, "printing", False): |
|
1518 |
DrawHighlightedText(dc, self.Name, self.Highlights, xtext, ytext) |
|
1519 |
||
1166
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1520 |
if self.Value is not None and not isinstance(self.Value, BooleanType) and self.Value != "undefined": |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1521 |
dc.SetFont(self.ParentBlock.Parent.GetMiniFont()) |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1522 |
dc.SetTextForeground(wx.NamedColour("purple")) |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1523 |
if self.ValueSize is None and isinstance(self.ComputedValue, (StringType, UnicodeType)): |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1524 |
self.ValueSize = self.ParentBlock.Parent.GetMiniTextExtent(self.ComputedValue) |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1525 |
if self.ValueSize is not None: |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1526 |
width, height = self.ValueSize |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1527 |
dc.DrawText(self.ComputedValue, |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1528 |
parent_pos[0] + self.Pos.x + CONNECTOR_SIZE * self.Direction[0] + \ |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1529 |
width * (self.Direction[0] - 1) / 2, |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1530 |
parent_pos[1] + self.Pos.y + CONNECTOR_SIZE * self.Direction[1] + \ |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1531 |
height * (self.Direction[1] - 1)) |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1532 |
dc.SetFont(self.ParentBlock.Parent.GetFont()) |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1533 |
dc.SetTextForeground(wx.BLACK) |
2ed9675be08d
Added support for displaying value of unconnected block connectors in debug
Laurent Bessard
parents:
1120
diff
changeset
|
1534 |
|
814 | 1535 |
#------------------------------------------------------------------------------- |
1536 |
# Common Wire Element |
|
1537 |
#------------------------------------------------------------------------------- |
|
1538 |
||
1539 |
""" |
|
1540 |
Class that implements a wire for connecting two blocks |
|
1541 |
""" |
|
1542 |
||
1543 |
class Wire(Graphic_Element, DebugDataConsumer): |
|
1544 |
||
1545 |
# Create a new wire |
|
1546 |
def __init__(self, parent, start = None, end = None): |
|
1547 |
Graphic_Element.__init__(self, parent) |
|
1548 |
DebugDataConsumer.__init__(self) |
|
1549 |
self.StartPoint = start |
|
1550 |
self.EndPoint = end |
|
1551 |
self.StartConnected = None |
|
1552 |
self.EndConnected = None |
|
1553 |
# If the start and end points are defined, calculate the wire |
|
1554 |
if start and end: |
|
1555 |
self.ResetPoints() |
|
1556 |
self.GeneratePoints() |
|
1557 |
else: |
|
1558 |
self.Points = [] |
|
1559 |
self.Segments = [] |
|
1560 |
self.SelectedSegment = None |
|
1561 |
self.Valid = True |
|
1377
cc8f9177d41c
Fixed bug when debugging wire connected to output connector with modifiers even if connector/continuation is used to replace long wires
Laurent Bessard
parents:
1258
diff
changeset
|
1562 |
self.Modifier = "none" |
cc8f9177d41c
Fixed bug when debugging wire connected to output connector with modifiers even if connector/continuation is used to replace long wires
Laurent Bessard
parents:
1258
diff
changeset
|
1563 |
self.PreviousValue = None |
814 | 1564 |
self.ValueSize = None |
1565 |
self.ComputedValue = None |
|
1566 |
self.OverStart = False |
|
1567 |
self.OverEnd = False |
|
1568 |
self.ComputingType = False |
|
1569 |
self.Font = parent.GetMiniFont() |
|
1544
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
1570 |
self.ErrHighlight = False |
814 | 1571 |
|
1572 |
def GetDefinition(self): |
|
1573 |
if self.StartConnected is not None and self.EndConnected is not None: |
|
1574 |
startblock = self.StartConnected.GetParentBlock() |
|
1575 |
endblock = self.EndConnected.GetParentBlock() |
|
1576 |
return [], [(startblock.GetId(), endblock.GetId())] |
|
1577 |
return [], [] |
|
1578 |
||
1579 |
def Flush(self): |
|
1580 |
self.StartConnected = None |
|
1581 |
self.EndConnected = None |
|
1582 |
||
1583 |
# Returns the RedrawRect |
|
1584 |
def GetRedrawRect(self, movex = 0, movey = 0): |
|
1585 |
rect = Graphic_Element.GetRedrawRect(self, movex, movey) |
|
1586 |
if self.StartConnected: |
|
1587 |
rect = rect.Union(self.StartConnected.GetRedrawRect(movex, movey)) |
|
1588 |
if self.EndConnected: |
|
1589 |
rect = rect.Union(self.EndConnected.GetRedrawRect(movex, movey)) |
|
1590 |
if self.ValueSize is None and isinstance(self.ComputedValue, (StringType, UnicodeType)): |
|
1591 |
self.ValueSize = self.Parent.GetMiniTextExtent(self.ComputedValue) |
|
1592 |
if self.ValueSize is not None: |
|
1593 |
width, height = self.ValueSize |
|
1594 |
if self.BoundingBox[2] > width * 4 or self.BoundingBox[3] > height * 4: |
|
1595 |
x = self.Points[0].x + width * self.StartPoint[1][0] / 2 |
|
1596 |
y = self.Points[0].y + height * (self.StartPoint[1][1] - 1) |
|
1597 |
rect = rect.Union(wx.Rect(x, y, width, height)) |
|
1598 |
x = self.Points[-1].x + width * self.EndPoint[1][0] / 2 |
|
1599 |
y = self.Points[-1].y + height * (self.EndPoint[1][1] - 1) |
|
1600 |
rect = rect.Union(wx.Rect(x, y, width, height)) |
|
1601 |
else: |
|
1602 |
middle = len(self.Segments) / 2 + len(self.Segments) % 2 - 1 |
|
1603 |
x = (self.Points[middle].x + self.Points[middle + 1].x - width) / 2 |
|
1604 |
if self.BoundingBox[3] > height and self.Segments[middle] in [NORTH, SOUTH]: |
|
1605 |
y = (self.Points[middle].y + self.Points[middle + 1].y - height) / 2 |
|
1606 |
else: |
|
1607 |
y = self.Points[middle].y - height |
|
1608 |
rect = rect.Union(wx.Rect(x, y, width, height)) |
|
1609 |
return rect |
|
1610 |
||
1611 |
def Clone(self, parent, connectors = {}, dx = 0, dy = 0): |
|
1612 |
start_connector = connectors.get(self.StartConnected, None) |
|
1613 |
end_connector = connectors.get(self.EndConnected, None) |
|
1614 |
if start_connector is not None and end_connector is not None: |
|
1615 |
wire = Wire(parent) |
|
1616 |
wire.SetPoints([(point.x + dx, point.y + dy) for point in self.Points]) |
|
1617 |
start_connector.Connect((wire, 0), False) |
|
1618 |
end_connector.Connect((wire, -1), False) |
|
1619 |
wire.ConnectStartPoint(start_connector.GetPosition(), start_connector) |
|
1620 |
wire.ConnectEndPoint(end_connector.GetPosition(), end_connector) |
|
1621 |
return wire |
|
1622 |
return None |
|
1623 |
||
1624 |
# Forbids to change the wire position |
|
1625 |
def SetPosition(x, y): |
|
1626 |
pass |
|
1627 |
||
1628 |
# Forbids to change the wire size |
|
1629 |
def SetSize(width, height): |
|
1630 |
pass |
|
1631 |
||
852
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
1632 |
# Forbids to et size of the group elements to their minimum size |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
1633 |
pass |
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
1634 |
|
814 | 1635 |
# Moves and Resizes the element for fitting scaling |
852
1009f956d2ee
Fix support for adjusting block size to block minimum size and to Viewer scaling
Laurent Bessard
parents:
825
diff
changeset
|
1636 |
def SetBestSize(self, scaling): |
814 | 1637 |
if scaling is not None: |
1638 |
movex_max = movey_max = 0 |
|
1639 |
for idx, point in enumerate(self.Points): |
|
1640 |
if 0 < idx < len(self.Points) - 1: |
|
1641 |
movex = round_scaling(point.x, scaling[0]) - point.x |
|
1642 |
movey = round_scaling(point.y, scaling[1]) - point.y |
|
1643 |
if idx == 1: |
|
1644 |
if self.Segments[0][0] == 0: |
|
1645 |
movex = 0 |
|
1646 |
elif (point.x + movex - self.Points[0].x) * self.Segments[0][0] < MIN_SEGMENT_SIZE: |
|
1647 |
movex = round_scaling(self.Points[0].x + MIN_SEGMENT_SIZE * self.Segments[0][0], scaling[0], self.Segments[0][0]) - point.x |
|
1648 |
if self.Segments[0][1] == 0: |
|
1649 |
movey = 0 |
|
1650 |
elif (point.y + movey - self.Points[0].y) * self.Segments[0][1] < MIN_SEGMENT_SIZE: |
|
1651 |
movey = round_scaling(self.Points[0].y + MIN_SEGMENT_SIZE * self.Segments[0][1], scaling[0], self.Segments[0][1]) - point.y |
|
1652 |
elif idx == len(self.Points) - 2: |
|
1653 |
if self.Segments[-1][0] == 0: |
|
1654 |
movex = 0 |
|
1655 |
elif (self.Points[-1].x - (point.x + movex)) * self.Segments[-1][0] < MIN_SEGMENT_SIZE: |
|
1656 |
movex = round_scaling(self.Points[-1].x + MIN_SEGMENT_SIZE * self.Segments[0][0], scaling[0], self.Segments[0][0]) - point.x |
|
1657 |
if self.Segments[-1][1] == 0: |
|
1658 |
movey = 0 |
|
1659 |
elif (self.Points[-1].y - (point.y + movey)) * self.Segments[-1][1] < MIN_SEGMENT_SIZE: |
|
1660 |
movey = round_scaling(self.Points[-1].y - MIN_SEGMENT_SIZE * self.Segments[-1][1], scaling[1], -self.Segments[-1][1]) - point.y |
|
1661 |
movex_max = max(movex_max, movex) |
|
1662 |
movey_max = max(movey_max, movey) |
|
1663 |
point.x += movex |
|
1664 |
point.y += movey |
|
1665 |
return movex_max, movey_max |
|
1666 |
return 0, 0 |
|
1667 |
||
1668 |
# Returns connector to which start point is connected |
|
1669 |
def GetStartConnected(self): |
|
1670 |
return self.StartConnected |
|
1671 |
||
1672 |
# Returns connector to which start point is connected |
|
1673 |
def GetStartConnectedType(self): |
|
1674 |
if self.StartConnected and not self.ComputingType: |
|
1675 |
self.ComputingType = True |
|
1676 |
computed_type = self.StartConnected.GetType() |
|
1677 |
self.ComputingType = False |
|
1678 |
return computed_type |
|
1679 |
return None |
|
1680 |
||
1681 |
# Returns connector to which end point is connected |
|
1682 |
def GetEndConnected(self): |
|
1683 |
return self.EndConnected |
|
1684 |
||
1685 |
# Returns connector to which end point is connected |
|
1686 |
def GetEndConnectedType(self): |
|
1687 |
if self.EndConnected and not self.ComputingType: |
|
1688 |
self.ComputingType = True |
|
1689 |
computed_type = self.EndConnected.GetType() |
|
1690 |
self.ComputingType = False |
|
1691 |
return computed_type |
|
1692 |
return None |
|
1693 |
||
1694 |
def GetConnectionDirection(self): |
|
1695 |
if self.StartConnected is None and self.EndConnected is None: |
|
1696 |
return None |
|
1697 |
elif self.StartConnected is not None and self.EndConnected is None: |
|
1698 |
return (-self.StartPoint[1][0], -self.StartPoint[1][1]) |
|
1699 |
elif self.StartConnected is None and self.EndConnected is not None: |
|
1700 |
return self.EndPoint |
|
1701 |
elif self.Handle is not None: |
|
1702 |
handle_type, handle = self.Handle |
|
1703 |
# A point has been handled |
|
1704 |
if handle_type == HANDLE_POINT: |
|
1705 |
if handle == 0: |
|
1706 |
return self.EndPoint |
|
1707 |
else: |
|
1708 |
return (-self.StartPoint[1][0], -self.StartPoint[1][1]) |
|
1709 |
return None |
|
1710 |
||
1711 |
def GetOtherConnected(self, connector): |
|
1712 |
if self.StartConnected == connector: |
|
1713 |
return self.EndConnected |
|
1714 |
else: |
|
1715 |
return self.StartConnected |
|
1716 |
||
1717 |
def GetOtherConnectedType(self, handle): |
|
1718 |
if handle == 0: |
|
1719 |
return self.GetEndConnectedType() |
|
1720 |
else: |
|
1721 |
return self.GetStartConnectedType() |
|
1722 |
||
1723 |
def IsConnectedCompatible(self): |
|
1724 |
if self.StartConnected: |
|
1725 |
return self.StartConnected.IsCompatible(self.GetEndConnectedType()) |
|
1726 |
elif self.EndConnected: |
|
1727 |
return True |
|
1728 |
return False |
|
1729 |
||
1730 |
def SetForced(self, forced): |
|
1731 |
if self.Forced != forced: |
|
1732 |
self.Forced = forced |
|
1733 |
if self.StartConnected: |
|
1734 |
self.StartConnected.RefreshForced() |
|
1735 |
if self.EndConnected: |
|
1736 |
self.EndConnected.RefreshForced() |
|
1737 |
if self.Visible: |
|
1738 |
self.Parent.ElementNeedRefresh(self) |
|
1739 |
||
1170
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1740 |
def GetComputedValue(self): |
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1741 |
if self.Value is not None and self.Value != "undefined" and not isinstance(self.Value, BooleanType): |
1176
f4b434672204
Moved and rewrote DebugViewer and DebusDataConsumer classes
Laurent Bessard
parents:
1173
diff
changeset
|
1742 |
return self.Value |
1170
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1743 |
return None |
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1744 |
|
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1745 |
def GetToolTipValue(self): |
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1746 |
return self.GetComputedValue() |
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1747 |
|
1377
cc8f9177d41c
Fixed bug when debugging wire connected to output connector with modifiers even if connector/continuation is used to replace long wires
Laurent Bessard
parents:
1258
diff
changeset
|
1748 |
def SetModifier(self, modifier): |
cc8f9177d41c
Fixed bug when debugging wire connected to output connector with modifiers even if connector/continuation is used to replace long wires
Laurent Bessard
parents:
1258
diff
changeset
|
1749 |
self.Modifier = modifier |
cc8f9177d41c
Fixed bug when debugging wire connected to output connector with modifiers even if connector/continuation is used to replace long wires
Laurent Bessard
parents:
1258
diff
changeset
|
1750 |
|
814 | 1751 |
def SetValue(self, value): |
1377
cc8f9177d41c
Fixed bug when debugging wire connected to output connector with modifiers even if connector/continuation is used to replace long wires
Laurent Bessard
parents:
1258
diff
changeset
|
1752 |
if self.Modifier == "rising": |
cc8f9177d41c
Fixed bug when debugging wire connected to output connector with modifiers even if connector/continuation is used to replace long wires
Laurent Bessard
parents:
1258
diff
changeset
|
1753 |
value, self.PreviousValue = value and not self.PreviousValue, value |
cc8f9177d41c
Fixed bug when debugging wire connected to output connector with modifiers even if connector/continuation is used to replace long wires
Laurent Bessard
parents:
1258
diff
changeset
|
1754 |
elif self.Modifier == "falling": |
cc8f9177d41c
Fixed bug when debugging wire connected to output connector with modifiers even if connector/continuation is used to replace long wires
Laurent Bessard
parents:
1258
diff
changeset
|
1755 |
value, self.PreviousValue = not value and self.PreviousValue, value |
cc8f9177d41c
Fixed bug when debugging wire connected to output connector with modifiers even if connector/continuation is used to replace long wires
Laurent Bessard
parents:
1258
diff
changeset
|
1756 |
elif self.Modifier == "negated": |
cc8f9177d41c
Fixed bug when debugging wire connected to output connector with modifiers even if connector/continuation is used to replace long wires
Laurent Bessard
parents:
1258
diff
changeset
|
1757 |
value = not value |
814 | 1758 |
if self.Value != value: |
1759 |
self.Value = value |
|
1170
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1760 |
computed_value = self.GetComputedValue() |
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1761 |
if computed_value is not None: |
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1762 |
self.ComputedValue = computed_value |
074e46cdedbc
Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
Laurent Bessard
parents:
1169
diff
changeset
|
1763 |
self.SetToolTipText(self.ComputedValue) |
814 | 1764 |
if len(self.ComputedValue) > 4: |
1765 |
self.ComputedValue = self.ComputedValue[:4] + "..." |
|
1766 |
self.ValueSize = None |
|
1767 |
if self.StartConnected: |
|
1768 |
self.StartConnected.RefreshValue() |
|
1769 |
if self.EndConnected: |
|
1770 |
self.EndConnected.RefreshValue() |
|
1771 |
if self.Visible: |
|
1772 |
self.Parent.ElementNeedRefresh(self) |
|
1773 |
if isinstance(value, BooleanType) and self.StartConnected is not None: |
|
1774 |
block = self.StartConnected.GetParentBlock() |
|
1775 |
block.SpreadCurrent() |
|
1776 |
||
1777 |
# Unconnect the start and end points |
|
1778 |
def Clean(self): |
|
1779 |
if self.StartConnected: |
|
1780 |
self.UnConnectStartPoint() |
|
1781 |
if self.EndConnected: |
|
1782 |
self.UnConnectEndPoint() |
|
1783 |
||
1784 |
# Delete this wire by calling the corresponding method |
|
1785 |
def Delete(self): |
|
1786 |
self.Parent.DeleteWire(self) |
|
1787 |
||
1788 |
# Select a segment and not the whole wire. It's useful for Ladder Diagram |
|
1789 |
def SetSelectedSegment(self, segment): |
|
1790 |
# The last segment is indicated |
|
1791 |
if segment == -1: |
|
1792 |
segment = len(self.Segments) - 1 |
|
1793 |
# The selected segment is reinitialised |
|
1794 |
if segment == None: |
|
1795 |
if self.StartConnected: |
|
1796 |
self.StartConnected.SetSelected(False) |
|
1797 |
if self.EndConnected: |
|
1798 |
self.EndConnected.SetSelected(False) |
|
1799 |
# The segment selected is the first |
|
1800 |
elif segment == 0: |
|
1801 |
if self.StartConnected: |
|
1802 |
self.StartConnected.SetSelected(True) |
|
1803 |
if self.EndConnected: |
|
1804 |
# There is only one segment |
|
1805 |
if len(self.Segments) == 1: |
|
1806 |
self.EndConnected.SetSelected(True) |
|
1807 |
else: |
|
1808 |
self.EndConnected.SetSelected(False) |
|
1809 |
# The segment selected is the last |
|
1810 |
elif segment == len(self.Segments) - 1: |
|
1811 |
if self.StartConnected: |
|
1812 |
self.StartConnected.SetSelected(False) |
|
1813 |
if self.EndConnected: |
|
1814 |
self.EndConnected.SetSelected(True) |
|
1815 |
self.SelectedSegment = segment |
|
1816 |
self.Refresh() |
|
1817 |
||
1818 |
def SetValid(self, valid): |
|
1819 |
self.Valid = valid |
|
1820 |
if self.StartConnected: |
|
1821 |
self.StartConnected.RefreshValid() |
|
1822 |
if self.EndConnected: |
|
1823 |
self.EndConnected.RefreshValid() |
|
1824 |
||
1825 |
def GetValid(self): |
|
1826 |
return self.Valid |
|
1827 |
||
1828 |
# Reinitialize the wire points |
|
1829 |
def ResetPoints(self): |
|
1830 |
if self.StartPoint and self.EndPoint: |
|
1831 |
self.Points = [self.StartPoint[0], self.EndPoint[0]] |
|
1832 |
self.Segments = [self.StartPoint[1]] |
|
1833 |
else: |
|
1834 |
self.Points = [] |
|
1835 |
self.Segments = [] |
|
1836 |
||
1837 |
# Refresh the wire bounding box |
|
1838 |
def RefreshBoundingBox(self): |
|
1839 |
if len(self.Points) > 0: |
|
1840 |
# If startpoint or endpoint is connected, save the point radius |
|
1841 |
start_radius = end_radius = 0 |
|
1842 |
if not self.StartConnected: |
|
1843 |
start_radius = POINT_RADIUS |
|
1844 |
if not self.EndConnected: |
|
1845 |
end_radius = POINT_RADIUS |
|
1846 |
# Initialize minimum and maximum from the first point |
|
1847 |
minx, minbbxx = self.Points[0].x, self.Points[0].x - start_radius |
|
1848 |
maxx, maxbbxx = self.Points[0].x, self.Points[0].x + start_radius |
|
1849 |
miny, minbbxy = self.Points[0].y, self.Points[0].y - start_radius |
|
1850 |
maxy, maxbbxy = self.Points[0].y, self.Points[0].y + start_radius |
|
1851 |
# Actualize minimum and maximum with the other points |
|
1852 |
for point in self.Points[1:-1]: |
|
1853 |
minx, minbbxx = min(minx, point.x), min(minbbxx, point.x) |
|
1854 |
maxx, maxbbxx = max(maxx, point.x), max(maxbbxx, point.x) |
|
1855 |
miny, minbbxy = min(miny, point.y), min(minbbxy, point.y) |
|
1856 |
maxy, maxbbxy = max(maxy, point.y), max(maxbbxy, point.y) |
|
1857 |
if len(self.Points) > 1: |
|
1858 |
minx, minbbxx = min(minx, self.Points[-1].x), min(minbbxx, self.Points[-1].x - end_radius) |
|
1859 |
maxx, maxbbxx = max(maxx, self.Points[-1].x), max(maxbbxx, self.Points[-1].x + end_radius) |
|
1860 |
miny, minbbxy = min(miny, self.Points[-1].y), min(minbbxy, self.Points[-1].y - end_radius) |
|
1861 |
maxy, maxbbxy = max(maxy, self.Points[-1].y), max(maxbbxy, self.Points[-1].y + end_radius) |
|
1862 |
self.Pos.x, self.Pos.y = minx, miny |
|
1863 |
self.Size = wx.Size(maxx - minx, maxy - miny) |
|
1864 |
self.BoundingBox = wx.Rect(minbbxx, minbbxy, maxbbxx - minbbxx + 1, maxbbxy - minbbxy + 1) |
|
1865 |
||
1866 |
# Refresh the realpoints that permits to keep the proportionality in wire during resizing |
|
1867 |
def RefreshRealPoints(self): |
|
1868 |
if len(self.Points) > 0: |
|
1869 |
self.RealPoints = [] |
|
1870 |
# Calculate float relative position of each point with the minimum point |
|
1871 |
for point in self.Points: |
|
1872 |
self.RealPoints.append([float(point.x - self.Pos.x), float(point.y - self.Pos.y)]) |
|
1873 |
||
1874 |
# Returns the wire minimum size |
|
1875 |
def GetMinSize(self): |
|
1876 |
width = 1 |
|
1877 |
height = 1 |
|
1878 |
dir_product = product(self.StartPoint[1], self.EndPoint[1]) |
|
1879 |
# The directions are opposed |
|
1880 |
if dir_product < 0: |
|
1881 |
if self.StartPoint[0] != 0: |
|
1882 |
width = MIN_SEGMENT_SIZE * 2 |
|
1883 |
if self.StartPoint[1] != 0: |
|
1884 |
height = MIN_SEGMENT_SIZE * 2 |
|
1885 |
# The directions are the same |
|
1886 |
elif dir_product > 0: |
|
1887 |
if self.StartPoint[0] != 0: |
|
1888 |
width = MIN_SEGMENT_SIZE |
|
1889 |
if self.StartPoint[1] != 0: |
|
1890 |
height = MIN_SEGMENT_SIZE |
|
1891 |
# The directions are perpendiculars |
|
1892 |
else: |
|
1893 |
width = MIN_SEGMENT_SIZE |
|
1894 |
height = MIN_SEGMENT_SIZE |
|
1895 |
return width + 1, height + 1 |
|
1896 |
||
1897 |
# Returns if the point given is on one of the wire segments |
|
1898 |
def HitTest(self, pt, connectors=True): |
|
1899 |
test = False |
|
1900 |
for i in xrange(len(self.Points) - 1): |
|
1901 |
rect = wx.Rect(0, 0, 0, 0) |
|
1902 |
if i == 0 and self.StartConnected is not None: |
|
1903 |
x1 = self.Points[i].x - self.Segments[0][0] * CONNECTOR_SIZE |
|
1904 |
y1 = self.Points[i].y - self.Segments[0][1] * CONNECTOR_SIZE |
|
1905 |
else: |
|
1906 |
x1, y1 = self.Points[i].x, self.Points[i].y |
|
1907 |
if i == len(self.Points) - 2 and self.EndConnected is not None: |
|
1908 |
x2 = self.Points[i + 1].x + self.Segments[-1][0] * CONNECTOR_SIZE |
|
1909 |
y2 = self.Points[i + 1].y + self.Segments[-1][1] * CONNECTOR_SIZE |
|
1910 |
else: |
|
1911 |
x2, y2 = self.Points[i + 1].x, self.Points[i + 1].y |
|
1912 |
# Calculate a rectangle around the segment |
|
1913 |
rect = wx.Rect(min(x1, x2) - ANCHOR_DISTANCE, min(y1, y2) - ANCHOR_DISTANCE, |
|
1914 |
abs(x1 - x2) + 2 * ANCHOR_DISTANCE, abs(y1 - y2) + 2 * ANCHOR_DISTANCE) |
|
1915 |
test |= rect.InsideXY(pt.x, pt.y) |
|
1916 |
return test |
|
1917 |
||
1918 |
# Returns the wire start or end point if the point given is on one of them |
|
1919 |
def TestPoint(self, pt): |
|
1920 |
# Test the wire start point |
|
1921 |
rect = wx.Rect(self.Points[0].x - ANCHOR_DISTANCE, self.Points[0].y - ANCHOR_DISTANCE, |
|
1922 |
2 * ANCHOR_DISTANCE, 2 * ANCHOR_DISTANCE) |
|
1923 |
if rect.InsideXY(pt.x, pt.y): |
|
1924 |
return 0 |
|
1925 |
# Test the wire end point |
|
1926 |
if len(self.Points) > 1: |
|
1927 |
rect = wx.Rect(self.Points[-1].x - ANCHOR_DISTANCE, self.Points[-1].y - ANCHOR_DISTANCE, |
|
1928 |
2 * ANCHOR_DISTANCE, 2 * ANCHOR_DISTANCE) |
|
1929 |
if rect.InsideXY(pt.x, pt.y): |
|
1930 |
return -1 |
|
1931 |
return None |
|
1932 |
||
1933 |
# Returns the wire segment if the point given is on it |
|
1934 |
def TestSegment(self, pt, all=False): |
|
1935 |
for i in xrange(len(self.Segments)): |
|
1936 |
# If wire is not in a Ladder Diagram, first and last segments are excluded |
|
1937 |
if all or 0 < i < len(self.Segments) - 1: |
|
1938 |
x1, y1 = self.Points[i].x, self.Points[i].y |
|
1939 |
x2, y2 = self.Points[i + 1].x, self.Points[i + 1].y |
|
1940 |
# Calculate a rectangle around the segment |
|
1941 |
rect = wx.Rect(min(x1, x2) - ANCHOR_DISTANCE, min(y1, y2) - ANCHOR_DISTANCE, |
|
1942 |
abs(x1 - x2) + 2 * ANCHOR_DISTANCE, abs(y1 - y2) + 2 * ANCHOR_DISTANCE) |
|
1943 |
if rect.InsideXY(pt.x, pt.y): |
|
1944 |
return i, self.Segments[i] |
|
1945 |
return None |
|
1946 |
||
1947 |
# Define the wire points |
|
1948 |
def SetPoints(self, points, verify=True): |
|
1949 |
if len(points) > 1: |
|
1950 |
self.Points = [wx.Point(x, y) for x, y in points] |
|
1951 |
# Calculate the start and end directions |
|
1952 |
self.StartPoint = [None, vector(self.Points[0], self.Points[1])] |
|
1953 |
self.EndPoint = [None, vector(self.Points[-1], self.Points[-2])] |
|
1954 |
# Calculate the start and end points |
|
1955 |
self.StartPoint[0] = wx.Point(self.Points[0].x + CONNECTOR_SIZE * self.StartPoint[1][0], |
|
1956 |
self.Points[0].y + CONNECTOR_SIZE * self.StartPoint[1][1]) |
|
1957 |
self.EndPoint[0] = wx.Point(self.Points[-1].x + CONNECTOR_SIZE * self.EndPoint[1][0], |
|
1958 |
self.Points[-1].y + CONNECTOR_SIZE * self.EndPoint[1][1]) |
|
1959 |
self.Points[0] = self.StartPoint[0] |
|
1960 |
self.Points[-1] = self.EndPoint[0] |
|
1961 |
# Calculate the segments directions |
|
1962 |
self.Segments = [] |
|
1963 |
i = 0 |
|
1964 |
while i < len(self.Points) - 1: |
|
1965 |
if verify and 0 < i < len(self.Points) - 2 and \ |
|
1966 |
self.Points[i] == self.Points[i + 1] and \ |
|
1967 |
self.Segments[-1] == vector(self.Points[i + 1], self.Points[i + 2]): |
|
1968 |
for j in xrange(2): |
|
1969 |
self.Points.pop(i) |
|
1970 |
else: |
|
1971 |
segment = vector(self.Points[i], self.Points[i + 1]) |
|
1972 |
if is_null_vector(segment) and i > 0: |
|
1973 |
segment = (self.Segments[-1][1], self.Segments[-1][0]) |
|
1974 |
if i < len(self.Points) - 2: |
|
1975 |
next = vector(self.Points[i + 1], self.Points[i + 2]) |
|
1976 |
if next == segment or is_null_vector(add_vectors(segment, next)): |
|
1977 |
self.Points.insert(i + 1, wx.Point(self.Points[i + 1].x, self.Points[i + 1].y)) |
|
1978 |
self.Segments.append(segment) |
|
1979 |
i += 1 |
|
1980 |
self.RefreshBoundingBox() |
|
1981 |
self.RefreshRealPoints() |
|
1982 |
||
1983 |
# Returns the position of the point indicated |
|
1984 |
def GetPoint(self, index): |
|
1985 |
if index < len(self.Points): |
|
1986 |
return self.Points[index].x, self.Points[index].y |
|
1987 |
return None |
|
1988 |
||
1989 |
# Returns a list of the position of all wire points |
|
1990 |
def GetPoints(self, invert = False): |
|
1991 |
points = self.VerifyPoints() |
|
1992 |
points[0] = wx.Point(points[0].x - CONNECTOR_SIZE * self.StartPoint[1][0], |
|
1993 |
points[0].y - CONNECTOR_SIZE * self.StartPoint[1][1]) |
|
1994 |
points[-1] = wx.Point(points[-1].x - CONNECTOR_SIZE * self.EndPoint[1][0], |
|
1995 |
points[-1].y - CONNECTOR_SIZE * self.EndPoint[1][1]) |
|
1996 |
# An inversion of the list is asked |
|
1997 |
if invert: |
|
1998 |
points.reverse() |
|
1999 |
return points |
|
2000 |
||
2001 |
# Returns the position of the two selected segment points |
|
2002 |
def GetSelectedSegmentPoints(self): |
|
2003 |
if self.SelectedSegment != None and len(self.Points) > 1: |
|
2004 |
return self.Points[self.SelectedSegment:self.SelectedSegment + 2] |
|
2005 |
return [] |
|
2006 |
||
2007 |
# Returns if the selected segment is the first and/or the last of the wire |
|
2008 |
def GetSelectedSegmentConnections(self): |
|
2009 |
if self.SelectedSegment != None and len(self.Points) > 1: |
|
2010 |
return self.SelectedSegment == 0, self.SelectedSegment == len(self.Segments) - 1 |
|
2011 |
return (True, True) |
|
2012 |
||
2013 |
# Returns the connectors on which the wire is connected |
|
2014 |
def GetConnected(self): |
|
2015 |
connected = [] |
|
2016 |
if self.StartConnected and self.StartPoint[1] == WEST: |
|
2017 |
connected.append(self.StartConnected) |
|
2018 |
if self.EndConnected and self.EndPoint[1] == WEST: |
|
2019 |
connected.append(self.EndConnected) |
|
2020 |
return connected |
|
2021 |
||
2022 |
# Returns the id of the block connected to the first or the last wire point |
|
2023 |
def GetConnectedInfos(self, index): |
|
2024 |
if index == 0 and self.StartConnected: |
|
2025 |
return self.StartConnected.GetBlockId(), self.StartConnected.GetName() |
|
2026 |
elif index == -1 and self.EndConnected: |
|
2027 |
return self.EndConnected.GetBlockId(), self.EndConnected.GetName() |
|
2028 |
return None |
|
2029 |
||
2030 |
# Update the wire points position by keeping at most possible the current positions |
|
2031 |
def GeneratePoints(self, realpoints = True): |
|
2032 |
i = 0 |
|
2033 |
# Calculate the start enad end points with the minimum segment size in the right direction |
|
2034 |
end = wx.Point(self.EndPoint[0].x + self.EndPoint[1][0] * MIN_SEGMENT_SIZE, |
|
2035 |
self.EndPoint[0].y + self.EndPoint[1][1] * MIN_SEGMENT_SIZE) |
|
2036 |
start = wx.Point(self.StartPoint[0].x + self.StartPoint[1][0] * MIN_SEGMENT_SIZE, |
|
2037 |
self.StartPoint[0].y + self.StartPoint[1][1] * MIN_SEGMENT_SIZE) |
|
2038 |
# Evaluate the point till it's the last |
|
2039 |
while i < len(self.Points) - 1: |
|
2040 |
# The next point is the last |
|
2041 |
if i + 1 == len(self.Points) - 1: |
|
2042 |
# Calculate the direction from current point to end point |
|
2043 |
v_end = vector(self.Points[i], end) |
|
2044 |
# The current point is the first |
|
2045 |
if i == 0: |
|
2046 |
# If the end point is not in the start direction, a point is added |
|
2047 |
if v_end != self.Segments[0] or v_end == self.EndPoint[1]: |
|
2048 |
self.Points.insert(1, wx.Point(start.x, start.y)) |
|
2049 |
self.Segments.insert(1, DirectionChoice((self.Segments[0][1], |
|
2050 |
self.Segments[0][0]), v_end, self.EndPoint[1])) |
|
2051 |
# The current point is the second |
|
2052 |
elif i == 1: |
|
2053 |
# The previous direction and the target direction are mainly opposed, a point is added |
|
2054 |
if product(v_end, self.Segments[0]) < 0: |
|
2055 |
self.Points.insert(2, wx.Point(self.Points[1].x, self.Points[1].y)) |
|
2056 |
self.Segments.insert(2, DirectionChoice((self.Segments[1][1], |
|
2057 |
self.Segments[1][0]), v_end, self.EndPoint[1])) |
|
2058 |
# The previous direction and the end direction are the same or they are |
|
2059 |
# perpendiculars and the end direction points towards current segment |
|
2060 |
elif product(self.Segments[0], self.EndPoint[1]) >= 0 and product(self.Segments[1], self.EndPoint[1]) <= 0: |
|
2061 |
# Current point and end point are aligned |
|
2062 |
if self.Segments[0][0] != 0: |
|
2063 |
self.Points[1].x = end.x |
|
2064 |
if self.Segments[0][1] != 0: |
|
2065 |
self.Points[1].y = end.y |
|
2066 |
# If the previous direction and the end direction are the same, a point is added |
|
2067 |
if product(self.Segments[0], self.EndPoint[1]) > 0: |
|
2068 |
self.Points.insert(2, wx.Point(self.Points[1].x, self.Points[1].y)) |
|
2069 |
self.Segments.insert(2, DirectionChoice((self.Segments[1][1], |
|
2070 |
self.Segments[1][0]), v_end, self.EndPoint[1])) |
|
2071 |
else: |
|
2072 |
# Current point is positioned in the middle of start point |
|
2073 |
# and end point on the current direction and a point is added |
|
2074 |
if self.Segments[0][0] != 0: |
|
2075 |
self.Points[1].x = (end.x + start.x) / 2 |
|
2076 |
if self.Segments[0][1] != 0: |
|
2077 |
self.Points[1].y = (end.y + start.y) / 2 |
|
2078 |
self.Points.insert(2, wx.Point(self.Points[1].x, self.Points[1].y)) |
|
2079 |
self.Segments.insert(2, DirectionChoice((self.Segments[1][1], |
|
2080 |
self.Segments[1][0]), v_end, self.EndPoint[1])) |
|
2081 |
else: |
|
2082 |
# The previous direction and the end direction are perpendiculars |
|
2083 |
if product(self.Segments[i - 1], self.EndPoint[1]) == 0: |
|
2084 |
# The target direction and the end direction aren't mainly the same |
|
2085 |
if product(v_end, self.EndPoint[1]) <= 0: |
|
2086 |
# Current point and end point are aligned |
|
2087 |
if self.Segments[i - 1][0] != 0: |
|
2088 |
self.Points[i].x = end.x |
|
2089 |
if self.Segments[i - 1][1] != 0: |
|
2090 |
self.Points[i].y = end.y |
|
2091 |
# Previous direction is updated from the new point |
|
2092 |
if product(vector(self.Points[i - 1], self.Points[i]), self.Segments[i - 1]) < 0: |
|
2093 |
self.Segments[i - 1] = (-self.Segments[i - 1][0], -self.Segments[i - 1][1]) |
|
2094 |
else: |
|
2095 |
test = True |
|
2096 |
# If the current point is the third, test if the second |
|
2097 |
# point can be aligned with the end point |
|
2098 |
if i == 2: |
|
2099 |
test_point = wx.Point(self.Points[1].x, self.Points[1].y) |
|
2100 |
if self.Segments[1][0] != 0: |
|
2101 |
test_point.y = end.y |
|
2102 |
if self.Segments[1][1] != 0: |
|
2103 |
test_point.x = end.x |
|
2104 |
vector_test = vector(self.Points[0], test_point, False) |
|
2105 |
test = norm(vector_test) > MIN_SEGMENT_SIZE and product(self.Segments[0], vector_test) > 0 |
|
2106 |
# The previous point can be aligned |
|
2107 |
if test: |
|
2108 |
self.Points[i].x, self.Points[i].y = end.x, end.y |
|
2109 |
if self.Segments[i - 1][0] != 0: |
|
2110 |
self.Points[i - 1].y = end.y |
|
2111 |
if self.Segments[i - 1][1] != 0: |
|
2112 |
self.Points[i - 1].x = end.x |
|
2113 |
self.Segments[i] = (-self.EndPoint[1][0], -self.EndPoint[1][1]) |
|
2114 |
else: |
|
2115 |
# Current point is positioned in the middle of previous point |
|
2116 |
# and end point on the current direction and a point is added |
|
2117 |
if self.Segments[1][0] != 0: |
|
2118 |
self.Points[2].x = (self.Points[1].x + end.x) / 2 |
|
2119 |
if self.Segments[1][1] != 0: |
|
2120 |
self.Points[2].y = (self.Points[1].y + end.y) / 2 |
|
2121 |
self.Points.insert(3, wx.Point(self.Points[2].x, self.Points[2].y)) |
|
2122 |
self.Segments.insert(3, DirectionChoice((self.Segments[2][1], |
|
2123 |
self.Segments[2][0]), v_end, self.EndPoint[1])) |
|
2124 |
else: |
|
2125 |
# Current point is aligned with end point |
|
2126 |
if self.Segments[i - 1][0] != 0: |
|
2127 |
self.Points[i].x = end.x |
|
2128 |
if self.Segments[i - 1][1] != 0: |
|
2129 |
self.Points[i].y = end.y |
|
2130 |
# Previous direction is updated from the new point |
|
2131 |
if product(vector(self.Points[i - 1], self.Points[i]), self.Segments[i - 1]) < 0: |
|
2132 |
self.Segments[i - 1] = (-self.Segments[i - 1][0], -self.Segments[i - 1][1]) |
|
2133 |
# If previous direction and end direction are opposed |
|
2134 |
if product(self.Segments[i - 1], self.EndPoint[1]) < 0: |
|
2135 |
# Current point is positioned in the middle of previous point |
|
2136 |
# and end point on the current direction |
|
2137 |
if self.Segments[i - 1][0] != 0: |
|
2138 |
self.Points[i].x = (end.x + self.Points[i - 1].x) / 2 |
|
2139 |
if self.Segments[i - 1][1] != 0: |
|
2140 |
self.Points[i].y = (end.y + self.Points[i - 1].y) / 2 |
|
2141 |
# A point is added |
|
2142 |
self.Points.insert(i + 1, wx.Point(self.Points[i].x, self.Points[i].y)) |
|
2143 |
self.Segments.insert(i + 1, DirectionChoice((self.Segments[i][1], |
|
2144 |
self.Segments[i][0]), v_end, self.EndPoint[1])) |
|
2145 |
else: |
|
2146 |
# Current point is the first, and second is not mainly in the first direction |
|
2147 |
if i == 0 and product(vector(start, self.Points[1]), self.Segments[0]) < 0: |
|
2148 |
# If first and second directions aren't perpendiculars, a point is added |
|
2149 |
if product(self.Segments[0], self.Segments[1]) != 0: |
|
2150 |
self.Points.insert(1, wx.Point(start.x, start.y)) |
|
2151 |
self.Segments.insert(1, DirectionChoice((self.Segments[0][1], |
|
2152 |
self.Segments[0][0]), vector(start, self.Points[1]), self.Segments[1])) |
|
2153 |
else: |
|
2154 |
self.Points[1].x, self.Points[1].y = start.x, start.y |
|
2155 |
else: |
|
2156 |
# Next point is aligned with current point |
|
2157 |
if self.Segments[i][0] != 0: |
|
2158 |
self.Points[i + 1].y = self.Points[i].y |
|
2159 |
if self.Segments[i][1] != 0: |
|
2160 |
self.Points[i + 1].x = self.Points[i].x |
|
2161 |
# Current direction is updated from the new point |
|
2162 |
if product(vector(self.Points[i], self.Points[i + 1]), self.Segments[i]) < 0: |
|
2163 |
self.Segments[i] = (-self.Segments[i][0], -self.Segments[i][1]) |
|
2164 |
i += 1 |
|
2165 |
self.RefreshBoundingBox() |
|
2166 |
if realpoints: |
|
2167 |
self.RefreshRealPoints() |
|
2168 |
||
2169 |
# Verify that two consecutive points haven't the same position |
|
2170 |
def VerifyPoints(self): |
|
2171 |
points = [point for point in self.Points] |
|
2172 |
segments = [segment for segment in self.Segments] |
|
2173 |
i = 1 |
|
2174 |
while i < len(points) - 1: |
|
2175 |
if points[i] == points[i + 1] and segments[i - 1] == segments[i + 1]: |
|
2176 |
for j in xrange(2): |
|
2177 |
points.pop(i) |
|
2178 |
segments.pop(i) |
|
2179 |
else: |
|
2180 |
i += 1 |
|
2181 |
# If the wire isn't in a Ladder Diagram, save the new point list |
|
2182 |
if self.Parent.__class__.__name__ != "LD_Viewer": |
|
2183 |
self.Points = [point for point in points] |
|
2184 |
self.Segments = [segment for segment in segments] |
|
2185 |
self.RefreshBoundingBox() |
|
2186 |
self.RefreshRealPoints() |
|
2187 |
return points |
|
2188 |
||
2189 |
# Moves all the wire points except the first and the last if they are connected |
|
2190 |
def Move(self, dx, dy, endpoints = False): |
|
2191 |
for i, point in enumerate(self.Points): |
|
2192 |
if endpoints or not (i == 0 and self.StartConnected) and not (i == len(self.Points) - 1 and self.EndConnected): |
|
2193 |
point.x += dx |
|
2194 |
point.y += dy |
|
2195 |
self.StartPoint[0] = self.Points[0] |
|
2196 |
self.EndPoint[0] = self.Points[-1] |
|
2197 |
self.GeneratePoints() |
|
2198 |
||
2199 |
# Resize the wire from position and size given |
|
2200 |
def Resize(self, x, y, width, height): |
|
2201 |
if len(self.Points) > 1: |
|
2202 |
# Calculate the new position of each point for testing the new size |
|
2203 |
minx, miny = self.Pos.x, self.Pos.y |
|
2204 |
lastwidth, lastheight = self.Size.width, self.Size.height |
|
2205 |
for i, point in enumerate(self.RealPoints): |
|
2206 |
# If start or end point is connected, it's not calculate |
|
2207 |
if not (i == 0 and self.StartConnected) and not (i == len(self.Points) - 1 and self.EndConnected): |
|
2208 |
if i == 0: |
|
2209 |
dir = self.StartPoint[1] |
|
2210 |
elif i == len(self.Points) - 1: |
|
2211 |
dir = self.EndPoint[1] |
|
2212 |
else: |
|
2213 |
dir = (0, 0) |
|
2214 |
pointx = max(-dir[0] * MIN_SEGMENT_SIZE, min(int(round(point[0] * width / float(max(lastwidth, 1)))), |
|
2215 |
width - dir[0] * MIN_SEGMENT_SIZE)) |
|
2216 |
pointy = max(-dir[1] * MIN_SEGMENT_SIZE, min(int(round(point[1] * height / float(max(lastheight, 1)))), |
|
2217 |
height - dir[1] * MIN_SEGMENT_SIZE)) |
|
2218 |
self.Points[i] = wx.Point(minx + x + pointx, miny + y + pointy) |
|
2219 |
self.StartPoint[0] = self.Points[0] |
|
2220 |
self.EndPoint[0] = self.Points[-1] |
|
2221 |
self.GeneratePoints(False) |
|
2222 |
# Test if the wire position or size have changed |
|
2223 |
if x != 0 and minx == self.Pos.x: |
|
2224 |
x = 0 |
|
2225 |
width = lastwidth |
|
2226 |
if y != 0 and miny == self.Pos.y: |
|
2227 |
y = 0 |
|
2228 |
height = lastwidth |
|
2229 |
if width != lastwidth and lastwidth == self.Size.width: |
|
2230 |
width = lastwidth |
|
2231 |
if height != lastheight and lastheight == self.Size.height: |
|
2232 |
height = lastheight |
|
2233 |
# Calculate the real points from the new size, it's important for |
|
2234 |
# keeping a proportionality in the points position with the size |
|
2235 |
# during a resize dragging |
|
2236 |
for i, point in enumerate(self.RealPoints): |
|
2237 |
if not (i == 0 and self.StartConnected) and not (i == len(self.Points) - 1 and self.EndConnected): |
|
2238 |
point[0] = point[0] * width / float(max(lastwidth, 1)) |
|
2239 |
point[1] = point[1] * height / float(max(lastheight, 1)) |
|
2240 |
# Calculate the correct position of the points from real points |
|
2241 |
for i, point in enumerate(self.RealPoints): |
|
2242 |
if not (i == 0 and self.StartConnected) and not (i == len(self.Points) - 1 and self.EndConnected): |
|
2243 |
if i == 0: |
|
2244 |
dir = self.StartPoint[1] |
|
2245 |
elif i == len(self.Points) - 1: |
|
2246 |
dir = self.EndPoint[1] |
|
2247 |
else: |
|
2248 |
dir = (0, 0) |
|
2249 |
realpointx = max(-dir[0] * MIN_SEGMENT_SIZE, min(int(round(point[0])), |
|
2250 |
width - dir[0] * MIN_SEGMENT_SIZE)) |
|
2251 |
realpointy = max(-dir[1] * MIN_SEGMENT_SIZE, min(int(round(point[1])), |
|
2252 |
height - dir[1] * MIN_SEGMENT_SIZE)) |
|
2253 |
self.Points[i] = wx.Point(minx + x + realpointx, miny + y + realpointy) |
|
2254 |
self.StartPoint[0] = self.Points[0] |
|
2255 |
self.EndPoint[0] = self.Points[-1] |
|
2256 |
self.GeneratePoints(False) |
|
2257 |
||
2258 |
# Moves the wire start point and update the wire points |
|
2259 |
def MoveStartPoint(self, point): |
|
2260 |
if len(self.Points) > 1: |
|
2261 |
self.StartPoint[0] = point |
|
2262 |
self.Points[0] = point |
|
2263 |
self.GeneratePoints() |
|
2264 |
||
2265 |
# Changes the wire start direction and update the wire points |
|
2266 |
def SetStartPointDirection(self, dir): |
|
2267 |
if len(self.Points) > 1: |
|
2268 |
self.StartPoint[1] = dir |
|
2269 |
self.Segments[0] = dir |
|
2270 |
self.GeneratePoints() |
|
2271 |
||
2272 |
# Rotates the wire start direction by an angle of 90 degrees anticlockwise |
|
2273 |
def RotateStartPoint(self): |
|
2274 |
self.SetStartPointDirection((self.StartPoint[1][1], -self.StartPoint[1][0])) |
|
2275 |
||
2276 |
# Connects wire start point to the connector given and moves wire start point |
|
2277 |
# to given point |
|
2278 |
def ConnectStartPoint(self, point, connector): |
|
2279 |
if point: |
|
2280 |
self.MoveStartPoint(point) |
|
2281 |
self.StartConnected = connector |
|
2282 |
self.RefreshBoundingBox() |
|
2283 |
||
2284 |
# Unconnects wire start point |
|
2285 |
def UnConnectStartPoint(self, delete = False): |
|
2286 |
if delete: |
|
2287 |
self.StartConnected = None |
|
2288 |
self.Delete() |
|
2289 |
elif self.StartConnected: |
|
2290 |
self.StartConnected.UnConnect(self, unconnect = False) |
|
2291 |
self.StartConnected = None |
|
2292 |
self.RefreshBoundingBox() |
|
2293 |
||
2294 |
# Moves the wire end point and update the wire points |
|
2295 |
def MoveEndPoint(self, point): |
|
2296 |
if len(self.Points) > 1: |
|
2297 |
self.EndPoint[0] = point |
|
2298 |
self.Points[-1] = point |
|
2299 |
self.GeneratePoints() |
|
2300 |
||
2301 |
# Changes the wire end direction and update the wire points |
|
2302 |
def SetEndPointDirection(self, dir): |
|
2303 |
if len(self.Points) > 1: |
|
2304 |
self.EndPoint[1] = dir |
|
2305 |
self.GeneratePoints() |
|
2306 |
||
2307 |
# Rotates the wire end direction by an angle of 90 degrees anticlockwise |
|
2308 |
def RotateEndPoint(self): |
|
2309 |
self.SetEndPointDirection((self.EndPoint[1][1], -self.EndPoint[1][0])) |
|
2310 |
||
2311 |
# Connects wire end point to the connector given and moves wire end point |
|
2312 |
# to given point |
|
2313 |
def ConnectEndPoint(self, point, connector): |
|
2314 |
if point: |
|
2315 |
self.MoveEndPoint(point) |
|
2316 |
self.EndConnected = connector |
|
2317 |
self.RefreshBoundingBox() |
|
2318 |
||
2319 |
# Unconnects wire end point |
|
2320 |
def UnConnectEndPoint(self, delete = False): |
|
2321 |
if delete: |
|
2322 |
self.EndConnected = None |
|
2323 |
self.Delete() |
|
2324 |
elif self.EndConnected: |
|
2325 |
self.EndConnected.UnConnect(self, unconnect = False) |
|
2326 |
self.EndConnected = None |
|
2327 |
self.RefreshBoundingBox() |
|
2328 |
||
2329 |
# Moves the wire segment given by its index |
|
2330 |
def MoveSegment(self, idx, movex, movey, scaling): |
|
2331 |
if 0 < idx < len(self.Segments) - 1: |
|
2332 |
if self.Segments[idx] in (NORTH, SOUTH): |
|
2333 |
start_x = self.Points[idx].x |
|
2334 |
if scaling is not None: |
|
2335 |
movex = round_scaling(self.Points[idx].x + movex, scaling[0]) - self.Points[idx].x |
|
2336 |
if idx == 1 and (self.Points[1].x + movex - self.Points[0].x) * self.Segments[0][0] < MIN_SEGMENT_SIZE: |
|
2337 |
movex = round_scaling(self.Points[0].x + MIN_SEGMENT_SIZE * self.Segments[0][0], scaling[0], self.Segments[0][0]) - self.Points[idx].x |
|
2338 |
elif idx == len(self.Segments) - 2 and (self.Points[-1].x - (self.Points[-2].x + movex)) * self.Segments[-1][0] < MIN_SEGMENT_SIZE: |
|
2339 |
movex = round_scaling(self.Points[-1].x - MIN_SEGMENT_SIZE * self.Segments[-1][0], scaling[0], -self.Segments[-1][0]) - self.Points[idx].x |
|
2340 |
self.Points[idx].x += movex |
|
2341 |
self.Points[idx + 1].x += movex |
|
2342 |
self.GeneratePoints() |
|
2343 |
if start_x != self.Points[idx].x: |
|
2344 |
return self.Points[idx].x - start_x, 0 |
|
2345 |
elif self.Segments[idx] in (EAST, WEST): |
|
2346 |
start_y = self.Points[idx].y |
|
2347 |
if scaling is not None: |
|
2348 |
movey = round_scaling(self.Points[idx].y + movey, scaling[1]) - self.Points[idx].y |
|
2349 |
if idx == 1 and (self.Points[1].y + movey - self.Points[0].y) * self.Segments[0][1] < MIN_SEGMENT_SIZE: |
|
2350 |
movex = round_scaling(self.Points[0].y + MIN_SEGMENT_SIZE * self.Segments[0][1], scaling[0], self.Segments[0][1]) - self.Points[idx].y |
|
2351 |
elif idx == len(self.Segments) - 2 and (self.Points[-1].y - (self.Points[-2].y + movey)) * self.Segments[-1][1] < MIN_SEGMENT_SIZE: |
|
2352 |
movey = round_scaling(self.Points[idx].y - MIN_SEGMENT_SIZE * self.Segments[-1][1], scaling[1], -self.Segments[-1][1]) - self.Points[idx].y |
|
2353 |
self.Points[idx].y += movey |
|
2354 |
self.Points[idx + 1].y += movey |
|
2355 |
self.GeneratePoints() |
|
2356 |
if start_y != self.Points[idx].y: |
|
2357 |
return 0, self.Points[idx].y - start_y |
|
2358 |
return 0, 0 |
|
2359 |
||
2360 |
# Adds two points in the middle of the handled segment |
|
2361 |
def AddSegment(self): |
|
2362 |
handle_type, handle = self.Handle |
|
2363 |
if handle_type == HANDLE_SEGMENT: |
|
2364 |
segment, dir = handle |
|
2365 |
if len(self.Segments) > 1: |
|
2366 |
pointx = self.Points[segment].x |
|
2367 |
pointy = self.Points[segment].y |
|
2368 |
if dir[0] != 0: |
|
2369 |
pointx = (self.Points[segment].x + self.Points[segment + 1].x) / 2 |
|
2370 |
if dir[1] != 0: |
|
2371 |
pointy = (self.Points[segment].y + self.Points[segment + 1].y) / 2 |
|
2372 |
self.Points.insert(segment + 1, wx.Point(pointx, pointy)) |
|
2373 |
self.Segments.insert(segment + 1, (dir[1], dir[0])) |
|
2374 |
self.Points.insert(segment + 2, wx.Point(pointx, pointy)) |
|
2375 |
self.Segments.insert(segment + 2, dir) |
|
2376 |
else: |
|
2377 |
p1x = p2x = self.Points[segment].x |
|
2378 |
p1y = p2y = self.Points[segment].y |
|
2379 |
if dir[0] != 0: |
|
2380 |
p1x = (2 * self.Points[segment].x + self.Points[segment + 1].x) / 3 |
|
2381 |
p2x = (self.Points[segment].x + 2 * self.Points[segment + 1].x) / 3 |
|
2382 |
if dir[1] != 0: |
|
2383 |
p1y = (2 * self.Points[segment].y + self.Points[segment + 1].y) / 3 |
|
2384 |
p2y = (self.Points[segment].y + 2 * self.Points[segment + 1].y) / 3 |
|
2385 |
self.Points.insert(segment + 1, wx.Point(p1x, p1y)) |
|
2386 |
self.Segments.insert(segment + 1, (dir[1], dir[0])) |
|
2387 |
self.Points.insert(segment + 2, wx.Point(p1x, p1y)) |
|
2388 |
self.Segments.insert(segment + 2, dir) |
|
2389 |
self.Points.insert(segment + 3, wx.Point(p2x, p2y)) |
|
2390 |
self.Segments.insert(segment + 3, (dir[1], dir[0])) |
|
2391 |
self.Points.insert(segment + 4, wx.Point(p2x, p2y)) |
|
2392 |
self.Segments.insert(segment + 4, dir) |
|
2393 |
self.GeneratePoints() |
|
2394 |
||
2395 |
# Delete the handled segment by removing the two segment points |
|
2396 |
def DeleteSegment(self): |
|
2397 |
handle_type, handle = self.Handle |
|
2398 |
if handle_type == HANDLE_SEGMENT: |
|
2399 |
segment, dir = handle |
|
2400 |
for i in xrange(2): |
|
2401 |
self.Points.pop(segment) |
|
2402 |
self.Segments.pop(segment) |
|
2403 |
self.GeneratePoints() |
|
2404 |
self.RefreshModel() |
|
2405 |
||
2406 |
# Method called when a LeftDown event have been generated |
|
2407 |
def OnLeftDown(self, event, dc, scaling): |
|
2408 |
pos = GetScaledEventPosition(event, dc, scaling) |
|
2409 |
# Test if a point have been handled |
|
2410 |
#result = self.TestPoint(pos) |
|
2411 |
#if result != None: |
|
2412 |
# self.Handle = (HANDLE_POINT, result) |
|
2413 |
# wx.CallAfter(self.Parent.SetCurrentCursor, 1) |
|
2414 |
#else: |
|
2415 |
# Test if a segment have been handled |
|
2416 |
result = self.TestSegment(pos) |
|
2417 |
if result != None: |
|
2418 |
if result[1] in (NORTH, SOUTH): |
|
2419 |
wx.CallAfter(self.Parent.SetCurrentCursor, 4) |
|
2420 |
elif result[1] in (EAST, WEST): |
|
2421 |
wx.CallAfter(self.Parent.SetCurrentCursor, 5) |
|
2422 |
self.Handle = (HANDLE_SEGMENT, result) |
|
2423 |
# Execute the default method for a graphic element |
|
2424 |
else: |
|
2425 |
Graphic_Element.OnLeftDown(self, event, dc, scaling) |
|
2426 |
self.oldPos = pos |
|
2427 |
||
2428 |
# Method called when a RightUp event has been generated |
|
2429 |
def OnRightUp(self, event, dc, scaling): |
|
2430 |
pos = GetScaledEventPosition(event, dc, scaling) |
|
2431 |
# Test if a segment has been handled |
|
2432 |
result = self.TestSegment(pos, True) |
|
2433 |
if result != None: |
|
2434 |
self.Handle = (HANDLE_SEGMENT, result) |
|
2435 |
# Popup the menu with special items for a wire |
|
2436 |
self.Parent.PopupWireMenu(0 < result[0] < len(self.Segments) - 1) |
|
2437 |
else: |
|
2438 |
# Execute the default method for a graphic element |
|
2439 |
Graphic_Element.OnRightUp(self, event, dc, scaling) |
|
2440 |
||
2441 |
# Method called when a LeftDClick event has been generated |
|
2442 |
def OnLeftDClick(self, event, dc, scaling): |
|
2443 |
rect = self.GetRedrawRect() |
|
2444 |
if event.ControlDown(): |
|
2445 |
direction = (self.StartPoint[1], self.EndPoint[1]) |
|
2446 |
if direction in [(EAST, WEST), (WEST, EAST)]: |
|
2447 |
avgy = (self.StartPoint[0].y + self.EndPoint[0].y) / 2 |
|
2448 |
if scaling is not None: |
|
2449 |
avgy = round(float(avgy) / scaling[1]) * scaling[1] |
|
2450 |
if self.StartConnected is not None: |
|
2451 |
movey = avgy - self.StartPoint[0].y |
|
2452 |
startblock = self.StartConnected.GetParentBlock() |
|
2453 |
startblock.Move(0, movey) |
|
2454 |
startblock.RefreshModel() |
|
2455 |
rect.Union(startblock.GetRedrawRect(0, movey)) |
|
2456 |
else: |
|
2457 |
self.MoveStartPoint(wx.Point(self.StartPoint[0].x, avgy)) |
|
2458 |
if self.EndConnected is not None: |
|
2459 |
movey = avgy - self.EndPoint[0].y |
|
2460 |
endblock = self.EndConnected.GetParentBlock() |
|
2461 |
endblock.Move(0, movey) |
|
2462 |
endblock.RefreshModel() |
|
2463 |
rect.Union(endblock.GetRedrawRect(0, movey)) |
|
2464 |
else: |
|
2465 |
self.MoveEndPoint(wx.Point(self.EndPoint[0].x, avgy)) |
|
2466 |
self.Parent.RefreshBuffer() |
|
2467 |
elif direction in [(NORTH, SOUTH), (SOUTH, NORTH)]: |
|
2468 |
avgx = (self.StartPoint[0].x + self.EndPoint[0].x) / 2 |
|
2469 |
if scaling is not None: |
|
2470 |
avgx = round(float(avgx) / scaling[0]) * scaling[0] |
|
2471 |
if self.StartConnected is not None: |
|
2472 |
movex = avgx - self.StartPoint[0].x |
|
2473 |
startblock = self.StartConnected.GetParentBlock() |
|
2474 |
startblock.Move(movex, 0) |
|
2475 |
startblock.RefreshModel() |
|
2476 |
rect.Union(startblock.GetRedrawRect(movex, 0)) |
|
2477 |
else: |
|
2478 |
self.MoveStartPoint(wx.Point(avgx, self.StartPoint[0].y)) |
|
2479 |
if self.EndConnected is not None: |
|
2480 |
movex = avgx - self.EndPoint[0].x |
|
2481 |
endblock = self.EndConnected.GetParentBlock() |
|
2482 |
endblock.Move(movex, 0) |
|
2483 |
endblock.RefreshModel() |
|
2484 |
rect.Union(endblock.GetRedrawRect(movex, 0)) |
|
2485 |
else: |
|
2486 |
self.MoveEndPoint(wx.Point(avgx, self.EndPoint[0].y)) |
|
2487 |
self.Parent.RefreshBuffer() |
|
2488 |
else: |
|
2489 |
self.ResetPoints() |
|
2490 |
self.GeneratePoints() |
|
2491 |
self.RefreshModel() |
|
2492 |
self.Parent.RefreshBuffer() |
|
2493 |
rect.Union(self.GetRedrawRect()) |
|
2494 |
self.Parent.RefreshRect(self.Parent.GetScrolledRect(rect), False) |
|
2495 |
||
2496 |
# Method called when a Motion event has been generated |
|
2497 |
def OnMotion(self, event, dc, scaling): |
|
2498 |
pos = GetScaledEventPosition(event, dc, scaling) |
|
2499 |
if not event.Dragging(): |
|
2500 |
# Test if a segment has been handled |
|
2501 |
result = self.TestSegment(pos) |
|
2502 |
if result: |
|
2503 |
if result[1] in (NORTH, SOUTH): |
|
2504 |
wx.CallAfter(self.Parent.SetCurrentCursor, 4) |
|
2505 |
elif result[1] in (EAST, WEST): |
|
2506 |
wx.CallAfter(self.Parent.SetCurrentCursor, 5) |
|
2507 |
return 0, 0 |
|
2508 |
else: |
|
2509 |
# Execute the default method for a graphic element |
|
2510 |
return Graphic_Element.OnMotion(self, event, dc, scaling) |
|
2511 |
else: |
|
2512 |
# Execute the default method for a graphic element |
|
2513 |
return Graphic_Element.OnMotion(self, event, dc, scaling) |
|
2514 |
||
2515 |
# Refreshes the wire state according to move defined and handle selected |
|
2516 |
def ProcessDragging(self, movex, movey, event, scaling): |
|
2517 |
handle_type, handle = self.Handle |
|
2518 |
# A point has been handled |
|
2519 |
if handle_type == HANDLE_POINT: |
|
2520 |
movex = max(-self.Points[handle].x + POINT_RADIUS, movex) |
|
2521 |
movey = max(-self.Points[handle].y + POINT_RADIUS, movey) |
|
2522 |
if scaling is not None: |
|
2523 |
movex = round_scaling(self.Points[handle].x + movex, scaling[0]) - self.Points[handle].x |
|
2524 |
movey = round_scaling(self.Points[handle].y + movey, scaling[1]) - self.Points[handle].y |
|
2525 |
# Try to connect point to a connector |
|
2526 |
new_pos = wx.Point(self.Points[handle].x + movex, self.Points[handle].y + movey) |
|
2527 |
connector = self.Parent.FindBlockConnector(new_pos, self.GetConnectionDirection()) |
|
2528 |
if connector: |
|
2529 |
if handle == 0 and self.EndConnected != connector: |
|
2530 |
connector.HighlightParentBlock(True) |
|
2531 |
connector.Connect((self, handle)) |
|
2532 |
self.SetStartPointDirection(connector.GetDirection()) |
|
2533 |
self.ConnectStartPoint(connector.GetPosition(), connector) |
|
2534 |
pos = connector.GetPosition() |
|
2535 |
movex = pos.x - self.oldPos.x |
|
2536 |
movey = pos.y - self.oldPos.y |
|
2537 |
if not connector.IsCompatible(self.GetEndConnectedType()): |
|
2538 |
self.SetValid(False) |
|
2539 |
self.Dragging = False |
|
2540 |
elif handle != 0 and self.StartConnected != connector: |
|
2541 |
connector.HighlightParentBlock(True) |
|
2542 |
connector.Connect((self, handle)) |
|
2543 |
self.SetEndPointDirection(connector.GetDirection()) |
|
2544 |
self.ConnectEndPoint(connector.GetPosition(), connector) |
|
2545 |
pos = connector.GetPosition() |
|
2546 |
movex = pos.x - self.oldPos.x |
|
2547 |
movey = pos.y - self.oldPos.y |
|
2548 |
if not connector.IsCompatible(self.GetStartConnectedType()): |
|
2549 |
self.SetValid(False) |
|
2550 |
self.Dragging = False |
|
2551 |
elif handle == 0: |
|
2552 |
self.MoveStartPoint(new_pos) |
|
2553 |
else: |
|
2554 |
self.MoveEndPoint(new_pos) |
|
2555 |
# If there is no connector, move the point |
|
2556 |
elif handle == 0: |
|
2557 |
self.SetValid(True) |
|
2558 |
if self.StartConnected: |
|
2559 |
self.StartConnected.HighlightParentBlock(False) |
|
2560 |
self.UnConnectStartPoint() |
|
2561 |
self.MoveStartPoint(new_pos) |
|
2562 |
else: |
|
2563 |
self.SetValid(True) |
|
2564 |
if self.EndConnected: |
|
2565 |
self.EndConnected.HighlightParentBlock(False) |
|
2566 |
self.UnConnectEndPoint() |
|
2567 |
self.MoveEndPoint(new_pos) |
|
2568 |
return movex, movey |
|
2569 |
# A segment has been handled, move a segment |
|
2570 |
elif handle_type == HANDLE_SEGMENT: |
|
2571 |
return self.MoveSegment(handle[0], movex, movey, scaling) |
|
2572 |
# Execute the default method for a graphic element |
|
2573 |
else: |
|
2574 |
return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling) |
|
2575 |
||
2576 |
# Refreshes the wire model |
|
2577 |
def RefreshModel(self, move=True): |
|
2578 |
if self.StartConnected and self.StartPoint[1] in [WEST, NORTH]: |
|
2579 |
self.StartConnected.RefreshParentBlock() |
|
2580 |
if self.EndConnected and self.EndPoint[1] in [WEST, NORTH]: |
|
2581 |
self.EndConnected.RefreshParentBlock() |
|
2582 |
||
2583 |
# Change the variable that indicates if this element is highlighted |
|
2584 |
def SetHighlighted(self, highlighted): |
|
2585 |
self.Highlighted = highlighted |
|
2586 |
if not highlighted: |
|
2587 |
self.OverStart = False |
|
2588 |
self.OverEnd = False |
|
2589 |
self.Refresh() |
|
2590 |
||
2591 |
def HighlightPoint(self, pos): |
|
2592 |
refresh = False |
|
2593 |
start, end = self.OverStart, self.OverEnd |
|
2594 |
self.OverStart = False |
|
2595 |
self.OverEnd = False |
|
2596 |
# Test if a point has been handled |
|
2597 |
result = self.TestPoint(pos) |
|
2598 |
if result != None: |
|
2599 |
if result == 0 and self.StartConnected is not None: |
|
2600 |
self.OverStart = True |
|
2601 |
elif result != 0 and self.EndConnected is not None: |
|
2602 |
self.OverEnd = True |
|
2603 |
if start != self.OverStart or end != self.OverEnd: |
|
2604 |
self.Refresh() |
|
2605 |
||
2606 |
# Draws the highlightment of this element if it is highlighted |
|
2607 |
def DrawHighlightment(self, dc): |
|
2608 |
scalex, scaley = dc.GetUserScale() |
|
2609 |
dc.SetUserScale(1, 1) |
|
1544
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
2610 |
# If user trying to connect wire with wrong input, highlight will become red. |
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
2611 |
if self.ErrHighlight == True and not (self.EndConnected): |
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
2612 |
highlightcolor = wx.RED |
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
2613 |
else: |
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
2614 |
highlightcolor = HIGHLIGHTCOLOR |
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
2615 |
dc.SetPen(MiterPen(highlightcolor, (2 * scalex + 5))) |
2969c2123105
Fix bug with two or more wires connected to one input. Now only one wire can be connected to one input, except BOOLean signals in LD and SFC. If user trying to connect wire with already connected input, wire highlight will become red.
Sergey Surkov <surkovsv93@gmail.com>
parents:
1377
diff
changeset
|
2616 |
dc.SetBrush(wx.Brush(highlightcolor)) |
814 | 2617 |
dc.SetLogicalFunction(wx.AND) |
2618 |
# Draw the start and end points if they are not connected or the mouse is over them |
|
2619 |
if len(self.Points) > 0 and (not self.StartConnected or self.OverStart): |
|
2620 |
dc.DrawCircle(round(self.Points[0].x * scalex), |
|
2621 |
round(self.Points[0].y * scaley), |
|
2622 |
(POINT_RADIUS + 1) * scalex + 2) |
|
2623 |
if len(self.Points) > 1 and (not self.EndConnected or self.OverEnd): |
|
2624 |
dc.DrawCircle(self.Points[-1].x * scalex, self.Points[-1].y * scaley, (POINT_RADIUS + 1) * scalex + 2) |
|
2625 |
# Draw the wire lines and the last point (it seems that DrawLines stop before the last point) |
|
2626 |
if len(self.Points) > 1: |
|
2627 |
points = [wx.Point(round((self.Points[0].x - self.Segments[0][0]) * scalex), |
|
2628 |
round((self.Points[0].y - self.Segments[0][1]) * scaley))] |
|
2629 |
points.extend([wx.Point(round(point.x * scalex), round(point.y * scaley)) for point in self.Points[1:-1]]) |
|
2630 |
points.append(wx.Point(round((self.Points[-1].x + self.Segments[-1][0]) * scalex), |
|
2631 |
round((self.Points[-1].y + self.Segments[-1][1]) * scaley))) |
|
2632 |
else: |
|
2633 |
points = [] |
|
2634 |
dc.DrawLines(points) |
|
2635 |
dc.SetLogicalFunction(wx.COPY) |
|
2636 |
dc.SetUserScale(scalex, scaley) |
|
2637 |
||
2638 |
if self.StartConnected is not None: |
|
2639 |
self.StartConnected.DrawHighlightment(dc) |
|
2640 |
self.StartConnected.Draw(dc) |
|
2641 |
if self.EndConnected is not None: |
|
2642 |
self.EndConnected.DrawHighlightment(dc) |
|
2643 |
self.EndConnected.Draw(dc) |
|
2644 |
||
2645 |
# Draws the wire lines and points |
|
2646 |
def Draw(self, dc): |
|
2647 |
Graphic_Element.Draw(self, dc) |
|
2648 |
if not self.Valid: |
|
2649 |
dc.SetPen(MiterPen(wx.RED)) |
|
2650 |
dc.SetBrush(wx.RED_BRUSH) |
|
2651 |
elif isinstance(self.Value, BooleanType) and self.Value: |
|
2652 |
if self.Forced: |
|
2653 |
dc.SetPen(MiterPen(wx.CYAN)) |
|
2654 |
dc.SetBrush(wx.CYAN_BRUSH) |
|
2655 |
else: |
|
2656 |
dc.SetPen(MiterPen(wx.GREEN)) |
|
2657 |
dc.SetBrush(wx.GREEN_BRUSH) |
|
2658 |
elif self.Value == "undefined": |
|
2659 |
dc.SetPen(MiterPen(wx.NamedColour("orange"))) |
|
2660 |
dc.SetBrush(wx.Brush(wx.NamedColour("orange"))) |
|
2661 |
elif self.Forced: |
|
2662 |
dc.SetPen(MiterPen(wx.BLUE)) |
|
2663 |
dc.SetBrush(wx.BLUE_BRUSH) |
|
2664 |
else: |
|
2665 |
dc.SetPen(MiterPen(wx.BLACK)) |
|
2666 |
dc.SetBrush(wx.BLACK_BRUSH) |
|
2667 |
# Draw the start and end points if they are not connected or the mouse is over them |
|
2668 |
if len(self.Points) > 0 and (not self.StartConnected or self.OverStart): |
|
2669 |
dc.DrawCircle(self.Points[0].x, self.Points[0].y, POINT_RADIUS) |
|
2670 |
if len(self.Points) > 1 and (not self.EndConnected or self.OverEnd): |
|
2671 |
dc.DrawCircle(self.Points[-1].x, self.Points[-1].y, POINT_RADIUS) |
|
2672 |
# Draw the wire lines and the last point (it seems that DrawLines stop before the last point) |
|
2673 |
if len(self.Points) > 1: |
|
2674 |
points = [wx.Point(self.Points[0].x - self.Segments[0][0], self.Points[0].y - self.Segments[0][1])] |
|
2675 |
points.extend([point for point in self.Points[1:-1]]) |
|
2676 |
points.append(wx.Point(self.Points[-1].x + self.Segments[-1][0], self.Points[-1].y + self.Segments[-1][1])) |
|
2677 |
else: |
|
2678 |
points = [] |
|
2679 |
dc.DrawLines(points) |
|
2680 |
# Draw the segment selected in red |
|
2681 |
if not getattr(dc, "printing", False) and self.SelectedSegment is not None: |
|
2682 |
dc.SetPen(MiterPen(wx.BLUE, 3)) |
|
2683 |
if self.SelectedSegment == len(self.Segments) - 1: |
|
2684 |
end = 0 |
|
2685 |
else: |
|
2686 |
end = 1 |
|
2687 |
dc.DrawLine(self.Points[self.SelectedSegment].x - 1, self.Points[self.SelectedSegment].y, |
|
2688 |
self.Points[self.SelectedSegment + 1].x + end, self.Points[self.SelectedSegment + 1].y) |
|
2689 |
if self.Value is not None and not isinstance(self.Value, BooleanType) and self.Value != "undefined": |
|
2690 |
dc.SetFont(self.Parent.GetMiniFont()) |
|
2691 |
dc.SetTextForeground(wx.NamedColour("purple")) |
|
2692 |
if self.ValueSize is None and isinstance(self.ComputedValue, (StringType, UnicodeType)): |
|
2693 |
self.ValueSize = self.Parent.GetMiniTextExtent(self.ComputedValue) |
|
2694 |
if self.ValueSize is not None: |
|
2695 |
width, height = self.ValueSize |
|
2696 |
if self.BoundingBox[2] > width * 4 or self.BoundingBox[3] > height * 4: |
|
2697 |
x = self.Points[0].x + width * (self.StartPoint[1][0] - 1) / 2 |
|
2698 |
y = self.Points[0].y + height * (self.StartPoint[1][1] - 1) |
|
2699 |
dc.DrawText(self.ComputedValue, x, y) |
|
2700 |
x = self.Points[-1].x + width * (self.EndPoint[1][0] - 1) / 2 |
|
2701 |
y = self.Points[-1].y + height * (self.EndPoint[1][1] - 1) |
|
2702 |
dc.DrawText(self.ComputedValue, x, y) |
|
2703 |
else: |
|
2704 |
middle = len(self.Segments) / 2 + len(self.Segments) % 2 - 1 |
|
2705 |
x = (self.Points[middle].x + self.Points[middle + 1].x - width) / 2 |
|
2706 |
if self.BoundingBox[3] > height and self.Segments[middle] in [NORTH, SOUTH]: |
|
2707 |
y = (self.Points[middle].y + self.Points[middle + 1].y - height) / 2 |
|
2708 |
else: |
|
2709 |
y = self.Points[middle].y - height |
|
2710 |
dc.DrawText(self.ComputedValue, x, y) |
|
2711 |
dc.SetFont(self.Parent.GetFont()) |
|
2712 |
dc.SetTextForeground(wx.BLACK) |
|
2713 |
||
2714 |
||
2715 |
#------------------------------------------------------------------------------- |
|
2716 |
# Graphic comment element |
|
2717 |
#------------------------------------------------------------------------------- |
|
2718 |
||
2719 |
def FilterHighlightsByRow(highlights, row, length): |
|
2720 |
_highlights = [] |
|
2721 |
for start, end, highlight_type in highlights: |
|
2722 |
if start[0] <= row and end[0] >= row: |
|
2723 |
if start[0] < row: |
|
2724 |
start = (row, 0) |
|
2725 |
if end[0] > row: |
|
2726 |
end = (row, length) |
|
2727 |
_highlights.append((start, end, highlight_type)) |
|
2728 |
return _highlights |
|
2729 |
||
2730 |
def FilterHighlightsByColumn(highlights, start_col, end_col): |
|
2731 |
_highlights = [] |
|
2732 |
for start, end, highlight_type in highlights: |
|
2733 |
if end[1] > start_col and start[1] < end_col: |
|
2734 |
start = (start[0], max(start[1], start_col) - start_col) |
|
2735 |
end = (end[0], min(end[1], end_col) - start_col) |
|
2736 |
_highlights.append((start, end, highlight_type)) |
|
2737 |
return _highlights |
|
2738 |
||
2739 |
""" |
|
2740 |
Class that implements a comment |
|
2741 |
""" |
|
2742 |
||
2743 |
class Comment(Graphic_Element): |
|
2744 |
||
2745 |
# Create a new comment |
|
2746 |
def __init__(self, parent, content, id = None): |
|
2747 |
Graphic_Element.__init__(self, parent) |
|
2748 |
self.Id = id |
|
2749 |
self.Content = content |
|
2750 |
self.Pos = wx.Point(0, 0) |
|
2751 |
self.Size = wx.Size(0, 0) |
|
2752 |
self.Highlights = [] |
|
2753 |
||
2754 |
# Make a clone of this comment |
|
2755 |
def Clone(self, parent, id = None, pos = None): |
|
2756 |
comment = Comment(parent, self.Content, id) |
|
2757 |
if pos is not None: |
|
2758 |
comment.SetPosition(pos.x, pos.y) |
|
2759 |
comment.SetSize(self.Size[0], self.Size[1]) |
|
2760 |
return comment |
|
2761 |
||
2762 |
# Method for keeping compatibility with others |
|
2763 |
def Clean(self): |
|
2764 |
pass |
|
2765 |
||
2766 |
# Delete this comment by calling the corresponding method |
|
2767 |
def Delete(self): |
|
2768 |
self.Parent.DeleteComment(self) |
|
2769 |
||
2770 |
# Refresh the comment bounding box |
|
2771 |
def RefreshBoundingBox(self): |
|
2772 |
self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1) |
|
2773 |
||
2774 |
# Changes the comment size |
|
2775 |
def SetSize(self, width, height): |
|
2776 |
self.Size.SetWidth(width) |
|
2777 |
self.Size.SetHeight(height) |
|
2778 |
self.RefreshBoundingBox() |
|
2779 |
||
2780 |
# Returns the comment size |
|
2781 |
def GetSize(self): |
|
2782 |
return self.Size.GetWidth(), self.Size.GetHeight() |
|
2783 |
||
2784 |
# Returns the comment minimum size |
|
2785 |
def GetMinSize(self): |
|
2786 |
dc = wx.ClientDC(self.Parent) |
|
2787 |
min_width = 0 |
|
2788 |
min_height = 0 |
|
2789 |
# The comment minimum size is the maximum size of words in the content |
|
2790 |
for line in self.Content.splitlines(): |
|
2791 |
for word in line.split(" "): |
|
2792 |
wordwidth, wordheight = dc.GetTextExtent(word) |
|
2793 |
min_width = max(min_width, wordwidth) |
|
2794 |
min_height = max(min_height, wordheight) |
|
2795 |
return min_width + 20, min_height + 20 |
|
2796 |
||
2797 |
# Changes the comment position |
|
2798 |
def SetPosition(self, x, y): |
|
2799 |
self.Pos.x = x |
|
2800 |
self.Pos.y = y |
|
2801 |
self.RefreshBoundingBox() |
|
2802 |
||
2803 |
# Changes the comment content |
|
2804 |
def SetContent(self, content): |
|
2805 |
self.Content = content |
|
2806 |
min_width, min_height = self.GetMinSize() |
|
2807 |
self.Size[0] = max(self.Size[0], min_width) |
|
2808 |
self.Size[1] = max(self.Size[1], min_height) |
|
2809 |
self.RefreshBoundingBox() |
|
2810 |
||
2811 |
# Returns the comment content |
|
2812 |
def GetContent(self): |
|
2813 |
return self.Content |
|
2814 |
||
2815 |
# Returns the comment position |
|
2816 |
def GetPosition(self): |
|
2817 |
return self.Pos.x, self.Pos.y |
|
2818 |
||
2819 |
# Moves the comment |
|
2820 |
def Move(self, dx, dy, connected = True): |
|
2821 |
self.Pos.x += dx |
|
2822 |
self.Pos.y += dy |
|
2823 |
self.RefreshBoundingBox() |
|
2824 |
||
2825 |
# Resizes the comment with the position and the size given |
|
2826 |
def Resize(self, x, y, width, height): |
|
2827 |
self.Move(x, y) |
|
2828 |
self.SetSize(width, height) |
|
2829 |
||
2830 |
# Method called when a RightUp event have been generated |
|
2831 |
def OnRightUp(self, event, dc, scaling): |
|
2832 |
# Popup the default menu |
|
2833 |
self.Parent.PopupDefaultMenu() |
|
2834 |
||
2835 |
# Refreshes the wire state according to move defined and handle selected |
|
2836 |
def ProcessDragging(self, movex, movey, event, scaling): |
|
2837 |
if self.Parent.GetDrawingMode() != FREEDRAWING_MODE and self.Parent.CurrentLanguage == "LD": |
|
2838 |
movex = movey = 0 |
|
2839 |
return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling) |
|
2840 |
||
2841 |
# Refreshes the comment model |
|
2842 |
def RefreshModel(self, move=True): |
|
2843 |
self.Parent.RefreshCommentModel(self) |
|
2844 |
||
2845 |
# Method called when a LeftDClick event have been generated |
|
2846 |
def OnLeftDClick(self, event, dc, scaling): |
|
2847 |
# Edit the comment content |
|
2848 |
self.Parent.EditCommentContent(self) |
|
2849 |
||
2850 |
# Adds an highlight to the comment |
|
2851 |
def AddHighlight(self, infos, start, end, highlight_type): |
|
2852 |
if infos[0] == "content": |
|
2853 |
AddHighlight(self.Highlights, (start, end, highlight_type)) |
|
2854 |
||
2855 |
# Removes an highlight from the comment |
|
2856 |
def RemoveHighlight(self, infos, start, end, highlight_type): |
|
2857 |
RemoveHighlight(self.Highlights, (start, end, highlight_type)) |
|
2858 |
||
2859 |
# Removes all the highlights of one particular type from the comment |
|
2860 |
def ClearHighlight(self, highlight_type=None): |
|
2861 |
self.Highlights = ClearHighlights(self.Highlights, highlight_type) |
|
2862 |
||
2863 |
# Draws the highlightment of this element if it is highlighted |
|
2864 |
def DrawHighlightment(self, dc): |
|
2865 |
scalex, scaley = dc.GetUserScale() |
|
2866 |
dc.SetUserScale(1, 1) |
|
2867 |
dc.SetPen(MiterPen(HIGHLIGHTCOLOR)) |
|
2868 |
dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR)) |
|
2869 |
dc.SetLogicalFunction(wx.AND) |
|
2870 |
||
2871 |
left = (self.Pos.x - 1) * scalex - 2 |
|
2872 |
right = (self.Pos.x + self.Size[0] + 1) * scalex + 2 |
|
2873 |
top = (self.Pos.y - 1) * scaley - 2 |
|
2874 |
bottom = (self.Pos.y + self.Size[1] + 1) * scaley + 2 |
|
2875 |
angle_top = (self.Pos.x + self.Size[0] - 9) * scalex + 2 |
|
2876 |
angle_right = (self.Pos.y + 9) * scaley - 2 |
|
2877 |
||
2878 |
polygon = [wx.Point(left, top), wx.Point(angle_top, top), |
|
2879 |
wx.Point(right, angle_right), wx.Point(right, bottom), |
|
2880 |
wx.Point(left, bottom)] |
|
2881 |
dc.DrawPolygon(polygon) |
|
2882 |
||
2883 |
dc.SetLogicalFunction(wx.COPY) |
|
2884 |
dc.SetUserScale(scalex, scaley) |
|
2885 |
||
2886 |
# Draws the comment and its content |
|
2887 |
def Draw(self, dc): |
|
2888 |
Graphic_Element.Draw(self, dc) |
|
2889 |
dc.SetPen(MiterPen(wx.BLACK)) |
|
2890 |
dc.SetBrush(wx.WHITE_BRUSH) |
|
2891 |
# Draws the comment shape |
|
2892 |
polygon = [wx.Point(self.Pos.x, self.Pos.y), |
|
2893 |
wx.Point(self.Pos.x + self.Size[0] - 10, self.Pos.y), |
|
2894 |
wx.Point(self.Pos.x + self.Size[0], self.Pos.y + 10), |
|
2895 |
wx.Point(self.Pos.x + self.Size[0], self.Pos.y + self.Size[1]), |
|
2896 |
wx.Point(self.Pos.x, self.Pos.y + self.Size[1])] |
|
2897 |
dc.DrawPolygon(polygon) |
|
1631
940e20a8865b
fix issue with printing scheme (FBD, LD or SFC) with comment element on GNU/Linux
Andrey Skvortsov <andrej.skvortzov@gmail.com>
parents:
1571
diff
changeset
|
2898 |
|
940e20a8865b
fix issue with printing scheme (FBD, LD or SFC) with comment element on GNU/Linux
Andrey Skvortsov <andrej.skvortzov@gmail.com>
parents:
1571
diff
changeset
|
2899 |
# dc.SetBrush call is workaround for the issue with wx.PrinterDC |
940e20a8865b
fix issue with printing scheme (FBD, LD or SFC) with comment element on GNU/Linux
Andrey Skvortsov <andrej.skvortzov@gmail.com>
parents:
1571
diff
changeset
|
2900 |
# with wxPython 3.0 on GNU/Linux (don't remove it) |
940e20a8865b
fix issue with printing scheme (FBD, LD or SFC) with comment element on GNU/Linux
Andrey Skvortsov <andrej.skvortzov@gmail.com>
parents:
1571
diff
changeset
|
2901 |
dc.SetBrush(wx.WHITE_BRUSH) |
814 | 2902 |
lines = [wx.Point(self.Pos.x + self.Size[0] - 10, self.Pos.y), |
2903 |
wx.Point(self.Pos.x + self.Size[0] - 10, self.Pos.y + 10), |
|
2904 |
wx.Point(self.Pos.x + self.Size[0], self.Pos.y + 10)] |
|
2905 |
dc.DrawLines(lines) |
|
1631
940e20a8865b
fix issue with printing scheme (FBD, LD or SFC) with comment element on GNU/Linux
Andrey Skvortsov <andrej.skvortzov@gmail.com>
parents:
1571
diff
changeset
|
2906 |
|
814 | 2907 |
# Draws the comment content |
2908 |
y = self.Pos.y + 10 |
|
2909 |
for idx, line in enumerate(self.Content.splitlines()): |
|
2910 |
first = True |
|
2911 |
linetext = "" |
|
2912 |
words = line.split(" ") |
|
2913 |
if not getattr(dc, "printing", False): |
|
2914 |
highlights = FilterHighlightsByRow(self.Highlights, idx, len(line)) |
|
2915 |
highlights_offset = 0 |
|
2916 |
for i, word in enumerate(words): |
|
2917 |
if first: |
|
2918 |
text = word |
|
2919 |
else: |
|
2920 |
text = linetext + " " + word |
|
2921 |
wordwidth, wordheight = dc.GetTextExtent(text) |
|
2922 |
if y + wordheight > self.Pos.y + self.Size[1] - 10: |
|
2923 |
break |
|
2924 |
if wordwidth < self.Size[0] - 20: |
|
2925 |
if i < len(words) - 1: |
|
2926 |
linetext = text |
|
2927 |
first = False |
|
2928 |
else: |
|
2929 |
dc.DrawText(text, self.Pos.x + 10, y) |
|
2930 |
if not getattr(dc, "printing", False): |
|
2931 |
DrawHighlightedText(dc, text, FilterHighlightsByColumn(highlights, highlights_offset, highlights_offset + len(text)), self.Pos.x + 10, y) |
|
2932 |
highlights_offset += len(text) + 1 |
|
2933 |
y += wordheight + 5 |
|
2934 |
else: |
|
2935 |
if not first: |
|
2936 |
dc.DrawText(linetext, self.Pos.x + 10, y) |
|
2937 |
if not getattr(dc, "printing", False): |
|
2938 |
DrawHighlightedText(dc, linetext, FilterHighlightsByColumn(highlights, highlights_offset, highlights_offset + len(linetext)), self.Pos.x + 10, y) |
|
2939 |
highlights_offset += len(linetext) + 1 |
|
2940 |
if first or i == len(words) - 1: |
|
2941 |
if not first: |
|
2942 |
y += wordheight + 5 |
|
2943 |
if y + wordheight > self.Pos.y + self.Size[1] - 10: |
|
2944 |
break |
|
2945 |
dc.DrawText(word, self.Pos.x + 10, y) |
|
2946 |
if not getattr(dc, "printing", False): |
|
2947 |
DrawHighlightedText(dc, word, FilterHighlightsByColumn(highlights, highlights_offset, highlights_offset + len(word)), self.Pos.x + 10, y) |
|
2948 |
highlights_offset += len(word) + 1 |
|
2949 |
else: |
|
2950 |
linetext = word |
|
2951 |
y += wordheight + 5 |
|
2952 |
if y + wordheight > self.Pos.y + self.Size[1] - 10: |
|
2953 |
break |
|
2954 |