diff -r dff0a4e40808 -r ad09b4a755ce graphics/RubberBand.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graphics/RubberBand.py Fri May 24 16:29:57 2013 +0200 @@ -0,0 +1,192 @@ +#!/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 graphics.GraphicCommons import GetScaledEventPosition + +#------------------------------------------------------------------------------- +# Viewer RubberBand +#------------------------------------------------------------------------------- + +""" +Class that implements a rubberband for graphic Viewers +""" + +class RubberBand: + + def __init__(self, viewer): + """ + Constructor + @param viewer: Viewer on which rubberband must be drawn + """ + self.Viewer = viewer + + # wx.Panel on which rubberband will be drawn + self.DrawingSurface = viewer.Editor + + self.Reset() + + def Reset(self): + """ + Initialize internal attributes of rubberband + """ + self.StartPoint = None + self.CurrentBBox = None + self.LastBBox = None + + def IsShown(self): + """ + Indicate if rubberband is drawn on viewer + @return: True if rubberband is drawn + """ + return self.CurrentBBox != None + + def GetCurrentExtent(self): + """ + Return the rubberband bounding box + @return: Rubberband bounding box (wx.Rect object) + """ + # In case of rubberband not shown, return the last rubberband + # bounding box + if self.IsShown(): + return self.CurrentBBox + return self.LastBBox + + def OnLeftDown(self, event, dc, scaling): + """ + Called when left mouse is pressed on Viewer. Starts to edit a new + rubberband bounding box + @param event: Mouse event + @param dc: Device Context of Viewer + @param scaling: PLCOpen scaling applied on Viewer + """ + # Save the point where mouse was pressed in Viewer unit, position may + # be modified by scroll and zoom applied on viewer + self.StartPoint = GetScaledEventPosition(event, dc, scaling) + + # Initialize rubberband bounding box + self.CurrentBBox = wx.Rect(self.StartPoint.x, self.StartPoint.y, 0, 0) + + # Change viewer mouse cursor to reflect a rubberband bounding box is + # edited + self.DrawingSurface.SetCursor(wx.StockCursor(wx.CURSOR_CROSS)) + + self.Redraw() + + def OnMotion(self, event, dc, scaling): + """ + Called when mouse is dragging over Viewer. Update the current edited + rubberband bounding box + @param event: Mouse event + @param dc: Device Context of Viewer + @param scaling: PLCOpen scaling applied on Viewer + """ + # Get mouse position in Viewer unit, position may be modified by scroll + # and zoom applied on viewer + pos = GetScaledEventPosition(event, dc, scaling) + + # Save the last bounding box drawn for erasing it later + self.LastBBox = wx.Rect(0, 0, 0, 0) + self.LastBBox.Union(self.CurrentBBox) + + # Calculate new position and size of the box + self.CurrentBBox.x = min(pos.x, self.StartPoint.x) + self.CurrentBBox.y = min(pos.y, self.StartPoint.y) + self.CurrentBBox.width = abs(pos.x - self.StartPoint.x) + 1 + self.CurrentBBox.height = abs(pos.y - self.StartPoint.y) + 1 + + self.Redraw() + + def OnLeftUp(self, event, dc, scaling): + """ + Called when mouse is release from Viewer. Erase the current edited + rubberband bounding box + @param event: Mouse event + @param dc: Device Context of Viewer + @param scaling: PLCOpen scaling applied on Viewer + """ + # Change viewer mouse cursor to default + self.DrawingSurface.SetCursor(wx.NullCursor) + + # Save the last edited bounding box + self.LastBBox = self.CurrentBBox + self.CurrentBBox = None + + self.Redraw() + + def DrawBoundingBoxes(self, bboxes, dc=None): + """ + Draw a list of bounding box on Viewer in the order given using XOR + logical function + @param bboxes: List of bounding boxes to draw on viewer + @param dc: Device Context of Viewer (default None) + """ + # Get viewer Device Context if not given + if dc is None: + dc = self.Viewer.GetLogicalDC() + + # Save current viewer scale factors before resetting them in order to + # avoid rubberband pen to be scaled + scalex, scaley = dc.GetUserScale() + dc.SetUserScale(1, 1) + + # Set DC drawing style + dc.SetPen(wx.Pen(wx.WHITE, style=wx.DOT)) + dc.SetBrush(wx.TRANSPARENT_BRUSH) + dc.SetLogicalFunction(wx.XOR) + + # Draw the bounding boxes using viewer scale factor + for bbox in bboxes: + if bbox is not None: + dc.DrawRectangle( + bbox.x * scalex, bbox.y * scaley, + bbox.width * scalex, bbox.height * scaley) + + # Restore Viewer scale factor + dc.SetUserScale(scalex, scaley) + + def Redraw(self, dc = None): + """ + Redraw rubberband on Viewer + @param dc: Device Context of Viewer (default None) + """ + # Erase last bbox and draw current bbox + self.DrawBoundingBoxes([self.LastBBox, self.CurrentBBox], dc) + + def Erase(self, dc = None): + """ + Erase rubberband from Viewer + @param dc: Device Context of Viewer (default None) + """ + # Erase last bbox + self.DrawBoundingBoxes([self.LastBBox], dc) + + def Draw(self, dc = None): + """ + Draw rubberband on Viewer + @param dc: Device Context of Viewer (default None) + """ + # Erase last bbox and draw current bbox + self.DrawBoundingBoxes([self.CurrentBBox], dc)