# Sketch - A Python-based interactive drawing program
# Copyright (C) 1997, 1998, 1999, 2001 by Bernhard Herzog
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 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
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library 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


#
# This file contains the root of the Sketch graphics class hierarchy.
#

from traceback import print_stack

from Sketch.warn import warn, INTERNAL
from Sketch.const import CHANGED, SelectSet, Button1Mask, ConstraintMask, \
     SCRIPT_GET, SCRIPT_OBJECT, SCRIPT_UNDO
from Sketch import NullUndo, CreateMultiUndo, Undo, UndoAfter

from Sketch import Point, NullPoint, UnionRects, Identity, Translation, Trafo

from blend import Blend, MismatchError, BlendTrafo
from properties import PropertyStack
import properties


# Class Draggable
#
# This class maintains some instance variables for a click and drag
# operation on a graphics object.
#
# The scenario is this: The user has selected a graphics object, say a
# straight line between the points A and B, for editing. As a hint for
# the user where to click, the application shows two inverted rectangles
# at the endpoints. These rectangles are called handles. The user clicks
# on one of the handles, and, with the mouse button still pressed, drags
# the mouse to the new location of the selected endpoint. As feedback to
# the user, the application shows a `rubber-band' line during the drag
# to indicate what the line would look like if the user released the
# button.
#
# Two aspects of this operation are handled by the classes Draggable and
# EditSelect: Keeping track of the start point, the current point, the
# amount dragged, drawing the object during the drag and, in the case of
# Selectable, which parts of the object the user selected.
#
# Keeping track of where the drag started and how far in which direction
# the user has moved the mouse so far, is important, because, in the
# above example the endpoint should be moved not simply to the point the
# user dragged to, but by the amount the user dragged.
#
# To make this a little clearer: the handle is usually a few pixels
# wide, so the user may not click exactly on the pixel the endpoint lies
# on, but some pixels away. In that case, releasing the button without
# moving the mouse would still move the endpoint which is not what the
# user expected.
#
# Using only the offset of the drag is even more important when the
# entire object is being moved. In the above example, clicking on the
# middle of the line should select the entire line, i.e. both endpoints,
# for the drag. During the drag and at the end of the drag we can't move
# one or both endpoints to the current location of the mouse pointer, we
# have to move both endpoints by the same offset.
#
# To achieve this, an instance of Draggable has the following instance
# variables:
#
#	dragging	True, while being dragged
#	drag_start	start point
#	drag_cur	current point
#	off		offset by which the pointer was moved,
#			i.e. drag_cur - drag_start
#	drawn		true, if the object is visible on the screen in its
#			dragged form (see Hide() and Show())
#
# These variables only have meaningful values during the drag, that is,
# between the calls to DragStart() and DragStop(), see below.
# drag_start, drag_cur and off are of type Point. (See the developer's guide)


