# HG changeset patch # User Laurent Bessard # Date 1369334350 -7200 # Node ID 074e46cdedbcafd07e2cc9c3f823ba9390e52c2c # Parent 53e4a2b775a7905d38837e7603fa0569fb5cf5f8 Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging diff -r 53e4a2b775a7 -r 074e46cdedbc controls/CustomToolTip.py --- a/controls/CustomToolTip.py Thu May 23 18:47:44 2013 +0200 +++ b/controls/CustomToolTip.py Thu May 23 20:39:10 2013 +0200 @@ -116,9 +116,9 @@ # Prevent to call wx method in non-wx threads wx.CallAfter(self.RefreshTip) - def MoveToolTip(self, pos): - """ - Move tool tip + def SetToolTipPosition(self, pos): + """ + Set tool tip position @param pos: New tool tip position """ # Get screen size to prevent tool tip to go out of the screen diff -r 53e4a2b775a7 -r 074e46cdedbc controls/LogViewer.py --- a/controls/LogViewer.py Thu May 23 18:47:44 2013 +0200 +++ b/controls/LogViewer.py Thu May 23 20:39:10 2013 +0200 @@ -702,7 +702,7 @@ tooltip_pos.y += 10 self.MessageToolTip = CustomToolTip(self.MessagePanel, message.GetFullText(), False) self.MessageToolTip.SetFont(self.Font) - self.MessageToolTip.MoveToolTip(tooltip_pos) + self.MessageToolTip.SetToolTipPosition(tooltip_pos) self.MessageToolTip.Show() event.Skip() diff -r 53e4a2b775a7 -r 074e46cdedbc editors/Viewer.py --- a/editors/Viewer.py Thu May 23 18:47:44 2013 +0200 +++ b/editors/Viewer.py Thu May 23 20:39:10 2013 +0200 @@ -1060,7 +1060,7 @@ self.AddDataConsumer("%s.Q" % self.InstancePath.upper(), self) if self.ToolTipElement is not None: - self.ToolTipElement.ClearToolTip() + self.ToolTipElement.DestroyToolTip() self.ToolTipElement = None self.Inhibit(True) @@ -1644,15 +1644,19 @@ self.ResetBuffer() element = None if not event.Leaving() and not event.LeftUp() and not event.LeftDClick(): - element = self.FindElement(event, True, False) + dc = self.GetLogicalDC() + pos = event.GetLogicalPosition(dc) + element = self.FindBlockConnector(pos) + if element is None: + element = self.FindElement(event, True, False) if self.ToolTipElement is not None: - self.ToolTipElement.ClearToolTip() + self.ToolTipElement.DestroyToolTip() self.ToolTipElement = element if self.ToolTipElement is not None: tooltip_pos = self.Editor.ClientToScreen(event.GetPosition()) tooltip_pos.x += 10 tooltip_pos.y += 10 - self.ToolTipElement.CreateToolTip(tooltip_pos) + self.ToolTipElement.DisplayToolTip(tooltip_pos) event.Skip() def OnViewerLeftDown(self, event): @@ -1889,7 +1893,7 @@ event.Skip() def OnViewerLeftDClick(self, event): - element = self.FindElement(event, connectors=False) + element = self.FindElement(event) if self.Mode == MODE_SELECTION and element is not None: if self.SelectedElement is not None and self.SelectedElement != element: self.SelectedElement.SetSelected(False) @@ -1902,15 +1906,24 @@ if self.Debug: if isinstance(self.SelectedElement, FBD_Block): - instance_type = self.SelectedElement.GetType() - pou_type = { - "program": ITEM_PROGRAM, - "functionBlock": ITEM_FUNCTIONBLOCK, - }.get(self.Controler.GetPouType(instance_type)) - if pou_type is not None and instance_type in self.Controler.GetProjectPouNames(self.Debug): - self.ParentWindow.OpenDebugViewer(pou_type, - "%s.%s"%(self.GetInstancePath(True), self.SelectedElement.GetName()), - self.Controler.ComputePouName(instance_type)) + dc = self.GetLogicalDC() + pos = event.GetLogicalPosition(dc) + connector = self.SelectedElement.TestConnector(pos, EAST) + if connector is not None and len(connector.GetWires()) == 0: + iec_path = self.GetElementIECPath(connector) + if iec_path is not None: + self.ParentWindow.OpenDebugViewer( + ITEM_VAR_LOCAL, iec_path, connector.GetType()) + else: + instance_type = self.SelectedElement.GetType() + pou_type = { + "program": ITEM_PROGRAM, + "functionBlock": ITEM_FUNCTIONBLOCK, + }.get(self.Controler.GetPouType(instance_type)) + if pou_type is not None and instance_type in self.Controler.GetProjectPouNames(self.Debug): + self.ParentWindow.OpenDebugViewer(pou_type, + "%s.%s"%(self.GetInstancePath(True), self.SelectedElement.GetName()), + self.Controler.ComputePouName(instance_type)) else: iec_path = self.GetElementIECPath(self.SelectedElement) if iec_path is not None: @@ -1993,7 +2006,15 @@ elif self.Debug and self.StartMousePos is not None and event.Dragging(): pos = event.GetPosition() if abs(self.StartMousePos.x - pos.x) > 5 or abs(self.StartMousePos.y - pos.y) > 5: - iec_path = self.GetElementIECPath(self.SelectedElement) + element = self.SelectedElement + if isinstance(self.SelectedElement, FBD_Block): + dc = self.GetLogicalDC() + connector = self.SelectedElement.TestConnector( + wx.Point(dc.DeviceToLogicalX(self.StartMousePos.x), + dc.DeviceToLogicalY(self.StartMousePos.y))) + if connector is not None: + element = connector + iec_path = self.GetElementIECPath(element) if iec_path is not None: self.StartMousePos = None if self.HighlightedElement is not None: diff -r 53e4a2b775a7 -r 074e46cdedbc graphics/GraphicCommons.py --- a/graphics/GraphicCommons.py Thu May 23 18:47:44 2013 +0200 +++ b/graphics/GraphicCommons.py Thu May 23 20:39:10 2013 +0200 @@ -29,7 +29,7 @@ import datetime from threading import Lock,Timer -from controls.CustomToolTip import CustomToolTip, TOOLTIP_WAIT_PERIOD +from graphics.ToolTipProducer import ToolTipProducer #------------------------------------------------------------------------------- # Common constants @@ -594,10 +594,11 @@ Class that implements a generic graphic element """ -class Graphic_Element: +class Graphic_Element(ToolTipProducer): # Create a new graphic element def __init__(self, parent, id = None): + ToolTipProducer.__init__(self, parent) self.Parent = parent self.Id = id self.oldPos = None @@ -611,13 +612,6 @@ self.Size = wx.Size(0, 0) self.BoundingBox = wx.Rect(0, 0, 0, 0) self.Visible = False - self.ToolTip = None - self.ToolTipPos = None - self.ToolTipTimer = wx.Timer(self.Parent, -1) - self.Parent.Bind(wx.EVT_TIMER, self.OnToolTipTimer, self.ToolTipTimer) - - def __del__(self): - self.ToolTipTimer.Stop() def GetDefinition(self): return [self.Id], [] @@ -990,36 +984,6 @@ return movex, movey return 0, 0 - def OnToolTipTimer(self, event): - value = self.GetToolTipValue() - if value is not None and self.ToolTipPos is not None: - self.ToolTip = CustomToolTip(self.Parent, value) - self.ToolTip.MoveToolTip(self.ToolTipPos) - self.ToolTip.Show() - - def GetToolTipValue(self): - return None - - def CreateToolTip(self, pos): - value = self.GetToolTipValue() - if value is not None: - self.ToolTipPos = pos - self.ToolTipTimer.Start(int(TOOLTIP_WAIT_PERIOD * 1000), oneShot=True) - - def MoveToolTip(self, pos): - if self.ToolTip is not None: - self.ToolTip.MoveToolTip(pos) - elif self.ToolTipPos is not None: - self.ToolTipPos = pos - self.ToolTipTimer.Start(int(TOOLTIP_WAIT_PERIOD * 1000), oneShot=True) - - def ClearToolTip(self): - self.ToolTipTimer.Stop() - self.ToolTipPos = None - if self.ToolTip is not None: - self.ToolTip.Destroy() - self.ToolTip = None - # Override this method for defining the method to call for adding an highlight to this element def AddHighlight(self, infos, start, end, highlight_type): pass @@ -1400,11 +1364,12 @@ Class that implements a connector for any type of block """ -class Connector(DebugDataConsumer): +class Connector(DebugDataConsumer, ToolTipProducer): # Create a new connector def __init__(self, parent, name, type, position, direction, negated = False, edge = "none", onlyone = False): DebugDataConsumer.__init__(self) + ToolTipProducer.__init__(self, parent.Parent) self.ParentBlock = parent self.Name = name self.Type = type @@ -1526,20 +1491,28 @@ self.Forced = forced if self.Visible: self.Parent.ElementNeedRefresh(self) - + + def GetComputedValue(self): + if self.Value is not None and self.Value != "undefined" and not isinstance(self.Value, BooleanType): + wire_type = self.GetType() + if wire_type == "STRING": + return "'%s'"%self.Value + elif wire_type == "WSTRING": + return "\"%s\""%self.Value + else: + return str(self.Value) + return None + + def GetToolTipValue(self): + return self.GetComputedValue() + def SetValue(self, value): if self.Value != value: self.Value = value - if value is not None and not isinstance(value, BooleanType): - connector_type = self.GetType() - if connector_type == "STRING": - self.ComputedValue = "'%s'"%value - elif connector_type == "WSTRING": - self.ComputedValue = "\"%s\""%value - else: - self.ComputedValue = str(value) - #if self.ToolTip is not None: - # self.ToolTip.SetTip(self.ComputedValue) + computed_value = self.GetComputedValue() + if computed_value is not None: + self.ComputedValue = computed_value + self.SetToolTipText(self.ComputedValue) if len(self.ComputedValue) > 4: self.ComputedValue = self.ComputedValue[:4] + "..." self.ValueSize = None @@ -1945,17 +1918,6 @@ self.StartConnected = None self.EndConnected = None - def GetToolTipValue(self): - if self.Value is not None and self.Value != "undefined" and not isinstance(self.Value, BooleanType): - wire_type = self.GetEndConnectedType() - if wire_type == "STRING": - return "'%s'"%self.Value - elif wire_type == "WSTRING": - return "\"%s\""%self.Value - else: - return str(self.Value) - return None - # Returns the RedrawRect def GetRedrawRect(self, movex = 0, movey = 0): rect = Graphic_Element.GetRedrawRect(self, movex, movey) @@ -2113,19 +2075,27 @@ if self.Visible: self.Parent.ElementNeedRefresh(self) + def GetComputedValue(self): + if self.Value is not None and self.Value != "undefined" and not isinstance(self.Value, BooleanType): + wire_type = self.GetEndConnectedType() + if wire_type == "STRING": + return "'%s'"%self.Value + elif wire_type == "WSTRING": + return "\"%s\""%self.Value + else: + return str(self.Value) + return None + + def GetToolTipValue(self): + return self.GetComputedValue() + def SetValue(self, value): if self.Value != value: self.Value = value - if value is not None and not isinstance(value, BooleanType): - wire_type = self.GetEndConnectedType() - if wire_type == "STRING": - self.ComputedValue = "'%s'"%value - elif wire_type == "WSTRING": - self.ComputedValue = "\"%s\""%value - else: - self.ComputedValue = str(value) - if self.ToolTip is not None: - self.ToolTip.SetTip(self.ComputedValue) + computed_value = self.GetComputedValue() + if computed_value is not None: + self.ComputedValue = computed_value + self.SetToolTipText(self.ComputedValue) if len(self.ComputedValue) > 4: self.ComputedValue = self.ComputedValue[:4] + "..." self.ValueSize = None diff -r 53e4a2b775a7 -r 074e46cdedbc graphics/ToolTipProducer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graphics/ToolTipProducer.py Thu May 23 20:39:10 2013 +0200 @@ -0,0 +1,116 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor +#based on the plcopen standard. +# +#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD +# +#See COPYING file for copyrights details. +# +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +# +#This library is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#General Public License for more details. +# +#You should have received a copy of the GNU General Public +#License along with this library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import wx + +from controls.CustomToolTip import CustomToolTip, TOOLTIP_WAIT_PERIOD + +#------------------------------------------------------------------------------- +# Tool Tip Producer class +#------------------------------------------------------------------------------- + +""" +Class that implements an element that generate Tool Tip +""" + +class ToolTipProducer: + + def __init__(self, parent): + """ + Constructor + @param parent: Parent Viewer + """ + self.Parent = parent + + self.ToolTip = None + self.ToolTipPos = None + + # Timer for firing Tool tip display + self.ToolTipTimer = wx.Timer(self.Parent, -1) + self.Parent.Bind(wx.EVT_TIMER, + self.OnToolTipTimer, + self.ToolTipTimer) + + def __del__(self): + """ + Destructor + """ + self.DestroyToolTip() + + def OnToolTipTimer(self, event): + """ + Callback for Tool Tip firing timer Event + @param event: Tool tip text + """ + # Get Tool Tip text + value = self.GetToolTipValue() + + if value is not None and self.ToolTipPos is not None: + # Create Tool Tip + self.ToolTip = CustomToolTip(self.Parent, value) + self.ToolTip.SetToolTipPosition(self.ToolTipPos) + self.ToolTip.Show() + + def GetToolTipValue(self): + """ + Generic method that have to be overridden by derived classes + @return: Tool tip text (None if not overridden) + """ + return None + + def DisplayToolTip(self, pos): + """ + Display Tool tip + @param pos: Tool tip position + """ + # Destroy current displayed Tool tip + self.DestroyToolTip() + + # Save Tool Tip position + self.ToolTipPos = pos + # Start Tool tip firing timer + self.ToolTipTimer.Start( + int(TOOLTIP_WAIT_PERIOD * 1000), + oneShot=True) + + def SetToolTipText(self, text): + """ + Set current Tool tip text + @param text: Tool tip Text + """ + if self.ToolTip is not None: + self.ToolTip.SetTip(text) + + def DestroyToolTip(self): + """ + Destroy current displayed Tool Tip + """ + # Stop Tool tip firing timer + self.ToolTipTimer.Stop() + self.ToolTipPos = None + + # Destroy Tool Tip + if self.ToolTip is not None: + self.ToolTip.Destroy() + self.ToolTip = None