graphics/RubberBand.py
author Andrey Skvortsov <andrej.skvortzov@gmail.com>
Fri, 25 Aug 2017 11:22:08 +0300
changeset 1789 492e2cd6157e
parent 1782 5b6ad7a7fd9d
child 1831 56b48961cc68
permissions -rw-r--r--
fix problem when Beremiz is running without matiec installed

set matiec settings only once on first use of ProjectController class and give
user-friendly message on compilation about missing matiec
installation.


Traceback (most recent call last):
File "Beremiz.py", line 197, in <module>
beremiz.Start()
File "Beremiz.py", line 192, in Start
self.CreateApplication()
File "Beremiz.py", line 130, in CreateApplication
self.BackgroundInitialization()
File "Beremiz.py", line 137, in BackgroundInitialization
self.ImportModules()
File "Beremiz.py", line 176, in ImportModules
import BeremizIDE
File
"BeremizIDE.py", line 76, in <module>
from ProjectController import ProjectController, GetAddMenuItems,
MATIEC_ERROR_MODEL, ITEM_CONFNODE
File
"ProjectController.py", line 177, in <module>
iec2c_cfg = Iec2CSettings()
File
"ProjectController.py", line 101, in __init__
self.ieclib_c_path = self.findLibCPath()
File
"ProjectController.py", line 135, in findLibCPath
os.path.join(self.ieclib_path, "C"),
File "/usr/lib/python2.7/posixpath.py", line 70, in join
elif path == '' or path.endswith('/'):
AttributeError: 'NoneType' object has no attribute 'endswith'
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# This file is part of Beremiz, a Integrated Development Environment for
# programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
#
# Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
#
# See COPYING file for copyrights details.
#
# This program 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
# of the License, or (at your option) any later version.
#
# This program 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 program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

import wx

from graphics.GraphicCommons import GetScaledEventPosition


# -------------------------------------------------------------------------------
#                               Viewer RubberBand
# -------------------------------------------------------------------------------


class RubberBand:
    """
    Class that implements a rubberband for graphic Viewers
    """

    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 is not 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)

        dc.SetLogicalFunction(wx.COPY)

        # 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)