class Draggable:

    drawn	= 0
    dragging	= 0
    drag_start	= NullPoint
    drag_cur	= NullPoint
    off		= NullPoint

    drag_mask = Button1Mask # XXX move this to some other class ?


    def __init__(self):
        # not needed here, but if some derived class wants to call the
        # base class constructor...
        pass

    def DragStart(self, p):
        # Start the drag at P. Initialize the instance variables. Set
        # dragging to true.
        # XXX: document the meaning of the return value
        self.drawn = 0		# the object is not visible yet
        self.dragging = 1
        self.drag_start = p
        self.drag_cur = p
        self.off = NullPoint
        return self.off

    def DragMove(self, p):
        # The pointer has moved to p. Compute the new offset.
        self.off = p - self.drag_start
        self.drag_cur = p


    def MouseMove(self, p, state):
        # XXX add documentation for this
        if state & self.drag_mask:
            self.off = p - self.drag_start
            self.drag_cur = p

    def DragStop(self, p):
        # The drag stopped at p. Update drag_cur and off for the last
        # time, and set dragging to false.
        self.dragging = 0
        self.off = p - self.drag_start
        self.drag_cur = p

    def DragCancel(self):
        self.dragging = 0

    # The rest of Draggable's methods deal with drawing the object in
    # `dragged' form (usually an outline) on the screen. The output
    # device is assumed to be set up in such a way that drawing the same
    # object twice removes it again (usually using GCxor). Currently,
    # this will be an instance of InvertingDevice (graphics.py)
    #
    # Show() and Hide() use this assumption and the instance variable
    # drawn, to make certain that the object is visible or invisible,
    # respectively. If drawn is false Show() calls DrawDragged() to draw
    # the object and then sets drawn to true. This way Show() may be
    # called multiple times by the canvas widget if it thinks the
    # outline of the object should be visible, without removing the
    # outline accidentally.
    #
    # DrawDragged(), which obviously has to be implemented by some
    # derived class, has to draw the outline of the object on the output
    # device, using drag_cur or off to compute coordinates. The internal
    # state of the object, for example the endpoints of lines, should
    # only be changed temporarily during DrawDragged; the state of the
    # object should only change if the drag is completed successfully.
    #
    # The boolean parameter PARTIALLY indicates whether the object has
    # to be drawn completely or if it is sufficient to draw only the
    # parts that are changed by the drag. For instance, if a vertex of a
    # polygon is dragged, it might suffice to draw the two edges sharing
    # this vertex. It is safe to ignore this parameter and always draw
    # the whole object. It is especially useful for complex objects like
    # polygons or poly beziers, where it improves performance and
    # reduces flickering on the screen
    #
    # Implementation Note: Show and Hide are the methods normally used
    # by the canvas to show or hide the object while dragging. An
    # exception is the RedrawMethod of the canvas object where
    # DrawDragged is called directly.

    def DrawDragged(self, device, partially):
        pass

    def Show(self, device, partially = 0):
        if not self.drawn:
            self.DrawDragged(device, partially)
        self.drawn = 1

    def Hide(self, device, partially = 0):
        if self.drawn:
            self.DrawDragged(device, partially)
        self.drawn = 0

#
# Class Selectable
#
# This class defines the interface and default implementation for
# objects that can be selected by the user with a mouse click.
#

class Selectable:

    def __init__(self):
        # only needed for derived classes.
        pass

    def Hit(self, p, rect, device):
        return None

    def SelectSubobject(self, p, rect, device, path = None, *rest):
        return self

    def GetObjectHandle(self, multiple):
        # Return a single point marking an important point of the
        # object. This point is highlighted by a small rectangle in the
        # canvas to indicate that the object is selected. Alternatively,
        # a list of such points can be returned to mark several points,
        # but that feature should only be used by compound objects.
        #
        # If multiple is false, self is the only object selected. If
        # it's true, there may be more than one selected object.
        return []


class EditSelect(Selectable):

    def SelectPoint(self, p, rect, device, mode = SelectSet):
        # Select (sub)object at P. If something is selected, return
        # true, false otherwise.
        return 0

    def SelectHandle(self, handle, mode = SelectSet):
        pass

    def SelectRect(self, rect, mode = SelectSet):
        # select (sub-)object(s) in RECT
        pass

    def GetHandles(self):
        # In edit mode, this method will be called to get a list of
        # handles. A handle should be shown at every `hot' spot of the
        # object (e.g. the nodes of a PolyBezier). Handles are described
        # by tuples which can be easily created by the functions in
        # handle.py
        return []



class SelectAndDrag(Draggable, EditSelect):

    def __init__(self):
        Draggable.__init__(self)
        Selectable.__init__(self)

    def CurrentInfoText(self):
        # return a string describing the current state of the object
        # during a drag
        return ''


#
#	Class Protocols
#
#	Some boolean flags that describe the object's capabilities
#

class Protocols:

    is_GraphicsObject   = 0
    is_Primitive        = 0
    is_Editor           = 0
    is_Creator          = 0

    has_edit_mode = 0	# true if object has an edit mode. If true, the
                        # Editor() method must be implemented

    is_curve = 0	# true, if object can be represented by and
                        # converted to a PolyBezier object. If true, the
                        # AsBezier() and Paths() methods must be
                        # implemented
    is_clip = 0

    has_fill		= 0	# True, iff object can have fill properties
    has_line		= 0	# True, iff object can have line properties
    has_font		= 0	# True, iff object can have a font
    has_properties	= 0

    is_Bezier		= 0
    is_Rectangle	= 0
    is_Ellipse		= 0
    is_Text		= 0	# Text objects must have a Font() method
                                # returning a font.
    is_SimpleText       = 0
    is_PathTextGroup    = 0 
    is_PathTextText     = 0     # The text part of a path text group
    is_Image		= 0
    is_Eps		= 0

    is_Group		= 0
    is_Compound		= 0
    is_Layer		= 0

    is_Blend		= 0     # The blendgroup
    is_BlendInterpolation = 0   # The interpolation child of a blend group
    is_Clone		= 0
    is_MaskGroup        = 0
    is_GuideLine	= 0

    is_Plugin		= 0


