changeset 928 | a94e7fea7051 |
parent 927 | bd3e5b65e8be |
child 929 | c562031146e4 |
927:bd3e5b65e8be | 928:a94e7fea7051 |
---|---|
37 import matplotlib.pyplot |
37 import matplotlib.pyplot |
38 from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas |
38 from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas |
39 from matplotlib.backends.backend_wxagg import _convert_agg_to_wx_bitmap |
39 from matplotlib.backends.backend_wxagg import _convert_agg_to_wx_bitmap |
40 from matplotlib.backends.backend_agg import FigureCanvasAgg |
40 from matplotlib.backends.backend_agg import FigureCanvasAgg |
41 from mpl_toolkits.mplot3d import Axes3D |
41 from mpl_toolkits.mplot3d import Axes3D |
42 color_cycle = matplotlib.rcParams['axes.color_cycle'] |
|
42 USE_MPL = True |
43 USE_MPL = True |
43 except: |
44 except: |
44 USE_MPL = False |
45 USE_MPL = False |
45 |
46 |
46 from graphics import DebugDataConsumer, DebugViewer, REFRESH_PERIOD |
47 from graphics import DebugDataConsumer, DebugViewer, REFRESH_PERIOD |
182 if self.Value != value: |
183 if self.Value != value: |
183 self.Value = value |
184 self.Value = value |
184 self.Parent.HasNewData = True |
185 self.Parent.HasNewData = True |
185 |
186 |
186 def GetValue(self, tick=None, raw=False): |
187 def GetValue(self, tick=None, raw=False): |
187 if tick is not None and self.IsNumVariable() and len(self.Data) > 0: |
188 if tick is not None and self.IsNumVariable(): |
188 idx = numpy.argmin(abs(self.Data[:, 0] - tick)) |
189 if len(self.Data) > 0: |
189 if self.VariableType in ["STRING", "WSTRING"]: |
190 idx = numpy.argmin(abs(self.Data[:, 0] - tick)) |
190 value, forced = self.RawData[int(self.Data[idx, 2])] |
191 if self.VariableType in ["STRING", "WSTRING"]: |
191 if not raw: |
192 value, forced = self.RawData[int(self.Data[idx, 2])] |
192 if self.VariableType == "STRING": |
193 if not raw: |
193 value = "'%s'" % value |
194 if self.VariableType == "STRING": |
194 else: |
195 value = "'%s'" % value |
195 value = '"%s"' % value |
196 else: |
196 return value, forced |
197 value = '"%s"' % value |
197 else: |
198 return value, forced |
198 value = self.Data[idx, 1] |
199 else: |
199 if not raw and isinstance(value, FloatType): |
200 value = self.Data[idx, 1] |
200 value = "%.6g" % value |
201 if not raw and isinstance(value, FloatType): |
201 return value, self.IsForced() |
202 value = "%.6g" % value |
203 return value, self.Data[idx, 2] |
|
204 return self.Value, self.IsForced() |
|
202 elif not raw: |
205 elif not raw: |
203 if self.VariableType == "STRING": |
206 if self.VariableType == "STRING": |
204 return "'%s'" % self.Value |
207 return "'%s'" % self.Value |
205 elif self.VariableType == "WSTRING": |
208 elif self.VariableType == "WSTRING": |
206 return '"%s"' % self.Value |
209 return '"%s"' % self.Value |
298 |
301 |
299 def __del__(self): |
302 def __del__(self): |
300 self.ParentWindow = None |
303 self.ParentWindow = None |
301 self.ParentControl = None |
304 self.ParentControl = None |
302 |
305 |
306 def OnDragOver(self, x, y, d): |
|
307 if self.ParentControl is not None: |
|
308 self.ParentControl.OnCanvasDragging(x, y) |
|
309 return wx.TextDropTarget.OnDragOver(self, x, y, d) |
|
310 |
|
303 def OnDropText(self, x, y, data): |
311 def OnDropText(self, x, y, data): |
304 message = None |
312 message = None |
305 try: |
313 try: |
306 values = eval(data) |
314 values = eval(data) |
307 except: |
315 except: |
347 self.ParentWindow.InsertValue(values[0], target_idx, force=True) |
355 self.ParentWindow.InsertValue(values[0], target_idx, force=True) |
348 elif len(values) > 2 and values[2] == "move": |
356 elif len(values) > 2 and values[2] == "move": |
349 self.ParentWindow.MoveGraph(values[0]) |
357 self.ParentWindow.MoveGraph(values[0]) |
350 else: |
358 else: |
351 self.ParentWindow.InsertValue(values[0], force=True) |
359 self.ParentWindow.InsertValue(values[0], force=True) |
352 |
360 |
361 def OnLeave(self): |
|
362 if self.ParentControl is not None: |
|
363 self.ParentControl.OnCanvasLeave() |
|
364 return wx.TextDropTarget.OnLeave(self) |
|
365 |
|
353 def ShowMessage(self, message): |
366 def ShowMessage(self, message): |
354 dialog = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR) |
367 dialog = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR) |
355 dialog.ShowModal() |
368 dialog.ShowModal() |
356 dialog.Destroy() |
369 dialog.Destroy() |
357 |
370 |
406 self.SetBackgroundColour(wx.WHITE) |
419 self.SetBackgroundColour(wx.WHITE) |
407 self.SetDropTarget(DebugVariableDropTarget(window, self)) |
420 self.SetDropTarget(DebugVariableDropTarget(window, self)) |
408 |
421 |
409 self.ParentWindow = window |
422 self.ParentWindow = window |
410 self.Items = items |
423 self.Items = items |
411 self.ResetVariableNameMask() |
|
412 |
424 |
413 self.MainSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=0) |
425 self.MainSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=0) |
414 self.AddViewer() |
426 self.AddViewer() |
415 self.AddButtons() |
427 self.AddButtons() |
416 self.MainSizer.AddGrowableCol(0) |
428 self.MainSizer.AddGrowableCol(0) |
438 if self.GraphType == GRAPH_ORTHOGONAL: |
450 if self.GraphType == GRAPH_ORTHOGONAL: |
439 return tuple(variables) |
451 return tuple(variables) |
440 return variables |
452 return variables |
441 return self.Items[0].GetVariable() |
453 return self.Items[0].GetVariable() |
442 |
454 |
443 def ResetVariableNameMask(self): |
|
444 if len(self.Items) > 1: |
|
445 self.VariableNameMask = reduce(compute_mask, |
|
446 [item.GetVariable().split('.') for item in self.Items]) |
|
447 elif len(self.Items) > 0: |
|
448 self.VariableNameMask = self.Items[0].GetVariable().split('.')[:-1] + ['*'] |
|
449 else: |
|
450 self.VariableNameMask = [] |
|
451 |
|
452 def AddItem(self, item): |
455 def AddItem(self, item): |
453 self.Items.append(item) |
456 self.Items.append(item) |
454 self.ResetVariableNameMask() |
457 |
455 |
|
456 def RemoveItem(self, item): |
458 def RemoveItem(self, item): |
457 if item in self.Items: |
459 if item in self.Items: |
458 self.Items.remove(item) |
460 self.Items.remove(item) |
459 self.ResetVariableNameMask() |
|
460 |
461 |
461 def Clear(self): |
462 def Clear(self): |
462 for item in self.Items: |
463 for item in self.Items: |
463 self.ParentWindow.RemoveDataConsumer(item) |
464 self.ParentWindow.RemoveDataConsumer(item) |
464 self.Items = [] |
465 self.Items = [] |
465 self.ResetVariableNameMask() |
466 |
466 |
|
467 def IsEmpty(self): |
467 def IsEmpty(self): |
468 return len(self.Items) == 0 |
468 return len(self.Items) == 0 |
469 |
469 |
470 def UnregisterObsoleteData(self): |
470 def UnregisterObsoleteData(self): |
471 for item in self.Items[:]: |
471 for item in self.Items[:]: |
474 self.ParentWindow.RemoveDataConsumer(item) |
474 self.ParentWindow.RemoveDataConsumer(item) |
475 self.RemoveItem(item) |
475 self.RemoveItem(item) |
476 else: |
476 else: |
477 self.ParentWindow.AddDataConsumer(iec_path, item) |
477 self.ParentWindow.AddDataConsumer(iec_path, item) |
478 item.RefreshVariableType() |
478 item.RefreshVariableType() |
479 self.ResetVariableNameMask() |
479 |
480 |
|
481 def ResetData(self): |
480 def ResetData(self): |
482 for item in self.Items: |
481 for item in self.Items: |
483 item.ResetData() |
482 item.ResetData() |
484 |
483 |
485 def Refresh(self): |
484 def Refresh(self): |
491 else: |
490 else: |
492 menu = wx.Menu(title='') |
491 menu = wx.Menu(title='') |
493 for item in self.Items: |
492 for item in self.Items: |
494 new_id = wx.NewId() |
493 new_id = wx.NewId() |
495 AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, |
494 AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, |
496 text=item.GetVariable(self.VariableNameMask)) |
495 text=item.GetVariable(self.ParentWindow.GetVariableNameMask())) |
497 self.Bind(wx.EVT_MENU, |
496 self.Bind(wx.EVT_MENU, |
498 self.GetForceVariableMenuFunction(item), |
497 self.GetForceVariableMenuFunction(item), |
499 id=new_id) |
498 id=new_id) |
500 self.PopupMenu(menu) |
499 self.PopupMenu(menu) |
501 event.Skip() |
500 event.Skip() |
506 else: |
505 else: |
507 menu = wx.Menu(title='') |
506 menu = wx.Menu(title='') |
508 for item in self.Items: |
507 for item in self.Items: |
509 new_id = wx.NewId() |
508 new_id = wx.NewId() |
510 AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, |
509 AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, |
511 text=item.GetVariable(self.VariableNameMask)) |
510 text=item.GetVariable(self.ParentWindow.GetVariableNameMask())) |
512 self.Bind(wx.EVT_MENU, |
511 self.Bind(wx.EVT_MENU, |
513 self.GetReleaseVariableMenuFunction(item), |
512 self.GetReleaseVariableMenuFunction(item), |
514 id=new_id) |
513 id=new_id) |
515 |
514 |
516 self.PopupMenu(menu) |
515 self.PopupMenu(menu) |
522 else: |
521 else: |
523 menu = wx.Menu(title='') |
522 menu = wx.Menu(title='') |
524 for item in self.Items: |
523 for item in self.Items: |
525 new_id = wx.NewId() |
524 new_id = wx.NewId() |
526 AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, |
525 AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, |
527 text=item.GetVariable(self.VariableNameMask)) |
526 text=item.GetVariable(self.ParentWindow.GetVariableNameMask())) |
528 self.Bind(wx.EVT_MENU, |
527 self.Bind(wx.EVT_MENU, |
529 self.GetDeleteValueMenuFunction(item), |
528 self.GetDeleteValueMenuFunction(item), |
530 id=new_id) |
529 id=new_id) |
531 |
530 |
532 new_id = wx.NewId() |
531 new_id = wx.NewId() |
617 mask.append(xp) |
616 mask.append(xp) |
618 else: |
617 else: |
619 mask.append("*") |
618 mask.append("*") |
620 return mask |
619 return mask |
621 |
620 |
621 #CANVAS_HIGHLIGHT_TYPES |
|
622 [HIGHLIGHT_NONE, |
|
623 HIGHLIGHT_BEFORE, |
|
624 HIGHLIGHT_AFTER, |
|
625 HIGHLIGHT_LEFT, |
|
626 HIGHLIGHT_RIGHT] = range(5) |
|
627 |
|
628 HIGHLIGHT_PEN = wx.Pen(wx.Colour(0, 128, 255)) |
|
629 HIGHLIGHT_BRUSH = wx.Brush(wx.Colour(0, 128, 255, 128)) |
|
630 |
|
622 class DraggingFigureCanvas(FigureCanvas): |
631 class DraggingFigureCanvas(FigureCanvas): |
623 |
632 |
624 def __init__(self, parent, window, *args, **kwargs): |
633 def __init__(self, parent, window, *args, **kwargs): |
625 FigureCanvas.__init__(self, parent, *args, **kwargs) |
634 FigureCanvas.__init__(self, parent, *args, **kwargs) |
626 |
635 |
627 self.ParentWindow = window |
636 self.ParentWindow = window |
628 |
637 self.Highlight = HIGHLIGHT_NONE |
638 |
|
639 def SetHighlight(self, highlight): |
|
640 if self.Highlight != highlight: |
|
641 self.Highlight = highlight |
|
642 return True |
|
643 return False |
|
644 |
|
645 def GetAxesBoundingBox(self): |
|
646 width, height = self.GetSize() |
|
647 ax, ay, aw, ah = self.figure.gca().get_position().bounds |
|
648 return wx.Rect(ax * width, height - (ay + ah) * height - 1, |
|
649 aw * width + 2, ah * height + 1) |
|
650 |
|
629 def draw(self, drawDC=None): |
651 def draw(self, drawDC=None): |
630 FigureCanvasAgg.draw(self) |
652 FigureCanvasAgg.draw(self) |
631 |
653 |
632 self.bitmap = _convert_agg_to_wx_bitmap(self.get_renderer(), None) |
654 self.bitmap = _convert_agg_to_wx_bitmap(self.get_renderer(), None) |
655 self.bitmap.UseAlpha() |
|
656 width, height = self.GetSize() |
|
657 bbox = self.GetAxesBoundingBox() |
|
658 |
|
659 destDC = wx.MemoryDC() |
|
660 destDC.SelectObject(self.bitmap) |
|
661 |
|
662 destGC = wx.GCDC(destDC) |
|
663 |
|
664 destGC.BeginDrawing() |
|
665 destGC.SetPen(HIGHLIGHT_PEN) |
|
666 destGC.SetBrush(HIGHLIGHT_BRUSH) |
|
667 if self.Highlight == HIGHLIGHT_BEFORE: |
|
668 destGC.DrawLine(0, 0, width - 1, 0) |
|
669 elif self.Highlight == HIGHLIGHT_AFTER: |
|
670 destGC.DrawLine(0, height - 1, width - 1, height - 1) |
|
671 elif self.Highlight == HIGHLIGHT_LEFT: |
|
672 destGC.DrawRectangle(bbox.x, bbox.y, |
|
673 bbox.width / 2, bbox.height) |
|
674 elif self.Highlight == HIGHLIGHT_RIGHT: |
|
675 destGC.DrawRectangle(bbox.x + bbox.width / 2, bbox.y, |
|
676 bbox.width / 2, bbox.height) |
|
677 |
|
633 if self.ParentWindow.IsDragging(): |
678 if self.ParentWindow.IsDragging(): |
634 destBBox = self.ParentWindow.GetDraggingAxesClippingRegion(self.Parent) |
679 destBBox = self.ParentWindow.GetDraggingAxesClippingRegion(self.Parent) |
635 if destBBox.width > 0 and destBBox.height > 0: |
680 if destBBox.width > 0 and destBBox.height > 0: |
636 srcPanel = self.ParentWindow.DraggingAxesPanel |
681 srcPanel = self.ParentWindow.DraggingAxesPanel |
637 srcBBox = srcPanel.GetAxesBoundingBox() |
682 srcBBox = srcPanel.GetAxesBoundingBox() |
647 |
692 |
648 srcBmp = _convert_agg_to_wx_bitmap(srcPanel.Canvas.get_renderer(), None) |
693 srcBmp = _convert_agg_to_wx_bitmap(srcPanel.Canvas.get_renderer(), None) |
649 srcDC = wx.MemoryDC() |
694 srcDC = wx.MemoryDC() |
650 srcDC.SelectObject(srcBmp) |
695 srcDC.SelectObject(srcBmp) |
651 |
696 |
652 destDC = wx.MemoryDC() |
697 destGC.Blit(destBBox.x, destBBox.y, |
653 destDC.SelectObject(self.bitmap) |
|
654 |
|
655 destDC.BeginDrawing() |
|
656 destDC.Blit(destBBox.x, destBBox.y, |
|
657 int(destBBox.width), int(destBBox.height), |
698 int(destBBox.width), int(destBBox.height), |
658 srcDC, srcX, srcY) |
699 srcDC, srcX, srcY) |
659 destDC.EndDrawing() |
|
660 |
700 |
701 destGC.EndDrawing() |
|
702 |
|
661 self._isDrawn = True |
703 self._isDrawn = True |
662 self.gui_repaint(drawDC=drawDC) |
704 self.gui_repaint(drawDC=drawDC) |
663 |
705 |
664 class DebugVariableGraphic(DebugVariableViewer): |
706 class DebugVariableGraphic(DebugVariableViewer): |
665 |
707 |
666 def __init__(self, parent, window, items, graph_type): |
708 def __init__(self, parent, window, items, graph_type): |
667 DebugVariableViewer.__init__(self, parent, window, items) |
709 DebugVariableViewer.__init__(self, parent, window, items) |
668 |
710 |
669 self.GraphType = graph_type |
711 self.GraphType = graph_type |
670 self.CursorTick = None |
712 self.CursorTick = None |
713 self.MouseStartPos = None |
|
714 self.StartCursorTick = None |
|
671 |
715 |
672 self.ResetGraphics() |
716 self.ResetGraphics() |
673 |
717 |
674 def AddViewer(self): |
718 def AddViewer(self): |
675 self.Figure = matplotlib.figure.Figure(facecolor='w') |
719 self.Figure = matplotlib.figure.Figure(facecolor='w') |
676 |
720 |
677 self.Canvas = DraggingFigureCanvas(self, self.ParentWindow, -1, self.Figure) |
721 self.Canvas = DraggingFigureCanvas(self, self.ParentWindow, -1, self.Figure) |
678 self.Canvas.SetMinSize(wx.Size(200, 200)) |
722 self.Canvas.SetMinSize(wx.Size(200, 200)) |
679 self.Canvas.SetDropTarget(DebugVariableDropTarget(self.ParentWindow, self)) |
723 self.Canvas.SetDropTarget(DebugVariableDropTarget(self.ParentWindow, self)) |
680 self.Canvas.Bind(wx.EVT_LEFT_DOWN, self.OnCanvasLeftDown) |
724 self.Canvas.Bind(wx.EVT_LEFT_DOWN, self.OnCanvasLeftDown) |
725 self.Canvas.mpl_connect('button_press_event', self.OnCanvasButtonPressed) |
|
681 self.Canvas.mpl_connect('motion_notify_event', self.OnCanvasMotion) |
726 self.Canvas.mpl_connect('motion_notify_event', self.OnCanvasMotion) |
682 self.Canvas.mpl_connect('button_release_event', self.OnCanvasLeftUp) |
727 self.Canvas.mpl_connect('button_release_event', self.OnCanvasButtonReleased) |
728 self.Canvas.mpl_connect('scroll_event', self.OnCanvasScroll) |
|
683 |
729 |
684 self.MainSizer.AddWindow(self.Canvas, flag=wx.GROW) |
730 self.MainSizer.AddWindow(self.Canvas, flag=wx.GROW) |
685 |
731 |
686 def AddButtons(self): |
732 def AddButtons(self): |
687 button_sizer = wx.BoxSizer(wx.VERTICAL) |
733 button_sizer = wx.BoxSizer(wx.VERTICAL) |
701 setattr(self, name, button) |
747 setattr(self, name, button) |
702 self.Bind(wx.EVT_BUTTON, getattr(self, "On" + name), button) |
748 self.Bind(wx.EVT_BUTTON, getattr(self, "On" + name), button) |
703 button_sizer.AddWindow(button, border=5, flag=wx.LEFT) |
749 button_sizer.AddWindow(button, border=5, flag=wx.LEFT) |
704 |
750 |
705 def GetAxesBoundingBox(self, absolute=False): |
751 def GetAxesBoundingBox(self, absolute=False): |
706 width, height = self.Canvas.GetSize() |
752 bbox = self.Canvas.GetAxesBoundingBox() |
707 ax, ay, aw, ah = self.Axes.get_position().bounds |
|
708 bbox = wx.Rect(ax * width, height - (ay + ah) * height - 1, |
|
709 aw * width + 2, ah * height + 1) |
|
710 if absolute: |
753 if absolute: |
711 xw, yw = self.GetPosition() |
754 xw, yw = self.GetPosition() |
712 bbox.x += xw |
755 bbox.x += xw |
713 bbox.y += yw |
756 bbox.y += yw |
714 return bbox |
757 return bbox |
715 |
758 |
716 def OnCanvasLeftDown(self, event): |
759 def OnCanvasLeftDown(self, event): |
717 x, y = event.GetPosition() |
760 if not self.Is3DCanvas(): |
718 width, height = self.Canvas.GetSize() |
761 x, y = event.GetPosition() |
719 if len(self.Items) == 1: |
762 width, height = self.Canvas.GetSize() |
720 rect = self.GetAxesBoundingBox() |
763 rect = self.GetAxesBoundingBox() |
721 if rect.InsideXY(x, y): |
764 if rect.InsideXY(x, y): |
722 xw, yw = self.GetPosition() |
765 self.MouseStartPos = wx.Point(x, y) |
723 self.ParentWindow.StartDragNDrop(self, x + xw, y + yw) |
766 if self.Legend is not None: |
724 return |
767 item_idx = None |
725 elif self.Legend is not None: |
768 for i, t in enumerate(self.Legend.get_texts()): |
726 item_idx = None |
769 (x0, y0), (x1, y1) = t.get_window_extent().get_points() |
727 for i, t in enumerate(self.Legend.get_texts()): |
770 rect = wx.Rect(x0, height - y1, x1 - x0, y1 - y0) |
728 (x0, y0), (x1, y1) = t.get_window_extent().get_points() |
771 if rect.InsideXY(x, y): |
729 rect = wx.Rect(x0, height - y1, x1 - x0, y1 - y0) |
772 item_idx = i |
730 if rect.InsideXY(x, y): |
773 break |
731 item_idx = i |
774 if item_idx is not None: |
732 break |
775 self.DoDragDrop(item_idx) |
733 if item_idx is not None: |
776 return |
734 self.DoDragDrop(item_idx) |
|
735 return |
|
736 event.Skip() |
777 event.Skip() |
737 |
778 |
738 def OnCanvasLeftUp(self, event): |
779 def OnCanvasButtonPressed(self, event): |
780 if not self.Is3DCanvas(): |
|
781 if event.button == 1: |
|
782 self.HandleCursorMove(event) |
|
783 elif event.button == 2 and self.GraphType == GRAPH_PARALLEL: |
|
784 width, height = self.Canvas.GetSize() |
|
785 start_tick, end_tick = self.ParentWindow.GetRange() |
|
786 self.MouseStartPos = wx.Point(event.x, height - event.y) |
|
787 self.StartCursorTick = start_tick |
|
788 |
|
789 def OnCanvasButtonReleased(self, event): |
|
739 if self.ParentWindow.IsDragging(): |
790 if self.ParentWindow.IsDragging(): |
740 width, height = self.Canvas.GetSize() |
791 width, height = self.Canvas.GetSize() |
741 xw, yw = self.GetPosition() |
792 xw, yw = self.GetPosition() |
742 self.ParentWindow.StopDragNDrop( |
793 self.ParentWindow.StopDragNDrop( |
743 self.Items[0].GetVariable(), |
794 self.Items[0].GetVariable(), |
744 xw + event.x, |
795 xw + event.x, |
745 yw + height - event.y) |
796 yw + height - event.y) |
746 |
797 else: |
747 def DoDragDrop(self, item_idx): |
798 self.MouseStartPos = None |
748 self.ParentWindow.ResetCursorTickRatio() |
799 self.StartCursorTick = None |
749 data = wx.TextDataObject(str((self.Items[item_idx].GetVariable(), "debug", "move"))) |
|
750 dragSource = wx.DropSource(self.Canvas) |
|
751 dragSource.SetData(data) |
|
752 dragSource.DoDragDrop() |
|
753 |
|
754 def OnAxesMotion(self, event): |
|
755 if self.Is3DCanvas(): |
|
756 current_time = gettime() |
|
757 if current_time - self.LastMotionTime > REFRESH_PERIOD: |
|
758 self.LastMotionTime = current_time |
|
759 Axes3D._on_move(self.Axes, event) |
|
760 |
800 |
761 def OnCanvasMotion(self, event): |
801 def OnCanvasMotion(self, event): |
762 if self.ParentWindow.IsDragging(): |
802 if self.ParentWindow.IsDragging(): |
763 width, height = self.Canvas.GetSize() |
803 width, height = self.Canvas.GetSize() |
764 xw, yw = self.GetPosition() |
804 xw, yw = self.GetPosition() |
765 self.ParentWindow.MoveDragNDrop( |
805 self.ParentWindow.MoveDragNDrop( |
766 xw + event.x, |
806 xw + event.x, |
767 yw + height - event.y) |
807 yw + height - event.y) |
768 elif not self.Is3DCanvas(): |
808 elif not self.Is3DCanvas(): |
769 if event.inaxes == self.Axes: |
809 if event.button == 1: |
810 if event.inaxes == self.Axes: |
|
811 if self.MouseStartPos is not None: |
|
812 self.HandleCursorMove(event) |
|
813 elif self.MouseStartPos is not None: |
|
814 xw, yw = self.GetPosition() |
|
815 width, height = self.Canvas.GetSize() |
|
816 self.ParentWindow.StartDragNDrop(self, |
|
817 event.x + xw, height - event.y + yw, |
|
818 self.MouseStartPos.x + xw, self.MouseStartPos.y + yw) |
|
819 elif event.button == 2 and self.GraphType == GRAPH_PARALLEL: |
|
770 start_tick, end_tick = self.ParentWindow.GetRange() |
820 start_tick, end_tick = self.ParentWindow.GetRange() |
771 cursor_tick_ratio = None |
821 rect = self.GetAxesBoundingBox() |
772 if self.GraphType == GRAPH_ORTHOGONAL: |
822 self.ParentWindow.SetCanvasPosition( |
773 x_data = self.Items[0].GetData(start_tick, end_tick) |
823 self.StartCursorTick + (self.MouseStartPos.x - event.x) * |
774 y_data = self.Items[1].GetData(start_tick, end_tick) |
824 (end_tick - start_tick) / rect.width) |
775 if len(x_data) > 0 and len(y_data) > 0: |
825 |
776 length = min(len(x_data), len(y_data)) |
826 def OnCanvasDragging(self, x, y, refresh=True): |
777 d = numpy.sqrt((x_data[:length,1]-event.xdata) ** 2 + (y_data[:length,1]-event.ydata) ** 2) |
827 width, height = self.Canvas.GetSize() |
778 cursor_tick_ratio = float(x_data[numpy.argmin(d), 0] - start_tick) / (end_tick - start_tick) |
828 bbox = self.Canvas.GetAxesBoundingBox() |
779 else: |
829 if bbox.InsideXY(x, y): |
780 data = self.Items[0].GetData(start_tick, end_tick) |
830 rect = wx.Rect(bbox.x, bbox.y, bbox.width / 2, bbox.height) |
781 if len(data) > 0: |
831 if rect.InsideXY(x, y): |
782 x_min, x_max = self.Axes.get_xlim() |
832 self.Canvas.SetHighlight(HIGHLIGHT_LEFT) |
783 cursor_tick_ratio = float(event.xdata - x_min) / (x_max - x_min) |
|
784 if cursor_tick_ratio is not None: |
|
785 self.ParentWindow.SetCursorTickRatio(cursor_tick_ratio) |
|
786 else: |
833 else: |
787 self.ParentWindow.ResetCursorTickRatio() |
834 self.Canvas.SetHighlight(HIGHLIGHT_RIGHT) |
835 elif y < height / 2: |
|
836 self.Canvas.SetHighlight(HIGHLIGHT_BEFORE) |
|
837 else: |
|
838 self.Canvas.SetHighlight(HIGHLIGHT_AFTER) |
|
839 if refresh: |
|
840 self.ParentWindow.ForceRefresh() |
|
841 |
|
842 def OnCanvasLeave(self, refresh=True): |
|
843 self.Canvas.SetHighlight(HIGHLIGHT_NONE) |
|
844 if refresh: |
|
845 self.ParentWindow.ForceRefresh() |
|
846 |
|
847 def OnCanvasScroll(self, event): |
|
848 if event.inaxes is not None: |
|
849 if self.GraphType == GRAPH_ORTHOGONAL: |
|
850 start_tick, end_tick = self.ParentWindow.GetRange() |
|
851 tick = (start_tick + end_tick) / 2. |
|
852 else: |
|
853 tick = event.xdata |
|
854 self.ParentWindow.ChangeRange(int(-event.step) / 3, tick) |
|
855 |
|
856 def HandleCursorMove(self, event): |
|
857 start_tick, end_tick = self.ParentWindow.GetRange() |
|
858 cursor_tick = None |
|
859 if self.GraphType == GRAPH_ORTHOGONAL: |
|
860 x_data = self.Items[0].GetData(start_tick, end_tick) |
|
861 y_data = self.Items[1].GetData(start_tick, end_tick) |
|
862 if len(x_data) > 0 and len(y_data) > 0: |
|
863 length = min(len(x_data), len(y_data)) |
|
864 d = numpy.sqrt((x_data[:length,1]-event.xdata) ** 2 + (y_data[:length,1]-event.ydata) ** 2) |
|
865 cursor_tick = x_data[numpy.argmin(d), 0] |
|
866 else: |
|
867 data = self.Items[0].GetData(start_tick, end_tick) |
|
868 if len(data) > 0: |
|
869 cursor_tick = data[numpy.argmin(numpy.abs(data[:,0] - event.xdata)), 0] |
|
870 if cursor_tick is not None: |
|
871 self.ParentWindow.SetCursorTick(cursor_tick) |
|
872 |
|
873 def DoDragDrop(self, item_idx): |
|
874 data = wx.TextDataObject(str((self.Items[item_idx].GetVariable(), "debug", "move"))) |
|
875 dragSource = wx.DropSource(self.Canvas) |
|
876 dragSource.SetData(data) |
|
877 dragSource.DoDragDrop() |
|
878 |
|
879 def OnAxesMotion(self, event): |
|
880 if self.Is3DCanvas(): |
|
881 current_time = gettime() |
|
882 if current_time - self.LastMotionTime > REFRESH_PERIOD: |
|
883 self.LastMotionTime = current_time |
|
884 Axes3D._on_move(self.Axes, event) |
|
788 |
885 |
789 def OnSplitButton(self, event): |
886 def OnSplitButton(self, event): |
790 if len(self.Items) == 2 or self.GraphType == GRAPH_ORTHOGONAL: |
887 if len(self.Items) == 2 or self.GraphType == GRAPH_ORTHOGONAL: |
791 wx.CallAfter(self.ParentWindow.SplitGraphs, self) |
888 wx.CallAfter(self.ParentWindow.SplitGraphs, self) |
792 else: |
889 else: |
793 menu = wx.Menu(title='') |
890 menu = wx.Menu(title='') |
794 for item in self.Items: |
891 for item in self.Items: |
795 new_id = wx.NewId() |
892 new_id = wx.NewId() |
796 AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, |
893 AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, |
797 text=item.GetVariable(self.VariableNameMask)) |
894 text=item.GetVariable(self.ParentWindow.GetVariableNameMask())) |
798 self.Bind(wx.EVT_MENU, |
895 self.Bind(wx.EVT_MENU, |
799 self.GetSplitGraphMenuFunction(item), |
896 self.GetSplitGraphMenuFunction(item), |
800 id=new_id) |
897 id=new_id) |
801 |
898 |
802 new_id = wx.NewId() |
899 new_id = wx.NewId() |
814 self.LastMotionTime = gettime() |
911 self.LastMotionTime = gettime() |
815 setattr(self.Axes, "_on_move", self.OnAxesMotion) |
912 setattr(self.Axes, "_on_move", self.OnAxesMotion) |
816 self.Axes.mouse_init() |
913 self.Axes.mouse_init() |
817 else: |
914 else: |
818 self.Axes = self.Figure.gca() |
915 self.Axes = self.Figure.gca() |
916 self.Figure.subplotpars.update(top=0.95) |
|
819 if self.GraphType == GRAPH_ORTHOGONAL: |
917 if self.GraphType == GRAPH_ORTHOGONAL: |
820 self.Figure.subplotpars.update(bottom=0.15) |
918 self.Figure.subplotpars.update(bottom=0.15) |
821 self.Axes.set_title('.'.join(self.VariableNameMask)) |
|
822 self.Plots = [] |
919 self.Plots = [] |
823 self.VLine = None |
920 self.VLine = None |
824 self.HLine = None |
921 self.HLine = None |
825 self.TickLabel = None |
922 self.Legend = None |
923 self.Labels = [] |
|
924 if self.GraphType == GRAPH_PARALLEL: |
|
925 num_item = len(self.Items) |
|
926 for idx in xrange(num_item): |
|
927 self.Labels.append( |
|
928 self.Axes.text(0.95, 0.05 + (num_item - idx - 1) * 0.1, |
|
929 "", size = 'large', |
|
930 horizontalalignment='right', |
|
931 color = color_cycle[idx % len(color_cycle)], |
|
932 transform = self.Axes.transAxes)) |
|
826 self.SplitButton.Enable(len(self.Items) > 1) |
933 self.SplitButton.Enable(len(self.Items) > 1) |
827 |
934 |
828 def AddItem(self, item): |
935 def AddItem(self, item): |
829 DebugVariableViewer.AddItem(self, item) |
936 DebugVariableViewer.AddItem(self, item) |
830 self.ResetGraphics() |
937 self.ResetGraphics() |
831 |
938 |
832 def RemoveItem(self, item): |
939 def RemoveItem(self, item): |
833 DebugVariableViewer.RemoveItem(self, item) |
940 DebugVariableViewer.RemoveItem(self, item) |
834 if not self.IsEmpty(): |
941 if not self.IsEmpty(): |
835 self.ResetVariableNameMask() |
|
836 self.ResetGraphics() |
942 self.ResetGraphics() |
837 |
943 |
838 def UnregisterObsoleteData(self): |
944 def UnregisterObsoleteData(self): |
839 DebugVariableViewer.UnregisterObsoleteData(self) |
945 DebugVariableViewer.UnregisterObsoleteData(self) |
840 if not self.IsEmpty(): |
946 if not self.IsEmpty(): |
841 self.ResetVariableNameMask() |
|
842 self.ResetGraphics() |
947 self.ResetGraphics() |
843 |
948 |
844 def Is3DCanvas(self): |
949 def Is3DCanvas(self): |
845 return self.GraphType == GRAPH_ORTHOGONAL and len(self.Items) == 3 |
950 return self.GraphType == GRAPH_ORTHOGONAL and len(self.Items) == 3 |
846 |
951 |
881 y_center = 0.5 |
986 y_center = 0.5 |
882 y_range = 1.0 |
987 y_range = 1.0 |
883 x_min, x_max = start_tick, end_tick |
988 x_min, x_max = start_tick, end_tick |
884 y_min, y_max = y_center - y_range * 0.55, y_center + y_range * 0.55 |
989 y_min, y_max = y_center - y_range * 0.55, y_center + y_range * 0.55 |
885 |
990 |
886 if self.CursorTick is not None: |
991 if self.CursorTick is not None and start_tick <= self.CursorTick <= end_tick: |
887 if self.VLine is None: |
992 if self.VLine is None: |
888 self.VLine = self.Axes.axvline(self.CursorTick, color='r') |
993 self.VLine = self.Axes.axvline(self.CursorTick, color='r') |
889 else: |
994 else: |
890 self.VLine.set_xdata((self.CursorTick, self.CursorTick)) |
995 self.VLine.set_xdata((self.CursorTick, self.CursorTick)) |
891 self.VLine.set_visible(True) |
996 self.VLine.set_visible(True) |
892 tick_label = self.ParentWindow.GetTickLabel(self.CursorTick) |
|
893 if self.TickLabel is None: |
|
894 self.TickLabel = self.Axes.text(0.5, 0.05, tick_label, |
|
895 size = 'small', transform = self.Axes.transAxes) |
|
896 else: |
|
897 self.TickLabel.set_text(tick_label) |
|
898 else: |
997 else: |
899 if self.VLine is not None: |
998 if self.VLine is not None: |
900 self.VLine.set_visible(False) |
999 self.VLine.set_visible(False) |
901 if self.TickLabel is not None: |
|
902 self.TickLabel.set_text("") |
|
903 else: |
1000 else: |
904 min_start_tick = reduce(max, [item.GetData()[0, 0] |
1001 min_start_tick = reduce(max, [item.GetData()[0, 0] |
905 for item in self.Items |
1002 for item in self.Items |
906 if len(item.GetData()) > 0], 0) |
1003 if len(item.GetData()) > 0], 0) |
907 start_tick = max(start_tick, min_start_tick) |
1004 start_tick = max(start_tick, min_start_tick) |
923 else: |
1020 else: |
924 self.Plots[0].set_data( |
1021 self.Plots[0].set_data( |
925 x_data[:, 1][:length], |
1022 x_data[:, 1][:length], |
926 y_data[:, 1][:length]) |
1023 y_data[:, 1][:length]) |
927 |
1024 |
928 if self.CursorTick is not None: |
1025 if self.CursorTick is not None and start_tick <= self.CursorTick <= end_tick: |
929 if self.VLine is None: |
1026 if self.VLine is None: |
930 self.VLine = self.Axes.axvline(x_cursor, color='r') |
1027 self.VLine = self.Axes.axvline(x_cursor, color='r') |
931 else: |
1028 else: |
932 self.VLine.set_xdata((x_cursor, x_cursor)) |
1029 self.VLine.set_xdata((x_cursor, x_cursor)) |
933 if self.HLine is None: |
1030 if self.HLine is None: |
934 self.HLine = self.Axes.axhline(y_cursor, color='r') |
1031 self.HLine = self.Axes.axhline(y_cursor, color='r') |
935 else: |
1032 else: |
936 self.HLine.set_ydata((y_cursor, y_cursor)) |
1033 self.HLine.set_ydata((y_cursor, y_cursor)) |
937 self.VLine.set_visible(True) |
1034 self.VLine.set_visible(True) |
938 self.HLine.set_visible(True) |
1035 self.HLine.set_visible(True) |
939 tick_label = self.ParentWindow.GetTickLabel(self.CursorTick) |
|
940 if self.TickLabel is None: |
|
941 self.TickLabel = self.Axes.text(0.05, 0.90, tick_label, |
|
942 size = 'small', transform = self.Axes.transAxes) |
|
943 else: |
|
944 self.TickLabel.set_text(tick_label) |
|
945 else: |
1036 else: |
946 if self.VLine is not None: |
1037 if self.VLine is not None: |
947 self.VLine.set_visible(False) |
1038 self.VLine.set_visible(False) |
948 if self.HLine is not None: |
1039 if self.HLine is not None: |
949 self.HLine.set_visible(False) |
1040 self.HLine.set_visible(False) |
950 if self.TickLabel is not None: |
|
951 self.TickLabel.set_text("") |
|
952 else: |
1041 else: |
953 while len(self.Axes.lines) > 0: |
1042 while len(self.Axes.lines) > 0: |
954 self.Axes.lines.pop() |
1043 self.Axes.lines.pop() |
955 z_data, z_min, z_max = OrthogonalData(self.Items[2], start_tick, end_tick) |
1044 z_data, z_min, z_max = OrthogonalData(self.Items[2], start_tick, end_tick) |
956 if self.CursorTick is not None: |
1045 if self.CursorTick is not None: |
959 length = min(length, len(z_data)) |
1048 length = min(length, len(z_data)) |
960 self.Axes.plot(x_data[:, 1][:length], |
1049 self.Axes.plot(x_data[:, 1][:length], |
961 y_data[:, 1][:length], |
1050 y_data[:, 1][:length], |
962 zs = z_data[:, 1][:length]) |
1051 zs = z_data[:, 1][:length]) |
963 self.Axes.set_zlim(z_min, z_max) |
1052 self.Axes.set_zlim(z_min, z_max) |
964 if self.CursorTick is not None: |
1053 if self.CursorTick is not None and start_tick <= self.CursorTick <= end_tick: |
965 for kwargs in [{"xs": numpy.array([x_min, x_max])}, |
1054 for kwargs in [{"xs": numpy.array([x_min, x_max])}, |
966 {"ys": numpy.array([y_min, y_max])}, |
1055 {"ys": numpy.array([y_min, y_max])}, |
967 {"zs": numpy.array([z_min, z_max])}]: |
1056 {"zs": numpy.array([z_min, z_max])}]: |
968 for param, value in [("xs", numpy.array([x_cursor, x_cursor])), |
1057 for param, value in [("xs", numpy.array([x_cursor, x_cursor])), |
969 ("ys", numpy.array([y_cursor, y_cursor])), |
1058 ("ys", numpy.array([y_cursor, y_cursor])), |
973 self.Axes.plot(**kwargs) |
1062 self.Axes.plot(**kwargs) |
974 |
1063 |
975 self.Axes.set_xlim(x_min, x_max) |
1064 self.Axes.set_xlim(x_min, x_max) |
976 self.Axes.set_ylim(y_min, y_max) |
1065 self.Axes.set_ylim(y_min, y_max) |
977 |
1066 |
1067 variable_name_mask = self.ParentWindow.GetVariableNameMask() |
|
978 if self.CursorTick is not None: |
1068 if self.CursorTick is not None: |
979 values, forced = apply(zip, [item.GetValue(self.CursorTick) for item in self.Items]) |
1069 values, forced = apply(zip, [item.GetValue(self.CursorTick) for item in self.Items]) |
980 else: |
1070 else: |
981 values, forced = apply(zip, [(item.GetValue(), item.IsForced()) for item in self.Items]) |
1071 values, forced = apply(zip, [(item.GetValue(), item.IsForced()) for item in self.Items]) |
982 names = [item.GetVariable(self.VariableNameMask) for item in self.Items] |
1072 names = [item.GetVariable(variable_name_mask) for item in self.Items] |
983 labels = map(lambda x: "%s: %s" % x, zip(names, values)) |
1073 labels = map(lambda x: "%s: %s" % x, zip(names, values)) |
984 colors = map(lambda x: {True: 'b', False: 'k'}[x], forced) |
1074 colors = map(lambda x: {True: 'b', False: 'k'}[x], forced) |
985 if self.GraphType == GRAPH_PARALLEL: |
1075 if self.GraphType == GRAPH_PARALLEL: |
986 self.Legend = self.Axes.legend(self.Plots, labels, |
1076 if self.Legend is None: |
987 loc="upper left", frameon=False, |
1077 self.Legend = self.Axes.legend(self.Plots, labels, |
988 prop={'size':'small'}) |
1078 loc="upper left", frameon=False, prop={'size':'small'}, |
1079 title = '.'.join(variable_name_mask)) |
|
1080 self.Legend.get_title().set_fontsize('small') |
|
989 for t, color in zip(self.Legend.get_texts(), colors): |
1081 for t, color in zip(self.Legend.get_texts(), colors): |
990 t.set_color(color) |
1082 t.set_color(color) |
1083 for label, value in zip(self.Labels, values): |
|
1084 label.set_text(value) |
|
991 else: |
1085 else: |
992 self.Legend = None |
1086 self.Legend = None |
993 self.Axes.set_xlabel(labels[0], fontdict={'size':'small','color':colors[0]}) |
1087 self.Axes.set_xlabel(labels[0], fontdict={'size':'small','color':colors[0]}) |
994 self.Axes.set_ylabel(labels[1], fontdict={'size':'small','color':colors[1]}) |
1088 self.Axes.set_ylabel(labels[1], fontdict={'size':'small','color':colors[1]}) |
995 if len(labels) > 2: |
1089 if len(labels) > 2: |
1006 |
1100 |
1007 class DebugVariablePanel(wx.Panel, DebugViewer): |
1101 class DebugVariablePanel(wx.Panel, DebugViewer): |
1008 |
1102 |
1009 def __init__(self, parent, producer, window): |
1103 def __init__(self, parent, producer, window): |
1010 wx.Panel.__init__(self, parent, style=wx.SP_3D|wx.TAB_TRAVERSAL) |
1104 wx.Panel.__init__(self, parent, style=wx.SP_3D|wx.TAB_TRAVERSAL) |
1105 self.SetBackgroundColour(wx.WHITE) |
|
1011 |
1106 |
1012 self.ParentWindow = window |
1107 self.ParentWindow = window |
1013 |
1108 |
1014 DebugViewer.__init__(self, producer, True) |
1109 DebugViewer.__init__(self, producer, True) |
1015 |
1110 |
1021 self.Ticks = numpy.array([]) |
1116 self.Ticks = numpy.array([]) |
1022 self.RangeValues = None |
1117 self.RangeValues = None |
1023 self.StartTick = 0 |
1118 self.StartTick = 0 |
1024 self.Fixed = False |
1119 self.Fixed = False |
1025 self.Force = False |
1120 self.Force = False |
1026 self.CursorTickRatio = None |
1121 self.CursorTick = None |
1027 self.DraggingAxesPanel = None |
1122 self.DraggingAxesPanel = None |
1028 self.DraggingAxesBoundingBox = None |
1123 self.DraggingAxesBoundingBox = None |
1029 self.DraggingAxesMousePos = None |
1124 self.DraggingAxesMousePos = None |
1125 self.VariableNameMask = None |
|
1030 |
1126 |
1031 self.GraphicPanels = [] |
1127 self.GraphicPanels = [] |
1032 |
1128 |
1033 graphics_button_sizer = wx.BoxSizer(wx.HORIZONTAL) |
1129 graphics_button_sizer = wx.BoxSizer(wx.HORIZONTAL) |
1034 main_sizer.AddSizer(graphics_button_sizer, border=5, flag=wx.GROW|wx.ALL) |
1130 main_sizer.AddSizer(graphics_button_sizer, border=5, flag=wx.GROW|wx.ALL) |
1065 self.OnPositionChanging, self.CanvasPosition) |
1161 self.OnPositionChanging, self.CanvasPosition) |
1066 self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEDOWN, |
1162 self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEDOWN, |
1067 self.OnPositionChanging, self.CanvasPosition) |
1163 self.OnPositionChanging, self.CanvasPosition) |
1068 main_sizer.AddWindow(self.CanvasPosition, border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM) |
1164 main_sizer.AddWindow(self.CanvasPosition, border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM) |
1069 |
1165 |
1166 self.TickSizer = wx.BoxSizer(wx.HORIZONTAL) |
|
1167 main_sizer.AddSizer(self.TickSizer, border=5, flag=wx.ALL|wx.GROW) |
|
1168 |
|
1169 self.TickLabel = wx.StaticText(self) |
|
1170 self.TickSizer.AddWindow(self.TickLabel, 1, border=5, flag=wx.RIGHT|wx.GROW) |
|
1171 |
|
1172 self.TickTimeLabel = wx.StaticText(self) |
|
1173 self.TickSizer.AddWindow(self.TickTimeLabel) |
|
1174 |
|
1070 self.GraphicsWindow = wx.ScrolledWindow(self, style=wx.HSCROLL|wx.VSCROLL) |
1175 self.GraphicsWindow = wx.ScrolledWindow(self, style=wx.HSCROLL|wx.VSCROLL) |
1176 self.GraphicsWindow.SetBackgroundColour(wx.WHITE) |
|
1071 self.GraphicsWindow.SetDropTarget(DebugVariableDropTarget(self)) |
1177 self.GraphicsWindow.SetDropTarget(DebugVariableDropTarget(self)) |
1072 self.GraphicsWindow.Bind(wx.EVT_SIZE, self.OnGraphicsWindowResize) |
1178 self.GraphicsWindow.Bind(wx.EVT_SIZE, self.OnGraphicsWindowResize) |
1073 main_sizer.AddWindow(self.GraphicsWindow, 1, flag=wx.GROW) |
1179 main_sizer.AddWindow(self.GraphicsWindow, 1, flag=wx.GROW) |
1074 |
1180 |
1075 self.GraphicsSizer = wx.BoxSizer(wx.VERTICAL) |
1181 self.GraphicsSizer = wx.BoxSizer(wx.VERTICAL) |
1165 if len(self.Ticks) == 0: |
1271 if len(self.Ticks) == 0: |
1166 self.StartTick = tick |
1272 self.StartTick = tick |
1167 self.Ticks = numpy.append(self.Ticks, [tick]) |
1273 self.Ticks = numpy.append(self.Ticks, [tick]) |
1168 if not self.Fixed or tick < self.StartTick + self.CurrentRange: |
1274 if not self.Fixed or tick < self.StartTick + self.CurrentRange: |
1169 self.StartTick = max(self.StartTick, tick - self.CurrentRange) |
1275 self.StartTick = max(self.StartTick, tick - self.CurrentRange) |
1170 self.ResetCursorTick(False) |
1276 if self.Fixed and self.Ticks[-1] - self.Ticks[0] < self.CurrentRange: |
1277 self.Force = True |
|
1171 DebugViewer.NewDataAvailable(self, tick, *args, **kwargs) |
1278 DebugViewer.NewDataAvailable(self, tick, *args, **kwargs) |
1172 |
1279 |
1173 def ForceRefresh(self): |
1280 def ForceRefresh(self): |
1174 self.Force = True |
1281 self.Force = True |
1175 wx.CallAfter(self.NewDataAvailable, None, True) |
1282 wx.CallAfter(self.NewDataAvailable, None, True) |
1181 self.GraphicsSizer.AddWindow(panel, flag=wx.GROW) |
1288 self.GraphicsSizer.AddWindow(panel, flag=wx.GROW) |
1182 |
1289 |
1183 self.GraphicsSizer.Layout() |
1290 self.GraphicsSizer.Layout() |
1184 self.RefreshGraphicsWindowScrollbars() |
1291 self.RefreshGraphicsWindowScrollbars() |
1185 |
1292 |
1186 def SetCursorTickRatio(self, cursor_tick_ratio): |
1293 def SetCanvasPosition(self, tick): |
1187 self.CursorTickRatio = cursor_tick_ratio |
1294 tick = max(self.Ticks[0], min(tick, self.Ticks[-1] - self.CurrentRange)) |
1295 self.StartTick = self.Ticks[numpy.argmin(numpy.abs(self.Ticks - tick))] |
|
1296 self.Fixed = True |
|
1297 self.RefreshCanvasPosition() |
|
1298 self.ForceRefresh() |
|
1299 |
|
1300 def SetCursorTick(self, cursor_tick): |
|
1301 self.CursorTick = cursor_tick |
|
1302 self.Fixed = True |
|
1188 self.ResetCursorTick() |
1303 self.ResetCursorTick() |
1189 |
1304 |
1190 def ResetCursorTickRatio(self): |
1305 def ResetCursorTick(self): |
1191 self.CursorTickRatio = None |
1306 self.CursorTick = None |
1192 self.ResetCursorTick() |
1307 self.ResetCursorTick() |
1193 |
1308 |
1194 def ResetCursorTick(self, force_refresh=True): |
1309 def ResetCursorTick(self): |
1195 if self.CursorTickRatio is not None and len(self.Ticks) > 0: |
|
1196 raw_tick = self.StartTick + self.CursorTickRatio * self.CurrentRange |
|
1197 cursor_tick = self.Ticks[numpy.argmin(abs(self.Ticks - raw_tick))] |
|
1198 else: |
|
1199 cursor_tick = None |
|
1200 for panel in self.GraphicPanels: |
1310 for panel in self.GraphicPanels: |
1201 if isinstance(panel, DebugVariableGraphic): |
1311 if isinstance(panel, DebugVariableGraphic): |
1202 panel.SetCursorTick(cursor_tick) |
1312 panel.SetCursorTick(self.CursorTick) |
1203 if force_refresh: |
1313 self.ForceRefresh() |
1204 self.ForceRefresh() |
1314 |
1205 |
1315 def StartDragNDrop(self, panel, x_mouse, y_mouse, x_mouse_start, y_mouse_start): |
1206 def GetTickLabel(self, tick): |
|
1207 label = "Tick: %d" % tick |
|
1208 if self.Ticktime > 0: |
|
1209 tick_duration = int(tick * self.Ticktime) |
|
1210 not_null = False |
|
1211 duration = "" |
|
1212 for value, format in [(tick_duration / DAY, "%dd"), |
|
1213 ((tick_duration % DAY) / HOUR, "%dh"), |
|
1214 ((tick_duration % HOUR) / MINUTE, "%dm"), |
|
1215 ((tick_duration % MINUTE) / SECOND, "%ds")]: |
|
1216 |
|
1217 if value > 0 or not_null: |
|
1218 duration += format % value |
|
1219 not_null = True |
|
1220 |
|
1221 duration += "%gms" % (float(tick_duration % SECOND) / MILLISECOND) |
|
1222 label += "(%s)" % duration |
|
1223 return label |
|
1224 |
|
1225 def StartDragNDrop(self, panel, x_mouse, y_mouse): |
|
1226 self.DraggingAxesPanel = panel |
1316 self.DraggingAxesPanel = panel |
1227 self.DraggingAxesBoundingBox = panel.GetAxesBoundingBox(absolute=True) |
1317 self.DraggingAxesBoundingBox = panel.GetAxesBoundingBox(absolute=True) |
1228 self.DraggingAxesMousePos = wx.Point( |
1318 self.DraggingAxesMousePos = wx.Point( |
1229 x_mouse - self.DraggingAxesBoundingBox.x, |
1319 x_mouse_start - self.DraggingAxesBoundingBox.x, |
1230 y_mouse - self.DraggingAxesBoundingBox.y) |
1320 y_mouse_start - self.DraggingAxesBoundingBox.y) |
1231 self.ResetCursorTickRatio() |
1321 self.MoveDragNDrop(x_mouse, y_mouse) |
1232 |
1322 |
1233 def MoveDragNDrop(self, x_mouse, y_mouse): |
1323 def MoveDragNDrop(self, x_mouse, y_mouse): |
1234 self.DraggingAxesBoundingBox.x = x_mouse - self.DraggingAxesMousePos.x |
1324 self.DraggingAxesBoundingBox.x = x_mouse - self.DraggingAxesMousePos.x |
1235 self.DraggingAxesBoundingBox.y = y_mouse - self.DraggingAxesMousePos.y |
1325 self.DraggingAxesBoundingBox.y = y_mouse - self.DraggingAxesMousePos.y |
1326 for panel in self.GraphicPanels: |
|
1327 x, y = panel.GetPosition() |
|
1328 width, height = panel.Canvas.GetSize() |
|
1329 rect = wx.Rect(x, y, width, height) |
|
1330 if rect.InsideXY(x_mouse, y_mouse): |
|
1331 panel.OnCanvasDragging(x_mouse - x, y_mouse - y, False) |
|
1332 else: |
|
1333 panel.OnCanvasLeave(False) |
|
1236 self.ForceRefresh() |
1334 self.ForceRefresh() |
1237 |
1335 |
1238 def IsDragging(self): |
1336 def IsDragging(self): |
1239 return self.DraggingAxesPanel is not None |
1337 return self.DraggingAxesPanel is not None |
1240 |
1338 |
1250 def StopDragNDrop(self, variable, x_mouse, y_mouse): |
1348 def StopDragNDrop(self, variable, x_mouse, y_mouse): |
1251 self.DraggingAxesPanel = None |
1349 self.DraggingAxesPanel = None |
1252 self.DraggingAxesBoundingBox = None |
1350 self.DraggingAxesBoundingBox = None |
1253 self.DraggingAxesMousePos = None |
1351 self.DraggingAxesMousePos = None |
1254 for idx, panel in enumerate(self.GraphicPanels): |
1352 for idx, panel in enumerate(self.GraphicPanels): |
1353 panel.OnCanvasLeave(False) |
|
1255 xw, yw = panel.GetPosition() |
1354 xw, yw = panel.GetPosition() |
1256 width, height = panel.Canvas.GetSize() |
1355 width, height = panel.Canvas.GetSize() |
1257 bbox = wx.Rect(xw, yw, width, height) |
1356 bbox = wx.Rect(xw, yw, width, height) |
1258 if bbox.InsideXY(x_mouse, y_mouse): |
1357 if bbox.InsideXY(x_mouse, y_mouse): |
1259 merge_type = GRAPH_PARALLEL |
1358 merge_type = GRAPH_PARALLEL |
1289 for panel in self.GraphicPanels: |
1388 for panel in self.GraphicPanels: |
1290 if isinstance(panel, DebugVariableGraphic): |
1389 if isinstance(panel, DebugVariableGraphic): |
1291 panel.Refresh(refresh_graphics) |
1390 panel.Refresh(refresh_graphics) |
1292 else: |
1391 else: |
1293 panel.Refresh() |
1392 panel.Refresh() |
1294 |
1393 |
1394 if self.CursorTick is not None: |
|
1395 tick = self.CursorTick |
|
1396 elif len(self.Ticks) > 0: |
|
1397 tick = self.Ticks[-1] |
|
1398 else: |
|
1399 tick = None |
|
1400 if tick is not None: |
|
1401 self.TickLabel.SetLabel("Tick: %d" % tick) |
|
1402 if self.Ticktime > 0: |
|
1403 tick_duration = int(tick * self.Ticktime) |
|
1404 not_null = False |
|
1405 duration = "" |
|
1406 for value, format in [(tick_duration / DAY, "%dd"), |
|
1407 ((tick_duration % DAY) / HOUR, "%dh"), |
|
1408 ((tick_duration % HOUR) / MINUTE, "%dm"), |
|
1409 ((tick_duration % MINUTE) / SECOND, "%ds")]: |
|
1410 |
|
1411 if value > 0 or not_null: |
|
1412 duration += format % value |
|
1413 not_null = True |
|
1414 |
|
1415 duration += "%gms" % (float(tick_duration % SECOND) / MILLISECOND) |
|
1416 self.TickTimeLabel.SetLabel("t: %s" % duration) |
|
1417 else: |
|
1418 self.TickTimeLabel.SetLabel("") |
|
1419 else: |
|
1420 self.TickLabel.SetLabel("") |
|
1421 self.TickTimeLabel.SetLabel("") |
|
1422 self.TickSizer.Layout() |
|
1295 else: |
1423 else: |
1296 self.Freeze() |
1424 self.Freeze() |
1297 |
1425 |
1298 if only_values: |
1426 if only_values: |
1299 for col in xrange(self.Table.GetNumberCols()): |
1427 for col in xrange(self.Table.GetNumberCols()): |
1318 if panel.Canvas.HasCapture(): |
1446 if panel.Canvas.HasCapture(): |
1319 panel.Canvas.ReleaseMouse() |
1447 panel.Canvas.ReleaseMouse() |
1320 self.GraphicPanels.remove(panel) |
1448 self.GraphicPanels.remove(panel) |
1321 panel.Destroy() |
1449 panel.Destroy() |
1322 |
1450 |
1451 self.ResetVariableNameMask() |
|
1323 self.RefreshGraphicsSizer() |
1452 self.RefreshGraphicsSizer() |
1324 self.ForceRefresh() |
1453 self.ForceRefresh() |
1325 |
1454 |
1326 else: |
1455 else: |
1327 items = [(idx, item) for idx, item in enumerate(self.Table.GetData())] |
1456 items = [(idx, item) for idx, item in enumerate(self.Table.GetData())] |
1344 if USE_MPL: |
1473 if USE_MPL: |
1345 self.Fixed = False |
1474 self.Fixed = False |
1346 for panel in self.GraphicPanels: |
1475 for panel in self.GraphicPanels: |
1347 panel.Destroy() |
1476 panel.Destroy() |
1348 self.GraphicPanels = [] |
1477 self.GraphicPanels = [] |
1478 self.ResetVariableNameMask() |
|
1349 self.RefreshGraphicsSizer() |
1479 self.RefreshGraphicsSizer() |
1350 else: |
1480 else: |
1351 self.Table.Empty() |
1481 self.Table.Empty() |
1352 self.Freeze() |
1482 self.Freeze() |
1353 self.Table.ResetView(self.VariablesGrid) |
1483 self.Table.ResetView(self.VariablesGrid) |
1427 self.PopupMenu(menu) |
1557 self.PopupMenu(menu) |
1428 |
1558 |
1429 menu.Destroy() |
1559 menu.Destroy() |
1430 event.Skip() |
1560 event.Skip() |
1431 |
1561 |
1562 def ChangeRange(self, dir, tick): |
|
1563 current_range = self.CurrentRange |
|
1564 current_range_idx = self.CanvasRange.GetSelection() |
|
1565 new_range_idx = max(0, min(current_range_idx + dir, len(self.RangeValues) - 1)) |
|
1566 if new_range_idx != current_range_idx: |
|
1567 self.CanvasRange.SetSelection(new_range_idx) |
|
1568 if self.Ticktime == 0: |
|
1569 self.CurrentRange = self.RangeValues[new_range_idx][1] |
|
1570 else: |
|
1571 self.CurrentRange = self.RangeValues[new_range_idx][1] / self.Ticktime |
|
1572 if len(self.Ticks) > 0: |
|
1573 new_start_tick = tick - (tick - self.StartTick) * self.CurrentRange / current_range |
|
1574 self.StartTick = self.Ticks[numpy.argmin(numpy.abs(self.Ticks - new_start_tick))] |
|
1575 self.Fixed = self.StartTick < self.Ticks[-1] - self.CurrentRange |
|
1576 self.ForceRefresh() |
|
1577 |
|
1432 def RefreshRange(self): |
1578 def RefreshRange(self): |
1433 if len(self.Ticks) > 0: |
1579 if len(self.Ticks) > 0: |
1434 if self.Fixed and self.Ticks[-1] - self.Ticks[0] < self.CurrentRange: |
1580 if self.Fixed and self.Ticks[-1] - self.Ticks[0] < self.CurrentRange: |
1435 self.Fixed = False |
1581 self.Fixed = False |
1436 if self.Fixed: |
1582 if self.Fixed: |
1456 |
1602 |
1457 def OnCurrentButton(self, event): |
1603 def OnCurrentButton(self, event): |
1458 if len(self.Ticks) > 0: |
1604 if len(self.Ticks) > 0: |
1459 self.StartTick = max(self.Ticks[0], self.Ticks[-1] - self.CurrentRange) |
1605 self.StartTick = max(self.Ticks[0], self.Ticks[-1] - self.CurrentRange) |
1460 self.Fixed = False |
1606 self.Fixed = False |
1461 self.ForceRefresh() |
1607 self.CursorTick = None |
1608 self.ResetCursorTick() |
|
1462 event.Skip() |
1609 event.Skip() |
1463 |
1610 |
1464 def CopyDataToClipboard(self, variables): |
1611 def CopyDataToClipboard(self, variables): |
1465 text = "tick;%s;\n" % ";".join([item.GetVariable() for item, data in variables]) |
1612 text = "tick;%s;\n" % ";".join([item.GetVariable() for item, data in variables]) |
1466 next_tick = NextTick(variables) |
1613 next_tick = NextTick(variables) |
1513 def GetViewerIndex(self, viewer): |
1660 def GetViewerIndex(self, viewer): |
1514 if viewer in self.GraphicPanels: |
1661 if viewer in self.GraphicPanels: |
1515 return self.GraphicPanels.index(viewer) |
1662 return self.GraphicPanels.index(viewer) |
1516 return None |
1663 return None |
1517 |
1664 |
1665 def ResetVariableNameMask(self): |
|
1666 items = [] |
|
1667 for panel in self.GraphicPanels: |
|
1668 items.extend(panel.GetItems()) |
|
1669 if len(items) > 1: |
|
1670 self.VariableNameMask = reduce(compute_mask, |
|
1671 [item.GetVariable().split('.') for item in items]) |
|
1672 elif len(items) > 0: |
|
1673 self.VariableNameMask = items[0].GetVariable().split('.')[:-1] + ['*'] |
|
1674 else: |
|
1675 self.VariableNameMask = [] |
|
1676 |
|
1677 def GetVariableNameMask(self): |
|
1678 return self.VariableNameMask |
|
1679 |
|
1518 def InsertValue(self, iec_path, idx = None, force=False): |
1680 def InsertValue(self, iec_path, idx = None, force=False): |
1519 if USE_MPL: |
1681 if USE_MPL: |
1520 for panel in self.GraphicPanels: |
1682 for panel in self.GraphicPanels: |
1521 if panel.GetItem(iec_path) is not None: |
1683 if panel.GetItem(iec_path) is not None: |
1522 return |
1684 return |
1533 if result is not None or force: |
1695 if result is not None or force: |
1534 |
1696 |
1535 if USE_MPL: |
1697 if USE_MPL: |
1536 if item.IsNumVariable(): |
1698 if item.IsNumVariable(): |
1537 panel = DebugVariableGraphic(self.GraphicsWindow, self, [item], GRAPH_PARALLEL) |
1699 panel = DebugVariableGraphic(self.GraphicsWindow, self, [item], GRAPH_PARALLEL) |
1700 if self.CursorTick is not None: |
|
1701 panel.SetCursorTick(self.CursorTick) |
|
1538 else: |
1702 else: |
1539 panel = DebugVariableText(self.GraphicsWindow, self, [item]) |
1703 panel = DebugVariableText(self.GraphicsWindow, self, [item]) |
1540 if idx is not None: |
1704 if idx is not None: |
1541 self.GraphicPanels.insert(idx, panel) |
1705 self.GraphicPanels.insert(idx, panel) |
1542 else: |
1706 else: |
1543 self.GraphicPanels.append(panel) |
1707 self.GraphicPanels.append(panel) |
1708 self.ResetVariableNameMask() |
|
1544 self.RefreshGraphicsSizer() |
1709 self.RefreshGraphicsSizer() |
1545 else: |
1710 else: |
1546 self.Table.InsertItem(idx, item) |
1711 self.Table.InsertItem(idx, item) |
1547 |
1712 |
1548 self.ForceRefresh() |
1713 self.ForceRefresh() |
1564 source_panel.Canvas.ReleaseMouse() |
1729 source_panel.Canvas.ReleaseMouse() |
1565 self.GraphicPanels.remove(source_panel) |
1730 self.GraphicPanels.remove(source_panel) |
1566 source_panel.Destroy() |
1731 source_panel.Destroy() |
1567 |
1732 |
1568 panel = DebugVariableGraphic(self.GraphicsWindow, self, [item], GRAPH_PARALLEL) |
1733 panel = DebugVariableGraphic(self.GraphicsWindow, self, [item], GRAPH_PARALLEL) |
1734 if self.CursorTick is not None: |
|
1735 panel.SetCursorTick(self.CursorTick) |
|
1569 self.GraphicPanels.insert(idx, panel) |
1736 self.GraphicPanels.insert(idx, panel) |
1737 self.ResetVariableNameMask() |
|
1570 self.RefreshGraphicsSizer() |
1738 self.RefreshGraphicsSizer() |
1571 self.ForceRefresh() |
1739 self.ForceRefresh() |
1572 |
1740 |
1573 def SplitGraphs(self, source_panel, item=None): |
1741 def SplitGraphs(self, source_panel, item=None): |
1574 source_idx = self.GetViewerIndex(source_panel) |
1742 source_idx = self.GetViewerIndex(source_panel) |
1578 source_items = source_panel.GetItems() |
1746 source_items = source_panel.GetItems() |
1579 while len(source_items) > 1: |
1747 while len(source_items) > 1: |
1580 item = source_items.pop(-1) |
1748 item = source_items.pop(-1) |
1581 if item.IsNumVariable(): |
1749 if item.IsNumVariable(): |
1582 panel = DebugVariableGraphic(self.GraphicsWindow, self, [item], GRAPH_PARALLEL) |
1750 panel = DebugVariableGraphic(self.GraphicsWindow, self, [item], GRAPH_PARALLEL) |
1751 if self.CursorTick is not None: |
|
1752 panel.SetCursorTick(self.CursorTick) |
|
1583 else: |
1753 else: |
1584 panel = DebugVariableText(self.GraphicsWindow, self, [item]) |
1754 panel = DebugVariableText(self.GraphicsWindow, self, [item]) |
1585 self.GraphicPanels.insert(source_idx + 1, panel) |
1755 self.GraphicPanels.insert(source_idx + 1, panel) |
1586 if isinstance(source_panel, DebugVariableGraphic): |
1756 if isinstance(source_panel, DebugVariableGraphic): |
1587 source_panel.GraphType = GRAPH_PARALLEL |
1757 source_panel.GraphType = GRAPH_PARALLEL |
1589 |
1759 |
1590 else: |
1760 else: |
1591 source_panel.RemoveItem(item) |
1761 source_panel.RemoveItem(item) |
1592 if item.IsNumVariable(): |
1762 if item.IsNumVariable(): |
1593 panel = DebugVariableGraphic(self.GraphicsWindow, self, [item], GRAPH_PARALLEL) |
1763 panel = DebugVariableGraphic(self.GraphicsWindow, self, [item], GRAPH_PARALLEL) |
1764 if self.CursorTick is not None: |
|
1765 panel.SetCursorTick(self.CursorTick) |
|
1594 else: |
1766 else: |
1595 panel = DebugVariableText(self.GraphicsWindow, self, [item]) |
1767 panel = DebugVariableText(self.GraphicsWindow, self, [item]) |
1596 self.GraphicPanels.insert(source_idx + 1, panel) |
1768 self.GraphicPanels.insert(source_idx + 1, panel) |
1597 |
1769 |
1770 self.ResetVariableNameMask() |
|
1598 self.RefreshGraphicsSizer() |
1771 self.RefreshGraphicsSizer() |
1599 self.ForceRefresh() |
1772 self.ForceRefresh() |
1600 |
1773 |
1601 def MergeGraphs(self, source, target_idx, merge_type, force=False): |
1774 def MergeGraphs(self, source, target_idx, merge_type, force=False): |
1602 source_item = None |
1775 source_item = None |
1632 |
1805 |
1633 target_panel.AddItem(source_item) |
1806 target_panel.AddItem(source_item) |
1634 target_panel.GraphType = merge_type |
1807 target_panel.GraphType = merge_type |
1635 target_panel.ResetGraphics() |
1808 target_panel.ResetGraphics() |
1636 |
1809 |
1810 self.ResetVariableNameMask() |
|
1637 self.RefreshGraphicsSizer() |
1811 self.RefreshGraphicsSizer() |
1638 self.ForceRefresh() |
1812 self.ForceRefresh() |
1639 |
1813 |
1640 def DeleteValue(self, source_panel, item=None): |
1814 def DeleteValue(self, source_panel, item=None): |
1641 source_idx = self.GetViewerIndex(source_panel) |
1815 source_idx = self.GetViewerIndex(source_panel) |
1643 |
1817 |
1644 if item is None: |
1818 if item is None: |
1645 source_panel.Clear() |
1819 source_panel.Clear() |
1646 source_panel.Destroy() |
1820 source_panel.Destroy() |
1647 self.GraphicPanels.remove(source_panel) |
1821 self.GraphicPanels.remove(source_panel) |
1822 self.ResetVariableNameMask() |
|
1648 self.RefreshGraphicsSizer() |
1823 self.RefreshGraphicsSizer() |
1649 else: |
1824 else: |
1650 source_panel.RemoveItem(item) |
1825 source_panel.RemoveItem(item) |
1651 if source_panel.IsEmpty(): |
1826 if source_panel.IsEmpty(): |
1652 source_panel.Destroy() |
1827 source_panel.Destroy() |
1653 self.GraphicPanels.remove(source_panel) |
1828 self.GraphicPanels.remove(source_panel) |
1829 self.ResetVariableNameMask() |
|
1654 self.RefreshGraphicsSizer() |
1830 self.RefreshGraphicsSizer() |
1655 self.ForceRefresh() |
1831 self.ForceRefresh() |
1656 |
1832 |
1657 def GetDebugVariables(self): |
1833 def GetDebugVariables(self): |
1658 if USE_MPL: |
1834 if USE_MPL: |
1676 elif isinstance(variable, TupleType) and len(items) <= 3: |
1852 elif isinstance(variable, TupleType) and len(items) <= 3: |
1677 panel = DebugVariableGraphic(self.GraphicsWindow, self, items, GRAPH_ORTHOGONAL) |
1853 panel = DebugVariableGraphic(self.GraphicsWindow, self, items, GRAPH_ORTHOGONAL) |
1678 else: |
1854 else: |
1679 continue |
1855 continue |
1680 self.GraphicPanels.append(panel) |
1856 self.GraphicPanels.append(panel) |
1857 self.ResetVariableNameMask() |
|
1681 self.RefreshGraphicsSizer() |
1858 self.RefreshGraphicsSizer() |
1682 else: |
1859 else: |
1683 self.InsertValue(variable, force=True) |
1860 self.InsertValue(variable, force=True) |
1684 self.ForceRefresh() |
1861 self.ForceRefresh() |
1685 else: |
1862 else: |