commit-gnue
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnue] r8290 - in trunk/gnue-designer/src: base base/tools forms forms/P


From: jcater
Subject: [gnue] r8290 - in trunk/gnue-designer/src: base base/tools forms forms/PagePainter uidrivers/wx uidrivers/wx/uihelpers
Date: Mon, 3 Apr 2006 18:22:27 -0500 (CDT)

Author: jcater
Date: 2006-03-30 09:01:28 -0600 (Thu, 30 Mar 2006)
New Revision: 8290

Added:
   trunk/gnue-designer/src/forms/PagePainter/
   trunk/gnue-designer/src/forms/PagePainter/PagePainter.py
   trunk/gnue-designer/src/forms/PagePainter/PagePainterOGL.py
   trunk/gnue-designer/src/forms/PagePainter/__init__.py
   trunk/gnue-designer/src/uidrivers/wx/uihelpers/SimpleCanvas.py
Modified:
   trunk/gnue-designer/src/base/Document.py
   trunk/gnue-designer/src/base/ToolBase.py
   trunk/gnue-designer/src/base/tools/TriggerEditor.py
   trunk/gnue-designer/src/forms/Document.py
   trunk/gnue-designer/src/uidrivers/wx/Base.py
Log:
more work on wx2.6-ifying, and de-gnue-forms-uidriver-ifying designer 
(committing major changes that aren't 100% functional yet, so beware)

Modified: trunk/gnue-designer/src/base/Document.py
===================================================================
--- trunk/gnue-designer/src/base/Document.py    2006-03-30 08:15:26 UTC (rev 
8289)
+++ trunk/gnue-designer/src/base/Document.py    2006-03-30 15:01:28 UTC (rev 
8290)
@@ -69,15 +69,15 @@
   #==========================================================================
   wizardRunner = WizardRunner
 
-  def init(self): 
+  def init(self):
     """
-    initialize the instance (called at the 
+    initialize the instance (called at the
     beginning of the __init__ process)
     """
 
-  def init(self): 
+  def init(self):
     """
-    Finalize the instance (called at the 
+    Finalize the instance (called at the
     end of the __init__ process)
     """
 
@@ -164,20 +164,20 @@
   def registerEditor(self, baseclass, gtype, filter=None):
     """
     Register an editor class
-    
-    Parameters: 
-    
-      baseclass: An EditorComponent class    
-      
-      gtype: A string indicating a GObject._type identifier, 
+
+    Parameters:
+
+      baseclass: An EditorComponent class
+
+      gtype: A string indicating a GObject._type identifier,
          or a list of such strings.
-    
+
       filter: A function that is passed a GObject and should
          return True/False indicating if an editor instance
          should be created.
-       
+
     """
-    if isinstance(gtype,basestring): 
+    if isinstance(gtype,basestring):
       gtype = [gtype]
     for gtype1 in gtype:
       self._editorMapping[gtype1] = (filter, baseclass)
@@ -336,7 +336,7 @@
 
   def __init__(self, app, location=None, buffer=None, style=None):
     EventController.__init__(self)
-    
+
     self.app = app
     self.ui = app.ui.createInstance(self)
 
@@ -344,7 +344,7 @@
     # so we can execute them when everything has
     # been initialized.
     self.startCachingEvents()
-    
+
     # Local variables
     self.wizardName = ""
     self._isdirty = False
@@ -451,14 +451,14 @@
 
     # Set up the editor components...
     #   ... common
-    self.registerEditor(TriggerEditor.TriggerEditor, 'GCTrigger', 
+    self.registerEditor(TriggerEditor.TriggerEditor, 'GCTrigger',
                         TriggerEditor.EditorFilter)
     #   ... and document-centric
     self.createEditors()
 
     # Create the document-centric tools
     self.createTools()
-    
+
     # And tell the UI driver to create the UI portions
     self.ui.initTools()
 

Modified: trunk/gnue-designer/src/base/ToolBase.py
===================================================================
--- trunk/gnue-designer/src/base/ToolBase.py    2006-03-30 08:15:26 UTC (rev 
8289)
+++ trunk/gnue-designer/src/base/ToolBase.py    2006-03-30 15:01:28 UTC (rev 
8290)
@@ -82,20 +82,20 @@
   def __hide(self, event):
     self._visible = False
 #    self.dockpane.hide()
-    
+
   # Used by UI-specific subclasses below
-  def _createOuterInterfaces(self): 
+  def _createOuterInterfaces(self):
     pass
 
 # ===========================================================================
 # Notebook-based Component
 # ===========================================================================
-class ToolNotebook(ToolBase): 
+class ToolNotebook(ToolBase):
   """
   Tool interfaces with a Notebook control as their outer component
   """
-  def _createOuterInterfaces(self): 
-    notebook = self.notebook = NotebookCtrl.NotebookCtrl(self, -1, 
+  def _createOuterInterfaces(self):
+    notebook = self.notebook = NotebookCtrl.NotebookCtrl(self, -1,
             style=NotebookCtrl.NC_DEFAULT_STYLE|NotebookCtrl.NC_BOTTOM)
     notebook.HideOnSingleTab()
     notebook.EnableHiding()
@@ -103,15 +103,15 @@
     notebook.SetPadding(wx.Size(1,1))
 
     self.document.app.ui.autoSizer(self, notebook)
-    
+
     ToolBase._createOuterInterfaces(self)
 
-  def addPage(self, page, text): 
+  def addPage(self, page, text):
     self.notebook.AddPage(page, text)
     self.notebook.SetPageTextFont(self.notebook.GetPageCount()-1, wx.Font(9, 
wx.DEFAULT, wx.NORMAL, wx.NORMAL, False))
     return page
-  
-  def deletePage(self, id): 
+
+  def deletePage(self, id):
     return self.notebook.DeletePage(id)
 
 

Modified: trunk/gnue-designer/src/base/tools/TriggerEditor.py
===================================================================
--- trunk/gnue-designer/src/base/tools/TriggerEditor.py 2006-03-30 08:15:26 UTC 
(rev 8289)
+++ trunk/gnue-designer/src/base/tools/TriggerEditor.py 2006-03-30 15:01:28 UTC 
(rev 8290)
@@ -64,7 +64,6 @@
 
     self.__ignoreevent = 0
 
-    self.object = object
     self.editor.SetReadOnly(0)
 
     if not len(object._children):
@@ -104,7 +103,7 @@
 # ===========================================================================
 # Filter function
 # ===========================================================================
-def EditorFilter(gctrigger): 
+def EditorFilter(gctrigger):
   assert gctrigger._type == 'GCTrigger'
   return not gctrigger.src
 

Modified: trunk/gnue-designer/src/forms/Document.py
===================================================================
--- trunk/gnue-designer/src/forms/Document.py   2006-03-30 08:15:26 UTC (rev 
8289)
+++ trunk/gnue-designer/src/forms/Document.py   2006-03-30 15:01:28 UTC (rev 
8290)
@@ -55,6 +55,7 @@
 from WizardRunner import WizardRunner
 
 # Tool support...
+from PagePainter import PagePainter
 from LayoutEditor import LayoutEditor
 from TreeView import TreeView
 from PropertyEditor import PropertyEditor
@@ -114,16 +115,16 @@
     # Add our events/* stuff
     registerEvents(self)
 
-  def finalize(self): 
+  def finalize(self):
     # Convenience list to keep track of datasources and blocks
     # TODO: Anything that needs either of these two
     # TODO: should call getObjectList directly.
     # TODO: Left for historical reasons.
     self.datasources = self.getObjectList('datasource')
     self.blocks = self.getObjectList('block')
-    
-    
 
+
+
   # -------------------------------------------------------------------------
   # Load a form
   # -------------------------------------------------------------------------
@@ -149,7 +150,9 @@
   # -------------------------------------------------------------------------
   def createEditors(self):
     # Associate our LayoutEditor with GFPage objects
+
     self.registerEditor(LayoutEditor, 'GFPage')
+    self.registerEditor(PagePainter, 'GFPage')
 
 
   def createTools(self):

Added: trunk/gnue-designer/src/forms/PagePainter/PagePainter.py
===================================================================
--- trunk/gnue-designer/src/forms/PagePainter/PagePainter.py    2006-03-30 
08:15:26 UTC (rev 8289)
+++ trunk/gnue-designer/src/forms/PagePainter/PagePainter.py    2006-03-30 
15:01:28 UTC (rev 8290)
@@ -0,0 +1,195 @@
+#
+# Copyright 2001-2006 Free Software Foundation
+#
+# This file is part of GNU Enterprise
+#
+# GNU Enterprise 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, or (at your option) any later version.
+#
+# GNU Enterprise 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 program; see the file COPYING. If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place
+# - Suite 330, Boston, MA 02111-1307, USA.
+#
+# $Id: TriggerEditor.py 8210 2006-03-07 00:04:31Z jcater $
+
+__all__ = ['PagePainter']
+
+#----------------------------------------------------------------------------
+# System Imports
+#----------------------------------------------------------------------------
+import sys
+import string
+
+#--------------------------------------------------------------------------
+# GNUe Imports
+#--------------------------------------------------------------------------
+from gnue.designer.base.EditorBase import EditorBase
+
+#--------------------------------------------------------------------------
+# External Imports
+#--------------------------------------------------------------------------
+import wx
+import SimpleCanvas
+
+
+xscale = 1
+yscale = 1
+
+
+# ===========================================================================
+# The PagePainter class
+# ===========================================================================
+class PagePainter (EditorBase):
+
+  runtime_section = "FormsPagePainter"
+  icon = 'painter'
+
+  def init(self, object):
+
+    canvas = self.canvas = MyCanvas(self)
+    self.document.app.ui.autoSizer(self, canvas)
+
+    self.object = object
+
+    self.setCaption(hasattr(object,'caption') and object.caption \
+          or object.name)
+
+    self.registerEventListeners({
+                       # Object stuff
+                       'ObjectSelected'      : self.__objectSelected,
+                       'ObjectCreated'       : self.__objectCreated,
+                       'ObjectModified'      : self.__objectModified,
+                       'ObjectDeleted'       : self.__objectDeleted,
+                      })
+
+    # Determine text extents
+    dc = wx.MemoryDC()
+    dc.SetFont(wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT))
+    global xscale, yscale
+
+    for char in string.digits + string.letters:
+      w, h = dc.GetTextExtent(char)
+      xscale = max(xscale, w)
+      yscale = max(yscale, h)
+
+
+    # Draw initial objects
+    self.object.walk(self.inventoryObject)
+
+
+  def inventoryObject(self, object):
+
+    canvas = self.canvas
+    try:
+      x,y = object['Char:x'], object['Char:y']
+    except:
+      return
+
+    try:
+      w,h = object['Char:width'], object['Char:height']
+    except:
+      w,h = object['Char:width'], object['Char:height'] = 10,1
+
+    print x, y, w, h
+    widget = MyObject(object, canvas)
+    canvas.Add(widget)
+    widget.SetSize(w*xscale,h*yscale)
+    widget.MoveTo(x*xscale,y*yscale)
+    print widget.bounds
+
+  def __objectSelected(self, object):
+    pass
+
+  def __objectCreated(self, object):
+    print "(Object Created)"
+
+  def __objectModified(self, object):
+    pass
+
+  def __objectDeleted(self, object):
+    pass
+
+
+import cPickle
+from gnue.designer.uidrivers.wx.uihelpers import SimpleCanvas
+
+
+class MyObject(SimpleCanvas.wxSimpleDrawableObject):
+  def __init__(self, object, canvas):
+    self.__object = object
+    SimpleCanvas.wxSimpleDrawableObject.__init__(self, canvas)
+
+  def Draw(self, dc):
+    dc.BeginDrawing()
+    dc.SetPen(wx.Pen(wx.BLACK))
+    wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)
+    object = self.__object
+    x,y,w,h = self.bounds
+    dc.SetFont(wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT))
+    if object._type == 'GFLabel':
+      x = 0
+      for char in object.text:
+        dc.DrawText(char, x,0)
+        x += xscale
+    elif object._type == 'GFEntry':
+      dc.DrawRoundedRectangle(0,0,w,h, 1)
+    else:
+      dc.DrawRoundedRectangle(0,0,w,h, 4)
+
+  def DragHitTest (self, x, y):
+    if self.bounds.x <= x <= self.bounds.x + self.bounds.width and \
+       self.bounds.y <= y <= self.bounds.y + self.bounds.height:
+      return True
+    else:
+      return False
+
+  def ConvertDrawableObjectToDataObject (self, x, y):
+    object = self
+
+    data = [ { "Type" : "selectedWidgets",
+               "Attributes": {
+                   'startingX': x,
+                   'startingY': y,
+                   }
+               }]
+#        "name": dname,
+#        "table": object.name,
+#        "database": self.connectionName } }
+#
+#
+    do = 
wx.CustomDataObject(wx.CustomDataFormat("application/x-gnue-designer"))
+    do.SetData(cPickle.dumps(data,1))
+
+    return do
+
+  def SelectedHitTest(self, x, y):
+    if self.bounds.x <= x <= self.bounds.x + self.bounds.width and \
+       self.bounds.y <= y <= self.bounds.y + self.bounds.height:
+      return True
+    else:
+      return False
+
+
+class MyCanvas(SimpleCanvas.wxSimpleCanvas):
+  def DrawBackground(self, dc):
+    dc.BeginDrawing()
+    dc.SetBackgroundMode(wx.TRANSPARENT)
+    dc.Clear()
+
+    # Draw the grid (TODO: make this settable)
+    w, h = self.GetClientSizeTuple()
+    dc.SetPen(wx.Pen(wx.Colour(240,240,240)))
+    for x in range(0,w,xscale):
+      dc.DrawLine(x,0,x,h-1)
+
+    for y in range(0,h, yscale):
+      dc.DrawLine(0,y,w,y)
+    dc.EndDrawing()

