canvas.py :  » GUI » Sketch » skencil-0.6.17 » Sketch » UI » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » GUI » Sketch 
Sketch » skencil 0.6.17 » Sketch » UI » canvas.py
# Sketch - A Python-based interactive drawing program
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2004 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

#
# SketchCanvas
#
# Displays the contents of a document and accepts user input in the form
# of mouse and keyboard events.
#

import string
from types import TupleType

from Sketch.Lib.util import Empty,format

from Sketch import _,InvertingDevice,HitTestDevice,StandardColors,Point
from Sketch.Graphics.selection import SelectionRectangle

from Sketch import const,SketchInternalError,SelectionMode,EditMode
from Sketch.config import preferences
from Sketch.warn import pdebug,warn,INTERNAL

from Sketch.const import STATE,MODE,SELECTION,VIEW,POSITION,EDITED,\
     LAYER_STATE, LAYER_ACTIVE, CURRENTINFO, CHANGED, \
     SelectSet, SelectAdd, SelectSubtract, \
     SelectSubobjects, SelectDrag, SelectGuide
import Sketch

import command
import skpixmaps
pixmaps = skpixmaps.PixmapTk
from tkext import MakeCommand,UpdatedMenu

from cursorstack import CursorStack
from view import SketchView
from modes import MajorMode,TemporaryMode,WidgetWithModes,noop

from converters import converters


constraint_keysyms =   {'Control_L' : const.ControlMask,
      'Control_R' : const.ControlMask,
      'Shift_L'   : const.ShiftMask,
      'Shift_R'   : const.ShiftMask}

command_list = []
def AddCmd(name, menu_name, method_name = None, subscribe_to = STATE, **kw):
    # use name both as name and method name
    kw['menu_name'] = menu_name
    kw['subscribe_to'] = subscribe_to
    if not method_name:
  method_name = name
    cmd = apply(command.CommandClass, (name, method_name), kw)
    command_list.append(cmd)

def AddSelCmd(*args, **kw):
    if not kw.has_key('sensitive_cb'):
  kw['sensitive_cb'] = ('document', 'HasSelection')
    if not kw.has_key('subscribe_to'):
  kw['subscribe_to'] = SELECTION
    apply(AddCmd, args, kw)

def AddModeCmd(*args, **kw):
    if not kw.has_key('value_cb'):
  kw['value_cb'] = 'ModeName'
    if not kw.has_key('subscribe_to'):
  kw['subscribe_to'] = MODE
    if not kw.has_key('is_check'):
  kw['is_check'] = 1
    apply(AddCmd, args, kw)

class CanvasError(SketchInternalError):
    pass


# stop codes

stop_continue = 0
stop_regular = 1


def selection_type(state):
    state = state & const.AllowedModifierMask
    if state  == const.AddSelectionMask:
  type = SelectAdd
    elif state == const.SubtractSelectionMask:
  type = SelectSubtract
    elif state == const.SubobjectSelectionMask:
  type = SelectSubobjects
    else:
  type = SelectSet
    return type