#
# Class Bounded
#
# Instances of this class have various kinds of bounding rectangles
# These rectangles are accessible via instance variables to increase
# performance (important for bounding_rect, which is used when testing
# which object is selected by a click). All rectangles are given in
# document coords and are aligned with the axes. The variables are:
#
# coord_rect
#
#	The smallest rectangle that contains all points of the outline.
#	The line width, if applicable, is NOT taken into account here.
#	This rectangle is used to arrange objects (AlignSelected,
#	AbutHorizonal, ...)
#
# bounding_rect
#
#	Like coord rect but takes the line width into account. It is
#	meant to be useful as a PostScript BoundingBox.
#
# Method:
#
# LayoutPoint()
#
#	Return the point which should be snapped to a grid point.
#


class Bounded:

    _lazy_attrs = {'coord_rect' : 'update_rects',
                   'bounding_rect' : 'update_rects'}

    def __init__(self):
        pass

    def del_lazy_attrs(self):
        for key in self._lazy_attrs.keys():
            try:
                delattr(self, key)
            except:
                pass

    def update_rects(self):
        # compute the various bounding rects and other attributes that
        # use `lazy evaluation'. This method MUST be implemented by
        # derived classes. It MUST set self.bounding_rect and
        # self.coord_rect and other attributes where appropriate.
        pass

    def __getattr__(self, attr):
        # if a lazy attribute is accessed, compute it.
        method = self._lazy_attrs.get(attr)
        if method:
            getattr(self, method)()
            # now it should work... use self.__dict__ directly to avoid
            # recursion if the method is buggy
            try:
                return self.__dict__[attr]
            except KeyError, msg:
                warn(INTERNAL, '%s did not compute %s for %s.',
                     method, attr, self)
        if attr[:2] == attr[-2:] == '__':
            #if attr in ('__nonzero__', '__len__'):
            #	 print_stack()
            pass
        else:
            warn(INTERNAL, "%s instance doesn't have an attribute %s",
                 self.__class__, attr)
        raise AttributeError, attr

    def LayoutPoint(self):
        return Point(self.coord_rect.left, self.coord_rect.bottom)

    def GetSnapPoints(self):
        return []

#
# Class HierarchyNode
#
# This is base class for all objects that are part of the object
# hierarchy of a document. It manages the parent child relationship and
# the references to the document and other methods (and standard
# behavior) that every object needs. No object derived from this class
# should override the methods defined here except as documented.
#

class HierarchyNode:

    def __init__(self, duplicate = None):
        if duplicate is not None:
            self.document = duplicate.document
            if duplicate.was_untied:
                self.was_untied = duplicate.was_untied

    def __del__(self):
        if self.document:
            self.document.connector.RemovePublisher(self)

    def Destroy(self):
        # remove all circular references here...
        # May be extended by derived classes.
        self.parent = None

    parent = None
    def SetParent(self, parent):
        self.parent = parent

    def depth(self):
        if self.parent is not None:
            return self.parent.depth() + 1
        return 1

    def SelectionInfo(self):
        if self.parent is not None:
            return self.parent.SelectionInfo(self)

    document = None	# the document self belongs to

    def SetDocument(self, doc):
        self.document = doc
        if doc is not None and self.was_untied:
            self.TieToDocument()
            del self.was_untied

    def UntieFromDocument(self):
        # this will be called when self is being stored in the clipboard
        # (CopyForClipboard/CutForClipboard), but before self.document
        # becomes None. Disconnect will not be called in this case.
        # May be extended by derived classes.
        self.was_untied = 1

    def TieToDocument(self):
        # this will be called when self is being inserted into the
        # document from the clipboard, after self.document has been set.
        # Connect will not be called in this case.
        # May be extended by derived classes.
        pass

    def Subscribe(self, channel, func, *args):
        # XXX: what do we do if document has not been set (yet)
        if self.document is not None:
            self.document.connector.Connect(self, channel, func, args)

    def Unsubscribe(self, channel, func, *args):
        if self.document is not None:
            self.document.connector.Disconnect(self, channel, func, args)

    def Issue(self, channel, *args):
        if self.document is not None:
            apply(self.document.connector.Issue, (self, channel,) + args)

    def issue_changed(self):
        self.Issue(CHANGED, self)
        if self.parent is not None:
            self.parent.ChildChanged(self)

    def Connect(self):
        # May be extended by derived classes.
        pass

    def Disconnect(self):
        # May be extended by derived classes.
        pass

    def Duplicate(self):
        # return a duplicate of self
        return self.__class__(duplicate = self)



