Added support for displaying ToolTip, starting drag'n drop and Double click on Block connectors when debugging
--- 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
--- 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()
--- 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:
--- 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
--- /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