Added: trunk/gnue-designer/src/forms/PagePainter/PagePainterOGL.py
===================================================================
--- trunk/gnue-designer/src/forms/PagePainter/PagePainterOGL.py 2006-03-30 
08:15:26 UTC (rev 8289)
+++ trunk/gnue-designer/src/forms/PagePainter/PagePainterOGL.py 2006-03-30 
15:01:28 UTC (rev 8290)
@@ -0,0 +1,113 @@
+#
+# Copyright 2001-2006 Free Software Foundation
+#
+# This file is part of GNU Enterprise
+#
+# GNU Enterprise 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, or (at your option) any later version.
+#
+# GNU Enterprise 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 program; see the file COPYING. If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place
+# - Suite 330, Boston, MA 02111-1307, USA.
+#
+# $Id: TriggerEditor.py 8210 2006-03-07 00:04:31Z jcater $
+
+__all__ = ['PagePainter']
+
+#----------------------------------------------------------------------------
+# System Imports
+#----------------------------------------------------------------------------
+import sys
+import math
+
+#--------------------------------------------------------------------------
+# GNUe Imports
+#--------------------------------------------------------------------------
+from gnue.designer.base.EditorBase import EditorBase
+
+#--------------------------------------------------------------------------
+# External Imports
+#--------------------------------------------------------------------------
+import wx
+from wx.glcanvas import GLCanvas
+
+from OpenGL.GLUT import *
+from OpenGL.GLU import *
+from OpenGL.GL import *
+
+
+
+# ===========================================================================
+# The PagePainter class
+# ===========================================================================
+class PagePainter (EditorBase):
+
+  runtime_section = "FormsPagePainter"
+  icon = 'painter'
+
+  def init(self, object):
+
+    canvas = self.canvas = GLCanvas(self)
+    self.document.app.ui.autoSizer(self, canvas)
+
+    self.object = object
+
+    self.setCaption(hasattr(object,'caption') and object.caption \
+          or object.name)
+
+
+    #----------------------------------------------------------------------
+    # wxPython + OpenGL integration
+    #----------------------------------------------------------------------
+    wx.EVT_SIZE(canvas,self.__onResize)
+    wx.EVT_PAINT(canvas,self.__onPaint)
+    wx.EVT_ERASE_BACKGROUND(canvas, self.__onEraseBackground)
+
+
+  #--------------------------------------------------------------------------
+  # wxPython + OpenGL integration
+  #--------------------------------------------------------------------------
+  def drawCanvas(self):
+    print "Drawing!"
+
+
+  #--------------------------------------------------------------------------
+  # wxPython + OpenGL integration
+  #--------------------------------------------------------------------------
+  def __onResize(self, event):
+    size = self.canvas.GetClientSize()
+    if self.canvas.GetContext():
+      self.canvas.SetCurrent()
+      glViewport(0, 0, size.width, size.height)
+
+  def __onEraseBackground(self, event):
+    pass # Avoids flicker
+
+  def __onPaint(self, *args):
+    dc = wx.PaintDC(self.canvas)
+    self.__redraw(None)
+
+  def __redraw(self, *args):
+    #dc = wxPaintDC(self)
+    dc = wx.ClientDC(self.canvas)
+    self.canvas.SetCurrent()
+
+    mode = glGetDouble(GL_MATRIX_MODE)
+    glMatrixMode(GL_PROJECTION)
+
+    glPushMatrix()
+    self.drawCanvas()
+    glFlush()
+    glPopMatrix()
+    self.canvas.SwapBuffers()
+
+    glMatrixMode(mode)
+

