Laurent@814: #!/usr/bin/env python Laurent@814: # -*- coding: utf-8 -*- Laurent@814: andrej@1571: # This file is part of Beremiz, a Integrated Development Environment for andrej@1571: # programming IEC 61131-3 automates supporting plcopen standard and CanFestival. Laurent@814: # andrej@1571: # Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD Laurent@814: # andrej@1571: # See COPYING file for copyrights details. Laurent@814: # andrej@1571: # This program is free software; you can redistribute it and/or andrej@1571: # modify it under the terms of the GNU General Public License andrej@1571: # as published by the Free Software Foundation; either version 2 andrej@1571: # of the License, or (at your option) any later version. Laurent@814: # andrej@1571: # This program is distributed in the hope that it will be useful, andrej@1571: # but WITHOUT ANY WARRANTY; without even the implied warranty of andrej@1571: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the andrej@1571: # GNU General Public License for more details. Laurent@814: # andrej@1571: # You should have received a copy of the GNU General Public License andrej@1571: # along with this program; if not, write to the Free Software andrej@1571: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Laurent@814: Laurent@814: import wx Laurent@814: Laurent@1173: from graphics.GraphicCommons import GetScaledEventPosition Laurent@1169: Laurent@814: #------------------------------------------------------------------------------- Laurent@1173: # Viewer RubberBand Laurent@814: #------------------------------------------------------------------------------- Laurent@814: Laurent@814: """ Laurent@1173: Class that implements a rubberband for graphic Viewers Laurent@814: """ Laurent@814: Laurent@814: class RubberBand: andrej@1730: Laurent@814: def __init__(self, viewer): Laurent@1173: """ Laurent@1173: Constructor Laurent@1173: @param viewer: Viewer on which rubberband must be drawn Laurent@1173: """ Laurent@814: self.Viewer = viewer andrej@1730: Laurent@1173: # wx.Panel on which rubberband will be drawn Laurent@1173: self.DrawingSurface = viewer.Editor andrej@1730: Laurent@814: self.Reset() andrej@1730: Laurent@814: def Reset(self): Laurent@1173: """ Laurent@1173: Initialize internal attributes of rubberband Laurent@1173: """ Laurent@1173: self.StartPoint = None Laurent@1173: self.CurrentBBox = None Laurent@1173: self.LastBBox = None andrej@1730: Laurent@814: def IsShown(self): Laurent@1173: """ Laurent@1173: Indicate if rubberband is drawn on viewer Laurent@1173: @return: True if rubberband is drawn Laurent@1173: """ Laurent@1173: return self.CurrentBBox != None andrej@1730: Laurent@814: def GetCurrentExtent(self): Laurent@1173: """ Laurent@1173: Return the rubberband bounding box Laurent@1173: @return: Rubberband bounding box (wx.Rect object) Laurent@1173: """ Laurent@1173: # In case of rubberband not shown, return the last rubberband Laurent@1173: # bounding box Laurent@1173: if self.IsShown(): Laurent@1173: return self.CurrentBBox Laurent@1173: return self.LastBBox andrej@1730: Laurent@814: def OnLeftDown(self, event, dc, scaling): Laurent@1173: """ Laurent@1173: Called when left mouse is pressed on Viewer. Starts to edit a new Laurent@1173: rubberband bounding box Laurent@1173: @param event: Mouse event Laurent@1173: @param dc: Device Context of Viewer Laurent@1173: @param scaling: PLCOpen scaling applied on Viewer Laurent@1173: """ Laurent@1173: # Save the point where mouse was pressed in Viewer unit, position may Laurent@1173: # be modified by scroll and zoom applied on viewer Laurent@1173: self.StartPoint = GetScaledEventPosition(event, dc, scaling) andrej@1730: Laurent@1173: # Initialize rubberband bounding box Laurent@1173: self.CurrentBBox = wx.Rect(self.StartPoint.x, self.StartPoint.y, 0, 0) andrej@1730: Laurent@1173: # Change viewer mouse cursor to reflect a rubberband bounding box is Laurent@1173: # edited Laurent@1173: self.DrawingSurface.SetCursor(wx.StockCursor(wx.CURSOR_CROSS)) andrej@1730: Laurent@814: self.Redraw() andrej@1730: Laurent@814: def OnMotion(self, event, dc, scaling): Laurent@1173: """ Laurent@1173: Called when mouse is dragging over Viewer. Update the current edited Laurent@1173: rubberband bounding box Laurent@1173: @param event: Mouse event Laurent@1173: @param dc: Device Context of Viewer Laurent@1173: @param scaling: PLCOpen scaling applied on Viewer Laurent@1173: """ Laurent@1173: # Get mouse position in Viewer unit, position may be modified by scroll Laurent@1173: # and zoom applied on viewer Laurent@814: pos = GetScaledEventPosition(event, dc, scaling) andrej@1730: Laurent@1173: # Save the last bounding box drawn for erasing it later Laurent@1173: self.LastBBox = wx.Rect(0, 0, 0, 0) Laurent@1173: self.LastBBox.Union(self.CurrentBBox) andrej@1730: andrej@1730: # Calculate new position and size of the box Laurent@1173: self.CurrentBBox.x = min(pos.x, self.StartPoint.x) Laurent@1173: self.CurrentBBox.y = min(pos.y, self.StartPoint.y) Laurent@1173: self.CurrentBBox.width = abs(pos.x - self.StartPoint.x) + 1 Laurent@1173: self.CurrentBBox.height = abs(pos.y - self.StartPoint.y) + 1 andrej@1730: Laurent@814: self.Redraw() andrej@1730: Laurent@814: def OnLeftUp(self, event, dc, scaling): Laurent@1173: """ Laurent@1173: Called when mouse is release from Viewer. Erase the current edited Laurent@1173: rubberband bounding box Laurent@1173: @param event: Mouse event Laurent@1173: @param dc: Device Context of Viewer Laurent@1173: @param scaling: PLCOpen scaling applied on Viewer Laurent@1173: """ Laurent@1173: # Change viewer mouse cursor to default Laurent@1173: self.DrawingSurface.SetCursor(wx.NullCursor) andrej@1730: Laurent@1173: # Save the last edited bounding box Laurent@1173: self.LastBBox = self.CurrentBBox Laurent@1173: self.CurrentBBox = None andrej@1730: Laurent@814: self.Redraw() andrej@1730: Laurent@1173: def DrawBoundingBoxes(self, bboxes, dc=None): Laurent@1173: """ andrej@1730: Draw a list of bounding box on Viewer in the order given using XOR Laurent@1173: logical function Laurent@1173: @param bboxes: List of bounding boxes to draw on viewer Laurent@1173: @param dc: Device Context of Viewer (default None) Laurent@1173: """ Laurent@1173: # Get viewer Device Context if not given Laurent@814: if dc is None: Laurent@814: dc = self.Viewer.GetLogicalDC() andrej@1730: Laurent@1173: # Save current viewer scale factors before resetting them in order to Laurent@1173: # avoid rubberband pen to be scaled Laurent@814: scalex, scaley = dc.GetUserScale() Laurent@814: dc.SetUserScale(1, 1) andrej@1730: Laurent@1173: # Set DC drawing style Laurent@1173: dc.SetPen(wx.Pen(wx.WHITE, style=wx.DOT)) Laurent@814: dc.SetBrush(wx.TRANSPARENT_BRUSH) Laurent@814: dc.SetLogicalFunction(wx.XOR) andrej@1730: Laurent@1173: # Draw the bounding boxes using viewer scale factor Laurent@1173: for bbox in bboxes: Laurent@1173: if bbox is not None: Laurent@1173: dc.DrawRectangle( andrej@1730: bbox.x * scalex, bbox.y * scaley, Laurent@1173: bbox.width * scalex, bbox.height * scaley) andrej@1730: Laurent@1273: dc.SetLogicalFunction(wx.COPY) andrej@1730: Laurent@1173: # Restore Viewer scale factor Laurent@814: dc.SetUserScale(scalex, scaley) andrej@1730: Laurent@1173: def Redraw(self, dc = None): Laurent@1173: """ Laurent@1173: Redraw rubberband on Viewer Laurent@1173: @param dc: Device Context of Viewer (default None) Laurent@1173: """ Laurent@1173: # Erase last bbox and draw current bbox Laurent@1173: self.DrawBoundingBoxes([self.LastBBox, self.CurrentBBox], dc) andrej@1730: Laurent@814: def Erase(self, dc = None): Laurent@1173: """ Laurent@1173: Erase rubberband from Viewer Laurent@1173: @param dc: Device Context of Viewer (default None) Laurent@1173: """ Laurent@1173: # Erase last bbox Laurent@1173: self.DrawBoundingBoxes([self.LastBBox], dc) Laurent@814: Laurent@814: def Draw(self, dc = None): Laurent@1173: """ Laurent@1173: Draw rubberband on Viewer Laurent@1173: @param dc: Device Context of Viewer (default None) Laurent@1173: """ Laurent@1173: # Erase last bbox and draw current bbox Laurent@1173: self.DrawBoundingBoxes([self.CurrentBBox], dc)