class SketchCanvas(SketchView, CursorStack, WidgetWithModes):

    document = None
    commands = None

    context_menu_items = ['CreateFillStyleDialog',
        'FillSolid',
        'FillNone',
        None,
        'CreateLineStyleDialog',
        'LineNone',
        None,
        'CreateFontDialog',
        None,
        'CreateStyleFromSelection',
        None,
        'FitSelectedToWindow',
        'FitPageToWindow']

    def __init__(self, master=None, toplevel = None, main_window = None,
     document = None, **kw):
  self.init_handles()
  self.init_modes()
        self.init_cross_hairs()
  WidgetWithModes.__init__(self)
  kw['show_visible'] = 1
  kw['show_printable'] = 0
  self.snap_to_object = 0
  self.snap_to_guide = 0
        self.snap_correction_rect = 1
        self.snap_move_relative = 0 #1
  apply(SketchView.__init__, (self, master, toplevel, document), kw)
  CursorStack.__init__(self, const.CurStd, self.set_handle_cursor)

  self.main_window = main_window

  self.current_pos = Point(0, 0)
  self.current_info_text = None
  self.expect_release_event = 0
  self.ignore_key_press_events = 0
  self.start_drag = 0
        self.start_pos = None
  self.dragging = 0  # true if dragging with left button down
  self.current = None  # currently dragged/edited object
  self.correction = Point(0, 0)
  self.create_creator = None  # Class of object to create
        # None while in select/edit mode
  self.create_type = ''
  self.snap_to_grid = 0
  self.snap_points = ()
  self.init_bindings()

  self.SelectionMode()
  self.create_commands()
  self.context_commands = None

        preferences.Subscribe(CHANGED, self.preference_changed)

    def init_modes(self):
  self.modes = m = Empty()
  m.selection_mode = MajorMode(self.selection_enter,
             self.selection_down, self.drag_mouse,
             self.selection_up, noop,
             self.selection_cancel,
             start_drag = self.selection_start_drag,
             name = 'Select',
             text = _("Select"))
  m.edit_mode = MajorMode(self.edit_enter,
        self.edit_down, self.drag_mouse, self.edit_up,
        noop, self.edit_cancel,
        start_drag = self.edit_start_drag,
        name = 'Edit',
        text = _("Edit"))
  m.creation_mode = MajorMode(self.creation_enter,
            self.creation_begin, self.drag_to,
            self.creation_end, self.creation_exit,
            self.creation_cancel,
            name = 'Create',
            text = _("Create"))
  m.zoom_mode = TemporaryMode(self.zoom_enter, self.zoom_begin,
            self.drag_to, self.zoom_end,
            noop, self.zoom_cancel,
            name = 'Zoom',
            text = _("Zoom Area"))
  m.pick_mode = TemporaryMode(self.pick_enter, self.pick_begin, noop,
            self.pick_end, noop, self.pick_cancel,
            name = 'Pick',
            text = _("Pick Object"))
  m.place_mode = TemporaryMode(self.place_enter, self.place_begin,
             self.place_drag, self.place_end,
             noop, self.place_cancel,
             name = 'Place',
             text = _("Place Object"))

    def init_bindings(self):
  self.bind('<ButtonPress>', self.ButtonPressEvent)
  self.bind('<Motion>', self.PointerMotionEvent)
  self.bind('<ButtonRelease>', self.ButtonReleaseEvent)
  self.bind('<KeyPress>', self.KeyPressEvent)
  self.bind('<KeyRelease>', self.KeyReleaseEvent)
  self.bind('<Leave>', self.LeaveEvent)
  self.bind('<Enter>', self.EnterEvent)
  self.last_event = None

    scroll_timer = None
    def start_auto_scroll(self):
  intervall = preferences.autoscroll_interval
  if intervall:
      self.scroll_timer = self.after(intervall, self.auto_scroll)

    def cancel_auto_scroll(self):
  if self.scroll_timer is not None:
      self.after_cancel(self.scroll_timer)

    def auto_scroll(self):
  x, y, state = self.tkwin.QueryPointer()[4:7]
        if state & const.Button1Mask:
            amount = preferences.autoscroll_amount
            self.begin_transaction()
            if x < 0:
                self.ScrollXUnits(-amount)
            elif x > self.tkwin.width:
                self.ScrollXUnits(amount)
            if y < 0:
                self.ScrollYUnits(-amount)
            elif y > self.tkwin.height:
                self.ScrollYUnits(amount)
            self.start_auto_scroll()
            self.handle_update_pending = 0
            self.end_transaction()

    def LeaveEvent(self, event):
  if event.state & const.Button1Mask:
      self.start_auto_scroll()
        self.hide_crosshairs()
        self.crosshairs_visible = 0

    def EnterEvent(self, event):
  self.cancel_auto_scroll()
        self.crosshairs_visible = 1
        self.show_crosshairs()

    def create_obj_cmds(self, commands):
  cmds = command.Commands()
  keymap = command.Keymap()
  for cmd_class in commands:
      cmd = cmd_class.InstantiateFor(self)
      setattr(cmds, cmd.name, cmd)
      keymap.AddCommand(cmd)
  return cmds, keymap

    def create_commands(self):
  cmds = command.Commands()
  keymap = command.Keymap()
  for cmd_class in command_list:
      cmd = cmd_class.InstantiateFor(self)
      setattr(cmds, cmd.name, cmd)
      keymap.AddCommand(cmd)
  self.keymap = keymap

  class_maps = {}
  classes = Sketch.command_classes
  for aclass in classes:
            name = aclass.__name__
      if aclass.is_Editor:
    #name = aclass.EditedClass.__name__
    commands = aclass.commands + aclass.EditedClass.commands
      else:
    commands = aclass.commands
      ocmds, keymap = self.create_obj_cmds(commands)
      setattr(cmds, name, ocmds)
      class_maps[name] = keymap

      if self.context_menu_items[-1] != None:
    # insert a separator if necessary
    self.context_menu_items.append(None)
      self.context_menu_items = self.context_menu_items \
              + list(aclass.context_commands)

  self.commands = cmds
  self.object_keymap = None
  self.class_maps = class_maps

    def find_map(self, classes):
  maps = self.class_maps
  result = None
  for c in classes:
      map = maps.get(c.__name__)
      if map is not None:
    result =  map
    break
      map = self.find_map(c.__bases__)
      if map is not None:
    result =  map
    break
  return result

    def update_object_keymap(self):
  self.object_keymap = None
        obj = self.document.CurrentObject()
        if obj is not None:
            if self.document.selection.is_EditSelection:
                # XXX very ugly hack
                cls = self.document.selection.editor.editor.__class__
            else:
                cls = obj.__class__
            self.object_keymap = self.find_map((cls,))

    def UpdateCommands(self):
  # currently needed to ensure that all buttons have correct
  # sensitivity at startup
  self.commands.Update()

    def init_gcs(self):
  # XXX: integrate with SketchView
  self.gc.init_gc(self.tkwin, graphics_exposures = 1)
  self.invgc = InvertingDevice()
  self.invgc.init_gc(self.tkwin)
  self.hitgc = HitTestDevice()
  self.hitgc.init_gc(self.tkwin)
  #self.tk.call(self._w, 'motionhints')
  self.draw_handle_funcs = [self.invgc.DrawRectHandle,
          self.invgc.DrawRectHandle,
          self.invgc.DrawSmallRectHandle,
          self.invgc.DrawSmallRectHandle,
                                  self.invgc.DrawCircleHandle,
                                  self.invgc.DrawCircleHandle,
                                  self.invgc.DrawSmallCircleHandle,
                                  self.invgc.DrawSmallCircleHandle,
          self.invgc.DrawSmallRectHandleList,
          self.invgc.DrawHandleLine,
          self.invgc.DrawPixmapHandle,
          self.invgc.DrawCaretHandle]
  self.gcs_initialized = 1
  self.FitPageToWindow(save_viewport = 0)
  self.set_gc_transforms()

    def set_gc_transforms(self):
  SketchView.set_gc_transforms(self)
  if self.gcs_initialized:
      self.invgc.SetViewportTransform(self.scale, self.doc_to_win,
              self.win_to_doc)
      self.hitgc.SetViewportTransform(self.scale, self.doc_to_win,
              self.win_to_doc)


    #
    #  Channels
    #

    def issue_selection(self):
  self.queue_message(SELECTION)

    def issue_mode(self):
  self.queue_message(MODE)

    def queue_update_handles(self):
  self.handle_update_pending = 1

    def init_transactions(self):
  SketchView.init_transactions(self)
  self.handle_update_pending = 0

    def end_transaction(self):
  SketchView.end_transaction(self)
  if self.transaction == 0:
      if self.handle_update_pending:
    self.update_handles()
      self.handle_update_pending = 0

    def check_transaction(self):
  # for debugging, check whether a transaction is active
  if not self.transaction:
      pdebug(None, 'Warning: no transaction')

    def call_document_method(self, method, *args, **kwargs):
  method = getattr(self.document, method)
  apply(method, args, kwargs)

    #
    #  receivers for channels
    #

    def preference_changed(self, attr, value):
        if attr == 'default_unit':
            self.selection_info_text = None
            self.issue(CURRENTINFO)

    def selection_changed(self):
        self.selection_info_text = None
  self.issue_selection()
  self.update_handles()
  self.update_object_keymap()
        if self.gcs_initialized:
            x, y = self.tkwin.QueryPointer()[4:6]
            self.set_handle_cursor(x, y)

    def doc_was_edited(self, *rest):
        self.selection_info_text = None
  self.update_snap_points()
  self.update_handles()
  self.queue_message(EDITED)

    # extend the method of SketchView. SketchView subscribes this.
    def layer_changed(self, *args):
  if args:
      recompute = 0
      if args[0] == LAYER_STATE:
    layer, visible_changed, printable_changed, outlined_changed \
           = args[1]
    if layer.NumObjects():
        if ((self.show_printable and printable_changed)
      or (self.show_visible and visible_changed)):
      recompute = 1
      elif args[0] == LAYER_ACTIVE:
    if (self.mode is self.modes.creation_mode
        and self.document.ActiveLayer() is None):
        self.mode.cancel()
    else:
        self.issue_mode()
      if recompute:
    self.update_snap_points()
  apply(SketchView.layer_changed, (self,) + args)

    #
    #  Widget Methods (Redraw, ... )
    #

    def RedrawMethod(self, region = None):
  #self.hide_handles()
  #print 'RedrawMethod', region
  if hasattr(preferences, 'profile_redraw'):
      import profile
      warn(INTERNAL, 'profiling...')
      prof = profile.Profile()
      prof.runctx('region = SketchView.RedrawMethod(self, region)',
      globals(), locals())
      prof.dump_stats('/tmp/redraw.prof')
      warn(INTERNAL, 'profiling... (done)')
      del preferences.profile_redraw
  else:
      region = SketchView.RedrawMethod(self, region)

  # draw the handles
  self.invgc.InitClip()
  if region:
      self.invgc.PushClip()
      self.invgc.ClipRegion(region)
  if self.current is not None:
      self.current.DrawDragged(self.invgc, 0)
  else:
      self.show_handles(1)
        self.show_crosshairs(1)
  if region:
      self.invgc.PopClip()
  #self.show_handles()

  # The sync helps to avoid the scroll bug. Clicking once into the
  # scroll bar to scroll by a page could scroll twice for a
  # complex drawing.
  self.tkwin.Sync()

    #
    #  Event handler
    #

    def ButtonPressEvent(self, event):
  # handle button press event
        self.begin_transaction()
  self.expect_release_event = 1
  self.last_event = event
  try:
      self.ignore_key_press_events = 1
      button = event.num
      if button == const.Button1:
    p = self.WinToDoc(event.x, event.y)
    self.mode.button_down(p, button, event.state)
      elif button == const.ContextButton:
    self.popup_context_menu(event.x_root, event.y_root,
          button, event.state)
    self.ignore_key_press_events = 0
            elif button == const.Button4:
                self.ScrollYUnits(-3)
            elif button == const.Button5:
                self.ScrollYUnits(3)
  finally:
      self.end_transaction()

    def PointerMotionEvent(self, event):
  # handle Motion events
  #event.button = event.num
  #event.x, event.y = self.tkwin.QueryPointer()[4:6]
  self.last_event = event
  p = self.WinToDoc(event.x, event.y)
  self.set_current_pos(p, snap = 1)
  if self.start_drag or self.dragging:
      self.mode.mouse_move(p, event.state)
            self.update_current_info_text()
  else:
      if self.cursor_function:
    self.cursor_function(event.x, event.y)
        self.hide_crosshairs()
        self.show_crosshairs()

    def ButtonReleaseEvent(self, event):
  self.grab_release()
  self.cancel_auto_scroll()
  if not self.expect_release_event:
      return
  self.last_event = event
  self.begin_transaction()
  try:
      p = self.WinToDoc(event.x, event.y)
      event.button = event.num
      if event.button == const.Button1:
    self.mode.button_up(p, event.button, event.state)
    self.dragging = 0
      elif event.button == const.Button2:
    self.mode.button_up(p, event.button, event.state,
            force_stop = stop_regular)
    self.dragging = 0
  finally:
      if self.mode.isTemporaryMode:
    self.exit_temporary_mode()
      self.ignore_key_press_events = 0
      self.expect_release_event = 0
      self.end_transaction()

    def MapKeystroke(self, stroke):
  if self.object_keymap:
      cmd = self.object_keymap.MapKeystroke(stroke)
      if cmd:
    return cmd
  cmd = self.keymap.MapKeystroke(stroke)
  if cmd:
      return cmd

  return self.main_window.MapKeystroke(stroke)

    def KeyPressEvent(self, event):
  self.begin_transaction()
  try:
      state = event.state
      sym = event.keysym
            char = event.char
            try:
                char = self.tk.utf8_to_latin1(char)
            except AttributeError:
                # we're using Python's own _tkinter. FIXME: we should
                # handle this case properly, bit it only happens with
                # python <= 1.5.1, so it shouldn't be much of a problem
                pass
      # key events should probably be also handled by the modes
      if sym == 'Escape':
    self.cancel_current_mode()
    return
      mask = constraint_keysyms.get(sym, 0)
      if mask:
                # generate a `fake' motion event if a modifier changed. This is
                # done to reflect changes in the constraints during a drag
                # immediately.
                # modify the state, because it reflects the state before the
                # key press
    event.state = event.state ^ mask
    self.PointerMotionEvent(event)
      if self.ignore_key_press_events:
    return
      if char and ord(char) < 32:
    char = ''

      # build the modifier part of the key for the keymap
      modm = state & const.MetaMask and 'M-' or ''
      modc = state & const.ControlMask and 'C-' or ''
      mods = state & const.ShiftMask and 'S-' or ''
      if char:
    mod = modm + modc
      else:
    mod = modm + modc + mods

      cmd = None
      if char:
    # the key produced a normal character. Try the binding
    # for this first.
    stroke = mod + char
    cmd = self.MapKeystroke(stroke)

      if not cmd and char != sym:
    # there was no character or no entry in the keymap. Try
    # the keysym next.
    #
    # XXX: The current implementation allows bindings for
    # the Shift- and Control-keys, etc.
    stroke = mod + sym
    cmd = self.MapKeystroke(stroke)

      if cmd:
    if cmd.invoke_with_keystroke:
        cmd.Invoke(stroke)
    else:
        cmd.Invoke()
  finally:
      self.end_transaction()

    def KeyReleaseEvent(self, event):
  # generate a `fake' motion event if a modifier changed. This is
  # done to reflect changes in the constraints during a drag
  # immediately.
  mask = constraint_keysyms.get(event.keysym, 0)
  if mask:
      # modify the state, because it reflects the state before the
      # key release
      event.state = event.state ^ mask
      self.PointerMotionEvent(event)


    #
    #

    def build_context_commands(self):
  items = []
  for entry in self.context_menu_items:
      if entry:
    cmd = self.commands.Get(entry)
    if not cmd:
        cmd = self.main_window.commands.Get(entry)
    if cmd:
        items.append(cmd)
    else:
        # XXX: if the context menu is configurable by the
        # user, this should be visible to the user.
        warn(INTERNAL, 'unknown command', entry)
      else:
    items.append(entry)
  self.context_commands = items


    def popup_context_menu(self, x, y, button, state):
  if state & const.AllButtonsMask == 0:
      if __debug__:
    pdebug('context_menu', 'popup_context_menu',
           x, y, button, state)
      if self.context_commands is None:
    self.build_context_commands()

      items = []
      last = None
      for cmd in self.context_commands:
    if cmd and not cmd.InContext():
        cmd = None
    if cmd != last:
        items.append(cmd)
    last = cmd
      if items and items[0] is None:
    del items[0]
      if items and items[-1] is None:
    del items[-1]
      if items:
    context_menu = UpdatedMenu(self, map(MakeCommand, items))
    context_menu.Popup(x, y)
    context_menu.clean_up()

    #
    #  Report the current pointer position in doc coords.
    #  (might be also interesting for the view)
    #

    def set_current_pos(self, p, snap = 0):
  if snap and preferences.snap_current_pos:
      p = self.snap_point(p)
  self.current_pos = p
  self.issue(POSITION)

    def GetCurrentPos(self):
  return self.current_pos

    #
    #  Report the current state of the dragged object.
    #

    def update_current_info_text(self):
        if self.current is not None:
            self.current_info_text = self.current.CurrentInfoText()
            self.issue(CURRENTINFO)

    def CurrentInfoText(self):
        if self.current is not None and self.current_info_text:
            if type(self.current_info_text) == TupleType:
                template, dict = self.current_info_text
                self.current_info_text = format(template, converters, dict)
            return self.current_info_text
        else:
            if self.selection_info_text is None:
                text = self.document.SelectionInfoText()
                if type(text) == TupleType:
                    template, dict = text
                    text = format(template, converters, dict)
                self.selection_info_text = text
            return self.selection_info_text


    #
    #  The mode specific functions
    #
    #  Extend some inherited methods to issue the appropriate messages

    def push_mode(self, mode):
  WidgetWithModes.push_mode(self, mode)
  self.issue_mode()

    def pop_mode(self):
  WidgetWithModes.pop_mode(self)
  self.issue_mode()

    def enter_mode(self, mode, *args):
  apply(WidgetWithModes.enter_mode, (self, mode) + args)
  self.issue_mode()


    #
    def cancel_current_mode(self):
  if self.mode.isTemporaryMode:
      self.cancel_temporary_mode()
  else:
      self.mode.cancel()
    #
    #  Creation mode
    #

    def can_create(self):
  return self.document.ActiveLayer() is not None

    # enter creation mode for a gfx_name objects
    AddModeCmd('CreateRectangle', _("Draw Rectangle"), 'Create',
         args = 'RectangleCreator', bitmap = pixmaps.CreateRect,
         value_on = 'Create:RectangleCreator',
         sensitive_cb = 'can_create')
    AddModeCmd('CreateEllipse', _("Draw Ellipse"), 'Create',
         args = 'EllipseCreator', bitmap = pixmaps.CreateEllipse,
         value_on = 'Create:EllipseCreator',
         sensitive_cb = 'can_create')
    AddModeCmd('CreatePolyBezier', _("Draw Curve"), 'Create',
         args = 'PolyBezierCreator', bitmap = pixmaps.CreateCurve,
         value_on = 'Create:PolyBezierCreator',
         sensitive_cb = 'can_create')
    AddModeCmd('CreatePolyLine', _("Draw Poly-Line"), 'Create',
         args = 'PolyLineCreator', bitmap = pixmaps.CreatePoly,
         value_on = 'Create:PolyLineCreator',
         sensitive_cb = 'can_create')
    AddModeCmd('CreateSimpleText', _("Draw Text"), 'Create',
         args = 'SimpleTextCreator', bitmap = pixmaps.Text,
         value_on = 'Create:SimpleTextCreator',
         sensitive_cb = 'can_create')
    def Create(self, gfx_name = None):
  self.begin_transaction()
  if gfx_name is None:
      gfx_name = self.create_type
  self.enter_mode(self.modes.creation_mode, gfx_name)
  self.end_transaction()

    def creation_enter(self, gfx_name):
  self.create_creator = getattr(Sketch, gfx_name)
  self.create_type = gfx_name
  self.push_static_cursor(const.CurCreate)
  self.mode.text = self.create_creator.creation_text

    def creation_begin(self, p, button, state):
  # Begin creating an instance of self.create_creator.
  if __debug__:
      self.check_transaction()
  if self.create_creator is None:
      raise CanvasError('no create_creator in creation mode')
  self.begin_creator(self.create_creator, p, button, state)

    def begin_creator(self, creator, p, button, state):
  # Begin creating an instance of creator
  # also used by zoom_mode
  self.hide_handles()
  if self.current is not None:
      self.current.Hide(self.invgc)
  snapped = self.snap_point(p)
  self.current = creator(snapped)
  self.set_correction(self.current.ButtonDown(snapped, button, state))
  self.current.Show(self.invgc)
  self.start_drag = 1
  self.dragging = 0


    def creation_end(self, p, button, state, force_stop = stop_continue):
  if __debug__:
      self.check_transaction()
  if self.current is None:
      # current might be none if the user ends creation before
      # she's begun creating something (i.e. clicking button-2
      # immediately after selecting CreateCurve)
      self.creation_cancel()
      return
  self.current.ButtonUp(self.correct_and_snap(p), button, state)
  self.do_end_creation(force_stop, set_mode = 1)

    def do_end_creation(self, force_stop = stop_regular, set_mode = 0):
  if __debug__:
      self.check_transaction()
  self.pop_cursor_state()
  obj = self.current
  obj.Hide(self.invgc)
  self.current = None
  was_ok = 1

  if force_stop:
      self.create_creator = None
      was_ok = obj.EndCreation()
  else:
      self.create_creator = obj.ContinueCreation()
  if self.create_creator is None:
      self.start_drag = 0
      self.dragging = 0
      if preferences.creation_is_temporary:
    new_mode = self.SelectionMode
      else:
    new_mode = self.Create
      if was_ok:
    self.document.Insert(obj.CreatedObject())
    # switch to edit mode if the new object is a text object.
    # There should be a better way to achieve this
    if obj.is_Text:
        new_mode = self.EditMode
      else:
    self.document.SelectNone()
      if set_mode:
    new_mode()
  else:
      self.push_static_cursor(const.CurCreate)
      self.current = obj
      obj.Show(self.invgc)

    def creation_exit(self, set_mode = 0):
  if self.current is not None:
      self.do_end_creation(set_mode = set_mode)

    def creation_cancel(self):
        self.dragging = 0
        self.start_drag = 0
        if self.current is not None:
            self.current.Hide(self.invgc)
            self.current = None
        self.create_creator = None
        self.SelectionMode()


    #
    #  Selection and Edit mode
    #

    # two methods shared by the selection and edit modes
    def begin_edit_object(self, p, button, state, handle = None):
  # begin to edit OBJ
  self.current = self.document
  if handle is not None:
      self.current.SelectHandle(handle, SelectDrag)
  else:
      self.current.SelectPointPart(p, self.hitgc, SelectDrag)
  self.hide_handles()
  self.set_correction(self.current.ButtonDown(p, button, state))
  self.current.Show(self.invgc, 1)

    def stop_edit_object(self, p, button, state, force_stop = 0):
  if __debug__:
      self.check_transaction()
  if self.current is None:
      return None
  obj = self.current
        p = self.correct_and_snap(p)
  self.current = None
  self.start_drag = 0
  self.dragging = 0
  obj.Hide(self.invgc, 1)
  obj.ButtonUp(p, button, state)
  return obj

    def drag_mouse(self, p, state):
  if self.start_drag:
      # XXX it sometimes happens that self.start_pos has not been
      # set yet. Why?
      if abs(self.start_pos[0] - p) * self.scale > 3:
    apply(self.mode.start_drag, self.start_pos)
    self.start_drag = 0
      else:
    return
  self.dragging = 1
  if self.current is not None and (state & self.current.drag_mask):
      # if something is being edited, hide it and show it at new
      # position
      self.current.Hide(self.invgc, 1)
      self.current.MouseMove(self.correct_and_snap(p), state)
      self.current.Show(self.invgc, 1)

    def selection_rect(self, p, button, state):
  self.current = SelectionRectangle(p)
  self.set_correction(self.current.ButtonDown(p, button, state))
  self.current.Show(self.invgc)

    #
    #  Selection
    #

    # enter selection mode
    AddModeCmd('SelectionMode', _("Selection Mode"), value_on = 'Select',
         bitmap = pixmaps.SelectionMode)
    def SelectionMode(self):
  self.begin_transaction()
  self.document.SetMode(SelectionMode)
  self.end_transaction()

    def selection_mode(self):
  self.enter_mode(self.modes.selection_mode)

    def selection_enter(self):
  self.create_creator = None
  self.set_active_cursor(self.set_handle_cursor, const.CurStd)

    def selection_down(self, p, button, state):
  self.start_pos = (p, button, state)
  self.start_drag = 1
  self.dragging = 0
  self.hide_handles()

    def selection_start_drag(self, p, button, state):
  if selection_type(state) == SelectSet:
      handle = self.handle_hit(p)
      if handle is not None or self.document.SelectionHit(p, self.hitgc):
    # something is already selected and the user pressed the
    # button somewhere on the selection. Edit the current
    # object(s)
    self.begin_edit_object(p, button, state, handle)
    return
  # there's no selection or the user pressed the button somewhere
  # outside the current selection.

  # test for a guide line
  guide = self.document.SelectPoint(p, self.hitgc, SelectGuide)
  if guide is not None:
      self.current = guide
      self.set_correction(self.current.ButtonDown(p, button, state))
      self.current.Show(self.invgc)
  else:
      # Make a new selection
      self.selection_rect(p, button, state)

    def selection_click(self, p, button, state):
  type = selection_type(state)
  if type == SelectSet and self.document.SelectionHit(p, self.hitgc):
      self.document.ToggleSelectionBehaviour()
  else:
      self.document.SelectPoint(p, self.hitgc, type)

    def selection_up(self, p, button, state, force_stop = 0):
  if not self.dragging:
      self.selection_click(p, button, state)
  else:
      obj = self.stop_edit_object(p, button, state, force_stop)
      if obj is not None:
    if isinstance(obj, SelectionRectangle):
        self.document.SelectRect(obj.bounding_rect,
               selection_type(state))
    elif obj.is_GuideLine:
        # a guideline
        x = self.last_event.x
        y = self.last_event.y
        if (0 <= x < self.winfo_width()
      and 0 <= y <= self.winfo_height()):
      self.document.MoveGuideLine(obj, obj.drag_cur)
        else:
      self.document.RemoveGuideLine(obj)

  self.show_handles()
  self.current = None
  self.start_drag = self.dragging = 0

    def selection_cancel(self):
  if self.dragging:
      if self.current is not None:
    self.current.Hide(self.invgc)
    self.current = None
      self.dragging = 0
  else:
      self.document.SelectNone()
  self.start_drag = 0

    #
    #  Edit mode
    #
    AddModeCmd('EditMode', _("Edit Mode"), bitmap = pixmaps.EditMode,
         value_on = 'Edit')
    def EditMode(self):
  self.begin_transaction()
  self.document.SetMode(EditMode)
  self.end_transaction()

    def edit_mode(self):
  self.enter_mode(self.modes.edit_mode)

    def edit_enter(self):
  self.create_creator = None
  self.set_active_cursor(self.set_handle_cursor, const.CurEdit)

    def edit_down(self, p, button, state):
  self.start_pos = (p, button, state)
  self.start_drag = 1
  self.dragging = 0

    def edit_start_drag(self, p, button, state):
  handle = self.handle_hit(p)
  if handle is None:
      self.hitgc.StartOutlineMode()
      is_hit = self.document.SelectionHit(p, self.hitgc, test_all = 0)
      self.hitgc.EndOutlineMode()
  else:
      is_hit = 1
  if is_hit:
      # something is already selected and the user pressed the
      # button somewhere on the selection. Edit the current object
      self.begin_edit_object(p, button, state, handle)
  else:
      # there's no selection or the user pressed the button
      # somewhere outside the current selection.

      # test for a guide line
      guide = self.document.SelectPoint(p, self.hitgc, SelectGuide)
      if guide is not None:
    # edit the guide line
    self.current = guide
    self.set_correction(self.current.ButtonDown(p, button, state))
    self.current.Show(self.invgc)
      else:
    # Make a new selection
    self.selection_rect(p, button, state)

    def edit_click(self, p, button, state):
  handle = self.handle_hit(p)
  if handle is not None:
      self.document.SelectHandle(handle, selection_type(state))
  else:
            self.hitgc.StartOutlineMode()
      is_hit = self.document.SelectionHit(p, self.hitgc, test_all = 0)
      self.hitgc.EndOutlineMode()
            if is_hit:
                self.document.SelectPointPart(p, self.hitgc)
            else:
                self.document.SelectPoint(p, self.hitgc)

    def edit_up(self, p, button, state, force_stop = stop_continue):
  if not self.dragging:
      self.edit_click(p, button, state)
  else:
      obj = self.stop_edit_object(p, button, state, force_stop)
      if obj.__class__ == SelectionRectangle:
    self.document.SelectRectPart(obj.bounding_rect,
               selection_type(state))
      elif obj.is_GuideLine:
    # a guideline
    x = self.last_event.x
    y = self.last_event.y
    if 0 <= x < self.winfo_width() and 0<= y <=self.winfo_height():
        self.document.MoveGuideLine(obj, obj.drag_cur)
    else:
        self.document.RemoveGuideLine(obj)
  self.current = None
  self.show_handles()
  self.start_drag = 0
  self.dragging = 0

    def edit_cancel(self):
  if self.dragging:
      self.current.Hide(self.invgc)
      self.current = None
      self.dragging = 0
  self.show_handles()
  self.start_drag = 0

    #
    #  the standard mouse_move method for the modes
    #

    def drag_to(self, p, state):
  self.dragging = 1
  if self.current is not None and (state & self.current.drag_mask):
      # if something is being created/edited, hide it and show it
      # at new position
      self.current.Hide(self.invgc, 1)
      self.current.MouseMove(self.correct_and_snap(p), state)
      self.current.Show(self.invgc, 1)



    #
    #  Temporary modes
    #

    #
    #    Place object mode
    #

    def PlaceObject(self, object, text = None):
  self.begin_transaction()
        if self.IsCreationMode():
            self.creation_exit(set_mode = 1)
  self.enter_mode(self.modes.place_mode, object, text)
  self.end_transaction()

    def place_enter(self, object, text):
  #self.create_creator = None
  self.push_static_cursor(const.CurPlace)
  self.place_object = object
  self.place_text = text
  self.start_drag = 1

    def place_begin(self, p, button, state):
  if self.start_drag:
      self.place_start_drag(p, state)

    def place_start_drag(self, p, state):
  if self.place_object.is_GuideLine:
      self.place_object.SetPoint(p)
      self.current = self.place_object
  else:
      self.place_object.SetLowerLeftCorner(p)
      self.current = SelectionRectangle(self.place_object.coord_rect,
                                    anchor = self.place_object.LayoutPoint())
      self.current.Select()
  # selection rect doesn't use button and state:
  self.set_correction(self.current.ButtonDown(p, 0, state))
  self.current.Show(self.invgc)
  self.dragging = 1
  self.start_drag = 0

    def place_drag(self, p, state):
  if self.start_drag:
      self.place_start_drag(p, state)
  self.dragging = 1
  if self.current is not None:
      # if something is being placed, hide it and show it at new
      # position
      self.current.Hide(self.invgc, 1)
      state = state | const.Button1Mask
      self.current.MouseMove(self.correct_and_snap(p), state)
      self.current.Show(self.invgc, 1)

    def place_cancel(self):
  self.pop_cursor_state()
  if self.current is not None:
      self.current.Hide(self.invgc)
  self.current = None
  self.place_object = None
  self.place_text = None
  self.dragging = 0
  self.start_drag = 0

    def place_end(self, p, button, state, force_stop = stop_continue):
  self.pop_cursor_state()
  if self.current is None:
      return
  rect = self.current
  rect.Hide(self.invgc)
  p = self.correct_and_snap(p)
  rect.ButtonUp(p, button, state)
  self.current = None

  obj = self.place_object
  self.place_object = None
  if obj.is_GuideLine:
      x = self.last_event.x
      y = self.last_event.y
      if (0 <= x < self.winfo_width() and 0 <= y <= self.winfo_height()):
    obj.SetPoint(p)
      else:
    # guide line is outside of the canvas window.
    obj = None
  else:
      obj.SetLowerLeftCorner(rect.start)
  if obj:
      if self.place_text:
    self.document.Insert(obj, self.place_text)
      else:
    self.document.Insert(obj)
  self.place_text = None

    #
    #    Pick object mode
    #

    def PickObject(self, callback, args = ()):
  self.begin_transaction()
  self.enter_mode(self.modes.pick_mode, callback, args)
  self.end_transaction()

    def pick_enter(self, callback, args):
  self.create_creator = None
  self.push_static_cursor(const.CurPick)
  self.pick_object_cb = callback, args

    def pick_begin(self, p, button, state):
  pass

    def pick_cancel(self):
  self.pop_cursor_state()
  self.pick_object_cb = None

    def pick_end(self, p, button, state, force_stop = stop_continue):
  self.pop_cursor_state()
  object = self.document.PickObject(self.hitgc, p)
  cb, args = self.pick_object_cb
  self.pick_object_cb = None
  args = (object,) + args
  apply(cb, args)

    #
    #    Zoom mode
    #

    AddModeCmd('ZoomMode', _("Zoom Area"), bitmap = pixmaps.Zoom,
         value_on = 'Zoom')
    def ZoomMode(self):
  self.begin_transaction()
  self.enter_mode(self.modes.zoom_mode)
  self.end_transaction()

    def zoom_enter(self):
  self.push_static_cursor(const.CurZoom)

    def zoom_begin(self, p, button, state):
  self.begin_creator(SelectionRectangle, p, button, state)

    def zoom_cancel(self):
  self.pop_cursor_state()
  if self.current is not None:
      self.current.Hide(self.invgc)
  self.current = None
  self.dragging = 0
  self.start_drag = 0

    def zoom_end(self, p, button, state, force_stop = stop_continue):
  self.pop_cursor_state()
  obj = None
  if self.current is not None:
      obj = self.current
      obj.Hide(self.invgc)
      obj.ButtonUp(self.correct_and_snap(p), button, state)
      self.current = None

        zoom_out = state & const.ControlMask

  self.save_viewport()
        if self.dragging and obj is not None:
            epsilon = 1e-10
            rect = obj.bounding_rect
            rw = rect.right - rect.left
            rh = rect.top - rect.bottom
            width = self.tkwin.width
            height = self.tkwin.height
            if abs(rw) < epsilon or abs(rh) < epsilon:
                return
            scalex = width / rw
            scaley = height / rh
            if zoom_out:
                scale = (self.scale ** 2) / max(scalex, scaley)
                x, y = self.DocToWin(rect.center())
                center = rect.center() + Point(width / 2 - x,
                                               -height / 2 + y) / scale
            else:
                scale = min(scalex, scaley, self.max_scale)
                center = rect.center()
        else:
            if zoom_out:
                scale = 0.5 * self.scale
            else:
                scale = 2 * self.scale
            center = p
        self.SetScale(scale / self.pixel_per_point, do_center = 0)
        self.SetCenter(center, move_contents = 0)

  self.start_drag = 0
  self.dragging = 0

    #
    #  Other mode related methods
    #

    AddCmd('ToggleMode', _("Toggle Mode"), key_stroke = (' ', 'C-space'),
     subscribe_to = None)
    def ToggleMode(self):
  self.begin_transaction()
  try:
      if self.IsCreationMode():
    self.SelectionMode()
      elif self.IsSelectionMode():
    self.EditMode()
      else:
    # go to selection mode as default
    self.SelectionMode()
  finally:
      self.end_transaction()

    def set_mode_from_doc(self, *args, **kwargs):
  mode = self.document.Mode()
  if mode == SelectionMode:
      self.selection_mode()
  else:
      self.edit_mode()
  self.update_object_keymap()

    def IsSelectionMode(self):
  return self.mode == self.modes.selection_mode

    def IsEditMode(self):
  return self.mode == self.modes.edit_mode

    def IsCreationMode(self):
  return self.mode == self.modes.creation_mode

    def ModeInfoText(self):
  return self.mode.text

    def ModeName(self):
  name = self.mode.name
  if name == 'Create':
      name = name + ':' + self.create_type
  return name



    #
    #  Selection related methods
    #

    def SelectionInfoText(self):
  # Return a string describing the currently selected objects
  return self.document.SelectionInfoText()


    #
    #  correction, snapping
    #

    def set_correction(self, correct):
  if type(correct) == TupleType:
      correct, rect = correct
  else:
      rect = None
      if correct is None:
    correct = Point(0, 0)
  self.correction = correct
  self.correction_rect = rect

    snap_update_installed = 0
    def update_snap_points(self):
  if self.snap_to_object and not self.snap_update_installed:
      self.after_idle(self.idle_update_snap_points)
      self.snap_update_installed = 1

    def extract_snap_points(self, obj):
  self.snap_points[0:0] = obj.GetSnapPoints()

    def idle_update_snap_points(self):
  self.snap_update_installed = 0
  self.snap_points = []
  self.document.WalkHierarchy(self.extract_snap_points, visible = 1,
            printable = 0)
  self.snap_points.sort()

    def correct_and_snap(self, point):
  point = point - self.correction
        points = [point]
  if self.correction_rect and self.snap_correction_rect:
      l, b, r, t = self.correction_rect.translated(point)
            points = points + [Point(l,b), Point(l,t), Point(r,b), Point(r,t)]

        if self.dragging and self.start_pos \
           and self.snap_move_relative:
            start_pos = point - self.start_pos[0] + self.correction
            x, y = self.document.GridGeometry()[:2]
            points.append(Point(start_pos.x - x, start_pos.y - y))

        mindist = 1e100
        result = point
        #print points
        for p in points:
            dist, snapped = self.snap_point_dist(p)
            if dist < mindist:
                mindist = dist
                result = point - p + snapped

  self.set_current_pos(result)
  return result

    def snap_point(self, p):
  dist, p = self.snap_point_dist(p)
  return p

    def snap_point_dist(self, p):
  maxdist = preferences.max_snap_distance / self.scale
  pgrid = pobj = pguide = pmax = (maxdist, p)
  if self.snap_to_grid:
      pgrid = self.document.SnapToGrid(p)
  if self.snap_to_guide:
      pgh, pgv, pguide = self.document.SnapToGuide(p, maxdist)
            if (self.current is None
                or isinstance(self.current, SelectionRectangle)
                or not self.current.is_GuideLine):
                # We're not dragging a guideline, so snap to guide-lines
                # or to guide-objects. Otherwise, only snap to guide
                # objects
                pguide = min(pgh, pgv, pguide)
      if pguide == pgh or pguide == pgv:
    dist, (x, y) = pguide
    if x is None:
        if pgv[0] < maxdist:
      x = pgv[-1][0]
      dist = dist + pgv[0] - maxdist
        else:
      x = p.x
    else:
        if pgh[0] < maxdist:
      y = pgh[-1][1]
      dist = dist + pgh[0] - maxdist
        else:
      y = p.y
    pguide = dist, Point(x, y)
  if self.snap_to_object and self.snap_points:
      x, y = p
      mindist = 1e100;
      xlow = x - maxdist; ylow = y - maxdist
      xhigh = x + maxdist; yhigh = y + maxdist
      points = self.snap_points
      ilow = 0; ihigh = len(points)
      while ilow < ihigh:
    imid = (ilow + ihigh) / 2
    if points[imid].x > xlow:
        ihigh = imid
    else:
        ilow = imid + 1
      for idx in range(ilow, len(points)):
    pmin = points[idx]
    if pmin.x > xhigh:
        break
    if ylow < pmin.y < yhigh:
        dist = max(abs(pmin.x - x), abs(pmin.y - y))
        if dist < mindist:
      pobj = pmin
      mindist = dist
      if type(pobj) != TupleType:
    pobj = (abs(pobj - p), pobj)

  result = min(pgrid, pguide, pobj, pmax)
  return result

    AddCmd('ToggleSnapToGrid', _("Snap to Grid"), bitmap = pixmaps.GridOn,
     value = 0, value_cb = 'IsSnappingToGrid', is_check = 1)
    def ToggleSnapToGrid(self):
  self.begin_transaction()
  try:
      self.snap_to_grid = not self.snap_to_grid
      self.issue_state()
  finally:
      self.end_transaction()

    def IsSnappingToGrid(self):
  return self.snap_to_grid


    AddCmd('ToggleSnapToObjects', _("Snap to Objects"),
     value = 0, value_cb = 'IsSnappingToObjects', is_check = 1)
    def ToggleSnapToObjects(self):
  self.begin_transaction()
  try:
      self.snap_to_object = not self.snap_to_object
      self.snap_points = ()
      self.update_snap_points()
      self.issue_state()
  finally:
      self.end_transaction()

    def IsSnappingToObjects(self):
  return self.snap_to_object

    AddCmd('ToggleSnapToGuides', _("Snap to Guides"),
     value = 0, value_cb = 'IsSnappingToGuides', is_check = 1)
    def ToggleSnapToGuides(self):
  self.begin_transaction()
  try:
      self.snap_to_guide = not self.snap_to_guide
      self.issue_state()
  finally:
      self.end_transaction()

    def IsSnappingToGuides(self):
  return self.snap_to_guide

    AddCmd('ToggleSnapBoundingRect', _("Snap Bounding Rect"),
     value = 0, value_cb = 'IsSnappingBoundingRect', is_check = 1)
    def ToggleSnapBoundingRect(self):
  self.begin_transaction()
  try:
      self.snap_correction_rect = not self.snap_correction_rect
      self.issue_state()
  finally:
      self.end_transaction()

    def IsSnappingBoundingRect(self):
  return self.snap_correction_rect

    AddCmd('ToggleSnapMoveRelative', _("Snap Move Relative"),
     value = 0, value_cb = 'IsSnappingRelative', is_check = 1)
    def ToggleSnapMoveRelative(self):
  self.begin_transaction()
  try:
            self.snap_move_relative = not self.snap_move_relative
            self.issue_state()
  finally:
      self.end_transaction()

    def IsSnappingRelative(self):
  return self.snap_move_relative

    def SnapInfoText(self):
  # NLS might make problems here
  snap = []
  if self.snap_to_grid:
      snap.append(_("Grid"))
  if self.snap_to_object:
      snap.append(_("Objects"))
  if self.snap_to_guide:
      snap.append(_("Guide"))
  if snap:
      return _("Snap: ") + string.join(snap, '/')
  return _("No Snap")

    #
    #   Crosshairs
    #

    def init_cross_hairs(self):
        self.crosshairs = 0
        self.crosshairs_visible = 0
        self.crosshairs_pos = ()
        self.crosshairs_drawn = 0

    def draw_crosshairs(self, pos):
        x, y = self.DocToWin(pos)
        width = self.tkwin.width
        height = self.tkwin.height
        self.invgc.gc.DrawLine(0, y, width, y)
        self.invgc.gc.DrawLine(x, 0, x, height)
        self.crosshairs_pos = pos

    def show_crosshairs(self, force = 0):
        if self.crosshairs and self.crosshairs_visible:
            if not self.crosshairs_drawn or force:
                self.draw_crosshairs(self.current_pos)
            self.crosshairs_drawn = 1

    def hide_crosshairs(self):
        if self.crosshairs_drawn:
            self.draw_crosshairs(self.crosshairs_pos)
        self.crosshairs_drawn = 0

    AddCmd('ToggleCrosshairs', _("Crosshairs"), key_stroke = 'F2',
     value = 0, value_cb = 'IsShowingCrosshairs', is_check = 1)
    def ToggleCrosshairs(self):
  self.begin_transaction()
  try:
            self.hide_crosshairs()
            self.crosshairs = not self.crosshairs
            self.show_crosshairs()
            self.issue_state()
  finally:
      self.end_transaction()

    def IsShowingCrosshairs(self):
  return self.crosshairs


    
    #
    #  Handles
    #

    def init_handles(self):
  self.handle_points = []
  self.handle_funcs = []
  self.handles_drawn = 0

    handle_update_installed = 0
    def update_handles(self):
  self.hide_handles()
  if not self.handle_update_installed:
      self.after_idle(self.idle_update_handles)
  self.handle_update_installed = 1

    def idle_update_handles(self):
  self.handle_update_installed = 0
  self.set_handles(self.document.GetSelectionHandles())

    def set_handles(self, handles):
  from Sketch.const import HandleLine,Handle_Pixmap,Handle_Caret,\
       Handle_SmallOpenRectList
  points = []
  funcs = []
        used = {}
  if self.gcs_initialized:
      factor = self.gc.LengthToDoc(8)
  else:
      factor = 1

  for handle in handles:
      handle_type = handle.type
      p = handle.p
      cursor = handle.cursor

      if handle.offset is not None:
    offset = handle.offset
    p = p + Point(offset[0] * factor, offset[1] * factor)

      if handle_type == HandleLine:
    funcs.append((self.invgc.DrawHandleLine, (p, handle.p2)))
      elif handle_type == Handle_Pixmap:
    if cursor:
        points.append(self.DocToWin(p) + (cursor, handle))
    funcs.append((self.draw_handle_funcs[handle_type],
                              (p, handle.pixmap)))
      elif handle_type == Handle_Caret:
    funcs.append((self.invgc.DrawCaretHandle, (p, handle.p2)))
      elif handle_type == Handle_SmallOpenRectList:
    p = handle.list
    if p:
        pts = map(self.DocToWin, p)
        last = pts[-1]
        for idx in range(len(p) - 2, -1, -1):
      if pts[idx] == last:
          del p[idx]
      else:
          last = pts[idx]
        funcs.append((self.draw_handle_funcs[handle_type], (p, 0)))
      else:
                win = self.DocToWin(p)
                if cursor:
        points.append(win + (cursor, handle))
                if not used.has_key(win):
                    funcs.append((self.draw_handle_funcs[handle_type],
                                  (p, handle_type & 1)))
                    used[win] = 0

  self.hide_handles()
  self.handle_points = points
  self.handle_funcs  = funcs
  self.show_handles()

    def show_handles(self, force = 0):
  if __debug__:
      pdebug('handles',
       'show_handles: drawn = %d, force = %d, update = %d',
       self.handles_drawn, force, self.handle_update_installed)
  if not self.handle_update_installed\
     and (not self.handles_drawn or force):
      self.draw_handles()
      self.handles_drawn = 1

    def hide_handles(self):
  if __debug__:
      pdebug('handles', 'hide_handles: drawn = %d', self.handles_drawn)
  if self.handles_drawn:
      self.draw_handles()
      self.handles_drawn = 0

    def draw_handles(self):
  for f, args in self.handle_funcs:
      apply(f, args)


    handle_hit_radius = 4
    def set_handle_cursor(self, x, y):
  dist = self.handle_hit_radius
  for xp, yp, cursor, handle in self.handle_points:
      if abs(xp - x) < dist and abs(yp - y) < dist:
    self.set_window_cursor(cursor)
    break
  else:
            cursor = self.cursor_shape
            if preferences.active_cursor:
                object = self.document.PickActiveObject(self.hitgc,
                                                        self.win_to_doc(x, y))
                if object is not None:
                    if object.is_GuideLine:
                        if object.horizontal:
                            cursor = const.CurHGuide
                        else:
                            cursor = const.CurVGuide
                    elif self.IsSelectionMode():
                        cursor = const.CurMove
      self.set_window_cursor(cursor)

    def handle_hit(self, p):
  x, y = self.DocToWin(p)
  dist = self.handle_hit_radius
  handle_points = self.handle_points
  for idx in range(len(handle_points)):
      xp, yp, cursor, handle = handle_points[idx]
      if abs(xp - x) < dist and abs(yp - y) < dist:
    handle.index = idx
    return handle
  return None

    #
    #  Viewport- and related methods
    #
    #  extend some Viewport methods to handle handles and to issue VIEW
    #  whenever the displayed area changes
    #

    AddCmd('ForceRedraw', _("Redraw"), key_stroke = 'M-r', subscribe_to = None)


    def set_origin(self, xorg, yorg, move_contents = 1):
  self.begin_transaction()
  try:
      #self.hide_handles()
      SketchView.set_origin(self, xorg, yorg,
          move_contents = move_contents)
      self.queue_update_handles()
  finally:
      self.end_transaction()

    def SetScale(self, scale, do_center = 1):
  # Set current scale
  self.begin_transaction()
  try:
      self.hide_handles() # XXX: really necessary ?
      SketchView.SetScale(self, scale, do_center = do_center)
      self.queue_update_handles()
  finally:
      self.end_transaction()

    def ZoomFactor(self, factor):
        self.SetScale(self.scale * factor)
    AddCmd('ZoomIn', _("Zoom In"), 'ZoomFactor', args = 2.0,
           key_stroke = '>')
    AddCmd('ZoomOut', _("Zoom Out"), 'ZoomFactor', args = 0.5,
           key_stroke = '<')
           


    # add commands for inherited methods
    AddCmd('ScrollYPages', 'Page Up', args = -1, key_stroke = 'Prior',
     subscribe_to = None)
    AddCmd('ScrollYPages', 'Page Down', args = +1, key_stroke = 'Next',
     subscribe_to = None)

    # scrolling with the cursor keys
    AddCmd('ScrollYPages', '', args = -1, key_stroke = 'C-Up',
     subscribe_to = None)
    AddCmd('ScrollYPages', '', args = +1, key_stroke = 'C-Down',
     subscribe_to = None)
    AddCmd('ScrollXPages', '', args = -1, key_stroke = 'C-Left',
     subscribe_to = None)
    AddCmd('ScrollXPages', '', args = +1, key_stroke = 'C-Right',
     subscribe_to = None)

    #  other view related methods

    AddCmd('FitToWindow', _("Fit to Window"), key_stroke = 'S-F4',
     subscribe_to = None)
    AddSelCmd('FitSelectedToWindow', _("Fit Selected to Window"),
        'FitToWindow', args = 1, key_stroke = 'C-F4')
    def FitToWindow(self, selected_only = 0, save_viewport = 1):
  self.begin_transaction()
  try:
      self.hide_handles() # XXX: really necessary ?
      SketchView.FitToWindow(self, selected_only = selected_only,
           save_viewport = save_viewport)
  finally:
      self.end_transaction()

    AddCmd('FitPageToWindow', _("Fit Page to Window"), key_stroke = 'F4',
     subscribe_to = None)
    def FitPageToWindow(self, save_viewport = 1):
  self.begin_transaction()
  try:
      self.hide_handles()   # XXX: really necessary ?
      SketchView.FitPageToWindow(self, save_viewport = save_viewport)
  finally:
      self.end_transaction()

    def CanRestoreViewport(self):
  return len(self.viewport_ring)

    AddCmd('RestoreViewport', _("Restore Previous View"), key_stroke = 'F3',
     subscribe_to = VIEW, sensitive_cb = 'CanRestoreViewport')
    def RestoreViewport(self):
  if self.viewport_ring:
      self.begin_transaction()
      try:
    self.restore_viewport()
      finally:
    self.end_transaction()

    AddCmd('ToggleOutlineMode', _("Outline"), key_stroke = 'S-F9',
     value = 0, value_cb = 'IsOutlineMode', subscribe_to = VIEW,
     is_check = 1)

    AddCmd('TogglePageOutlineMode', _("Draw Page Outline"),
     value = 0, value_cb = 'IsPageOutlineMode', subscribe_to = VIEW,
     is_check = 1)

    #
    #
    #

    def unsubscribe_doc(self):
  if self.document is not None:
      self.document.Unsubscribe(SELECTION,self.selection_changed)
      self.document.Unsubscribe(EDITED,self.doc_was_edited)
      self.document.Unsubscribe(MODE, self.set_mode_from_doc)
  SketchView.unsubscribe_doc(self)

    def subscribe_doc(self):
  self.document.Subscribe(SELECTION, self.selection_changed)
  self.document.Subscribe(EDITED,self.doc_was_edited)
  self.document.Subscribe(MODE, self.set_mode_from_doc)
  SketchView.subscribe_doc(self)

    def SetDocument(self, doc):
  self.begin_transaction()
  try:
      SketchView.SetDocument(self, doc)
      self.SelectionMode()
      self.hide_handles()
      self.issue_selection()
      self.issue_mode()
      self.update_handles()
      self.update_snap_points()
  finally:
      self.end_transaction()
      self.init_viewport_ring()


    #
    #  Fill
    #

    AddSelCmd('FillSolid', _("Set Fill Color..."))
    def FillSolid(self, col = None):
  # Set the fill style of the currently selected objects to a
  # solid fill of color COL. If COL is None let the user
  # interactively select a color.
  if col is None:
      import colordlg
      current_color = self.document.CurrentFillColor()
      if current_color is None:
    current_color = StandardColors.white
      col = colordlg.GetColor(self, current_color)
      if not col:
    return
  from Sketch import SolidPattern
        import styledlg
        styledlg.set_properties(self.master, self.document,
                                _("Set Fill Color"), 'fill',
                                {'fill_pattern' : SolidPattern(col)})


    #
    #  LineStyle
    #
    def LineColor(self, color):
  # Set the line color of the currently selected objects to COLOR
  # XXX: should be removed; only needed by skapp to connect
  # palette with canvas. (Dec 97)
  if self.document.CountSelected() > 1:
      self.call_document_method('SetLineColor', color)
  else:
      from Sketch import SolidPattern
            import styledlg
            styledlg.set_properties(self.master, self.document,
                                    _("Set Line Color"), 'line',
                                    {'line_pattern' : SolidPattern(color)})

www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.