changeset 1784 | 64beb9e9c749 |
parent 1783 | 3311eea28d56 |
child 1828 | 396da88d7b5c |
1729:31e63e25b4cc | 1784:64beb9e9c749 |
---|---|
28 |
28 |
29 import wx |
29 import wx |
30 import wx.lib.buttons |
30 import wx.lib.buttons |
31 |
31 |
32 import matplotlib |
32 import matplotlib |
33 matplotlib.use('WX') |
33 matplotlib.use('WX') # noqa |
34 import matplotlib.pyplot |
34 import matplotlib.pyplot |
35 from matplotlib.backends.backend_wxagg import _convert_agg_to_wx_bitmap |
35 from matplotlib.backends.backend_wxagg import _convert_agg_to_wx_bitmap |
36 |
|
36 |
37 |
37 from editors.DebugViewer import DebugViewer |
38 from editors.DebugViewer import DebugViewer |
38 from util.BitmapLibrary import GetBitmap |
39 from util.BitmapLibrary import GetBitmap |
39 |
40 |
40 from DebugVariableItem import DebugVariableItem |
41 from DebugVariableItem import DebugVariableItem |
41 from DebugVariableTextViewer import DebugVariableTextViewer |
42 from DebugVariableTextViewer import DebugVariableTextViewer |
42 from DebugVariableGraphicViewer import * |
43 from DebugVariableGraphicViewer import * |
43 |
44 |
44 MILLISECOND = 1000000 # Number of nanosecond in a millisecond |
45 |
45 SECOND = 1000 * MILLISECOND # Number of nanosecond in a second |
46 MILLISECOND = 1000000 # Number of nanosecond in a millisecond |
46 MINUTE = 60 * SECOND # Number of nanosecond in a minute |
47 SECOND = 1000 * MILLISECOND # Number of nanosecond in a second |
47 HOUR = 60 * MINUTE # Number of nanosecond in a hour |
48 MINUTE = 60 * SECOND # Number of nanosecond in a minute |
48 DAY = 24 * HOUR # Number of nanosecond in a day |
49 HOUR = 60 * MINUTE # Number of nanosecond in a hour |
50 DAY = 24 * HOUR # Number of nanosecond in a day |
|
49 |
51 |
50 # List of values possible for graph range |
52 # List of values possible for graph range |
51 # Format is [(time_in_plain_text, value_in_nanosecond),...] |
53 # Format is [(time_in_plain_text, value_in_nanosecond),...] |
52 RANGE_VALUES = \ |
54 RANGE_VALUES = \ |
53 [(_("%dms") % i, i * MILLISECOND) for i in (10, 20, 50, 100, 200, 500)] + \ |
55 [(_("%dms") % i, i * MILLISECOND) for i in (10, 20, 50, 100, 200, 500)] + \ |
56 [(_("%dh") % i, i * HOUR) for i in (1, 2, 3, 6, 12, 24)] |
58 [(_("%dh") % i, i * HOUR) for i in (1, 2, 3, 6, 12, 24)] |
57 |
59 |
58 # Scrollbar increment in pixel |
60 # Scrollbar increment in pixel |
59 SCROLLBAR_UNIT = 10 |
61 SCROLLBAR_UNIT = 10 |
60 |
62 |
63 |
|
61 def compute_mask(x, y): |
64 def compute_mask(x, y): |
62 return [(xp if xp == yp else "*") |
65 return [(xp if xp == yp else "*") |
63 for xp, yp in zip(x, y)] |
66 for xp, yp in zip(x, y)] |
67 |
|
64 |
68 |
65 def NextTick(variables): |
69 def NextTick(variables): |
66 next_tick = None |
70 next_tick = None |
67 for item, data in variables: |
71 for item, data in variables: |
68 if len(data) == 0: |
72 if len(data) == 0: |
69 continue |
73 continue |
70 |
74 |
71 next_tick = (data[0][0] |
75 next_tick = (data[0][0] |
72 if next_tick is None |
76 if next_tick is None |
73 else min(next_tick, data[0][0])) |
77 else min(next_tick, data[0][0])) |
74 |
78 |
75 return next_tick |
79 return next_tick |
76 |
80 |
77 #------------------------------------------------------------------------------- |
81 # ------------------------------------------------------------------------------- |
78 # Debug Variable Graphic Panel Drop Target |
82 # Debug Variable Graphic Panel Drop Target |
79 #------------------------------------------------------------------------------- |
83 # ------------------------------------------------------------------------------- |
80 |
84 |
81 """ |
|
82 Class that implements a custom drop target class for Debug Variable Graphic |
|
83 Panel |
|
84 """ |
|
85 |
85 |
86 class DebugVariableDropTarget(wx.TextDropTarget): |
86 class DebugVariableDropTarget(wx.TextDropTarget): |
87 |
87 """ |
88 Class that implements a custom drop target class for Debug Variable Graphic |
|
89 Panel |
|
90 """ |
|
91 |
|
88 def __init__(self, window): |
92 def __init__(self, window): |
89 """ |
93 """ |
90 Constructor |
94 Constructor |
91 @param window: Reference to the Debug Variable Panel |
95 @param window: Reference to the Debug Variable Panel |
92 """ |
96 """ |
93 wx.TextDropTarget.__init__(self) |
97 wx.TextDropTarget.__init__(self) |
94 self.ParentWindow = window |
98 self.ParentWindow = window |
95 |
99 |
96 def __del__(self): |
100 def __del__(self): |
97 """ |
101 """ |
98 Destructor |
102 Destructor |
99 """ |
103 """ |
100 # Remove reference to Debug Variable Panel |
104 # Remove reference to Debug Variable Panel |
101 self.ParentWindow = None |
105 self.ParentWindow = None |
102 |
106 |
103 def OnDragOver(self, x, y, d): |
107 def OnDragOver(self, x, y, d): |
104 """ |
108 """ |
105 Function called when mouse is dragged over Drop Target |
109 Function called when mouse is dragged over Drop Target |
106 @param x: X coordinate of mouse pointer |
110 @param x: X coordinate of mouse pointer |
107 @param y: Y coordinate of mouse pointer |
111 @param y: Y coordinate of mouse pointer |
108 @param d: Suggested default for return value |
112 @param d: Suggested default for return value |
109 """ |
113 """ |
110 # Signal Debug Variable Panel to refresh highlight giving mouse position |
114 # Signal Debug Variable Panel to refresh highlight giving mouse position |
111 self.ParentWindow.RefreshHighlight(x, y) |
115 self.ParentWindow.RefreshHighlight(x, y) |
112 return wx.TextDropTarget.OnDragOver(self, x, y, d) |
116 return wx.TextDropTarget.OnDragOver(self, x, y, d) |
113 |
117 |
114 def OnDropText(self, x, y, data): |
118 def OnDropText(self, x, y, data): |
115 """ |
119 """ |
116 Function called when mouse is released in Drop Target |
120 Function called when mouse is released in Drop Target |
117 @param x: X coordinate of mouse pointer |
121 @param x: X coordinate of mouse pointer |
118 @param y: Y coordinate of mouse pointer |
122 @param y: Y coordinate of mouse pointer |
119 @param data: Text associated to drag'n drop |
123 @param data: Text associated to drag'n drop |
120 """ |
124 """ |
121 # Signal Debug Variable Panel to reset highlight |
125 # Signal Debug Variable Panel to reset highlight |
122 self.ParentWindow.ResetHighlight() |
126 self.ParentWindow.ResetHighlight() |
123 |
127 |
124 message = None |
128 message = None |
125 |
129 |
126 # Check that data is valid regarding DebugVariablePanel |
130 # Check that data is valid regarding DebugVariablePanel |
127 try: |
131 try: |
128 values = eval(data) |
132 values = eval(data) |
129 if not isinstance(values, TupleType): |
133 if not isinstance(values, TupleType): |
130 raise ValueError |
134 raise ValueError |
131 except: |
135 except Exception: |
132 message = _("Invalid value \"%s\" for debug variable")%data |
136 message = _("Invalid value \"%s\" for debug variable") % data |
133 values = None |
137 values = None |
134 |
138 |
135 # Display message if data is invalid |
139 # Display message if data is invalid |
136 if message is not None: |
140 if message is not None: |
137 wx.CallAfter(self.ShowMessage, message) |
141 wx.CallAfter(self.ShowMessage, message) |
138 |
142 |
139 # Data contain a reference to a variable to debug |
143 # Data contain a reference to a variable to debug |
140 elif values[1] == "debug": |
144 elif values[1] == "debug": |
141 |
145 |
142 # Drag'n Drop is an internal is an internal move inside Debug |
146 # Drag'n Drop is an internal is an internal move inside Debug |
143 # Variable Panel |
147 # Variable Panel |
144 if len(values) > 2 and values[2] == "move": |
148 if len(values) > 2 and values[2] == "move": |
145 self.ParentWindow.MoveValue(values[0]) |
149 self.ParentWindow.MoveValue(values[0]) |
146 |
150 |
147 # Drag'n Drop was initiated by another control of Beremiz |
151 # Drag'n Drop was initiated by another control of Beremiz |
148 else: |
152 else: |
149 self.ParentWindow.InsertValue(values[0], force=True) |
153 self.ParentWindow.InsertValue(values[0], force=True) |
150 |
154 |
151 def OnLeave(self): |
155 def OnLeave(self): |
152 """ |
156 """ |
153 Function called when mouse is leave Drop Target |
157 Function called when mouse is leave Drop Target |
154 """ |
158 """ |
155 # Signal Debug Variable Panel to reset highlight |
159 # Signal Debug Variable Panel to reset highlight |
156 self.ParentWindow.ResetHighlight() |
160 self.ParentWindow.ResetHighlight() |
157 return wx.TextDropTarget.OnLeave(self) |
161 return wx.TextDropTarget.OnLeave(self) |
158 |
162 |
159 def ShowMessage(self, message): |
163 def ShowMessage(self, message): |
160 """ |
164 """ |
161 Show error message in Error Dialog |
165 Show error message in Error Dialog |
162 @param message: Error message to display |
166 @param message: Error message to display |
163 """ |
167 """ |
164 dialog = wx.MessageDialog(self.ParentWindow, |
168 dialog = wx.MessageDialog(self.ParentWindow, |
165 message, |
169 message, |
166 _("Error"), |
170 _("Error"), |
167 wx.OK|wx.ICON_ERROR) |
171 wx.OK | wx.ICON_ERROR) |
168 dialog.ShowModal() |
172 dialog.ShowModal() |
169 dialog.Destroy() |
173 dialog.Destroy() |
170 |
174 |
171 |
175 |
172 #------------------------------------------------------------------------------- |
|
173 # Debug Variable Graphic Panel Class |
|
174 #------------------------------------------------------------------------------- |
|
175 |
|
176 """ |
|
177 Class that implements a Viewer that display variable values as a graphs |
|
178 """ |
|
179 |
|
180 class DebugVariablePanel(wx.Panel, DebugViewer): |
176 class DebugVariablePanel(wx.Panel, DebugViewer): |
181 |
177 """ |
178 Class that implements a Viewer that display variable values as a graphs |
|
179 """ |
|
180 |
|
182 def __init__(self, parent, producer, window): |
181 def __init__(self, parent, producer, window): |
183 """ |
182 """ |
184 Constructor |
183 Constructor |
185 @param parent: Reference to the parent wx.Window |
184 @param parent: Reference to the parent wx.Window |
186 @param producer: Object receiving debug value and dispatching them to |
185 @param producer: Object receiving debug value and dispatching them to |
187 consumers |
186 consumers |
188 @param window: Reference to Beremiz frame |
187 @param window: Reference to Beremiz frame |
189 """ |
188 """ |
190 wx.Panel.__init__(self, parent, style=wx.SP_3D|wx.TAB_TRAVERSAL) |
189 wx.Panel.__init__(self, parent, style=wx.SP_3D | wx.TAB_TRAVERSAL) |
191 |
190 |
192 # Save Reference to Beremiz frame |
191 # Save Reference to Beremiz frame |
193 self.ParentWindow = window |
192 self.ParentWindow = window |
194 |
193 |
195 # Variable storing flag indicating that variable displayed in table |
194 # Variable storing flag indicating that variable displayed in table |
196 # received new value and then table need to be refreshed |
195 # received new value and then table need to be refreshed |
197 self.HasNewData = False |
196 self.HasNewData = False |
198 |
197 |
199 # Variable storing flag indicating that refresh has been forced, and |
198 # Variable storing flag indicating that refresh has been forced, and |
200 # that next time refresh is possible, it will be done even if no new |
199 # that next time refresh is possible, it will be done even if no new |
201 # data is available |
200 # data is available |
202 self.Force = False |
201 self.Force = False |
203 |
202 |
204 self.SetBackgroundColour(wx.WHITE) |
203 self.SetBackgroundColour(wx.WHITE) |
205 |
204 |
206 main_sizer = wx.BoxSizer(wx.VERTICAL) |
205 main_sizer = wx.BoxSizer(wx.VERTICAL) |
207 |
206 |
208 self.Ticks = numpy.array([]) # List of tick received |
207 self.Ticks = numpy.array([]) # List of tick received |
209 self.StartTick = 0 # Tick starting range of data displayed |
208 self.StartTick = 0 # Tick starting range of data displayed |
210 self.Fixed = False # Flag that range of data is fixed |
209 self.Fixed = False # Flag that range of data is fixed |
211 self.CursorTick = None # Tick of cursor for displaying values |
210 self.CursorTick = None # Tick of cursor for displaying values |
212 |
211 |
213 self.DraggingAxesPanel = None |
212 self.DraggingAxesPanel = None |
214 self.DraggingAxesBoundingBox = None |
213 self.DraggingAxesBoundingBox = None |
215 self.DraggingAxesMousePos = None |
214 self.DraggingAxesMousePos = None |
216 self.VetoScrollEvent = False |
215 self.VetoScrollEvent = False |
217 |
216 |
218 self.VariableNameMask = [] |
217 self.VariableNameMask = [] |
219 |
218 |
220 self.GraphicPanels = [] |
219 self.GraphicPanels = [] |
221 |
220 |
222 graphics_button_sizer = wx.BoxSizer(wx.HORIZONTAL) |
221 graphics_button_sizer = wx.BoxSizer(wx.HORIZONTAL) |
223 main_sizer.AddSizer(graphics_button_sizer, border=5, flag=wx.GROW|wx.ALL) |
222 main_sizer.AddSizer(graphics_button_sizer, border=5, flag=wx.GROW | wx.ALL) |
224 |
223 |
225 range_label = wx.StaticText(self, label=_('Range:')) |
224 range_label = wx.StaticText(self, label=_('Range:')) |
226 graphics_button_sizer.AddWindow(range_label, flag=wx.ALIGN_CENTER_VERTICAL) |
225 graphics_button_sizer.AddWindow(range_label, flag=wx.ALIGN_CENTER_VERTICAL) |
227 |
226 |
228 self.CanvasRange = wx.ComboBox(self, style=wx.CB_READONLY) |
227 self.CanvasRange = wx.ComboBox(self, style=wx.CB_READONLY) |
229 self.Bind(wx.EVT_COMBOBOX, self.OnRangeChanged, self.CanvasRange) |
228 self.Bind(wx.EVT_COMBOBOX, self.OnRangeChanged, self.CanvasRange) |
230 graphics_button_sizer.AddWindow(self.CanvasRange, 1, |
229 graphics_button_sizer.AddWindow(self.CanvasRange, 1, |
231 border=5, flag=wx.LEFT|wx.ALIGN_CENTER_VERTICAL) |
230 border=5, |
232 |
231 flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL) |
232 |
|
233 self.CanvasRange.Clear() |
233 self.CanvasRange.Clear() |
234 default_range_idx = 0 |
234 default_range_idx = 0 |
235 for idx, (text, value) in enumerate(RANGE_VALUES): |
235 for idx, (text, value) in enumerate(RANGE_VALUES): |
236 self.CanvasRange.Append(text) |
236 self.CanvasRange.Append(text) |
237 if text == "1s": |
237 if text == "1s": |
238 default_range_idx = idx |
238 default_range_idx = idx |
239 self.CanvasRange.SetSelection(default_range_idx) |
239 self.CanvasRange.SetSelection(default_range_idx) |
240 |
240 |
241 for name, bitmap, help in [ |
241 for name, bitmap, help in [ |
242 ("CurrentButton", "current", _("Go to current value")), |
242 ("CurrentButton", "current", _("Go to current value")), |
243 ("ExportGraphButton", "export_graph", _("Export graph values to clipboard"))]: |
243 ("ExportGraphButton", "export_graph", _("Export graph values to clipboard"))]: |
244 button = wx.lib.buttons.GenBitmapButton(self, |
244 button = wx.lib.buttons.GenBitmapButton( |
245 bitmap=GetBitmap(bitmap), |
245 self, bitmap=GetBitmap(bitmap), |
246 size=wx.Size(28, 28), style=wx.NO_BORDER) |
246 size=wx.Size(28, 28), style=wx.NO_BORDER) |
247 button.SetToolTipString(help) |
247 button.SetToolTipString(help) |
248 setattr(self, name, button) |
248 setattr(self, name, button) |
249 self.Bind(wx.EVT_BUTTON, getattr(self, "On" + name), button) |
249 self.Bind(wx.EVT_BUTTON, getattr(self, "On" + name), button) |
250 graphics_button_sizer.AddWindow(button, border=5, flag=wx.LEFT) |
250 graphics_button_sizer.AddWindow(button, border=5, flag=wx.LEFT) |
251 |
251 |
252 self.CanvasPosition = wx.ScrollBar(self, |
252 self.CanvasPosition = wx.ScrollBar( |
253 size=wx.Size(0, 16), style=wx.SB_HORIZONTAL) |
253 self, size=wx.Size(0, 16), style=wx.SB_HORIZONTAL) |
254 self.CanvasPosition.Bind(wx.EVT_SCROLL_THUMBTRACK, |
254 self.CanvasPosition.Bind(wx.EVT_SCROLL_THUMBTRACK, |
255 self.OnPositionChanging, self.CanvasPosition) |
255 self.OnPositionChanging, self.CanvasPosition) |
256 self.CanvasPosition.Bind(wx.EVT_SCROLL_LINEUP, |
256 self.CanvasPosition.Bind(wx.EVT_SCROLL_LINEUP, |
257 self.OnPositionChanging, self.CanvasPosition) |
257 self.OnPositionChanging, self.CanvasPosition) |
258 self.CanvasPosition.Bind(wx.EVT_SCROLL_LINEDOWN, |
258 self.CanvasPosition.Bind(wx.EVT_SCROLL_LINEDOWN, |
259 self.OnPositionChanging, self.CanvasPosition) |
259 self.OnPositionChanging, self.CanvasPosition) |
260 self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEUP, |
260 self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEUP, |
261 self.OnPositionChanging, self.CanvasPosition) |
261 self.OnPositionChanging, self.CanvasPosition) |
262 self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEDOWN, |
262 self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEDOWN, |
263 self.OnPositionChanging, self.CanvasPosition) |
263 self.OnPositionChanging, self.CanvasPosition) |
264 main_sizer.AddWindow(self.CanvasPosition, border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM) |
264 main_sizer.AddWindow(self.CanvasPosition, border=5, flag=wx.GROW | wx.LEFT | wx.RIGHT | wx.BOTTOM) |
265 |
265 |
266 self.TickSizer = wx.BoxSizer(wx.HORIZONTAL) |
266 self.TickSizer = wx.BoxSizer(wx.HORIZONTAL) |
267 main_sizer.AddSizer(self.TickSizer, border=5, flag=wx.ALL|wx.GROW) |
267 main_sizer.AddSizer(self.TickSizer, border=5, flag=wx.ALL | wx.GROW) |
268 |
268 |
269 self.TickLabel = wx.StaticText(self) |
269 self.TickLabel = wx.StaticText(self) |
270 self.TickSizer.AddWindow(self.TickLabel, border=5, flag=wx.RIGHT) |
270 self.TickSizer.AddWindow(self.TickLabel, border=5, flag=wx.RIGHT) |
271 |
271 |
272 self.MaskLabel = wx.TextCtrl(self, style=wx.TE_READONLY|wx.TE_CENTER|wx.NO_BORDER) |
272 self.MaskLabel = wx.TextCtrl(self, style=wx.TE_READONLY | wx.TE_CENTER | wx.NO_BORDER) |
273 self.TickSizer.AddWindow(self.MaskLabel, 1, border=5, flag=wx.RIGHT|wx.GROW) |
273 self.TickSizer.AddWindow(self.MaskLabel, 1, border=5, flag=wx.RIGHT | wx.GROW) |
274 |
274 |
275 self.TickTimeLabel = wx.StaticText(self) |
275 self.TickTimeLabel = wx.StaticText(self) |
276 self.TickSizer.AddWindow(self.TickTimeLabel) |
276 self.TickSizer.AddWindow(self.TickTimeLabel) |
277 |
277 |
278 self.GraphicsWindow = wx.ScrolledWindow(self, style=wx.HSCROLL|wx.VSCROLL) |
278 self.GraphicsWindow = wx.ScrolledWindow(self, style=wx.HSCROLL | wx.VSCROLL) |
279 self.GraphicsWindow.SetBackgroundColour(wx.WHITE) |
279 self.GraphicsWindow.SetBackgroundColour(wx.WHITE) |
280 self.GraphicsWindow.SetDropTarget(DebugVariableDropTarget(self)) |
280 self.GraphicsWindow.SetDropTarget(DebugVariableDropTarget(self)) |
281 self.GraphicsWindow.Bind(wx.EVT_ERASE_BACKGROUND, self.OnGraphicsWindowEraseBackground) |
281 self.GraphicsWindow.Bind(wx.EVT_ERASE_BACKGROUND, self.OnGraphicsWindowEraseBackground) |
282 self.GraphicsWindow.Bind(wx.EVT_PAINT, self.OnGraphicsWindowPaint) |
282 self.GraphicsWindow.Bind(wx.EVT_PAINT, self.OnGraphicsWindowPaint) |
283 self.GraphicsWindow.Bind(wx.EVT_SIZE, self.OnGraphicsWindowResize) |
283 self.GraphicsWindow.Bind(wx.EVT_SIZE, self.OnGraphicsWindowResize) |
284 self.GraphicsWindow.Bind(wx.EVT_MOUSEWHEEL, self.OnGraphicsWindowMouseWheel) |
284 self.GraphicsWindow.Bind(wx.EVT_MOUSEWHEEL, self.OnGraphicsWindowMouseWheel) |
285 |
285 |
286 main_sizer.AddWindow(self.GraphicsWindow, 1, flag=wx.GROW) |
286 main_sizer.AddWindow(self.GraphicsWindow, 1, flag=wx.GROW) |
287 |
287 |
288 self.GraphicsSizer = wx.BoxSizer(wx.VERTICAL) |
288 self.GraphicsSizer = wx.BoxSizer(wx.VERTICAL) |
289 self.GraphicsWindow.SetSizer(self.GraphicsSizer) |
289 self.GraphicsWindow.SetSizer(self.GraphicsSizer) |
290 |
290 |
291 DebugViewer.__init__(self, producer, True) |
291 DebugViewer.__init__(self, producer, True) |
292 |
292 |
293 self.SetSizer(main_sizer) |
293 self.SetSizer(main_sizer) |
294 self.SetTickTime() |
294 self.SetTickTime() |
295 |
295 |
296 def SetTickTime(self, ticktime=0): |
296 def SetTickTime(self, ticktime=0): |
297 """ |
297 """ |
298 Set Ticktime for calculate data range according to time range selected |
298 Set Ticktime for calculate data range according to time range selected |
299 @param ticktime: Ticktime to apply to range (default: 0) |
299 @param ticktime: Ticktime to apply to range (default: 0) |
300 """ |
300 """ |
301 # Save ticktime |
301 # Save ticktime |
302 self.Ticktime = ticktime |
302 self.Ticktime = ticktime |
303 |
303 |
304 # Set ticktime to millisecond if undefined |
304 # Set ticktime to millisecond if undefined |
305 if self.Ticktime == 0: |
305 if self.Ticktime == 0: |
306 self.Ticktime = MILLISECOND |
306 self.Ticktime = MILLISECOND |
307 |
307 |
308 # Calculate range to apply to data |
308 # Calculate range to apply to data |
309 self.CurrentRange = RANGE_VALUES[ |
309 self.CurrentRange = RANGE_VALUES[ |
310 self.CanvasRange.GetSelection()][1] / self.Ticktime |
310 self.CanvasRange.GetSelection()][1] / self.Ticktime |
311 |
311 |
312 def SetDataProducer(self, producer): |
312 def SetDataProducer(self, producer): |
313 """ |
313 """ |
314 Set Data Producer |
314 Set Data Producer |
315 @param producer: Data Producer |
315 @param producer: Data Producer |
316 """ |
316 """ |
317 DebugViewer.SetDataProducer(self, producer) |
317 DebugViewer.SetDataProducer(self, producer) |
318 |
318 |
319 # Set ticktime if data producer is available |
319 # Set ticktime if data producer is available |
320 if self.DataProducer is not None: |
320 if self.DataProducer is not None: |
321 self.SetTickTime(self.DataProducer.GetTicktime()) |
321 self.SetTickTime(self.DataProducer.GetTicktime()) |
322 |
322 |
323 def RefreshNewData(self): |
323 def RefreshNewData(self): |
324 """ |
324 """ |
325 Called to refresh Panel according to values received by variables |
325 Called to refresh Panel according to values received by variables |
326 Can receive any parameters (not used here) |
326 Can receive any parameters (not used here) |
327 """ |
327 """ |
328 # Refresh graphs if new data is available or refresh is forced |
328 # Refresh graphs if new data is available or refresh is forced |
329 if self.HasNewData or self.Force: |
329 if self.HasNewData or self.Force: |
330 self.HasNewData = False |
330 self.HasNewData = False |
331 self.RefreshView() |
331 self.RefreshView() |
332 |
332 |
333 DebugViewer.RefreshNewData(self) |
333 DebugViewer.RefreshNewData(self) |
334 |
334 |
335 def NewDataAvailable(self, ticks): |
335 def NewDataAvailable(self, ticks): |
336 """ |
336 """ |
337 Called by DataProducer for each tick captured or by panel to refresh |
337 Called by DataProducer for each tick captured or by panel to refresh |
338 graphs |
338 graphs |
339 @param tick: PLC tick captured |
339 @param tick: PLC tick captured |
340 All other parameters are passed to refresh function |
340 All other parameters are passed to refresh function |
341 """ |
341 """ |
342 # If tick given |
342 # If tick given |
343 if ticks is not None: |
343 if ticks is not None: |
344 tick = ticks[-1] |
344 tick = ticks[-1] |
345 |
345 |
346 # Save tick as start tick for range if data is still empty |
346 # Save tick as start tick for range if data is still empty |
347 if len(self.Ticks) == 0: |
347 if len(self.Ticks) == 0: |
348 self.StartTick = ticks[0] |
348 self.StartTick = ticks[0] |
349 |
349 |
350 # Add tick to list of ticks received |
350 # Add tick to list of ticks received |
351 self.Ticks = numpy.append(self.Ticks, ticks) |
351 self.Ticks = numpy.append(self.Ticks, ticks) |
352 |
352 |
353 # Update start tick for range if range follow ticks received |
353 # Update start tick for range if range follow ticks received |
354 if not self.Fixed or tick < self.StartTick + self.CurrentRange: |
354 if not self.Fixed or tick < self.StartTick + self.CurrentRange: |
355 self.StartTick = max(self.StartTick, tick - self.CurrentRange) |
355 self.StartTick = max(self.StartTick, tick - self.CurrentRange) |
356 |
356 |
357 # Force refresh if graph is fixed because range of data received |
357 # Force refresh if graph is fixed because range of data received |
358 # is too small to fill data range selected |
358 # is too small to fill data range selected |
359 if self.Fixed and \ |
359 if self.Fixed and \ |
360 self.Ticks[-1] - self.Ticks[0] < self.CurrentRange: |
360 self.Ticks[-1] - self.Ticks[0] < self.CurrentRange: |
361 self.Force = True |
361 self.Force = True |
362 |
362 |
363 self.HasNewData = False |
363 self.HasNewData = False |
364 self.RefreshView() |
364 self.RefreshView() |
365 |
365 |
366 else: |
366 else: |
367 DebugViewer.NewDataAvailable(self, ticks) |
367 DebugViewer.NewDataAvailable(self, ticks) |
368 |
368 |
369 def ForceRefresh(self): |
369 def ForceRefresh(self): |
370 """ |
370 """ |
371 Called to force refresh of graphs |
371 Called to force refresh of graphs |
372 """ |
372 """ |
373 self.Force = True |
373 self.Force = True |
374 wx.CallAfter(self.NewDataAvailable, None) |
374 wx.CallAfter(self.NewDataAvailable, None) |
375 |
375 |
376 def SetCursorTick(self, cursor_tick): |
376 def SetCursorTick(self, cursor_tick): |
377 """ |
377 """ |
378 Set Cursor for displaying values of items at a tick given |
378 Set Cursor for displaying values of items at a tick given |
379 @param cursor_tick: Tick of cursor |
379 @param cursor_tick: Tick of cursor |
380 """ |
380 """ |
381 # Save cursor tick |
381 # Save cursor tick |
382 self.CursorTick = cursor_tick |
382 self.CursorTick = cursor_tick |
383 self.Fixed = cursor_tick is not None |
383 self.Fixed = cursor_tick is not None |
384 self.UpdateCursorTick() |
384 self.UpdateCursorTick() |
385 |
385 |
386 def MoveCursorTick(self, move): |
386 def MoveCursorTick(self, move): |
387 if self.CursorTick is not None: |
387 if self.CursorTick is not None: |
388 cursor_tick = max(self.Ticks[0], |
388 cursor_tick = max(self.Ticks[0], |
389 min(self.CursorTick + move, |
389 min(self.CursorTick + move, self.Ticks[-1])) |
390 self.Ticks[-1])) |
|
391 cursor_tick_idx = numpy.argmin(numpy.abs(self.Ticks - cursor_tick)) |
390 cursor_tick_idx = numpy.argmin(numpy.abs(self.Ticks - cursor_tick)) |
392 if self.Ticks[cursor_tick_idx] == self.CursorTick: |
391 if self.Ticks[cursor_tick_idx] == self.CursorTick: |
393 cursor_tick_idx = max(0, |
392 cursor_tick_idx = max(0, |
394 min(cursor_tick_idx + abs(move) / move, |
393 min(cursor_tick_idx + abs(move) / move, |
395 len(self.Ticks) - 1)) |
394 len(self.Ticks) - 1)) |
396 self.CursorTick = self.Ticks[cursor_tick_idx] |
395 self.CursorTick = self.Ticks[cursor_tick_idx] |
397 self.StartTick = max(self.Ticks[ |
396 self.StartTick = max( |
398 numpy.argmin(numpy.abs(self.Ticks - |
397 self.Ticks[numpy.argmin( |
399 self.CursorTick + self.CurrentRange))], |
398 numpy.abs(self.Ticks - self.CursorTick + self.CurrentRange))], |
400 min(self.StartTick, self.CursorTick)) |
399 min(self.StartTick, self.CursorTick)) |
401 self.RefreshCanvasPosition() |
400 self.RefreshCanvasPosition() |
402 self.UpdateCursorTick() |
401 self.UpdateCursorTick() |
403 |
402 |
404 def ResetCursorTick(self): |
403 def ResetCursorTick(self): |
405 self.CursorTick = None |
404 self.CursorTick = None |
406 self.Fixed = False |
405 self.Fixed = False |
407 self.UpdateCursorTick() |
406 self.UpdateCursorTick() |
408 |
407 |
409 def UpdateCursorTick(self): |
408 def UpdateCursorTick(self): |
410 for panel in self.GraphicPanels: |
409 for panel in self.GraphicPanels: |
411 if isinstance(panel, DebugVariableGraphicViewer): |
410 if isinstance(panel, DebugVariableGraphicViewer): |
412 panel.SetCursorTick(self.CursorTick) |
411 panel.SetCursorTick(self.CursorTick) |
413 self.ForceRefresh() |
412 self.ForceRefresh() |
414 |
413 |
415 def StartDragNDrop(self, panel, item, x_mouse, y_mouse, x_mouse_start, y_mouse_start): |
414 def StartDragNDrop(self, panel, item, x_mouse, y_mouse, x_mouse_start, y_mouse_start): |
416 if len(panel.GetItems()) > 1: |
415 if len(panel.GetItems()) > 1: |
417 self.DraggingAxesPanel = DebugVariableGraphicViewer(self.GraphicsWindow, self, [item], GRAPH_PARALLEL) |
416 self.DraggingAxesPanel = DebugVariableGraphicViewer(self.GraphicsWindow, self, [item], GRAPH_PARALLEL) |
418 self.DraggingAxesPanel.SetCursorTick(self.CursorTick) |
417 self.DraggingAxesPanel.SetCursorTick(self.CursorTick) |
419 width, height = panel.GetSize() |
418 width, height = panel.GetSize() |
422 self.DraggingAxesPanel.SetPosition(wx.Point(0, -height)) |
421 self.DraggingAxesPanel.SetPosition(wx.Point(0, -height)) |
423 else: |
422 else: |
424 self.DraggingAxesPanel = panel |
423 self.DraggingAxesPanel = panel |
425 self.DraggingAxesBoundingBox = panel.GetAxesBoundingBox(parent_coordinate=True) |
424 self.DraggingAxesBoundingBox = panel.GetAxesBoundingBox(parent_coordinate=True) |
426 self.DraggingAxesMousePos = wx.Point( |
425 self.DraggingAxesMousePos = wx.Point( |
427 x_mouse_start - self.DraggingAxesBoundingBox.x, |
426 x_mouse_start - self.DraggingAxesBoundingBox.x, |
428 y_mouse_start - self.DraggingAxesBoundingBox.y) |
427 y_mouse_start - self.DraggingAxesBoundingBox.y) |
429 self.MoveDragNDrop(x_mouse, y_mouse) |
428 self.MoveDragNDrop(x_mouse, y_mouse) |
430 |
429 |
431 def MoveDragNDrop(self, x_mouse, y_mouse): |
430 def MoveDragNDrop(self, x_mouse, y_mouse): |
432 self.DraggingAxesBoundingBox.x = x_mouse - self.DraggingAxesMousePos.x |
431 self.DraggingAxesBoundingBox.x = x_mouse - self.DraggingAxesMousePos.x |
433 self.DraggingAxesBoundingBox.y = y_mouse - self.DraggingAxesMousePos.y |
432 self.DraggingAxesBoundingBox.y = y_mouse - self.DraggingAxesMousePos.y |
434 self.RefreshHighlight(x_mouse, y_mouse) |
433 self.RefreshHighlight(x_mouse, y_mouse) |
435 |
434 |
436 def RefreshHighlight(self, x_mouse, y_mouse): |
435 def RefreshHighlight(self, x_mouse, y_mouse): |
437 for idx, panel in enumerate(self.GraphicPanels): |
436 for idx, panel in enumerate(self.GraphicPanels): |
438 x, y = panel.GetPosition() |
437 x, y = panel.GetPosition() |
439 width, height = panel.GetSize() |
438 width, height = panel.GetSize() |
440 rect = wx.Rect(x, y, width, height) |
439 rect = wx.Rect(x, y, width, height) |
441 if (rect.InsideXY(x_mouse, y_mouse) or |
440 if rect.InsideXY(x_mouse, y_mouse) or \ |
442 idx == 0 and y_mouse < 0 or |
441 idx == 0 and y_mouse < 0 or \ |
443 idx == len(self.GraphicPanels) - 1 and y_mouse > panel.GetPosition()[1]): |
442 idx == len(self.GraphicPanels) - 1 and y_mouse > panel.GetPosition()[1]: |
444 panel.RefreshHighlight(x_mouse - x, y_mouse - y) |
443 panel.RefreshHighlight(x_mouse - x, y_mouse - y) |
445 else: |
444 else: |
446 panel.SetHighlight(HIGHLIGHT_NONE) |
445 panel.SetHighlight(HIGHLIGHT_NONE) |
447 if wx.Platform == "__WXMSW__": |
446 if wx.Platform == "__WXMSW__": |
448 self.RefreshView() |
447 self.RefreshView() |
449 else: |
448 else: |
450 self.ForceRefresh() |
449 self.ForceRefresh() |
451 |
450 |
452 def ResetHighlight(self): |
451 def ResetHighlight(self): |
453 for panel in self.GraphicPanels: |
452 for panel in self.GraphicPanels: |
454 panel.SetHighlight(HIGHLIGHT_NONE) |
453 panel.SetHighlight(HIGHLIGHT_NONE) |
455 if wx.Platform == "__WXMSW__": |
454 if wx.Platform == "__WXMSW__": |
456 self.RefreshView() |
455 self.RefreshView() |
457 else: |
456 else: |
458 self.ForceRefresh() |
457 self.ForceRefresh() |
459 |
458 |
460 def IsDragging(self): |
459 def IsDragging(self): |
461 return self.DraggingAxesPanel is not None |
460 return self.DraggingAxesPanel is not None |
462 |
461 |
463 def GetDraggingAxesClippingRegion(self, panel): |
462 def GetDraggingAxesClippingRegion(self, panel): |
464 x, y = panel.GetPosition() |
463 x, y = panel.GetPosition() |
465 width, height = panel.GetSize() |
464 width, height = panel.GetSize() |
466 bbox = wx.Rect(x, y, width, height) |
465 bbox = wx.Rect(x, y, width, height) |
467 bbox = bbox.Intersect(self.DraggingAxesBoundingBox) |
466 bbox = bbox.Intersect(self.DraggingAxesBoundingBox) |
468 bbox.x -= x |
467 bbox.x -= x |
469 bbox.y -= y |
468 bbox.y -= y |
470 return bbox |
469 return bbox |
471 |
470 |
472 def GetDraggingAxesPosition(self, panel): |
471 def GetDraggingAxesPosition(self, panel): |
473 x, y = panel.GetPosition() |
472 x, y = panel.GetPosition() |
474 return wx.Point(self.DraggingAxesBoundingBox.x - x, |
473 return wx.Point(self.DraggingAxesBoundingBox.x - x, |
475 self.DraggingAxesBoundingBox.y - y) |
474 self.DraggingAxesBoundingBox.y - y) |
476 |
475 |
477 def StopDragNDrop(self, variable, x_mouse, y_mouse): |
476 def StopDragNDrop(self, variable, x_mouse, y_mouse): |
478 if self.DraggingAxesPanel not in self.GraphicPanels: |
477 if self.DraggingAxesPanel not in self.GraphicPanels: |
479 self.DraggingAxesPanel.Destroy() |
478 self.DraggingAxesPanel.Destroy() |
480 self.DraggingAxesPanel = None |
479 self.DraggingAxesPanel = None |
481 self.DraggingAxesBoundingBox = None |
480 self.DraggingAxesBoundingBox = None |
502 else: |
501 else: |
503 if y_mouse > yw + height / 2: |
502 if y_mouse > yw + height / 2: |
504 idx += 1 |
503 idx += 1 |
505 wx.CallAfter(self.MoveValue, variable, idx, True) |
504 wx.CallAfter(self.MoveValue, variable, idx, True) |
506 self.ForceRefresh() |
505 self.ForceRefresh() |
507 return |
506 return |
508 width, height = self.GraphicsWindow.GetVirtualSize() |
507 width, height = self.GraphicsWindow.GetVirtualSize() |
509 rect = wx.Rect(0, 0, width, height) |
508 rect = wx.Rect(0, 0, width, height) |
510 if rect.InsideXY(x_mouse, y_mouse): |
509 if rect.InsideXY(x_mouse, y_mouse): |
511 wx.CallAfter(self.MoveValue, variable, len(self.GraphicPanels), True) |
510 wx.CallAfter(self.MoveValue, variable, len(self.GraphicPanels), True) |
512 self.ForceRefresh() |
511 self.ForceRefresh() |
513 |
512 |
514 def RefreshGraphicsSizer(self): |
513 def RefreshGraphicsSizer(self): |
515 self.GraphicsSizer.Clear() |
514 self.GraphicsSizer.Clear() |
516 |
515 |
517 for panel in self.GraphicPanels: |
516 for panel in self.GraphicPanels: |
518 self.GraphicsSizer.AddWindow(panel, flag=wx.GROW) |
517 self.GraphicsSizer.AddWindow(panel, flag=wx.GROW) |
519 |
518 |
520 self.GraphicsSizer.Layout() |
519 self.GraphicsSizer.Layout() |
521 self.RefreshGraphicsWindowScrollbars() |
520 self.RefreshGraphicsWindowScrollbars() |
522 |
521 |
523 def RefreshView(self): |
522 def RefreshView(self): |
524 self.RefreshCanvasPosition() |
523 self.RefreshCanvasPosition() |
525 |
524 |
526 width, height = self.GraphicsWindow.GetVirtualSize() |
525 width, height = self.GraphicsWindow.GetVirtualSize() |
527 bitmap = wx.EmptyBitmap(width, height) |
526 bitmap = wx.EmptyBitmap(width, height) |
528 dc = wx.BufferedDC(wx.ClientDC(self.GraphicsWindow), bitmap) |
527 dc = wx.BufferedDC(wx.ClientDC(self.GraphicsWindow), bitmap) |
529 dc.Clear() |
528 dc.Clear() |
530 dc.BeginDrawing() |
529 dc.BeginDrawing() |
531 if self.DraggingAxesPanel is not None: |
530 if self.DraggingAxesPanel is not None: |
532 destBBox = self.DraggingAxesBoundingBox |
531 destBBox = self.DraggingAxesBoundingBox |
533 srcBBox = self.DraggingAxesPanel.GetAxesBoundingBox() |
532 srcBBox = self.DraggingAxesPanel.GetAxesBoundingBox() |
534 |
533 |
535 srcBmp = _convert_agg_to_wx_bitmap(self.DraggingAxesPanel.get_renderer(), None) |
534 srcBmp = _convert_agg_to_wx_bitmap(self.DraggingAxesPanel.get_renderer(), None) |
536 srcDC = wx.MemoryDC() |
535 srcDC = wx.MemoryDC() |
537 srcDC.SelectObject(srcBmp) |
536 srcDC.SelectObject(srcBmp) |
538 |
537 |
539 dc.Blit(destBBox.x, destBBox.y, |
538 dc.Blit(destBBox.x, destBBox.y, |
540 int(destBBox.width), int(destBBox.height), |
539 int(destBBox.width), int(destBBox.height), |
541 srcDC, srcBBox.x, srcBBox.y) |
540 srcDC, srcBBox.x, srcBBox.y) |
542 dc.EndDrawing() |
541 dc.EndDrawing() |
543 |
542 |
544 if not self.Fixed or self.Force: |
543 if not self.Fixed or self.Force: |
545 self.Force = False |
544 self.Force = False |
546 refresh_graphics = True |
545 refresh_graphics = True |
547 else: |
546 else: |
548 refresh_graphics = False |
547 refresh_graphics = False |
549 |
548 |
550 if self.DraggingAxesPanel is not None and self.DraggingAxesPanel not in self.GraphicPanels: |
549 if self.DraggingAxesPanel is not None and self.DraggingAxesPanel not in self.GraphicPanels: |
551 self.DraggingAxesPanel.RefreshViewer(refresh_graphics) |
550 self.DraggingAxesPanel.RefreshViewer(refresh_graphics) |
552 for panel in self.GraphicPanels: |
551 for panel in self.GraphicPanels: |
553 if isinstance(panel, DebugVariableGraphicViewer): |
552 if isinstance(panel, DebugVariableGraphicViewer): |
554 panel.RefreshViewer(refresh_graphics) |
553 panel.RefreshViewer(refresh_graphics) |
555 else: |
554 else: |
556 panel.RefreshViewer() |
555 panel.RefreshViewer() |
557 |
556 |
558 if self.CursorTick is not None: |
557 if self.CursorTick is not None: |
559 tick = self.CursorTick |
558 tick = self.CursorTick |
560 elif len(self.Ticks) > 0: |
559 elif len(self.Ticks) > 0: |
561 tick = self.Ticks[-1] |
560 tick = self.Ticks[-1] |
562 else: |
561 else: |
568 duration = "" |
567 duration = "" |
569 for value, format in [(tick_duration / DAY, _("%dd")), |
568 for value, format in [(tick_duration / DAY, _("%dd")), |
570 ((tick_duration % DAY) / HOUR, _("%dh")), |
569 ((tick_duration % DAY) / HOUR, _("%dh")), |
571 ((tick_duration % HOUR) / MINUTE, _("%dm")), |
570 ((tick_duration % HOUR) / MINUTE, _("%dm")), |
572 ((tick_duration % MINUTE) / SECOND, _("%ds"))]: |
571 ((tick_duration % MINUTE) / SECOND, _("%ds"))]: |
573 |
572 |
574 if value > 0 or not_null: |
573 if value > 0 or not_null: |
575 duration += format % value |
574 duration += format % value |
576 not_null = True |
575 not_null = True |
577 |
576 |
578 duration += _("%03gms") % (float(tick_duration % SECOND) / MILLISECOND) |
577 duration += _("%03gms") % (float(tick_duration % SECOND) / MILLISECOND) |
579 self.TickTimeLabel.SetLabel("t: %s" % duration) |
578 self.TickTimeLabel.SetLabel("t: %s" % duration) |
580 else: |
579 else: |
581 self.TickLabel.SetLabel("") |
580 self.TickLabel.SetLabel("") |
582 self.TickTimeLabel.SetLabel("") |
581 self.TickTimeLabel.SetLabel("") |
583 self.TickSizer.Layout() |
582 self.TickSizer.Layout() |
584 |
583 |
585 def SubscribeAllDataConsumers(self): |
584 def SubscribeAllDataConsumers(self): |
586 DebugViewer.SubscribeAllDataConsumers(self) |
585 DebugViewer.SubscribeAllDataConsumers(self) |
587 |
586 |
588 if self.DataProducer is not None: |
587 if self.DataProducer is not None: |
589 if self.DataProducer is not None: |
588 if self.DataProducer is not None: |
590 self.SetTickTime(self.DataProducer.GetTicktime()) |
589 self.SetTickTime(self.DataProducer.GetTicktime()) |
591 |
590 |
592 self.ResetCursorTick() |
591 self.ResetCursorTick() |
593 |
592 |
594 for panel in self.GraphicPanels[:]: |
593 for panel in self.GraphicPanels[:]: |
595 panel.SubscribeAllDataConsumers() |
594 panel.SubscribeAllDataConsumers() |
596 if panel.ItemsIsEmpty(): |
595 if panel.ItemsIsEmpty(): |
597 if panel.HasCapture(): |
596 if panel.HasCapture(): |
598 panel.ReleaseMouse() |
597 panel.ReleaseMouse() |
599 self.GraphicPanels.remove(panel) |
598 self.GraphicPanels.remove(panel) |
600 panel.Destroy() |
599 panel.Destroy() |
601 |
600 |
602 self.ResetVariableNameMask() |
601 self.ResetVariableNameMask() |
603 self.RefreshGraphicsSizer() |
602 self.RefreshGraphicsSizer() |
604 self.ForceRefresh() |
603 self.ForceRefresh() |
605 |
604 |
606 def ResetView(self): |
605 def ResetView(self): |
607 self.UnsubscribeAllDataConsumers() |
606 self.UnsubscribeAllDataConsumers() |
608 |
607 |
609 self.Fixed = False |
608 self.Fixed = False |
610 for panel in self.GraphicPanels: |
609 for panel in self.GraphicPanels: |
611 panel.Destroy() |
610 panel.Destroy() |
612 self.GraphicPanels = [] |
611 self.GraphicPanels = [] |
613 self.ResetVariableNameMask() |
612 self.ResetVariableNameMask() |
614 self.RefreshGraphicsSizer() |
613 self.RefreshGraphicsSizer() |
615 |
614 |
616 def SetCanvasPosition(self, tick): |
615 def SetCanvasPosition(self, tick): |
617 tick = max(self.Ticks[0], min(tick, self.Ticks[-1] - self.CurrentRange)) |
616 tick = max(self.Ticks[0], min(tick, self.Ticks[-1] - self.CurrentRange)) |
618 self.StartTick = self.Ticks[numpy.argmin(numpy.abs(self.Ticks - tick))] |
617 self.StartTick = self.Ticks[numpy.argmin(numpy.abs(self.Ticks - tick))] |
619 self.Fixed = True |
618 self.Fixed = True |
620 self.RefreshCanvasPosition() |
619 self.RefreshCanvasPosition() |
621 self.ForceRefresh() |
620 self.ForceRefresh() |
622 |
621 |
623 def RefreshCanvasPosition(self): |
622 def RefreshCanvasPosition(self): |
624 if len(self.Ticks) > 0: |
623 if len(self.Ticks) > 0: |
625 pos = int(self.StartTick - self.Ticks[0]) |
624 pos = int(self.StartTick - self.Ticks[0]) |
626 range = int(self.Ticks[-1] - self.Ticks[0]) |
625 range = int(self.Ticks[-1] - self.Ticks[0]) |
627 else: |
626 else: |
628 pos = 0 |
627 pos = 0 |
629 range = 0 |
628 range = 0 |
630 self.CanvasPosition.SetScrollbar(pos, self.CurrentRange, range, self.CurrentRange) |
629 self.CanvasPosition.SetScrollbar(pos, self.CurrentRange, range, self.CurrentRange) |
631 |
630 |
632 def ChangeRange(self, dir, tick=None): |
631 def ChangeRange(self, dir, tick=None): |
633 current_range = self.CurrentRange |
632 current_range = self.CurrentRange |
634 current_range_idx = self.CanvasRange.GetSelection() |
633 current_range_idx = self.CanvasRange.GetSelection() |
635 new_range_idx = max(0, min(current_range_idx + dir, len(RANGE_VALUES) - 1)) |
634 new_range_idx = max(0, min(current_range_idx + dir, len(RANGE_VALUES) - 1)) |
636 if new_range_idx != current_range_idx: |
635 if new_range_idx != current_range_idx: |
642 new_start_tick = min(tick - (tick - self.StartTick) * self.CurrentRange / current_range, |
641 new_start_tick = min(tick - (tick - self.StartTick) * self.CurrentRange / current_range, |
643 self.Ticks[-1] - self.CurrentRange) |
642 self.Ticks[-1] - self.CurrentRange) |
644 self.StartTick = self.Ticks[numpy.argmin(numpy.abs(self.Ticks - new_start_tick))] |
643 self.StartTick = self.Ticks[numpy.argmin(numpy.abs(self.Ticks - new_start_tick))] |
645 self.Fixed = new_start_tick < self.Ticks[-1] - self.CurrentRange |
644 self.Fixed = new_start_tick < self.Ticks[-1] - self.CurrentRange |
646 self.ForceRefresh() |
645 self.ForceRefresh() |
647 |
646 |
648 def RefreshRange(self): |
647 def RefreshRange(self): |
649 if len(self.Ticks) > 0: |
648 if len(self.Ticks) > 0: |
650 if self.Fixed and self.Ticks[-1] - self.Ticks[0] < self.CurrentRange: |
649 if self.Fixed and self.Ticks[-1] - self.Ticks[0] < self.CurrentRange: |
651 self.Fixed = False |
650 self.Fixed = False |
652 if self.Fixed: |
651 if self.Fixed: |
653 self.StartTick = min(self.StartTick, self.Ticks[-1] - self.CurrentRange) |
652 self.StartTick = min(self.StartTick, self.Ticks[-1] - self.CurrentRange) |
654 else: |
653 else: |
655 self.StartTick = max(self.Ticks[0], self.Ticks[-1] - self.CurrentRange) |
654 self.StartTick = max(self.Ticks[0], self.Ticks[-1] - self.CurrentRange) |
656 self.ForceRefresh() |
655 self.ForceRefresh() |
657 |
656 |
658 def OnRangeChanged(self, event): |
657 def OnRangeChanged(self, event): |
659 try: |
658 try: |
660 self.CurrentRange = RANGE_VALUES[self.CanvasRange.GetSelection()][1] / self.Ticktime |
659 self.CurrentRange = RANGE_VALUES[self.CanvasRange.GetSelection()][1] / self.Ticktime |
661 except ValueError, e: |
660 except ValueError, e: |
662 self.CanvasRange.SetValue(str(self.CurrentRange)) |
661 self.CanvasRange.SetValue(str(self.CurrentRange)) |
663 wx.CallAfter(self.RefreshRange) |
662 wx.CallAfter(self.RefreshRange) |
664 event.Skip() |
663 event.Skip() |
665 |
664 |
666 def OnCurrentButton(self, event): |
665 def OnCurrentButton(self, event): |
667 if len(self.Ticks) > 0: |
666 if len(self.Ticks) > 0: |
668 self.StartTick = max(self.Ticks[0], self.Ticks[-1] - self.CurrentRange) |
667 self.StartTick = max(self.Ticks[0], self.Ticks[-1] - self.CurrentRange) |
669 self.ResetCursorTick() |
668 self.ResetCursorTick() |
670 event.Skip() |
669 event.Skip() |
671 |
670 |
672 def CopyDataToClipboard(self, variables): |
671 def CopyDataToClipboard(self, variables): |
673 text = "tick;%s;\n" % ";".join([item.GetVariable() for item, data in variables]) |
672 text = "tick;%s;\n" % ";".join([item.GetVariable() for item, data in variables]) |
674 next_tick = NextTick(variables) |
673 next_tick = NextTick(variables) |
675 while next_tick is not None: |
674 while next_tick is not None: |
676 values = [] |
675 values = [] |
691 else: |
690 else: |
692 values.append("") |
691 values.append("") |
693 text += "%d;%s;\n" % (next_tick, ";".join(values)) |
692 text += "%d;%s;\n" % (next_tick, ";".join(values)) |
694 next_tick = NextTick(variables) |
693 next_tick = NextTick(variables) |
695 self.ParentWindow.SetCopyBuffer(text) |
694 self.ParentWindow.SetCopyBuffer(text) |
696 |
695 |
697 def OnExportGraphButton(self, event): |
696 def OnExportGraphButton(self, event): |
698 items = reduce(lambda x, y: x + y, |
697 items = reduce(lambda x, y: x + y, |
699 [panel.GetItems() for panel in self.GraphicPanels], |
698 [panel.GetItems() for panel in self.GraphicPanels], |
700 []) |
699 []) |
701 variables = [(item, [entry for entry in item.GetData()]) |
700 variables = [(item, [entry for entry in item.GetData()]) |
702 for item in items |
701 for item in items |
703 if item.IsNumVariable()] |
702 if item.IsNumVariable()] |
704 wx.CallAfter(self.CopyDataToClipboard, variables) |
703 wx.CallAfter(self.CopyDataToClipboard, variables) |
705 event.Skip() |
704 event.Skip() |
706 |
705 |
707 def OnPositionChanging(self, event): |
706 def OnPositionChanging(self, event): |
708 if len(self.Ticks) > 0: |
707 if len(self.Ticks) > 0: |
709 self.StartTick = self.Ticks[0] + event.GetPosition() |
708 self.StartTick = self.Ticks[0] + event.GetPosition() |
710 self.Fixed = True |
709 self.Fixed = True |
711 self.ForceRefresh() |
710 self.ForceRefresh() |
712 event.Skip() |
711 event.Skip() |
713 |
712 |
714 def GetRange(self): |
713 def GetRange(self): |
715 return self.StartTick, self.StartTick + self.CurrentRange |
714 return self.StartTick, self.StartTick + self.CurrentRange |
716 |
715 |
717 def GetViewerIndex(self, viewer): |
716 def GetViewerIndex(self, viewer): |
718 if viewer in self.GraphicPanels: |
717 if viewer in self.GraphicPanels: |
719 return self.GraphicPanels.index(viewer) |
718 return self.GraphicPanels.index(viewer) |
720 return None |
719 return None |
721 |
720 |
722 def IsViewerFirst(self, viewer): |
721 def IsViewerFirst(self, viewer): |
723 return viewer == self.GraphicPanels[0] |
722 return viewer == self.GraphicPanels[0] |
724 |
723 |
725 def HighlightPreviousViewer(self, viewer): |
724 def HighlightPreviousViewer(self, viewer): |
726 if self.IsViewerFirst(viewer): |
725 if self.IsViewerFirst(viewer): |
727 return |
726 return |
728 idx = self.GetViewerIndex(viewer) |
727 idx = self.GetViewerIndex(viewer) |
729 if idx is None: |
728 if idx is None: |
730 return |
729 return |
731 self.GraphicPanels[idx-1].SetHighlight(HIGHLIGHT_AFTER) |
730 self.GraphicPanels[idx-1].SetHighlight(HIGHLIGHT_AFTER) |
732 |
731 |
733 def ResetVariableNameMask(self): |
732 def ResetVariableNameMask(self): |
734 items = [] |
733 items = [] |
735 for panel in self.GraphicPanels: |
734 for panel in self.GraphicPanels: |
736 items.extend(panel.GetItems()) |
735 items.extend(panel.GetItems()) |
737 if len(items) > 1: |
736 if len(items) > 1: |
738 self.VariableNameMask = reduce(compute_mask, |
737 self.VariableNameMask = reduce( |
739 [item.GetVariable().split('.') for item in items]) |
738 compute_mask, [item.GetVariable().split('.') for item in items]) |
740 elif len(items) > 0: |
739 elif len(items) > 0: |
741 self.VariableNameMask = items[0].GetVariable().split('.')[:-1] + ['*'] |
740 self.VariableNameMask = items[0].GetVariable().split('.')[:-1] + ['*'] |
742 else: |
741 else: |
743 self.VariableNameMask = [] |
742 self.VariableNameMask = [] |
744 self.MaskLabel.ChangeValue(".".join(self.VariableNameMask)) |
743 self.MaskLabel.ChangeValue(".".join(self.VariableNameMask)) |
745 self.MaskLabel.SetInsertionPoint(self.MaskLabel.GetLastPosition()) |
744 self.MaskLabel.SetInsertionPoint(self.MaskLabel.GetLastPosition()) |
746 |
745 |
747 def GetVariableNameMask(self): |
746 def GetVariableNameMask(self): |
748 return self.VariableNameMask |
747 return self.VariableNameMask |
749 |
748 |
750 def InsertValue(self, iec_path, idx = None, force=False, graph=False): |
749 def InsertValue(self, iec_path, idx=None, force=False, graph=False): |
751 for panel in self.GraphicPanels: |
750 for panel in self.GraphicPanels: |
752 if panel.GetItem(iec_path) is not None: |
751 if panel.GetItem(iec_path) is not None: |
753 if graph and isinstance(panel, DebugVariableTextViewer): |
752 if graph and isinstance(panel, DebugVariableTextViewer): |
754 self.ToggleViewerType(panel) |
753 self.ToggleViewerType(panel) |
755 return |
754 return |
756 if idx is None: |
755 if idx is None: |
757 idx = len(self.GraphicPanels) |
756 idx = len(self.GraphicPanels) |
758 item = DebugVariableItem(self, iec_path, True) |
757 item = DebugVariableItem(self, iec_path, True) |
759 result = self.AddDataConsumer(iec_path.upper(), item, True) |
758 result = self.AddDataConsumer(iec_path.upper(), item, True) |
760 if result is not None or force: |
759 if result is not None or force: |
761 |
760 |
762 self.Freeze() |
761 self.Freeze() |
763 if item.IsNumVariable() and graph: |
762 if item.IsNumVariable() and graph: |
764 panel = DebugVariableGraphicViewer(self.GraphicsWindow, self, [item], GRAPH_PARALLEL) |
763 panel = DebugVariableGraphicViewer(self.GraphicsWindow, self, [item], GRAPH_PARALLEL) |
765 if self.CursorTick is not None: |
764 if self.CursorTick is not None: |
766 panel.SetCursorTick(self.CursorTick) |
765 panel.SetCursorTick(self.CursorTick) |
772 self.GraphicPanels.append(panel) |
771 self.GraphicPanels.append(panel) |
773 self.ResetVariableNameMask() |
772 self.ResetVariableNameMask() |
774 self.RefreshGraphicsSizer() |
773 self.RefreshGraphicsSizer() |
775 self.Thaw() |
774 self.Thaw() |
776 self.ForceRefresh() |
775 self.ForceRefresh() |
777 |
776 |
778 def MoveValue(self, iec_path, idx = None, graph=False): |
777 def MoveValue(self, iec_path, idx=None, graph=False): |
779 if idx is None: |
778 if idx is None: |
780 idx = len(self.GraphicPanels) |
779 idx = len(self.GraphicPanels) |
781 source_panel = None |
780 source_panel = None |
782 item = None |
781 item = None |
783 for panel in self.GraphicPanels: |
782 for panel in self.GraphicPanels: |
785 if item is not None: |
784 if item is not None: |
786 source_panel = panel |
785 source_panel = panel |
787 break |
786 break |
788 if source_panel is not None: |
787 if source_panel is not None: |
789 source_panel_idx = self.GraphicPanels.index(source_panel) |
788 source_panel_idx = self.GraphicPanels.index(source_panel) |
790 |
789 |
791 if (len(source_panel.GetItems()) == 1): |
790 if (len(source_panel.GetItems()) == 1): |
792 |
791 |
793 if source_panel_idx < idx: |
792 if source_panel_idx < idx: |
794 self.GraphicPanels.insert(idx, source_panel) |
793 self.GraphicPanels.insert(idx, source_panel) |
795 self.GraphicPanels.pop(source_panel_idx) |
794 self.GraphicPanels.pop(source_panel_idx) |
796 elif source_panel_idx > idx: |
795 elif source_panel_idx > idx: |
797 self.GraphicPanels.pop(source_panel_idx) |
796 self.GraphicPanels.pop(source_panel_idx) |
798 self.GraphicPanels.insert(idx, source_panel) |
797 self.GraphicPanels.insert(idx, source_panel) |
799 else: |
798 else: |
800 return |
799 return |
801 |
800 |
802 else: |
801 else: |
803 source_panel.RemoveItem(item) |
802 source_panel.RemoveItem(item) |
804 source_size = source_panel.GetSize() |
803 source_size = source_panel.GetSize() |
805 if item.IsNumVariable() and graph: |
804 if item.IsNumVariable() and graph: |
806 panel = DebugVariableGraphicViewer(self.GraphicsWindow, self, [item], GRAPH_PARALLEL) |
805 panel = DebugVariableGraphicViewer(self.GraphicsWindow, self, [item], GRAPH_PARALLEL) |
807 panel.SetCanvasHeight(source_size.height) |
806 panel.SetCanvasHeight(source_size.height) |
808 if self.CursorTick is not None: |
807 if self.CursorTick is not None: |
809 panel.SetCursorTick(self.CursorTick) |
808 panel.SetCursorTick(self.CursorTick) |
810 |
809 |
811 else: |
810 else: |
812 panel = DebugVariableTextViewer(self.GraphicsWindow, self, [item]) |
811 panel = DebugVariableTextViewer(self.GraphicsWindow, self, [item]) |
813 |
812 |
814 self.GraphicPanels.insert(idx, panel) |
813 self.GraphicPanels.insert(idx, panel) |
815 |
814 |
816 if source_panel.ItemsIsEmpty(): |
815 if source_panel.ItemsIsEmpty(): |
817 if source_panel.HasCapture(): |
816 if source_panel.HasCapture(): |
818 source_panel.ReleaseMouse() |
817 source_panel.ReleaseMouse() |
819 source_panel.Destroy() |
818 source_panel.Destroy() |
820 self.GraphicPanels.remove(source_panel) |
819 self.GraphicPanels.remove(source_panel) |
821 |
820 |
822 self.ResetVariableNameMask() |
821 self.ResetVariableNameMask() |
823 self.RefreshGraphicsSizer() |
822 self.RefreshGraphicsSizer() |
824 self.ForceRefresh() |
823 self.ForceRefresh() |
825 |
824 |
826 def MergeGraphs(self, source, target_idx, merge_type, force=False): |
825 def MergeGraphs(self, source, target_idx, merge_type, force=False): |
827 source_item = None |
826 source_item = None |
828 source_panel = None |
827 source_panel = None |
829 for panel in self.GraphicPanels: |
828 for panel in self.GraphicPanels: |
830 source_item = panel.GetItem(source) |
829 source_item = panel.GetItem(source) |
844 source_size = None |
843 source_size = None |
845 target_panel = self.GraphicPanels[target_idx] |
844 target_panel = self.GraphicPanels[target_idx] |
846 graph_type = target_panel.GraphType |
845 graph_type = target_panel.GraphType |
847 if target_panel != source_panel: |
846 if target_panel != source_panel: |
848 if (merge_type == GRAPH_PARALLEL and graph_type != merge_type or |
847 if (merge_type == GRAPH_PARALLEL and graph_type != merge_type or |
849 merge_type == GRAPH_ORTHOGONAL and |
848 merge_type == GRAPH_ORTHOGONAL and |
850 (graph_type == GRAPH_PARALLEL and len(target_panel.Items) > 1 or |
849 (graph_type == GRAPH_PARALLEL and len(target_panel.Items) > 1 or |
851 graph_type == GRAPH_ORTHOGONAL and len(target_panel.Items) >= 3)): |
850 graph_type == GRAPH_ORTHOGONAL and len(target_panel.Items) >= 3)): |
852 return |
851 return |
853 |
852 |
854 if source_panel is not None: |
853 if source_panel is not None: |
855 source_panel.RemoveItem(source_item) |
854 source_panel.RemoveItem(source_item) |
856 if source_panel.ItemsIsEmpty(): |
855 if source_panel.ItemsIsEmpty(): |
857 if source_panel.HasCapture(): |
856 if source_panel.HasCapture(): |
858 source_panel.ReleaseMouse() |
857 source_panel.ReleaseMouse() |
860 self.GraphicPanels.remove(source_panel) |
859 self.GraphicPanels.remove(source_panel) |
861 elif (merge_type != graph_type and len(target_panel.Items) == 2): |
860 elif (merge_type != graph_type and len(target_panel.Items) == 2): |
862 target_panel.RemoveItem(source_item) |
861 target_panel.RemoveItem(source_item) |
863 else: |
862 else: |
864 target_panel = None |
863 target_panel = None |
865 |
864 |
866 if target_panel is not None: |
865 if target_panel is not None: |
867 target_panel.AddItem(source_item) |
866 target_panel.AddItem(source_item) |
868 target_panel.GraphType = merge_type |
867 target_panel.GraphType = merge_type |
869 size = target_panel.GetSize() |
868 size = target_panel.GetSize() |
870 if merge_type == GRAPH_ORTHOGONAL: |
869 if merge_type == GRAPH_ORTHOGONAL: |
872 elif source_size is not None and source_panel != target_panel: |
871 elif source_size is not None and source_panel != target_panel: |
873 target_panel.SetCanvasHeight(size.height + source_size.height) |
872 target_panel.SetCanvasHeight(size.height + source_size.height) |
874 else: |
873 else: |
875 target_panel.SetCanvasHeight(size.height) |
874 target_panel.SetCanvasHeight(size.height) |
876 target_panel.ResetGraphics() |
875 target_panel.ResetGraphics() |
877 |
876 |
878 self.ResetVariableNameMask() |
877 self.ResetVariableNameMask() |
879 self.RefreshGraphicsSizer() |
878 self.RefreshGraphicsSizer() |
880 self.ForceRefresh() |
879 self.ForceRefresh() |
881 |
880 |
882 def DeleteValue(self, source_panel, item=None): |
881 def DeleteValue(self, source_panel, item=None): |
883 source_idx = self.GetViewerIndex(source_panel) |
882 source_idx = self.GetViewerIndex(source_panel) |
884 if source_idx is not None: |
883 if source_idx is not None: |
885 |
884 |
886 if item is None: |
885 if item is None: |
887 source_panel.ClearItems() |
886 source_panel.ClearItems() |
888 source_panel.Destroy() |
887 source_panel.Destroy() |
889 self.GraphicPanels.remove(source_panel) |
888 self.GraphicPanels.remove(source_panel) |
890 self.ResetVariableNameMask() |
889 self.ResetVariableNameMask() |
898 self.RefreshGraphicsSizer() |
897 self.RefreshGraphicsSizer() |
899 if len(self.GraphicPanels) == 0: |
898 if len(self.GraphicPanels) == 0: |
900 self.Fixed = False |
899 self.Fixed = False |
901 self.ResetCursorTick() |
900 self.ResetCursorTick() |
902 self.ForceRefresh() |
901 self.ForceRefresh() |
903 |
902 |
904 def ToggleViewerType(self, panel): |
903 def ToggleViewerType(self, panel): |
905 panel_idx = self.GetViewerIndex(panel) |
904 panel_idx = self.GetViewerIndex(panel) |
906 if panel_idx is not None: |
905 if panel_idx is not None: |
907 self.GraphicPanels.remove(panel) |
906 self.GraphicPanels.remove(panel) |
908 items = panel.GetItems() |
907 items = panel.GetItems() |
914 new_panel = DebugVariableGraphicViewer(self.GraphicsWindow, self, items, GRAPH_PARALLEL) |
913 new_panel = DebugVariableGraphicViewer(self.GraphicsWindow, self, items, GRAPH_PARALLEL) |
915 self.GraphicPanels.insert(panel_idx, new_panel) |
914 self.GraphicPanels.insert(panel_idx, new_panel) |
916 panel.Destroy() |
915 panel.Destroy() |
917 self.RefreshGraphicsSizer() |
916 self.RefreshGraphicsSizer() |
918 self.ForceRefresh() |
917 self.ForceRefresh() |
919 |
918 |
920 def ResetGraphicsValues(self): |
919 def ResetGraphicsValues(self): |
921 self.Ticks = numpy.array([]) |
920 self.Ticks = numpy.array([]) |
922 self.StartTick = 0 |
921 self.StartTick = 0 |
923 for panel in self.GraphicPanels: |
922 for panel in self.GraphicPanels: |
924 panel.ResetItemsData() |
923 panel.ResetItemsData() |
929 window_size = self.GraphicsWindow.GetClientSize() |
928 window_size = self.GraphicsWindow.GetClientSize() |
930 vwidth, vheight = self.GraphicsSizer.GetMinSize() |
929 vwidth, vheight = self.GraphicsSizer.GetMinSize() |
931 posx = max(0, min(xstart, (vwidth - window_size[0]) / SCROLLBAR_UNIT)) |
930 posx = max(0, min(xstart, (vwidth - window_size[0]) / SCROLLBAR_UNIT)) |
932 posy = max(0, min(ystart, (vheight - window_size[1]) / SCROLLBAR_UNIT)) |
931 posy = max(0, min(ystart, (vheight - window_size[1]) / SCROLLBAR_UNIT)) |
933 self.GraphicsWindow.Scroll(posx, posy) |
932 self.GraphicsWindow.Scroll(posx, posy) |
934 self.GraphicsWindow.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, |
933 self.GraphicsWindow.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, |
935 vwidth / SCROLLBAR_UNIT, vheight / SCROLLBAR_UNIT, posx, posy) |
934 vwidth / SCROLLBAR_UNIT, vheight / SCROLLBAR_UNIT, |
936 |
935 posx, posy) |
936 |
|
937 def OnGraphicsWindowEraseBackground(self, event): |
937 def OnGraphicsWindowEraseBackground(self, event): |
938 pass |
938 pass |
939 |
939 |
940 def OnGraphicsWindowPaint(self, event): |
940 def OnGraphicsWindowPaint(self, event): |
941 self.RefreshView() |
941 self.RefreshView() |
942 event.Skip() |
942 event.Skip() |
943 |
943 |
944 def OnGraphicsWindowResize(self, event): |
944 def OnGraphicsWindowResize(self, event): |
945 size = self.GetSize() |
945 size = self.GetSize() |
946 for panel in self.GraphicPanels: |
946 for panel in self.GraphicPanels: |
947 panel_size = panel.GetSize() |
947 panel_size = panel.GetSize() |
948 if (isinstance(panel, DebugVariableGraphicViewer) and |
948 if isinstance(panel, DebugVariableGraphicViewer) and \ |
949 panel.GraphType == GRAPH_ORTHOGONAL and |
949 panel.GraphType == GRAPH_ORTHOGONAL and \ |
950 panel_size.width == panel_size.height): |
950 panel_size.width == panel_size.height: |
951 panel.SetCanvasHeight(size.width) |
951 panel.SetCanvasHeight(size.width) |
952 self.RefreshGraphicsWindowScrollbars() |
952 self.RefreshGraphicsWindowScrollbars() |
953 self.GraphicsSizer.Layout() |
953 self.GraphicsSizer.Layout() |
954 event.Skip() |
954 event.Skip() |
955 |
955 |