#
# Class	GraphicsObject
#
# The base class for all `normal' objects that are part of the drawing
# itself, like rectangles or groups (the experimental clone objects are
# derived from HierarchyNode (Sep98))
#

class GraphicsObject(Bounded, HierarchyNode, Selectable, Protocols):

    is_GraphicsObject = 1

    keymap = None
    commands = []
    context_commands = ()
    was_untied = 0

    script_access = {}

    def __init__(self, duplicate = None):
        Selectable.__init__(self)
        HierarchyNode.__init__(self, duplicate = duplicate)

    def ChildChanged(self, child):
        # in compound objects, this method is called by the child
        # whenever it changes (normally via the issue_changed method)
        pass

    def __cmp__(self, other):
        return cmp(id(self), id(other))

    def _changed(self):
        self.del_lazy_attrs()
        self.issue_changed()
        return (self._changed,)

    def SetLowerLeftCorner(self, corner):
        # move self so that self's lower left corner is at CORNER. This
        # used when interactively placing an object
        rect = self.coord_rect
        ll = Point(rect.left, rect.bottom)
        return self.Translate(corner - ll)

    def RemoveTransformation(self):
        # Some objects accumulate the transformation applied by
        # Transform() and apply them every time the object is displayed
        # Restore this transformation to Identity.
        return NullUndo
    script_access['RemoveTransformation'] = SCRIPT_UNDO

    def AsBezier(self):
        # Return self as bezier if possible. See is_curve above.
        return None
    script_access['AsBezier'] = SCRIPT_OBJECT

    def Paths(self):
        # Return a tuple of curve objects describing the outline of self
        # if possible. The curve objects can be the ones used internally
        # by self. The calling code is expected not to modify the curve
        # objects in place.
        # See is_curve above.
        return None
    script_access['Paths'] = SCRIPT_GET

    def Blend(self, other, frac1, frac2):
        # Return the weighted average of SELF and OTHER. FRAC1 and FRAC2
        # are the weights (if SELF and OTHER were numbers this should be
        # FRAC1 * SELF + FRAC2 * OTHER).
        #
        # This method is used by the function Blend() in blend.py. If
        # SELF and OTHER can't be blended, raise the blend.MismatchError
        # exception. This is also the default behaviour.
        raise MismatchError
    script_access['Blend'] = SCRIPT_OBJECT

    def Snap(self, p):
        # Determine the point Q on self's outline closest to P and
        # return a tuple (abs(Q - P), Q)
        return (1e100, p)
    script_access['Snap'] = SCRIPT_GET

    def ObjectChanged(self, obj):
        return 0

    def ObjectRemoved(self, obj):
        return NullUndo

    # Add some inherited method's script access flags
    script_access['coord_rect'] = SCRIPT_GET
    script_access['bounding_rect'] = SCRIPT_GET
    script_access['LayoutPoint'] = SCRIPT_GET
    script_access['Duplicate'] = SCRIPT_OBJECT

    # and flags for standard methods
    script_access['Transform'] = SCRIPT_UNDO
    script_access['Translate'] = SCRIPT_UNDO

#
#
#

