Fixing ToolTip behavior and bug with INOUT interface variables in Function Blocks and adding support for display connection point between wire and connector when mouse passing over.
--- a/Viewer.py Wed Jan 25 01:26:29 2012 +0100
+++ b/Viewer.py Mon Jan 30 16:12:19 2012 +0100
@@ -539,6 +539,7 @@
self.Editor.Bind(wx.EVT_SCROLLWIN_THUMBRELEASE, self.OnScrollStop)
self.Editor.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheelWindow)
self.Editor.Bind(wx.EVT_SIZE, self.OnMoveWindow)
+ self.Editor.Bind(wx.EVT_MOUSE_EVENTS, self.OnViewerMouseEvent)
def __del__(self):
DebugViewer.__del__(self)
@@ -621,6 +622,9 @@
def GetScale(self):
return self.CurrentScale
+ def GetViewScale(self):
+ return self.ViewScale
+
def GetLogicalDC(self, buffered=False):
if buffered:
bitmap = wx.EmptyBitmap(*self.Editor.GetClientSize())
@@ -781,6 +785,7 @@
self.Subscribed = {}
self.SelectedElement = None
self.HighlightedElement = None
+ self.ToolTipElement = None
def Flush(self):
self.DeleteDataConsumers()
@@ -1130,14 +1135,14 @@
return wire
return None
- def FindElement(self, event, exclude_group = False):
+ def FindElement(self, event, exclude_group = False, connectors = True):
dc = self.GetLogicalDC()
pos = event.GetLogicalPosition(dc)
if self.SelectedElement and not (exclude_group and isinstance(self.SelectedElement, Graphic_Group)):
- if self.SelectedElement.HitTest(pos) or self.SelectedElement.TestHandle(event) != (0, 0):
+ if self.SelectedElement.HitTest(pos, connectors) or self.SelectedElement.TestHandle(event) != (0, 0):
return self.SelectedElement
for element in self.GetElements():
- if element.HitTest(pos) or element.TestHandle(event) != (0, 0):
+ if element.HitTest(pos, connectors) or element.TestHandle(event) != (0, 0):
return element
return None
@@ -1400,6 +1405,21 @@
# Mouse event functions
#-------------------------------------------------------------------------------
+ def OnViewerMouseEvent(self, event):
+ if not event.Entering():
+ element = None
+ if not event.Leaving():
+ element = self.FindElement(event, True, False)
+ if self.ToolTipElement is not None:
+ self.ToolTipElement.ClearToolTip()
+ 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)
+ event.Skip()
+
def OnViewerLeftDown(self, event):
if self.Mode == MODE_SELECTION:
dc = self.GetLogicalDC()
@@ -1466,8 +1486,11 @@
if self.SelectedElement is not None:
self.SelectedElement.SetSelected(False)
self.SelectedElement = wire
+ if self.HighlightedElement is not None:
+ self.HighlightedElement.SetHighlighted(False)
+ self.HighlightedElement = wire
self.RefreshVisibleElements()
- self.SelectedElement.Refresh()
+ self.SelectedElement.SetHighlighted(True)
else:
if self.SelectedElement is not None and self.SelectedElement != element:
self.SelectedElement.SetSelected(False)
@@ -1556,12 +1579,8 @@
self.SelectedElement.OnMotion(event, dc, self.Scaling)
self.SelectedElement.GeneratePoints()
self.SelectedElement.RefreshModel()
- if self.HighlightedElement is not None:
- self.HighlightedElement.SetHighlighted(False)
- self.HighlightedElement = None
- self.SelectedElement.SetHighlighted(True)
- self.HighlightedElement = self.SelectedElement
self.SelectedElement.SetSelected(True)
+ self.SelectedElement.HighlightPoint(pos)
self.RefreshBuffer()
elif connector is None or self.SelectedElement.GetDragging():
self.DrawingWire = False
@@ -1666,20 +1685,15 @@
self.RefreshVisibleElements()
else:
if not event.Dragging():
- highlighted = self.FindElement(event)
+ highlighted = self.FindElement(event, connectors=False)
if self.HighlightedElement is not None and self.HighlightedElement != highlighted:
- self.HighlightedElement.ClearToolTip()
self.HighlightedElement.SetHighlighted(False)
self.HighlightedElement = None
if highlighted is not None:
- tooltip_pos = self.Editor.ClientToScreen(event.GetPosition())
- tooltip_pos.x += 10
- tooltip_pos.y += 10
+ if isinstance(highlighted, (Wire, Graphic_Group)):
+ highlighted.HighlightPoint(pos)
if self.HighlightedElement != highlighted:
- highlighted.CreateToolTip(tooltip_pos)
highlighted.SetHighlighted(True)
- else:
- highlighted.MoveToolTip(tooltip_pos)
self.HighlightedElement = highlighted
if self.rubberBand.IsShown():
self.rubberBand.OnMotion(event, dc, self.Scaling)
@@ -1692,6 +1706,8 @@
self.SelectedElement.GeneratePoints()
if movex != 0 or movey != 0:
self.RefreshRect(self.GetScrolledRect(self.SelectedElement.GetRedrawRect(movex, movey)), False)
+ else:
+ self.SelectedElement.HighlightPoint(pos)
else:
movex, movey = self.SelectedElement.OnMotion(event, dc, self.Scaling)
if movex != 0 or movey != 0:
@@ -1703,8 +1719,6 @@
if iec_path is not None:
self.StartMousePos = None
if self.HighlightedElement is not None:
- if isinstance(self.HighlightedElement, Wire):
- self.HighlightedElement.ClearToolTip()
self.HighlightedElement.SetHighlighted(False)
self.HighlightedElement = None
data = wx.TextDataObject(str((iec_path, "debug")))
@@ -1720,7 +1734,6 @@
if self.SelectedElement is not None and self.SelectedElement.GetDragging():
event.Skip()
elif self.HighlightedElement is not None:
- self.HighlightedElement.ClearToolTip()
self.HighlightedElement.SetHighlighted(False)
self.HighlightedElement = None
event.Skip()
--- a/graphics/FBD_Objects.py Wed Jan 25 01:26:29 2012 +0100
+++ b/graphics/FBD_Objects.py Mon Jan 30 16:12:19 2012 +0100
@@ -160,11 +160,11 @@
# Returns the block connector that starts with the point given if it exists
def GetConnector(self, position, name = None):
# if a name is given
- if name:
+ if name is not None:
# Test each input and output connector
- for input in self.Inputs:
- if name == input.GetName():
- return input
+ #for input in self.Inputs:
+ # if name == input.GetName():
+ # return input
for output in self.Outputs:
if name == output.GetName():
return output
@@ -583,10 +583,10 @@
# Returns the block connector that starts with the point given if it exists
def GetConnector(self, position, name = None):
# if a name is given
- if name:
+ if name is not None:
# Test input and output connector if they exists
- if self.Input and name == self.Input.GetName():
- return self.Input
+ #if self.Input and name == self.Input.GetName():
+ # return self.Input
if self.Output and name == self.Output.GetName():
return self.Output
connectors = []
--- a/graphics/GraphicCommons.py Wed Jan 25 01:26:29 2012 +0100
+++ b/graphics/GraphicCommons.py Mon Jan 30 16:12:19 2012 +0100
@@ -454,7 +454,7 @@
# Method that erase the last box and draw the new box
def Redraw(self, dc = None):
- if not dc:
+ if dc is None:
dc = self.Viewer.GetLogicalDC()
scalex, scaley = dc.GetUserScale()
dc.SetUserScale(1, 1)
@@ -473,7 +473,7 @@
# Erase last box
def Erase(self, dc = None):
- if not dc:
+ if dc is None:
dc = self.Viewer.GetLogicalDC()
scalex, scaley = dc.GetUserScale()
dc.SetUserScale(1, 1)
@@ -487,7 +487,7 @@
# Draw current box
def Draw(self, dc = None):
- if not dc:
+ if dc is None:
dc = self.Viewer.GetLogicalDC()
scalex, scaley = dc.GetUserScale()
dc.SetUserScale(1, 1)
@@ -523,6 +523,9 @@
'size' : 12,
}
+TOOLTIP_MAX_CHARACTERS = 30
+TOOLTIP_MAX_LINE = 5
+
class ToolTip(wx.PopupWindow):
def __init__(self, parent, tip):
@@ -536,7 +539,28 @@
self.Bind(wx.EVT_PAINT, self.OnPaint)
def SetTip(self, tip):
- self.Tip = tip
+ lines = []
+ for line in tip.splitlines():
+ if line != "":
+ words = line.split()
+ new_line = words[0]
+ for word in words[1:]:
+ if len(new_line + " " + word) <= TOOLTIP_MAX_CHARACTERS:
+ new_line += " " + word
+ else:
+ lines.append(new_line)
+ new_line = word
+ lines.append(new_line)
+ else:
+ lines.append(line)
+ if len(lines) > TOOLTIP_MAX_LINE:
+ self.Tip = lines[:TOOLTIP_MAX_LINE]
+ if len(self.Tip[-1]) < TOOLTIP_MAX_CHARACTERS - 3:
+ self.Tip[-1] += "..."
+ else:
+ self.Tip[-1] = self.Tip[-1][:TOOLTIP_MAX_CHARACTERS - 3] + "..."
+ else:
+ self.Tip = lines
wx.CallAfter(self.RefreshTip)
def MoveToolTip(self, pos):
@@ -546,7 +570,7 @@
def GetTipExtent(self):
max_width = 0
max_height = 0
- for line in self.Tip.splitlines():
+ for line in self.Tip:
w, h = self.GetTextExtent(line)
max_width = max(max_width, w)
max_height += h
@@ -569,7 +593,7 @@
w, h = self.GetTipExtent()
dc.DrawRectangle(0, 0, w + 4, h + 4)
offset = 0
- for line in self.Tip.splitlines():
+ for line in self.Tip:
dc.DrawText(line, 2, offset + 2)
w, h = dc.GetTextExtent(line)
offset += h
@@ -640,7 +664,7 @@
self.Parent.Bind(wx.EVT_TIMER, self.OnToolTipTimer, self.ToolTipTimer)
def __del__(self):
- self
+ self.ToolTipTimer.Stop()
def GetDefinition(self):
return [self.Id], []
@@ -733,8 +757,11 @@
return self.Id
# Returns if the point given is in the bounding box
- def HitTest(self, pt):
- rect = self.BoundingBox
+ def HitTest(self, pt, connectors=True):
+ if connectors:
+ rect = self.BoundingBox
+ else:
+ rect = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0], self.Size[1])
return rect.InsideXY(pt.x, pt.y)
# Returns if the point given is in the bounding box
@@ -751,8 +778,7 @@
# Returns the RedrawRect
def GetRedrawRect(self, movex = 0, movey = 0):
- dc = self.Parent.GetLogicalDC()
- scalex, scaley = dc.GetUserScale()
+ scalex, scaley = self.Parent.GetViewScale()
rect = wx.Rect()
rect.x = self.BoundingBox.x - int(HANDLE_SIZE / scalex) - 3 - abs(movex)
rect.y = self.BoundingBox.y - int(HANDLE_SIZE / scaley) - 3 - abs(movey)
@@ -1212,10 +1238,10 @@
self.WireExcluded = []
# Returns if the point given is in the bounding box of one of the elements of this group
- def HitTest(self, pt):
+ def HitTest(self, pt, connectors=True):
result = False
for element in self.Elements:
- result |= element.HitTest(pt)
+ result |= element.HitTest(pt, connectors)
return result
# Returns if the element given is in this group
@@ -1359,7 +1385,12 @@
def SetHighlighted(self, highlighted):
for element in self.Elements:
element.SetHighlighted(highlighted)
-
+
+ def HighlightPoint(self, pos):
+ for element in self.Elements:
+ if isinstance(element, Wire):
+ element.HighlightPoint(pos)
+
# Method called when a LeftDown event have been generated
def OnLeftDown(self, event, dc, scaling):
Graphic_Element.OnLeftDown(self, event, dc, scaling)
@@ -2181,12 +2212,20 @@
return width + 1, height + 1
# Returns if the point given is on one of the wire segments
- def HitTest(self, pt):
+ def HitTest(self, pt, connectors=True):
test = False
for i in xrange(len(self.Points) - 1):
rect = wx.Rect(0, 0, 0, 0)
- x1, y1 = self.Points[i].x, self.Points[i].y
- x2, y2 = self.Points[i + 1].x, self.Points[i + 1].y
+ if i == 0 and self.StartConnected is not None:
+ x1 = self.Points[i].x - self.Segments[0][0] * CONNECTOR_SIZE
+ y1 = self.Points[i].y - self.Segments[0][1] * CONNECTOR_SIZE
+ else:
+ x1, y1 = self.Points[i].x, self.Points[i].y
+ if i == len(self.Points) - 2 and self.EndConnected is not None:
+ x2 = self.Points[i + 1].x + self.Segments[-1][0] * CONNECTOR_SIZE
+ y2 = self.Points[i + 1].y + self.Segments[-1][1] * CONNECTOR_SIZE
+ else:
+ x2, y2 = self.Points[i + 1].x, self.Points[i + 1].y
# Calculate a rectangle around the segment
rect = wx.Rect(min(x1, x2) - ANCHOR_DISTANCE, min(y1, y2) - ANCHOR_DISTANCE,
abs(x1 - x2) + 2 * ANCHOR_DISTANCE, abs(y1 - y2) + 2 * ANCHOR_DISTANCE)
@@ -2784,16 +2823,6 @@
wx.CallAfter(self.Parent.SetCurrentCursor, 5)
return 0, 0
else:
- # Test if a point has been handled
- #result = self.TestPoint(pos)
- #if result != None:
- # if result == 0 and self.StartConnected:
- # self.OverStart = True
- # elif result != 0 and self.EndConnected:
- # self.OverEnd = True
- #else:
- # self.OverStart = False
- # self.OverEnd = False
# Execute the default method for a graphic element
return Graphic_Element.OnMotion(self, event, dc, scaling)
else:
@@ -2868,6 +2897,29 @@
if self.EndConnected and self.EndPoint[1] in [WEST, NORTH]:
self.EndConnected.RefreshParentBlock()
+ # Change the variable that indicates if this element is highlighted
+ def SetHighlighted(self, highlighted):
+ self.Highlighted = highlighted
+ if not highlighted:
+ self.OverStart = False
+ self.OverEnd = False
+ self.Refresh()
+
+ def HighlightPoint(self, pos):
+ refresh = False
+ start, end = self.OverStart, self.OverEnd
+ self.OverStart = False
+ self.OverEnd = False
+ # Test if a point has been handled
+ result = self.TestPoint(pos)
+ if result != None:
+ if result == 0 and self.StartConnected is not None:
+ self.OverStart = True
+ elif result != 0 and self.EndConnected is not None:
+ self.OverEnd = True
+ if start != self.OverStart or end != self.OverEnd:
+ self.Refresh()
+
# Draws the highlightment of this element if it is highlighted
def DrawHighlightment(self, dc):
scalex, scaley = dc.GetUserScale()
--- a/graphics/LD_Objects.py Wed Jan 25 01:26:29 2012 +0100
+++ b/graphics/LD_Objects.py Mon Jan 30 16:12:19 2012 +0100
@@ -89,9 +89,9 @@
self.RefreshConnectors()
# Forbids to select a power rail
- def HitTest(self, pt):
+ def HitTest(self, pt, connectors=True):
if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
- return Graphic_Element.HitTest(self, pt) or self.TestConnector(pt, exclude=False) != None
+ return Graphic_Element.HitTest(self, pt, connectors) or self.TestConnector(pt, exclude=False) != None
return False
# Forbids to select a power rail
@@ -199,7 +199,7 @@
# Returns the power rail connector that starts with the point given if it exists
def GetConnector(self, position, name = None):
# if a name is given
- if name:
+ if name is not None:
# Test each connector if it exists
for connector in self.Connectors:
if name == connector.GetName():
@@ -509,10 +509,10 @@
# Returns the contact connector that starts with the point given if it exists
def GetConnector(self, position, name = None):
# if a name is given
- if name:
+ if name is not None:
# Test input and output connector
- if name == self.Input.GetName():
- return self.Input
+ #if name == self.Input.GetName():
+ # return self.Input
if name == self.Output.GetName():
return self.Output
return self.FindNearestConnector(position, [self.Input, self.Output])
@@ -828,10 +828,10 @@
# Returns the coil connector that starts with the point given if it exists
def GetConnector(self, position, name = None):
# if a name is given
- if name:
+ if name is not None:
# Test input and output connector
- if self.Input and name == self.Input.GetName():
- return self.Input
+ #if self.Input and name == self.Input.GetName():
+ # return self.Input
if self.Output and name == self.Output.GetName():
return self.Output
return self.FindNearestConnector(position, [self.Input, self.Output])
--- a/graphics/SFC_Objects.py Wed Jan 25 01:26:29 2012 +0100
+++ b/graphics/SFC_Objects.py Mon Jan 30 16:12:19 2012 +0100
@@ -253,10 +253,10 @@
# Returns the step connector that starts with the point given if it exists
def GetConnector(self, position, name = None):
# if a name is given
- if name:
+ if name is not None:
# Test input, output and action connector if they exists
- if self.Input and name == self.Input.GetName():
- return self.Input
+ #if self.Input and name == self.Input.GetName():
+ # return self.Input
if self.Output and name == self.Output.GetName():
return self.Output
if self.Action and name == self.Action.GetName():
@@ -757,10 +757,10 @@
# Returns the transition connector that starts with the point given if it exists
def GetConnector(self, position, name = None):
# if a name is given
- if name:
+ if name is not None:
# Test input and output connector
- if name == self.Input.GetName():
- return self.Input
+ #if name == self.Input.GetName():
+ # return self.Input
if name == self.Output.GetName():
return self.Output
if self.Type == "connection" and name == self.Condition.GetName():
@@ -1178,8 +1178,11 @@
return len(self.Inputs)
# Returns if the point given is in the bounding box
- def HitTest(self, pt):
- rect = self.BoundingBox
+ def HitTest(self, pt, connectors=True):
+ if connectors:
+ rect = self.BoundingBox
+ else:
+ rect = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0], self.Size[1])
return rect.InsideXY(pt.x, pt.y) or self.TestConnector(pt, exclude=False) != None
# Refresh the divergence bounding box
@@ -1229,11 +1232,11 @@
# Returns the divergence connector that starts with the point given if it exists
def GetConnector(self, position, name = None):
# if a name is given
- if name:
+ if name is not None:
# Test each input and output connector
- for input in self.Inputs:
- if name == input.GetName():
- return input
+ #for input in self.Inputs:
+ # if name == input.GetName():
+ # return input
for output in self.Outputs:
if name == output.GetName():
return output
--- a/plcopen/plcopen.py Wed Jan 25 01:26:29 2012 +0100
+++ b/plcopen/plcopen.py Mon Jan 30 16:12:19 2012 +0100
@@ -433,13 +433,8 @@
def AddCustomBlockType(self, pou):
pou_name = pou.getname()
pou_type = pou.getpouType()
- pou_description = pou.getdescription()
- if pou_description != "":
- pou_comment = "%s\n%s" % (pou_name, pou_description)
- else:
- pou_comment = pou_name
block_infos = {"name" : pou_name, "type" : pou_type, "extensible" : False,
- "inputs" : [], "outputs" : [], "comment" : pou_comment,
+ "inputs" : [], "outputs" : [], "comment" : pou.getdescription(),
"generate" : generate_block, "initialise" : initialise_block}
if pou.getinterface():
return_type = pou.interface.getreturnType()