Added: trunk/gnue-designer/src/forms/PagePainter/__init__.py
===================================================================
--- trunk/gnue-designer/src/forms/PagePainter/__init__.py       2006-03-30 
08:15:26 UTC (rev 8289)
+++ trunk/gnue-designer/src/forms/PagePainter/__init__.py       2006-03-30 
15:01:28 UTC (rev 8290)
@@ -0,0 +1 @@
+from PagePainter import *

Modified: trunk/gnue-designer/src/uidrivers/wx/Base.py
===================================================================
--- trunk/gnue-designer/src/uidrivers/wx/Base.py        2006-03-30 08:15:26 UTC 
(rev 8289)
+++ trunk/gnue-designer/src/uidrivers/wx/Base.py        2006-03-30 15:01:28 UTC 
(rev 8290)
@@ -95,7 +95,7 @@
     # This has to happen after setWxApp, otherwise bad things happen
     from gnue.forms.uidrivers.wx import UILoginHandler
     self.app.getConnectionManager().setLoginHandler(UILoginHandler())
-    
+
     # Call wx's MainLoop
     self.app.init()
 

Added: trunk/gnue-designer/src/uidrivers/wx/uihelpers/SimpleCanvas.py
===================================================================
--- trunk/gnue-designer/src/uidrivers/wx/uihelpers/SimpleCanvas.py      
2006-03-30 08:15:26 UTC (rev 8289)
+++ trunk/gnue-designer/src/uidrivers/wx/uihelpers/SimpleCanvas.py      
2006-03-30 15:01:28 UTC (rev 8290)
@@ -0,0 +1,602 @@
+#
+# Copyright 2001-2006 Free Software Foundation
+#
+# This file is part of GNU Enterprise
+#
+# GNU Enterprise 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, or(at your option) any later version.
+#
+# GNU Enterprise 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 program; see the file COPYING. If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place
+# - Suite 330, Boston, MA 02111-1307, USA.
+#
+# $Id: TriggerEditor.py 8210 2006-03-07 00:04:31Z jcater $
+
+#
+# These classes are based on SimpleCanvas from OSA's Chandler
+# application, but heavily commented and debugged.
+#
+
+import wx
+import time
+
+
+# ===================================================================
+# A Drawable canvas widget
+# ===================================================================
+class wxSimpleDrawableObject(wx.EvtHandler):
+  def __init__(self, canvas):
+    super(wxSimpleDrawableObject, self).__init__()
+
+    self.bounds = wx.Rect()
+    self.canvas = canvas
+    self.visible = True
+    self.selected = False
+    self.dragStartPos = None
+
+    self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseEvent)
+
+  def MoveTo(self, x, y):
+    self.canvas.RefreshScrolledRect(self.bounds);
+    self.bounds.SetLeft(x)
+    self.bounds.SetTop(y)
+    self.canvas.RefreshScrolledRect(self.bounds);
+
+  def SetSize(self, width, height):
+    self.canvas.RefreshScrolledRect(self.bounds);
+    self.bounds.SetWidth(width)
+    self.bounds.SetHeight(height)
+    self.canvas.RefreshScrolledRect(self.bounds);
+
+  def OnMouseEvent(self, event):
+    x, y = event.GetPositionTuple()
+    print "(x,y)=(%s,%s)" % (x,y)
+    if event.ButtonDown(1):
+      if self.SelectedHitTest(x, y) :
+        self.canvas.DeSelectAll()
+        self.SetSelected()
+        self.canvas.Update()
+        if self.DragHitTest(x, y):
+          self.dragStartPos =(x, y)
+      else:
+        self.dragStartPos =(x,y)
+    elif event.ButtonUp(1):
+      self.dragStartPos = None
+    elif event.Dragging() and event.LeftIsDown():
+      tolerance = 2
+      if abs(x - self.dragStartPos[0]) > tolerance or abs(y - 
self.dragStartPos[1]) > tolerance:
+        self.DoDrag(x, y)
+        return True
+    event.Skip()
+    return False
+
+  def SetBounds(self, bounds):
+    self.canvas.RefreshScrolledRect(self.bounds);
+    self.bounds = bounds
+    self.canvas.RefreshScrolledRect(self.bounds);
+
+  def Show(self, show):
+
+    # Make sure show is a Boolean
+    show = bool(show)
+
+    if(show ^ self.visible):
+      self.visible = show
+      self.canvas.RefreshScrolledRect(self.bounds);
+      self.canvas.Update()
+
+  def ConvertToCanvasDeviceCoordinates(self, x, y):
+    return self.canvas.CalcScrolledPosition(self.bounds.GetLeft() + x,
+                                              self.bounds.GetTop() + y)
+
+  def DoDrag(self, x, y):
+    """
+      Implement all the drag and drop functionality:
+    """
+
+    """
+      Create the dragImage and begin dragging over the full screen
+    """
+    offscreenBuffer = wx.EmptyBitmap(self.bounds.GetWidth(), 
self.bounds.GetHeight())
+    memoryDC = wx.MemoryDC()
+    memoryDC.SelectObject(offscreenBuffer)
+
+    memoryDC.BeginDrawing()
+    memoryDC.Clear()
+    self.Draw(memoryDC)
+
+    maskBitmap = wx.EmptyBitmap(self.bounds.GetWidth(), 
self.bounds.GetHeight(), 1)
+    memoryDC.SelectObject(maskBitmap)
+
+    memoryDC.SetBackground(wx.BLACK_BRUSH)
+    memoryDC.Clear()
+
+    self.DrawMask(memoryDC)
+    memoryDC.EndDrawing()
+
+    memoryDC.SelectObject(wx.NullBitmap)
+
+    if "__WXMAC__" in wx.PlatformInfo:  # workaround for wxMac bug
+        offscreenBuffer.SetMask(wx.MaskColour(maskBitmap, wx.BLACK))
+    else:
+        offscreenBuffer.SetMask(wx.Mask(maskBitmap))
+
+    """
+      Create the dragImage and begin dragging
+    """
+    if "__WXGTK__" in wx.PlatformInfo:
+        # The "hole punching" trick dosen't work on wxGTK, move the hostspot
+        # to be just outside the image
+        x, y = -1, -1
+    self.dragImage = wxCanvasDragImage(offscreenBuffer)
+
+    self.dragImage.BeginDrag(wx.Point(x,y), self.canvas, True)
+    self.dragImage.Move(self.ConvertToCanvasDeviceCoordinates(x, y))
+    self.dragImage.Show()
+
+    """
+      We need to keep a reference to the dataObject, rather than create
+    it in the construction because wxCanvasDropSource doesn't own the
+    data so the garbage collector will delete it.
+    """
+    dataObject = self.ConvertDrawableObjectToDataObject(x, y)
+    dropSource = wxCanvasDropSource(self, dataObject)
+
+    self.canvas.internalDnDItem = self
+    result = dropSource.DoDragDrop(wx.Drag_AllowMove)
+    self.canvas.internalDnDItem = None
+    self.dragImage.Hide()
+    self.dragImage.EndDrag()
+    del self.dragImage
+
+  def DrawMask(self, dc):
+    """
+      optionally implement this routine to draw a mask
+    """
+    pass
+
+  def SizeDrag(self, dragRect, startDrag, endDrag):
+    self.canvas.RefreshScrolledRect(self.bounds)
+    self.bounds = dragRect
+    self.canvas.RefreshScrolledRect(self.bounds)
+
+  """
+    You must implement the following functions
+  """
+  def Draw(self, dc):
+    """
+      You must implement this routine to do draw
+    """
+    assert(False)
+
+  def DragHitTest(self, x, y):
+    """
+      You must implement this routine to do hit testing for dragable region
+    of drawable object
+    """
+    assert(False)
+
+  def ConvertDrawableObjectToDataObject(self, x, y):
+    """
+      You must implement this routine to create data object for drag and drop
+    """
+    assert(False)
+
+  def SelectedHitTest(self, x, y):
+    """
+    You must implement this routine to do hit testing to identify the region
+    for selecting the object.
+    """
+    assert(False)
+
+  def SetSelected(self, selected=True):
+    """
+    Sets the selected bit for this object. Does a canvas refresh on the object
+    if it has changed state. Does not call Update on the canvas.
+    """
+    # Use the same trick as Show()
+    selected = bool(selected)
+
+    # Only do a refresh if we've changed state.
+    if(selected ^ self.selected):
+      self.selected = selected
+      self.canvas.RefreshScrolledRect(self.bounds);
+
+
+# ===================================================================
+# The canvas to draw on
+# ===================================================================
+class wxSimpleCanvas(wx.ScrolledWindow):
+  def __init__(self, *arguments, **keywords):
+    super(wxSimpleCanvas, self).__init__(*arguments, **keywords)
+
+    self.autoCreateDistance = 0
+    self.zOrderedDrawableObjects = []
+    self.internalDnDItem = None
+    self.Bind(wx.EVT_PAINT, self.OnPaint)
+    self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
+    self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseEvent)
+
+
+  def __del__(self):
+    for item in self.zOrderedDrawableObjects:
+      item.Destroy()
+
+  def RefreshScrolledRect(self, rect):
+    position = rect.GetPosition()
+    x, y = self.CalcScrolledPosition(position.x, position.y)
+    self.RefreshRect(wx.Rect(x, y, rect.GetWidth(), rect.GetHeight()));
+
+  def OnPaint(self, event):
+    """
+      wx.BufferedDC doesn't work here since it doesn't handle scrolled windows
+    and always allocates a buffer the size of the client area. So instead we'll
+    allocate a wx.MemoryDC, draw into it then blit it to our paintDC.
+      Eventually, if we're printing, we should bypass the wx.MemoryDC.
+      The updateRegion is not in scrolled coordinates.
+    """
+    scrollWindowOriginX, scrollWindowOriginY = self.CalcUnscrolledPosition(0, 
0)
+
+    paintDC = wx.PaintDC(self)
+    self.PrepareDC(paintDC)
+
+    """
+      Calculate the rectangle that needs updating in scrolled coordinates
+    """
+    updateRect = self.GetUpdateRegion().GetBox()
+    bufferX = updateRect.GetLeft() + scrollWindowOriginX
+    bufferY = updateRect.GetTop() + scrollWindowOriginY
+    bufferWidth = updateRect.GetWidth()
+    bufferHeight = updateRect.GetHeight()
+
+    memoryDC = wx.MemoryDC()
+    offscreenBuffer = wx.EmptyBitmap(bufferWidth, bufferHeight)
+    memoryDC.SelectObject(offscreenBuffer)
+    memoryDC.SetDeviceOrigin(-bufferX, -bufferY)
+
+    """
+      Debugging code that makes it easy to see which areas are updating.
+    """
+    if 0:
+      success = paintDC.Blit(bufferX, bufferY,
+                              bufferWidth, bufferHeight,
+                              paintDC,
+                              bufferX, bufferY,
+                              wx.SRC_INVERT)
+      time.sleep(1)
+      success = paintDC.Blit(bufferX, bufferY,
+                              bufferWidth, bufferHeight,
+                              paintDC,
+                              bufferX, bufferY,
+                              wx.SRC_INVERT)
+
+
+    memoryDC.BeginDrawing()
+
+    self.DrawBackground(memoryDC)
+    self.Draw(memoryDC)
+
+    paintDC.Blit(bufferX, bufferY,
+                  bufferWidth, bufferHeight,
+                  memoryDC,
+                  bufferX, bufferY)
+
+    memoryDC.EndDrawing()
+
+  def Draw(self, dc):
+    updateRegion = self.GetUpdateRegion()
+    scrollWindowOriginX, scrollWindowOriginY = self.CalcUnscrolledPosition(0, 
0)
+    dcOriginX, dcOriginY = dc.GetDeviceOrigin()
+    index = len(self.zOrderedDrawableObjects) - 1
+    while index >= 0:
+      drawableObject = self.zOrderedDrawableObjects [index]
+      objectX = drawableObject.bounds.GetLeft()
+      objectY = drawableObject.bounds.GetTop()
+      objectWidth = drawableObject.bounds.GetWidth()
+      objectHeight = drawableObject.bounds.GetHeight()
+
+      bounds = wx.Rect(objectX - scrollWindowOriginX,
+                        objectY - scrollWindowOriginY,
+                        objectWidth,
+                        objectHeight)
+
+      if updateRegion.ContainsRect(bounds) != wx.OutRegion and 
drawableObject.visible:
+        dc.SetDeviceOrigin(objectX + dcOriginX, objectY + dcOriginY)
+        drawableObject.Draw(dc)
+        dc.SetDeviceOrigin(dcOriginX, dcOriginY)
+      index -= 1
+
+  def OnEraseBackground(self, event):
+    """
+      Override OnEraseBackground to avoid erasing background. Instead
+    implement OnDrawBackground to draw/erase the background. This
+    design alternative will eliminate flicker
+    """
+    pass
+
+  def OnMouseEvent(self, event):
+    x, y = event.GetPositionTuple()
+    x, y = self.CalcUnscrolledPosition(x, y)
+    for drawableObject in self.zOrderedDrawableObjects:
+      if drawableObject.bounds.Inside((x, y)):
+        event.m_x = x - drawableObject.bounds.GetX()
+        event.m_y = y - drawableObject.bounds.GetY()
+        if drawableObject.ProcessEvent(event):
+          return True
+
+    if self.autoCreateDistance != 0:
+      if event.ButtonDown() and self.CreateHitTest(x, y):
+          self.dragStart = wx.Point(x, y)
+          self.CaptureMouse()
+          return True
+      elif hasattr(self, 'dragStart'):
+        if event.Dragging():
+          """
+            Clip mouse position to the scrolling window's bounds
+          """
+          boundsX, boundsY = self.GetVirtualSizeTuple()
+          if x < 0:
+            x = 0
+          if x > boundsX:
+            x = boundsX
+          if y < 0:
+            y = 0
+          if y > boundsY:
+            y = boundsY
+
+          deltaX =  x - self.dragStart.x
+          deltaY =  y - self.dragStart.y
+
+          if deltaX >= 0:
+            left = self.dragStart.x
+            width = deltaX
+          else:
+            left = x
+            width = -deltaX
+
+          if deltaY >= 0:
+            top = self.dragStart.y
+            height = deltaY
+          else:
+            top = y
+            height = -deltaY
+          dragRect = wx.Rect(left, top, width, height)
+
+          if not hasattr(self, 'dragCreateDrawableObject'):
+            if(deltaX * deltaX) +(deltaY * deltaY) >(self.autoCreateDistance * 
self.autoCreateDistance):
+              """
+              Create a new drawable object if we've dragged autoCreateDistance
+              pixels
+              """
+              object = self.dragCreateDrawableObject = 
self.CreateNewDrawableObject(dragRect,
+                                                                            
self.dragStart,
+                                                                            
wx.Point(x, y))
+              # if we weren't allowed to create one, give up
+              if object is None:
+                  return True
+
+              self.DeSelectAll()
+              object.selected = True
+
+
+              #self.zOrderedDrawableObjects.insert(0, 
self.dragCreateDrawableObject)
+              #self.RefreshScrolledRect(self.dragCreateDrawableObject.bounds);
+              self.Add(object)
+
+            return True
+          else:
+            if self.dragCreateDrawableObject != None:
+              self.dragCreateDrawableObject.SizeDrag(dragRect,
+                                                      self.dragStart,
+                                                      wx.Point(x, y))
+
+        elif event.ButtonUp():
+          del self.dragStart
+          if hasattr(self, 'dragCreateDrawableObject'):
+              del self.dragCreateDrawableObject
+          self.ReleaseMouse()
+          return True
+    return False
+
+  def OnData(self, dataObject, x, y, result):
+    """
+      Handle default behavior of copy and move
+    """
+    if result == wx.DragMove or result == wx.DragCopy:
+        if(self.internalDnDItem != None) and(result == wx.DragMove):
+            assert(self.zOrderedDrawableObjects.count(self.internalDnDItem) == 
1)
+
+            drawableObject = 
self.ConvertDataObjectToDrawableObject(dataObject, x, y, True)
+            x = drawableObject.bounds.GetLeft()
+            y = drawableObject.bounds.GetTop()
+
+            self.zOrderedDrawableObjects.remove(self.internalDnDItem)
+            self.zOrderedDrawableObjects.insert(0, self.internalDnDItem)
+            self.internalDnDItem.MoveTo(x, y)
+            self.internalDnDItem.Show(True)
+        else:
+
+            drawableObject = 
self.ConvertDataObjectToDrawableObject(dataObject, x, y, False)
+            x = drawableObject.bounds.GetLeft()
+            y = drawableObject.bounds.GetTop()
+
+            self.zOrderedDrawableObjects.insert(0, drawableObject)
+            self.RefreshScrolledRect(drawableObject.bounds);
+    return result
+
+  def CreateHitTest(self, x, y):
+    """
+      Set self.autoCreateDistance to some value other than zero to enable
+    dragging autoCreateDistance pixels to automatically create new drawable
+    objects.
+      By default, drawable objects are created if you click and drag in the
+    canvas anwhere there isn't a drawable object. You can restrict this 
location
+    that drawable objects are created by overriding this routine
+    """
+    return True
+  """
+    You must implement the following functions
+  """
+  def ConvertDataObjectToDrawableObject(self, dataObject, x, y, move):
+    """
+      You must implement this routine to convert a dataobject, used in
+    drag and drop into a drawable object.
+    """
+    assert(False)
+
+  def CreateNewDrawableObject(self, dragRect, startDrag, endDrag):
+    """
+      You must implement this routine to create new drawable objects by
+    dragging on the blank canvas.
+    """
+    assert(False)
+
+  def DeSelectAll(self):
+    """
+    Mark all selected objects as not selected. Only Refresh the objects
+    that change, don't call Update.
+    """
+    for drawableObject in self.zOrderedDrawableObjects:
+        if(drawableObject.selected):
+            drawableObject.selected = False
+            self.RefreshScrolledRect(drawableObject.bounds)
+
+  # -----------------------------------------------------------------
+  # Additions by GNUe
+  # -----------------------------------------------------------------
+  def Add(self, object):
+    """
+    Add a DrawableObject to the canvas
+    """
+    self.zOrderedDrawableObjects.insert(0, object)
+    self.RefreshScrolledRect(object.bounds);
+
+  def Remove(self, object):
+    self.zOrderedDrawableObjects.remove(object)
+    bounds = object.bounds
+    self.RefreshScrolledRect(bounds)
+    object.Destroy()
+
+
+# ===================================================================
+# A draggable image frame
+# ===================================================================
+class wxCanvasDragImage(wx.Frame):
+  """
+  A class similar to wx.DragImage except that it uses a shaped frame
+  to display the image, and that it is always full screen.
+  """
+  def __init__(self, bitmap):
+    super(wxCanvasDragImage, self).__init__(
+            None, -1, "",
+            style = wx.FRAME_SHAPED
+                  | wx.SIMPLE_BORDER
+                  | wx.FRAME_NO_TASKBAR
+                  | wx.STAY_ON_TOP)
+    self.bmp = bitmap
+    w, h = self.bmp.GetWidth(), self.bmp.GetHeight()
+    self.SetClientSize((w, h) )
+    self.hotspot = None
+    self.window = None
+
+    self.Bind(wx.EVT_PAINT, self.OnPaint)
+
+    if "__WXGTK__" in wx.PlatformInfo:
+      # wxGTK requires that the window be created before you can
+      # set its shape, so delay the call to SetWindowShape until
+      # this event.
+      self.Bind(wx.EVT_WINDOW_CREATE, self.SetWindowShape)
+    else:
+      # On wxMSW and wxMac the window has already been created, so go for it.
+      self.SetWindowShape()
+
+  def SetWindowShape(self, evt=None, hotspot=None):
+    # Use the bitmap's mask to determine the region
+    rgn = wx.RegionFromBitmap(self.bmp)
+    if hotspot is not None:
+      # punch a hole in the region at the hotspot to allow mouse events
+      # through to the window below
+      rect = wx.Rect(hotspot.x-1, hotspot.y-1, 3, 3)
+      rgn.SubtractRect(rect)
+    self.SetShape(rgn)
+
+  def BeginDrag(self, hotspot, window, *ignoreOthers):
+    self.hotspot = wx.Point(hotspot[0], hotspot[1])
+    if "__WXGTK__" not in wx.PlatformInfo:
+      self.SetWindowShape(hotspot = self.hotspot)
+    self.window = window
+    if self.window:
+      self.window.CaptureMouse()
+
+  def EndDrag(self, doDestroy=True):
+    if self.window and self.window.HasCapture():
+      self.window.ReleaseMouse()
+    self.Hide()
+    if doDestroy:
+      self.Destroy()
+
+  def Move(self, pt):
+    """
+    Move the image to a new location on screen.  The pt parameter
+    is a point in client coordinants relative to the window
+    specifed in BeginDrag. (Only for compatibility with
+    wx.DragImage, otherwise I would just use screen coordinants...)
+    """
+    pt2 = pt
+    if self.window:
+      pt2 = self.window.ClientToScreen(pt)
+    self.SetPosition(pt2 - self.hotspot)
+
+  def Show(self):
+    wx.Frame.Show(self)
+    self.Update()
+
+  def OnPaint(self, evt):
+    dc = wx.PaintDC(self)
+    dc.DrawBitmap(self.bmp, 0, 0, True)
+
+
+# ===================================================================
+# A draggable drop source
+# ===================================================================
+class wxCanvasDropSource(wx.DropSource):
+  def __init__(self, drawableObject, dataObject):
+    super(wxCanvasDropSource, self).__init__(drawableObject.canvas)
+    self.drawableObject = drawableObject
+    self.SetData(dataObject)
+
+  def GiveFeedback(self, effect):
+    windowX, windowY = wx.GetMousePosition()
+    self.drawableObject.Show(effect != wx.DragMove)
+    x, y = self.drawableObject.canvas.ScreenToClientXY(windowX, windowY)
+    self.drawableObject.dragImage.Move((x, y))
+    return False
+
+
+# ===================================================================
+# A draggable drop target
+# ===================================================================
+class wxCanvasDropTarget(wx.PyDropTarget):
+  def __init__(self, canvas, dropTargetDataObject):
+    super(wxCanvasDropTarget, self).__init__()
+    self.canvas = canvas
+    self.dataObject = dropTargetDataObject
+    self.SetDataObject(dropTargetDataObject)
+
+  def OnData(self, x, y, result):
+    """
+      Delegate functionality to the canvas
+    """
+    if(self.GetData()):
+      x, y = self.canvas.CalcUnscrolledPosition(x, y)
+      result = self.canvas.OnData(self.dataObject, x, y, result)
+    return result
+





reply via email to

[Prev in Thread] Current Thread [Next in Thread]