class Creator(SelectAndDrag, Protocols):

    is_Creator = 1
    creation_text = 'Create Object'

    def __init__(self, start):
        self.start = start

    def EndCreation(self):
        # This method will be called when the object was being created
        # interactively using more than one click-drag-release cycle,
        # and the user has finished. This method is needed by the
        # PolyBezier primitive for instance.
        #
        # Return true if creation was successful, false otherwise.
        return 1

    def ContinueCreation(self):
        # called during interactive creation when the user releases the
        # mouse button. Return true, if the object may need another
        # click-drag-release cycle, false for objects that are always
        # complete after one cycle. (XXX the `true' return value is
        # interpreted in a special way, see the PolyBezier primitive)
        #
        # XXX: Should we distinguish more cases? A rectangle for example
        # is always complete after one click-drag-release cycle. A
        # PolyBezier object needs at least two cycles but accepts any
        # number of additional cycles. A polygon (with straight lines)
        # needs at least one. We might return a value that indicates
        # whether the user *must* supply additional points, whether it's
        # optional or whether the object is complete and the user
        # *cannot* add points.
        return None

class Editor(SelectAndDrag):

    is_Editor = 1

    EditedClass = GraphicsObject
    context_commands = ()

    def __init__(self, object):
        self.object = object

    def __getattr__(self, attr):
        return getattr(self.object, attr)

    def Destroy(self):
        # called by the edit mode selection when the editor it not
        # needed anymore.
        pass

    def ChangeRect(self):
        # ChangeRect indicates the area that is going to change during
        # the current click-drag-release cycle. It is safe to make this
        # equal to bounding_rect. This rectangle is used to determine
        # which parts of the window have to be redrawn.
        return self.bounding_rect


#
# Class Primitive
#
# The baseclass for all graphics primitives like Polygon, Rectangle, ...
# but not for composite objects. Basically, this adds the management of
# properties and styles to GraphicsObject


class Primitive(GraphicsObject):

    has_fill	= 1
    has_line	= 1
    has_properties = 1
    is_Primitive = 1

    tie_info = None
    script_access = GraphicsObject.script_access.copy()

    def __init__(self, properties = None, duplicate = None):
        GraphicsObject.__init__(self, duplicate = duplicate)
        if duplicate is not None:
            self.properties = duplicate.properties.Duplicate()
            if duplicate.tie_info:
                self.tie_info = duplicate.tie_info
        else:
            if properties is not None:
                self.properties = properties
            else:
                self.properties = PropertyStack()

    def Destroy(self):
        GraphicsObject.Destroy(self)

    def UntieFromDocument(self):
        info = self.properties.Untie()
        if info:
            self.tie_info = info
        GraphicsObject.UntieFromDocument(self)

    def TieToDocument(self):
        if self.tie_info:
            self.properties.Tie(self.document, self.tie_info)
            del self.tie_info

    def Transform(self, trafo, rects = None):
        # Apply the affine transformation trafo to all coordinates and
        # the properties.
        undo = self.properties.Transform(trafo, rects)
        if undo is not NullUndo:
            return self.properties_changed(undo)
        return undo

    def Translate(self, offset):
        # Move all points by OFFSET. OFFSET is an SKPoint instance.
        return NullUndo

    def DrawShape(self, device):
        # Draw the object on device. Here we just set the properties.
        device.SetProperties(self.properties, self.bounding_rect)

    # The following functions manage the properties

    def set_property_stack(self, properties):
        self.properties = properties
    load_SetProperties = set_property_stack

    def properties_changed(self, undo):
        if undo is not NullUndo:
            return (UndoAfter, undo, self._changed())
        return undo

    def AddStyle(self, style):
        return self.properties_changed(self.properties.AddStyle(style))
    script_access['AddStyle'] = SCRIPT_UNDO

    def Filled(self):
        return self.properties.HasFill()
    script_access['Filled'] = SCRIPT_GET

    def Properties(self):
        return self.properties
    script_access['Properties'] = SCRIPT_OBJECT

    def SetProperties(self, if_type_present = 0, **kw):
        if if_type_present:
            # change properties of that type if properties of that are
            # already present.
            prop_types = properties.property_types
            LineProperty = properties.LineProperty
            FillProperty = properties.FillProperty
            FontProperty = properties.FontProperty
            types = map(prop_types.get, kw.keys())
            if LineProperty in types and not self.properties.HasLine():
                for key in kw.keys():
                    if prop_types[key] == LineProperty:
                        del kw[key]
            if FillProperty in types and not self.properties.HasFill():
                for key in kw.keys():
                    if prop_types[key] == FillProperty:
                        del kw[key]
            if FontProperty in types and not self.properties.HasFont():
                for key in kw.keys():
                    if prop_types[key] == FontProperty:
                        del kw[key]
        return self.properties_changed(apply(self.properties.SetProperty, (),
                                             kw))
    script_access['SetProperties'] = SCRIPT_UNDO

    def LineWidth(self):
        if self.properties.HasLine:
            return self.properties.line_width
        return 0
    script_access['LineWidth'] = SCRIPT_GET

    def ObjectChanged(self, obj):
        if self.properties.ObjectChanged(obj):
            rect = self.bounding_rect
            self.del_lazy_attrs()
            self.document.AddClearRect(UnionRects(rect, self.bounding_rect))
            self.issue_changed()
            return 1
        return 0

    def ObjectRemoved(self, obj):
        return self.properties.ObjectRemoved(obj)


    def set_blended_properties(self, blended, other, frac1, frac2):
        blended.set_property_stack(Blend(self.properties, other.properties,
                                         frac1, frac2))


    def SaveToFile(self, file):
        # save object to file. Must be extended by the subclasses. Here,
        # we just save the properties.
        self.properties.SaveToFile(file)


