# HG changeset patch # User Laurent Bessard # Date 1361228819 -3600 # Node ID 4be515ac635e8c8f714fd6f6500cd0fd3b231f1b # Parent c562031146e41f6967050917ac328ed4d1d12705 Improved matplotlib graphic debug panel implementation diff -r c562031146e4 -r 4be515ac635e IDEFrame.py --- a/IDEFrame.py Sun Feb 17 23:47:41 2013 +0100 +++ b/IDEFrame.py Tue Feb 19 00:06:59 2013 +0100 @@ -6,6 +6,13 @@ import wx, wx.grid import wx.aui +try: + import matplotlib + matplotlib.use('WX') + USE_MPL = True +except: + USE_MPL = False + from editors.EditorPanel import EditorPanel from editors.SFCViewer import SFC_Viewer from editors.LDViewer import LD_Viewer @@ -2014,6 +2021,7 @@ def OpenDebugViewer(self, instance_category, instance_path, instance_type): openedidx = self.IsOpened(instance_path) + new_window = None if openedidx is not None: old_selected = self.TabsOpened.GetSelection() if old_selected != openedidx: @@ -2023,12 +2031,14 @@ elif instance_category in ITEMS_VARIABLE: if self.Controler.IsNumType(instance_type, True): - new_window = GraphicViewer(self.TabsOpened, self, self.Controler, instance_path) - icon = GetBitmap("GRAPH") + if USE_MPL: + self.AddDebugVariable(instance_path, True) + else: + new_window = GraphicViewer(self.TabsOpened, self, self.Controler, instance_path) + icon = GetBitmap("GRAPH") else: bodytype = self.Controler.GetEditedElementBodyType(instance_type, True) - new_window = None if bodytype == "FBD": new_window = Viewer(self.TabsOpened, instance_type, self, self.Controler, True, instance_path) new_window.RefreshScaling(False) diff -r c562031146e4 -r 4be515ac635e controls/DebugVariablePanel.py --- a/controls/DebugVariablePanel.py Sun Feb 17 23:47:41 2013 +0100 +++ b/controls/DebugVariablePanel.py Tue Feb 19 00:06:59 2013 +0100 @@ -39,7 +39,8 @@ from matplotlib.backends.backend_wxagg import _convert_agg_to_wx_bitmap from matplotlib.backends.backend_agg import FigureCanvasAgg from mpl_toolkits.mplot3d import Axes3D - color_cycle = matplotlib.rcParams['axes.color_cycle'] + color_cycle = ['r', 'b', 'g', 'm', 'y', 'k'] + cursor_color = '#800080' USE_MPL = True except: USE_MPL = False @@ -618,61 +619,53 @@ HIGHLIGHT_PEN = wx.Pen(wx.Colour(0, 128, 255)) HIGHLIGHT_BRUSH = wx.Brush(wx.Colour(0, 128, 255, 128)) - if wx.Platform == '__WXMSW__': - popupclass = wx.PopupTransientWindow - else: - popupclass = wx.PopupWindow - - class PopupWithButtons(popupclass): - - def __init__(self, parent, window, item, style=wx.HORIZONTAL): - popupclass.__init__(self, parent, wx.NO_BORDER) - self.SetBackgroundColour(wx.WHITE) - - self.ParentWindow = window - self.Item = item - - main_sizer = wx.BoxSizer(style) - - if self.Item.IsForced(): - buttons = [("ReleaseButton", "release", _("Release value"))] - - else: - buttons = [("ForceButton", "force", _("Force value"))] - buttons.append(("DeleteButton", "delete_graph", _("Remove debug variable"))) - - for name, bitmap, help in buttons: - button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap), - size=wx.Size(20, 20), style=wx.NO_BORDER) - button.SetToolTipString(help) - setattr(self, name, button) - self.Bind(wx.EVT_BUTTON, getattr(self, "On" + name), button) - main_sizer.AddWindow(button) - main_sizer.Layout() - - self.SetSizer(main_sizer) - main_sizer.Fit(self) - - def GetItem(self): - return self.Item - - def OnForceButton(self, event): - wx.CallAfter(self.Parent.DismissButtons) - wx.CallAfter(self.Parent.ForceValue, self.Item) - event.Skip() - - def OnReleaseButton(self, event): - wx.CallAfter(self.Parent.DismissButtons) - wx.CallAfter(self.Parent.ReleaseValue, self.Item) - event.Skip() - - def OnDeleteButton(self, event): - wx.CallAfter(self.Parent.DismissButtons) - wx.CallAfter(self.ParentWindow.DeleteValue, self.Parent, self.Item) - event.Skip() - - def OnDismiss(self): - wx.CallAfter(self.Parent.DismissButtons) + #CANVAS_SIZE_TYPES + [SIZE_MINI, SIZE_MIDDLE, SIZE_MAXI] = range(3) + + class GraphButton(): + + def __init__(self, x, y, bitmap, callback): + self.Position = wx.Point(x, y) + self.Bitmap = bitmap + self.Shown = True + self.Callback = callback + + def __del__(self): + self.callback = None + + def GetSize(self): + return self.Bitmap.GetSize() + + def SetPosition(self, x, y): + self.Position = wx.Point(x, y) + + def SetBitmap(self, bitmap): + self.Bitmap = bitmap + + def SetCallback(self, callback): + self.Callback = callback + + def Show(self): + self.Shown = True + + def Hide(self): + self.Shown = False + + def HitTest(self, x, y): + if self.Shown: + w, h = self.Bitmap.GetSize() + rect = wx.Rect(self.Position.x, self.Position.y, w, h) + if rect.InsideXY(x, y): + return True + return False + + def ProcessCallback(self): + if self.Callback is not None: + wx.CallAfter(self.Callback) + + def Draw(self, dc): + if self.Shown: + dc.DrawBitmap(self.Bitmap, self.Position.x, self.Position.y, True) class DraggingFigureCanvas(FigureCanvas): @@ -685,17 +678,16 @@ self.ParentWindow = window self.Highlight = HIGHLIGHT_NONE - - self.ChangeSizeButton = wx.lib.buttons.GenBitmapToggleButton(self, - bitmap=GetBitmap("minimize_graph"), - size=wx.Size(20, 20), style=wx.NO_BORDER) - self.ChangeSizeButton.SetBitmapSelected(GetBitmap("maximize_graph")) - self.Bind(wx.EVT_BUTTON, self.OnChangeSizeButton, self.ChangeSizeButton) - - self.CloseButton = wx.lib.buttons.GenBitmapButton(self, - bitmap=GetBitmap("delete_graph"), - size=wx.Size(20, 20), style=wx.NO_BORDER) - self.Bind(wx.EVT_BUTTON, self.OnCloseButton, self.CloseButton) + self.CanvasSize = SIZE_MAXI + + self.Buttons = [] + self.ContextualButtons = [] + self.ContextualButtonsItem = None + + self.Buttons.append( + GraphButton(0, 0, GetBitmap("minimize_graph"), self.OnChangeSizeButton)) + self.Buttons.append( + GraphButton(0, 0, GetBitmap("delete_graph"), self.OnCloseButton)) self.ShowButtons(False) @@ -723,7 +715,7 @@ destDC.SelectObject(self.bitmap) destGC = wx.GCDC(destDC) - + destGC.BeginDrawing() destGC.SetPen(HIGHLIGHT_PEN) destGC.SetBrush(HIGHLIGHT_BRUSH) @@ -738,6 +730,9 @@ destGC.DrawRectangle(bbox.x + bbox.width / 2, bbox.y, bbox.width / 2, bbox.height) + for button in self.Buttons + self.ContextualButtons: + button.Draw(destGC) + if self.ParentWindow.IsDragging(): destBBox = self.ParentWindow.GetDraggingAxesClippingRegion(self.Parent) if destBBox.width > 0 and destBBox.height > 0: @@ -766,13 +761,71 @@ self._isDrawn = True self.gui_repaint(drawDC=drawDC) + def HandleButtons(self, x, y): + for button in self.Buttons + self.ContextualButtons: + if button.HitTest(x, y): + button.ProcessCallback() + return True + return False + + def PopupContextualButtons(self, item, rect, style=wx.HORIZONTAL): + if self.ContextualButtonsItem is not None and item != self.ContextualButtonsItem: + self.DismissContextualButtons() + + if self.ContextualButtonsItem is None: + self.ContextualButtonsItem = item + + if self.ContextualButtonsItem.IsForced(): + self.ContextualButtons.append( + GraphButton(0, 0, GetBitmap("release"), self.OnReleaseButton)) + else: + self.ContextualButtons.append( + GraphButton(0, 0, GetBitmap("force"), self.OnForceButton)) + self.ContextualButtons.append( + GraphButton(0, 0, GetBitmap("delete_graph"), self.OnRemoveItemButton)) + + offset = 0 + buttons = self.ContextualButtons[:] + if style == wx.VERTICAL: + buttons.reverse() + for button in buttons: + w, h = button.GetSize() + if style == wx.HORIZONTAL: + x = rect.x + rect.width + offset + y = rect.y + (rect.height - h) / 2 + offset += w + else: + x = rect.x + (rect.width - w ) / 2 + y = rect.y - h - offset + offset += h + button.SetPosition(x, y) + self.ParentWindow.ForceRefresh() + + def DismissContextualButtons(self): + if self.ContextualButtonsItem is not None: + self.ContextualButtonsItem = None + self.ContextualButtons = [] + self.ParentWindow.ForceRefresh() + + def IsOverButton(self, x, y): + for button in self.Buttons + self.ContextualButtons: + if button.HitTest(x, y): + return True + return False + + def IsOverContextualButton(self, x, y): + for button in self.ContextualButtons: + if button.HitTest(x, y): + return True + return False + def ShowButtons(self, show): - if show: - self.ChangeSizeButton.Show() - self.CloseButton.Show() - else: - self.ChangeSizeButton.Hide() - self.CloseButton.Hide() + for button in self.Buttons: + if show: + button.Show() + else: + button.Hide() + self.ParentWindow.ForceRefresh() def OnEnterWindow(self, event): self.ShowButtons(True) @@ -786,21 +839,41 @@ self.ShowButtons(False) event.Skip() - def OnChangeSizeButton(self, event): - if self.ChangeSizeButton.GetToggle(): + def OnChangeSizeButton(self): + if self.CanvasSize == SIZE_MAXI: + self.CanvasSize = SIZE_MIDDLE self.Parent.Minimize() else: + self.CanvasSize = SIZE_MAXI self.Parent.Maximize() - event.Skip() - - def OnCloseButton(self, event): - wx.CallAfter(self.ParentWindow.DeleteValue, self.Parent) - event.Skip() - + + def OnCloseButton(self): + self.ParentWindow.DeleteValue(self.Parent) + + def OnForceButton(self): + wx.CallAfter(self.Parent.ForceValue, + self.ContextualButtonsItem) + self.DismissContextualButtons() + + def OnReleaseButton(self): + wx.CallAfter(self.Parent.ReleaseValue, + self.ContextualButtonsItem) + self.DismissContextualButtons() + + def OnRemoveItemButton(self): + wx.CallAfter(self.ParentWindow.DeleteValue, self.Parent, + self.ContextualButtonsItem) + self.DismissContextualButtons() + def OnResizeWindow(self, event): width, height = self.GetSize() - self.ChangeSizeButton.SetPosition(wx.Point(width - 50, 5)) - self.CloseButton.SetPosition(wx.Point(width - 25, 5)) + offset = 0 + buttons = self.Buttons[:] + buttons.reverse() + for button in buttons: + w, h = button.GetSize() + button.SetPosition(width - 5 - w - offset, 5) + offset += w event.Skip() class DebugVariableGraphic(DebugVariableViewer): @@ -817,6 +890,7 @@ main_sizer = wx.BoxSizer(wx.VERTICAL) self.Figure = matplotlib.figure.Figure(facecolor='w') + self.Figure.subplotpars.update(top=0.95, left=0.1, bottom=0.1, right=0.95) self.Canvas = DraggingFigureCanvas(self, self.ParentWindow, -1, self.Figure) self.Canvas.SetMinSize(wx.Size(200, 200)) @@ -832,16 +906,34 @@ self.ResetGraphics() + def RefreshLabelsPosition(self, ratio): + self.MaskLabel.set_position((0.05, 1.0 - 0.1 * ratio)) + if self.GraphType == GRAPH_PARALLEL or self.Is3DCanvas(): + num_item = len(self.Items) + for idx in xrange(num_item): + if not self.Is3DCanvas(): + self.AxesLabels[idx].set_position((0.05, 1.0 - (0.1 + 0.075 * (idx + 1)) * ratio)) + self.Labels[idx].set_position((0.95, 0.1 + (num_item - idx - 1) * 0.1 * ratio)) + else: + self.AxesLabels[0].set_position((0.1, 0.05 * ratio)) + self.Labels[0].set_position((0.95, 0.05 * ratio)) + self.AxesLabels[1].set_position((0.05, 0.1 * ratio)) + self.Labels[1].set_position((0.05, 1.0 - 0.05 * ratio)) + def Minimize(self): self.Canvas.SetMinSize(wx.Size(200, 100)) - self.Figure.subplotpars.update(bottom=0.20) + self.Figure.subplotpars.update(top=0.9, bottom=0.2) + self.RefreshLabelsPosition(2) + self.Figure.subplots_adjust() self.ParentWindow.RefreshGraphicsSizer() - + def Maximize(self): self.Canvas.SetMinSize(wx.Size(200, 200)) - self.Figure.subplotpars.update(bottom=0.1) + self.Figure.subplotpars.update(top=0.95, bottom=0.1) + self.RefreshLabelsPosition(1) + self.Figure.subplots_adjust() self.ParentWindow.RefreshGraphicsSizer() - + def GetAxesBoundingBox(self, absolute=False): bbox = self.Canvas.GetAxesBoundingBox() if absolute: @@ -851,20 +943,14 @@ return bbox def OnCanvasButtonPressed(self, event): - if not self.Is3DCanvas(): - width, height = self.Canvas.GetSize() - x, y = event.x, height - event.y + width, height = self.Canvas.GetSize() + x, y = event.x, height - event.y + if not self.Canvas.IsOverButton(x, y) and not self.Is3DCanvas(): rect = self.GetAxesBoundingBox() if rect.InsideXY(x, y): self.MouseStartPos = wx.Point(x, y) - if self.Legend is not None: - texts = self.Legend.get_texts() - elif len(self.AxesLabels) > 0: - texts = self.AxesLabels - else: - texts = [] item_idx = None - for i, t in enumerate(texts): + for i, t in enumerate(self.AxesLabels): (x0, y0), (x1, y1) = t.get_window_extent().get_points() rect = wx.Rect(x0, height - y1, x1 - x0, y1 - y0) if rect.InsideXY(x, y): @@ -872,16 +958,16 @@ break if item_idx is not None: self.Canvas.ShowButtons(False) - self.DismissButtons() + self.Canvas.DismissContextualButtons() xw, yw = self.GetPosition() self.ParentWindow.StartDragNDrop(self, self.Items[item_idx], x + xw, y + yw, x + xw, y + yw) - elif event.button == 1: + elif event.button == 1 and event.inaxes == self.Axes: self.HandleCursorMove(event) elif event.button == 2 and self.GraphType == GRAPH_PARALLEL: width, height = self.Canvas.GetSize() start_tick, end_tick = self.ParentWindow.GetRange() - self.MouseStartPos = wx.Point(event.x, height - event.y) + self.MouseStartPos = wx.Point(x, y) self.StartCursorTick = start_tick def OnCanvasButtonReleased(self, event): @@ -895,6 +981,8 @@ else: self.MouseStartPos = None self.StartCursorTick = None + width, height = self.Canvas.GetSize() + self.Canvas.HandleButtons(event.x, height - event.y) def OnCanvasMotion(self, event): width, height = self.Canvas.GetSize() @@ -921,16 +1009,13 @@ self.StartCursorTick + (self.MouseStartPos.x - event.x) * (end_tick - start_tick) / rect.width) elif event.button is None: - if self.Legend is not None: - labels = self.Legend.get_texts() - texts = zip(labels, [wx.HORIZONTAL] * len(labels)) + if self.GraphType == GRAPH_PARALLEL: + orientation = [wx.HORIZONTAL] * len(self.AxesLabels) elif len(self.AxesLabels) > 0: - texts = zip(self.AxesLabels, [wx.HORIZONTAL, wx.VERTICAL]) - else: - texts = [] + orientation = [wx.HORIZONTAL, wx.VERTICAL] item_idx = None item_style = None - for i, (t, style) in enumerate(texts): + for i, (t, style) in enumerate(zip(self.AxesLabels, orientation)): (x0, y0), (x1, y1) = t.get_window_extent().get_points() rect = wx.Rect(x0, height - y1, x1 - x0, y1 - y0) if rect.InsideXY(event.x, height - event.y): @@ -938,10 +1023,10 @@ item_style = style break if item_idx is not None: - self.PopupButtons(item_idx, rect, item_style) + self.Canvas.PopupContextualButtons(self.Items[item_idx], rect, item_style) return - if self.ItemButtons is not None: - self.DismissButtons() + if not self.Canvas.IsOverContextualButton(event.x, height - event.y): + self.Canvas.DismissContextualButtons() def OnCanvasDragging(self, x, y, refresh=True): width, height = self.Canvas.GetSize() @@ -996,44 +1081,12 @@ def DoDragDrop(self, item_idx): self.Canvas.ShowButtons(False) - self.DismissButtons() + self.Canvas.DismissContextualButtons() data = wx.TextDataObject(str((self.Items[item_idx].GetVariable(), "debug", "move"))) dragSource = wx.DropSource(self.Canvas) dragSource.SetData(data) dragSource.DoDragDrop() - def PopupButtons(self, item_idx, rect, style=wx.HORIZONTAL): - item = self.Items[item_idx] - if self.ItemButtons is not None and item != self.ItemButtons.GetItem(): - self.DismissButtons() - if self.ItemButtons is None: - - self.ItemButtons = PopupWithButtons(self, self.ParentWindow, item, style) - - # Show the popup right below or above the button - # depending on available screen space... - w, h = self.ItemButtons.GetSize() - if style == wx.HORIZONTAL: - x = rect.x + rect.width - y = rect.y + (rect.height - h) / 2 - else: - x = rect.x + (rect.width - w ) / 2 - y = rect.y - h - self.ItemButtons.SetPosition(self.ClientToScreen((x, y))) - - if wx.Platform == '__WXMSW__': - self.ItemButtons.Popup() - else: - self.ItemButtons.Show() - - def DismissButtons(self): - if self.ItemButtons: - if wx.Platform == '__WXMSW__': - self.ItemButtons.Dismiss() - else: - self.ItemButtons.Destroy() - self.ItemButtons = None - def OnAxesMotion(self, event): if self.Is3DCanvas(): current_time = gettime() @@ -1049,46 +1102,62 @@ self.LastMotionTime = gettime() setattr(self.Axes, "_on_move", self.OnAxesMotion) self.Axes.mouse_init() + self.Axes.tick_params(axis='z', labelsize='small') else: self.Axes = self.Figure.gca() - self.Figure.subplotpars.update(top=0.95, right=0.95) + self.Axes.set_color_cycle(color_cycle) + self.Axes.tick_params(axis='x', labelsize='small') + self.Axes.tick_params(axis='y', labelsize='small') self.Plots = [] self.VLine = None self.HLine = None - self.Legend = None self.Labels = [] self.AxesLabels = [] + if not self.Is3DCanvas(): + text_func = self.Axes.text + else: + text_func = self.Axes.text2D + self.MaskLabel = text_func(0, 0, "", size='small', + transform=self.Axes.transAxes) if self.GraphType == GRAPH_PARALLEL or self.Is3DCanvas(): num_item = len(self.Items) - if not self.Is3DCanvas(): - text_func = self.Axes.text - else: - text_func = self.Axes.text2D for idx in xrange(num_item): + if num_item == 1: + color = 'k' + else: + color = color_cycle[idx % len(color_cycle)] + if not self.Is3DCanvas(): + self.AxesLabels.append( + text_func(0, 0, "", size='small', + color=color, + transform=self.Axes.transAxes)) self.Labels.append( - text_func(0.95, 0.05 + (num_item - idx - 1) * 0.1, - "", size='large', + text_func(0, 0, "", size='large', horizontalalignment='right', - color=color_cycle[idx % len(color_cycle)], + color=color, transform=self.Axes.transAxes)) else: self.AxesLabels.append( - self.Axes.text(0.1, 0.05, "", size='small', + self.Axes.text(0, 0, "", size='small', transform=self.Axes.transAxes)) self.Labels.append( - self.Axes.text(0.95, 0.05, "", size='large', + self.Axes.text(0, 0, "", size='large', horizontalalignment='right', transform=self.Axes.transAxes)) self.AxesLabels.append( - self.Axes.text(0.05, 0.1, "", size='small', + self.Axes.text(0, 0, "", size='small', rotation='vertical', verticalalignment='bottom', transform=self.Axes.transAxes)) self.Labels.append( - self.Axes.text(0.05, 0.95, "", size='large', + self.Axes.text(0, 0, "", size='large', rotation='vertical', verticalalignment='top', transform=self.Axes.transAxes)) + if self.Canvas.CanvasSize == SIZE_MAXI: + self.RefreshLabelsPosition(1) + else: + self.RefreshLabelsPosition(2) def AddItem(self, item): DebugVariableViewer.AddItem(self, item) @@ -1150,7 +1219,7 @@ if self.CursorTick is not None and start_tick <= self.CursorTick <= end_tick: if self.VLine is None: - self.VLine = self.Axes.axvline(self.CursorTick, color='r') + self.VLine = self.Axes.axvline(self.CursorTick, color=cursor_color) else: self.VLine.set_xdata((self.CursorTick, self.CursorTick)) self.VLine.set_visible(True) @@ -1184,11 +1253,11 @@ if self.CursorTick is not None and start_tick <= self.CursorTick <= end_tick: if self.VLine is None: - self.VLine = self.Axes.axvline(x_cursor, color='r') + self.VLine = self.Axes.axvline(x_cursor, color=cursor_color) else: self.VLine.set_xdata((x_cursor, x_cursor)) if self.HLine is None: - self.HLine = self.Axes.axhline(y_cursor, color='r') + self.HLine = self.Axes.axhline(y_cursor, color=cursor_color) else: self.HLine.set_ydata((y_cursor, y_cursor)) self.VLine.set_visible(True) @@ -1218,7 +1287,7 @@ ("ys", numpy.array([y_cursor, y_cursor])), ("zs", numpy.array([z_cursor, z_cursor]))]: kwargs.setdefault(param, value) - kwargs["color"] = 'r' + kwargs["color"] = cursor_color self.Axes.plot(**kwargs) self.Axes.set_xlim(x_min, x_max) @@ -1230,27 +1299,19 @@ else: values, forced = apply(zip, [(item.GetValue(), item.IsForced()) for item in self.Items]) labels = [item.GetVariable(variable_name_mask) for item in self.Items] - colors = map(lambda x: {True: 'b', False: 'k'}[x], forced) - if self.GraphType == GRAPH_PARALLEL: - if self.Legend is None: - self.Legend = self.Axes.legend(self.Plots, labels, - loc="upper left", frameon=False, prop={'size':'small'}, - title = '.'.join(variable_name_mask)) - self.Legend.get_title().set_fontsize('small') - for t, color in zip(self.Legend.get_texts(), colors): - t.set_color(color) - else: - self.Legend = None - if self.Is3DCanvas(): - self.Axes.set_xlabel(labels[0], fontdict={'size':'small','color':colors[0]}) - self.Axes.set_ylabel(labels[1], fontdict={'size':'small','color':colors[1]}) - self.Axes.set_zlabel(labels[2], fontdict={'size':'small','color':colors[2]}) - else: - for label, text, color in zip(self.AxesLabels, labels, colors): - label.set_text(text) - label.set_color(color) - for label, value in zip(self.Labels, values): + styles = map(lambda x: {True: 'italic', False: 'normal'}[x], forced) + self.MaskLabel.set_text('.'.join(variable_name_mask)) + if self.Is3DCanvas(): + for idx, label_func in enumerate([self.Axes.set_xlabel, + self.Axes.set_ylabel, + self.Axes.set_zlabel]): + label_func(labels[idx], fontdict={'size': 'small','color': color_cycle[idx]}) + else: + for label, text in zip(self.AxesLabels, labels): + label.set_text(text) + for label, value, style in zip(self.Labels, values, styles): label.set_text(value) + label.set_style(style) self.Canvas.draw() diff -r c562031146e4 -r 4be515ac635e controls/PouInstanceVariablesPanel.py --- a/controls/PouInstanceVariablesPanel.py Sun Feb 17 23:47:41 2013 +0100 +++ b/controls/PouInstanceVariablesPanel.py Tue Feb 19 00:06:59 2013 +0100 @@ -26,6 +26,13 @@ import wx.lib.buttons import wx.lib.agw.customtreectrl as CT +try: + import matplotlib + matplotlib.use('WX') + USE_MPL = True +except: + USE_MPL = False + from PLCControler import ITEMS_VARIABLE, ITEM_CONFIGURATION, ITEM_RESOURCE, ITEM_POU, ITEM_TRANSITION, ITEM_ACTION from util.BitmapLibrary import GetBitmap @@ -146,7 +153,7 @@ buttons = [] if var_infos["class"] in ITEMS_VARIABLE: - if (var_infos["debug"] and self.Debug and + if (not USE_MPL and var_infos["debug"] and self.Debug and (self.Controller.IsOfType(var_infos["type"], "ANY_NUM", True) or self.Controller.IsOfType(var_infos["type"], "ANY_BIT", True))): graph_button = wx.lib.buttons.GenBitmapButton(panel, diff -r c562031146e4 -r 4be515ac635e images/maximize_graph.png Binary file images/maximize_graph.png has changed diff -r c562031146e4 -r 4be515ac635e images/middle_graph.png Binary file images/middle_graph.png has changed diff -r c562031146e4 -r 4be515ac635e images/plcopen_icons.svg --- a/images/plcopen_icons.svg Sun Feb 17 23:47:41 2013 +0100 +++ b/images/plcopen_icons.svg Tue Feb 19 00:06:59 2013 +0100 @@ -10381,7 +10381,7 @@ x2="16.330999" y1="13.023" x1="36.011002" - gradientTransform="matrix(0.44717834,-0.00406845,-0.01961605,0.44676642,-78.185829,253.58647)" + gradientTransform="matrix(0.44717834,-0.00406845,-0.01961605,0.44676642,-30.185829,253.58647)" gradientUnits="userSpaceOnUse" id="linearGradient6801-3" xlink:href="#linearGradient7916-9-1" @@ -10406,7 +10406,7 @@ x2="81.401299" y2="234.28734" gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.96236471,0,0,5.1478585,-150.36967,-920.8619)" /> + gradientTransform="matrix(0.96236471,0,0,5.1478585,-102.36967,-920.8619)" /> <linearGradient id="linearGradient3234-0-5" y2="22" @@ -10815,6 +10815,109 @@ id="feGaussianBlur3409-6" stdDeviation="0.82668559" /> </filter> + <linearGradient + y2="32.702" + x2="16.330999" + y1="13.023" + x1="36.011002" + gradientTransform="matrix(0.44717834,-0.00406845,-0.01961605,0.44676642,-81.135865,253.52592)" + gradientUnits="userSpaceOnUse" + id="linearGradient6801-3-1" + xlink:href="#linearGradient7916-9-1-2" + inkscape:collect="always" /> + <linearGradient + id="linearGradient7916-9-1-2"> + <stop + id="stop7918-2-7-1" + style="stop-color:#fff" + offset="0" /> + <stop + id="stop7920-4-4-9" + style="stop-color:#fff;stop-opacity:0" + offset="1" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3234-0-5-8" + id="linearGradient6750-4-2" + x1="89.006996" + y1="228.31628" + x2="81.401299" + y2="234.28734" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.96236471,0,0,5.1478585,-153.3197,-920.92248)" /> + <linearGradient + id="linearGradient3234-0-5-8" + y2="22" + gradientUnits="userSpaceOnUse" + x2="11.192" + gradientTransform="matrix(0.57895,0,0,0.61111,1.0526,0.36108)" + y1="3" + x1="11.192"> + <stop + id="stop3205-5-5-8" + style="stop-color:#777976" + offset="0" /> + <stop + id="stop3207-15-6-0" + style="stop-color:#565755" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient5528-8-9" + y2="39.924" + gradientUnits="userSpaceOnUse" + x2="21.780001" + gradientTransform="matrix(0.45455,0,0,0.45902,-3.3637,-2.6312)" + y1="8.5762997" + x1="21.865999"> + <stop + id="stop2783-3-7-9" + style="stop-color:#505050" + offset="0" /> + <stop + id="stop6301-8-3-3" + style="stop-color:#6e6e6e" + offset=".13216" /> + <stop + id="stop2785-2-9-6" + style="stop-color:#8c8c8c" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient5525-3-1" + y2="15.044" + gradientUnits="userSpaceOnUse" + x2="16.075001" + gradientTransform="matrix(0.41935,0,0,0.41379,-2.4838,-1.431)" + y1="9.0734997" + x1="16.034"> + <stop + id="stop3692-4-8-3" + style="stop-color:#fff" + offset="0" /> + <stop + id="stop3694-1-8-1" + style="stop-color:#fff;stop-opacity:.46875" + offset="1" /> + </linearGradient> + <linearGradient + id="linearGradient5522-9-3" + y2="40" + gradientUnits="userSpaceOnUse" + x2="24" + gradientTransform="matrix(0.36842,0,0,0.48002992,-0.8421,-4.2013409)" + y1="13" + x1="24"> + <stop + id="stop6459-0-4-8" + style="stop-color:#fff;stop-opacity:.94118" + offset="0" /> + <stop + id="stop6461-6-4-9" + style="stop-color:#fff;stop-opacity:.70588" + offset="1" /> + </linearGradient> </defs> <sodipodi:namedview id="base" @@ -10824,8 +10927,8 @@ inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:zoom="1.9999999" - inkscape:cx="-254.99706" - inkscape:cy="-254.41678" + inkscape:cx="104.95693" + inkscape:cy="-309.97229" inkscape:document-units="px" inkscape:current-layer="layer1" width="16px" @@ -15568,24 +15671,24 @@ <text xml:space="preserve" style="font-size:4.49727678px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Vera Sans" - x="-93.511536" + x="-45.511536" y="255.83347" id="text3638-3-3-2-0-9-84-1-0-7-8-0"><tspan sodipodi:role="line" - x="-93.511536" + x="-45.511536" y="255.83347" id="tspan5713-0">%%maximize_graph%%</tspan></text> <rect inkscape:label="#rect3636" y="259.08347" - x="-75.261528" + x="-27.261528" height="16" width="16" id="maximize_graph" style="opacity:0;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> <g style="display:inline" - transform="translate(-75.199039,258.45845)" + transform="translate(-27.199039,258.45845)" id="g5498-6"> <rect id="rect1887-0-5" @@ -15613,14 +15716,14 @@ style="color:#000000;fill:url(#linearGradient6750-4);fill-opacity:1;fill-rule:nonzero;stroke:#565853;stroke-width:0.99638373;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="rect5849-1" width="11.037974" - height="8.9308977" - x="-72.785027" - y="263.14575" /> + height="9.2590332" + x="-24.785027" + y="262.81763" /> <path inkscape:connector-curvature="0" id="path7076-0-1" style="opacity:0.3;fill:none;stroke:url(#linearGradient6801-3);stroke-width:1;stroke-linecap:square;display:inline" - d="m -62.761059,271.04244 0.004,-6.90262 -9.03453,0.0166" + d="m -14.761059,271.04244 0.004,-7.23075 -9.03453,0.0166" sodipodi:nodetypes="ccc" /> <g transform="translate(-261.99974,259.1098)" @@ -15717,5 +15820,62 @@ d="m 31.844,17.125 c -0.003,-2.113 0.006,-4.2261 -0.0047,-6.339 -0.034,-1.6107 -0.543,-3.2452 -1.612,-4.4726 -1.355,-1.5843 -3.379,-2.4626 -5.414,-2.7423 -0.487,-0.0673 -0.978,-0.1013 -1.469,-0.1023 -2.075,0.00558 -4.1949,0.54216 -5.9005,1.7543 -1.1825,0.83615 -2.1108,2.0716 -2.4313,3.4977 -0.22328,0.90342 -0.15731,1.8388 -0.19188,2.7603 -0.03376,1.798 -0.06753,3.5959 -0.10129,5.3939" transform="matrix(0.29233,0,0,0.31489,6.45176,0.31291)" /> </g> + <text + xml:space="preserve" + style="font-size:4.49727678px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Bitstream Vera Sans" + x="-94.52224" + y="255.6499" + id="text3638-3-3-2-0-9-84-1-0-7-8-0-7"><tspan + sodipodi:role="line" + x="-94.52224" + y="255.6499" + id="tspan5713-0-6">%%middle_graph%%</tspan></text> + <rect + inkscape:label="#rect3636" + y="259.02292" + x="-78.211563" + height="16" + width="16" + id="middle_graph" + style="opacity:0;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> + <g + style="display:inline" + transform="translate(-78.149075,258.3979)" + id="g5498-6-6"> + <rect + id="rect1887-0-5-9" + style="fill:url(#linearGradient5528-8-9);stroke:#565853;stroke-width:0.99993002;stroke-linejoin:round" + height="14" + width="15" + y="1.5" + x="0.49996999" /> + <rect + id="rect2779-3-7-6" + style="opacity:0.2;fill:none;stroke:url(#linearGradient5525-3-1);stroke-width:1.00010002" + height="12" + width="13" + y="2.5000999" + x="1.5001" /> + <rect + id="rect6287-4-9-3" + style="fill:url(#linearGradient5522-9-3)" + height="12.960938" + width="14" + y="2.0390625" + x="1" /> + </g> + <rect + style="color:#000000;fill:url(#linearGradient6750-4-2);fill-opacity:1;fill-rule:nonzero;stroke:#565853;stroke-width:0.99638373;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + id="rect5849-1-0" + width="11.037971" + height="6.2522917" + x="-75.735062" + y="265.76382" /> + <path + inkscape:connector-curvature="0" + id="path7076-0-1-1" + style="opacity:0.3;fill:none;stroke:url(#linearGradient6801-3-1);stroke-width:1;stroke-linecap:square;display:inline" + d="m -65.711095,270.98189 0.004,-4.20727 -9.03453,0.0166" + sodipodi:nodetypes="ccc" /> </g> </svg>