#
# Class RectangularObject
#
# A mix-in class for graphics objects that are more or less rectangular
# and store their position and orientation in a SKTrafoObject.

class RectangularObject:

    def __init__(self, trafo = None, duplicate = None):
        if duplicate is not None:
            self.trafo = duplicate.trafo
        else:
            if not trafo:
                self.trafo = Identity
            else:
                self.trafo = trafo

    def Trafo(self):
        return self.trafo

    def LayoutPoint(self, *rest):
        # accept arguments to use this function as GetObjectHandle
        return self.trafo.offset()

    GetObjectHandle = LayoutPoint

    def Translate(self, offset):
        return self.Transform(Translation(offset))

    def set_transformation(self, trafo):
        undo = (self.set_transformation, self.trafo)
        self.trafo = trafo
        self._changed()
        return undo

    def Transform(self, trafo):
        trafo = trafo(self.trafo)
        return self.set_transformation(trafo)

    def Blend(self, other, p, q):
        if other.__class__ == self.__class__:
            blended = self.__class__(BlendTrafo(self.trafo, other.trafo, p, q))
            self.set_blended_properties(blended, other, p, q)
            return blended
        raise MismatchError


class RectangularPrimitive(RectangularObject, Primitive):

    def __init__(self, trafo = None, properties = None, duplicate = None):
        RectangularObject.__init__(self, trafo, duplicate = duplicate)
        Primitive.__init__(self, properties = properties,
                           duplicate = duplicate)

    def Transform(self, trafo, transform_properties = 1):
        undostyle = undo = NullUndo
        try:
            rect = self.bounding_rect
            undo = RectangularObject.Transform(self, trafo)
            if transform_properties:
                rects = (rect, self.bounding_rect)
                undostyle = Primitive.Transform(self, trafo, rects = rects)
            return CreateMultiUndo(undostyle, undo)
        except:
            Undo(undo)
            Undo(undostyle)
            raise

    def Translate(self, offset):
        return self.Transform(Translation(offset), transform_properties = 0)


class RectangularCreator(Creator):

    def __init__(self, start):
        Creator.__init__(self, start)
        self.trafo = Trafo(1, 0, 0, 1, start.x, start.y)

    def ButtonDown(self, p, button, state):
        Creator.DragStart(self, p)

    def apply_constraint(self, p, state):
        if state & ConstraintMask:
            trafo = self.trafo
            w, h = p - self.drag_start
            if w == 0:
                w = 0.00001
            a = h / w
            if a > 0:
                sign = 1
            else:
                sign = -1
            if abs(a) > 1.0:
                h = sign * w
            else:
                w = sign * h
            p = self.drag_start + Point(w, h)
        return p

    def MouseMove(self, p, state):
        p = self.apply_constraint(p, state)
        Creator.MouseMove(self, p, state)

    def ButtonUp(self, p, button, state):
        p = self.apply_constraint(p, state)
        Creator.DragStop(self, p)
        x, y = self.off
        self.trafo = Trafo(x, 0, 0, y, self.trafo.v1, self.trafo.v2)
