commit-gnue
[Top][All Lists]
Advanced

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

CVSROOT: /cvsroot/gnue


From: Jason Cater
Subject: CVSROOT: /cvsroot/gnue
Date: Fri, 22 Aug 2003 20:04:43 -0400

Module name:    gnue-designer
Branch:         layout-editor-rendering
Changes by:     Jason Cater <address@hidden>    03/08/22 20:04:42
Reply-to: address@hidden

CVSROOT:        /cvsroot/gnue
Module name:    gnue-designer
Branch:         layout-editor-rendering
Changes by:     Jason Cater <address@hidden>    03/08/22 20:04:42

Modified files:
        src/forms/LayoutEditor: LayoutEditor.py 
        src/forms/LayoutEditor/renderers/Base: Driver.py GridPane.py 
        src/forms/LayoutEditor/renderers/curses: Driver.py 
        src/forms/LayoutEditor/renderers/native: Driver.py 
                                                 WidgetHandler.py 

Log message:
        (branched) Splitting LayoutEditor into various smaller components and 
adding Renderer support

CVSWeb URLs:
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue-designer/src/forms/LayoutEditor/LayoutEditor.py.diff?only_with_tag=layout-editor-rendering&tr1=1.97&tr2=1.97.4.1&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue-designer/src/forms/LayoutEditor/renderers/Base/Driver.py.diff?only_with_tag=layout-editor-rendering&tr1=1.1&tr2=1.1.4.1&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue-designer/src/forms/LayoutEditor/renderers/Base/GridPane.py.diff?only_with_tag=layout-editor-rendering&tr1=1.7&tr2=1.7.4.1&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue-designer/src/forms/LayoutEditor/renderers/curses/Driver.py.diff?only_with_tag=layout-editor-rendering&tr1=1.1&tr2=1.1.4.1&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue-designer/src/forms/LayoutEditor/renderers/native/Driver.py.diff?only_with_tag=layout-editor-rendering&tr1=1.1&tr2=1.1.4.1&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnue-designer/src/forms/LayoutEditor/renderers/native/WidgetHandler.py.diff?only_with_tag=layout-editor-rendering&tr1=1.15&tr2=1.15.4.1&r1=text&r2=text

Patches:
Index: gnue-designer/src/forms/LayoutEditor/LayoutEditor.py
diff -c /dev/null gnue-designer/src/forms/LayoutEditor/LayoutEditor.py:1.97.4.1
*** /dev/null   Fri Aug 22 20:04:43 2003
--- gnue-designer/src/forms/LayoutEditor/LayoutEditor.py        Fri Aug 22 
20:04:42 2003
***************
*** 0 ****
--- 1,833 ----
+ #
+ # 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.
+ #
+ # Copyright 2001-2003 Free Software Foundation
+ #
+ # FILE:
+ # LayoutEditor.py
+ #
+ # DESCRIPTION:
+ #
+ # NOTES:
+ #
+ # TODO: Split this file up
+ #
+ 
+ __all__ = ['LayoutEditor']
+ 
+ import sys, os
+ from wxPython.wx import *
+ from gnue.common.apps import GDebug
+ from gnue.forms import GFObjects
+ from gnue.forms.uidrivers.wx import UIdriver as UIwxpython
+ from gnue.designer.base.PopupMenu import PageMenu
+ from gnue.designer.base.TemplateParser import TemplateParser
+ from gnue.designer.base.ToolBase import *
+ from gnue.common.events import Event
+ 
+ # My support files
+ from Utils import *
+ from LayoutEditorTools import LayoutEditorTools
+ from PropertyBar import PropertyBar
+ from DisplayDropTarget import DisplayDropTarget
+ from ReorderFocus import ReorderFocus
+ 
+ from renderers.native.WidgetHandler import WidgetHandler
+ from renderers.Base.GridPane import GridPane
+ from renderers.native.Driver import Renderer
+ 
+ from Workspace import Workspace
+ 
+ class LayoutEditor (ToolBase):
+ 
+   runtime_section = "FormsLayoutEditor"
+   default_dock = 'right-0'
+   uses_feedback_bar = 1
+   uses_toolbar = 1
+ 
+ 
+   def init(self):
+ 
+     self.renderer = Renderer(self.instance)
+ 
+     # TODO: blah.... historical reasons
+     self._instance = self.instance
+ 
+     self._app = self.instance._app
+ 
+     self.page = None
+     self.block = None
+     self.lastBlock = None
+     self.blockMap = {}
+     self.panel = None
+     self._notebookMap = {}
+     self.positionMappings = {}
+     self.widgetList = []
+     self._currentSelection = []
+ 
+     # Create our own WX GFUserInterface instance
+     self.uidriver = uidriver = UIwxpython.GFUserInterface(self.instance, 0)
+ 
+     # Create a list of all UI widgets
+     self.widgets = {}
+     self.widgets.update(uidriver._supportedWidgets)
+ 
+     # But we don't want a page to act like normal objects...
+     # we have special plans for it (bwahahaha)
+     del self.widgets['GFPage']
+ 
+ 
+     self.notebook = wxNotebook(self, -1, pos=wxPoint(4, 4), 
size=wxSize(32,32))
+     self.backcolor = wxWHITE
+ 
+     EVT_NOTEBOOK_PAGE_CHANGED(self,self.notebook.GetId(), self.OnPageSelected)
+     EVT_SIZE(self, self.OnSize)
+ 
+     self._currentObject = None
+     self.mode = 'move'
+     self.reorderfocus = ReorderFocus(self.instance)
+ 
+     # Internal mouse states... used by OnMotion, etc
+     self.__drawing = 0
+     self.__x = 0
+     self.__y = 0
+     self.__ox = 0
+     self.__oy = 0
+ 
+     # EventAware provided by ToolBase
+     self.registerEventListeners({
+                        'ObjectSelected'      : self.onSetCurrentObject,
+                        'ObjectCreated'       : self.onCreateObject,
+                        'ObjectModified'      : self.onModifyObject,
+                        'ObjectDeleted'       : self.onDeleteObject,
+                        'LayoutEditor:ZoomIn' : self.zoomIn,
+                        'LayoutEditor:ZoomOut': self.zoomOut,
+                        'LayoutEditor:FocusOrder': self.beginFocusOrder,
+                        'Cancel:LayoutEditor:FocusOrder': self.endFocusOrder,
+                        'LayoutEditor:Prepositioning': 
self.beginPrePositioningTemplate,
+                        'Cancel:LayoutEditor:Prepositioning': 
self.cancelPrePositioningTemplate,
+                        'LayoutEditor:Select': self.beginSelectMode,
+                        'Cancel:LayoutEditor:Select': self.cancelSelectMode,
+                        'EndWizard': self.endWizard,
+                       })
+ 
+     self.instance.rootObject.walk (self.inventoryObject)
+     try:
+       self._setCurrentPage(self._notebookMap[0])
+     except KeyError:
+       pass
+ 
+     ## Stuff needed by UIwxpython
+     self._pageList = []  # Needed by UIwxpython
+ 
+ 
+   def createToolbar(self, parent):
+     self.toolbar = LayoutEditorTools(parent, self.instance)
+     self.blockCombo = self.toolbar.blockCombo
+     EVT_COMBOBOX(self.toolbar, self.blockCombo.GetId(), self.OnBlockSelected)
+     self._rebuildBlockCombo()
+     return self.toolbar
+ 
+   # Recalculate the scrollbar sizes
+   def __OnGridSize(self, event):
+     w, h = self.panel.GetSizeTuple()
+     w2, h2 = self.workspacescroll.GetClientSizeTuple()
+     w = int(max(w, w2)*1.1+30)
+     h = int(max(h, h2)*1.1+30)
+     self.workspace.SetSize((w,h))
+     self.workspacescroll.SetScrollbars(w/30-1,h/30-1,30,30)
+ 
+ 
+   def inventoryObject(self, object):
+     if object._type == 'GFPage':
+       index = self.notebook.GetPageCount()
+       self._notebookMap[object] = index
+       self._notebookMap[index] = object
+ 
+       self.workspace = Workspace(self.notebook, self, object)
+ 
+       self.notebook.AddPage(self.workspace.scroller, object.name)
+       object.__workspace = self.workspace
+ 
+     elif object._type == 'GFBlock':
+       self.blockMap[object.name.lower()] = object
+       if not self.block:
+         self._setCurrentBlock(object)
+ 
+ 
+   def onSetCurrentObject (self, event):
+     object = event.object
+     handler = event.originator
+ 
+     try:
+       selection = event.selection
+     except:
+       selection = [object]
+ 
+     self._currentObject = object
+ 
+     if handler != "Forms::LayoutEditor":
+       self._setCurrentPage(object)
+     self._setFeedback()
+     self._setCurrentBlock(object)
+     self._setSelection(object, selection)
+ 
+   def _setCurrentBlock(self,object):
+     if not object:
+       return
+     block = object.findParentOfType('GFBlock')
+     if not block:
+       if object._type == 'GFEntry':
+         block = object._block
+     if block:
+       self.block = block
+       if hasattr(self,'blockCombo'):
+         self.blockCombo.SetValue(block.name)
+ ##      self._setFeedback()
+ 
+   def _rebuildBlockCombo(self):
+     if hasattr(self,'blockCombo'):
+       # TODO
+       srt = self.blockMap.keys()
+       srt.sort()
+       self.blockComboList = []
+       self.blockCombo.Clear()
+ 
+       for key in srt:
+         block = self.blockMap[key]
+         self.blockCombo.Append(block.name)
+         self.blockComboList.append(block)
+       if self.block:
+         self.blockCombo.SetValue(self.block.name)
+ 
+   def OnBlockSelected(self, event):
+     s= event.GetSelection()
+     block = self.blockComboList[s]
+     if block != self.block:
+       self.dispatchEvent('ObjectSelected',
+                          object = block,
+                          originator = None)
+ 
+   def _setFeedback(self):
+ 
+     object = self._currentObject
+ 
+     ft = ""
+ 
+     # This sets the feedback text at the top of the Layout Editor window
+     if object:
+       try:      ft += 'Name: % (%s)' % (object.name, object._type[2:])
+       except:   pass
+ 
+       try:      ft += '   Col: %s' % object.Char__x
+       except:   pass
+ 
+       try:      ft += '   Row: %s' % object.Char__y
+       except:   pass
+ 
+       try:      ft += '   Width: %s' % object.Char__width
+       except:   pass
+ 
+       try:
+         if object.Char__height > 1:
+           ft += '   Height: %s' % object.Char__height
+       except:
+         pass
+ 
+     if ft:
+      self.setFeedback(ft)
+ 
+ 
+   def _setCurrentPage(self, object):
+     if not object:
+       return
+     page = isinstance(object, GFObjects.GFPage) and object or \
+            object.findParentOfType('GFPage')
+ 
+     if page != None and page != self.page:
+       self.page = page
+       self.workspace = page.__workspace
+       self.notebook.SetSelection(self._notebookMap[page])
+ 
+ 
+   def _setSelection(self, focus, objects):
+ 
+     # Unhighlight any previously selected items
+     # that are no longer selected.
+     for key in self._currentSelection:
+       if key not in objects:
+         try:
+           key._widgetHandler.setSelected(0)
+         except AttributeError:
+           pass
+ 
+     # and now highlight any new items
+     for object in objects:
+       if hasattr(object, '_widgetHandler') and object not in 
self._currentSelection:
+         self._currentSelection.append(object)
+         object._widgetHandler.setSelected(1, object == focus)
+ 
+     self._currentSelection = objects[:]
+ 
+ 
+   def onCreateObject (self, event):
+     object = event.object
+     handler = event.originator
+ ##    self._currentSelection = []
+     if object == None:
+       return
+ 
+     if handler != "Forms::LayoutEditor":
+       origpage = self.page
+ 
+       if object._type != 'GFPage':
+         page = object.findParentOfType('GFPage')
+         if page:
+           self._setCurrentPage(page)
+           self.__drawItem(object)
+ 
+       self.inventoryObject(object)
+       self._setCurrentPage(origpage)
+     if object._type == 'GFBlock':
+       self.blockMap[object.name.lower()] = object
+       self._rebuildBlockCombo()
+ 
+ 
+   def onModifyObject (self, event):
+     object = event.object
+     handler = event.originator
+ 
+     # TODO: adjust label width to match new length...this shouldn't be here
+     if object._type == 'GFLabel':
+       mods = []
+       for field in event.new.keys():
+         value = event.new[field]
+         if field=='text':
+           if (not hasattr(object,'alignment')) or ( object.alignment == 
'left'):
+             if not hasattr(object,'Char__width') or object.Char__width != 
len(value):
+               object.Char__width=len(value)
+               # TODO: This should probably trigger a new ObjectModified event
+               event.new['Char:width'] = object.Char__width
+ 
+ ##    self.propBar.onModifyObject(object, event)
+ 
+     if handler != "Forms::LayoutEditor":
+       if object._type == 'GFPage':
+         self.notebook.SetPageText(self._notebookMap[object],object.name)
+         self.notebook.SetSelection(self.notebook.GetSelection())
+       else:
+         page = object.findParentOfType('GFPage')
+         if page:
+           self._setCurrentPage(page)
+ 
+       if object in (self.rootObject, self.page, self.rootObject._layout) or 
object in self.widgetList:
+         self.workspace.refreshPage(self.page)
+ 
+     if object._type == 'GFBlock' and event.old.has_key('name'):
+       del self.blockMap[event.old['name'].lower()]
+       self.blockMap[object.name.lower()] = object
+       self._rebuildBlockCombo()
+ 
+     self._setFeedback()
+ 
+ 
+   def onDeleteObject (self, event):
+ 
+     object = event.object
+     handler = event.originator
+ 
+     self._currentObject = None
+ 
+     if 1: ## handler != "Forms::LayoutEditor":
+       if object._type == 'GFPage':
+         index = self._notebookMap[object]
+         for i in range(index+1, len(self._notebookMap.keys())/2):
+           self._notebookMap[i-1] = self._notebookMap[i]
+         del self._notebookMap[int(len(self._notebookMap.keys())/2)-1]
+         del self._notebookMap[object]
+         self.notebook.DeletePage(index)
+ 
+     if hasattr(object, '_widgetHandler') and object._widgetHandler != None:
+       if object in self._currentSelection:
+         object._widgetHandler.setSelected(0)
+         del self._currentSelection[self._currentSelection.index(object)]
+ 
+       self.widgetList.remove(object)
+       ##for i in range(len(self.widgetList)):
+       ##  if self.widgetList[i] == object:
+       ##    self.widgetList.pop(i)
+       ##    break
+ 
+ ##      object._widget.cleanup(object)
+       object._widget._object = None
+       object._widget = None
+       object._widgetHandler.Destroy()
+       object._widgetHandler = None
+ 
+ 
+   def calcGridSpacing(self):
+       UIwxpython.initFont(self.panel)
+ 
+       maxWidth, maxHeight, maxDescent, maxLeading = [0,0,0,0]
+ 
+       checkchars = string.letters+string.digits+"-\|" + string.punctuation
+       for letter in checkchars:
+         width,height,descent,leading = self.panel.GetFullTextExtent(letter)
+         maxWidth = maxWidth > width and maxWidth or width
+         maxHeight = maxHeight > height and maxHeight or height
+         maxDescent = maxDescent > descent and maxDescent or descent
+         maxLeading = maxLeading > leading and maxLeading or leading
+ 
+       self.charWidth = maxWidth+maxLeading
+       self.charHeight = maxHeight+maxDescent
+ 
+       self.borderPercentage = (float(gConfig('borderPercentage')) / 100)
+       self.textPercentage = (float(gConfig('textPercentage')) / 100)
+ 
+       self.widgetWidth = int(self.charWidth * self.borderPercentage)
+       self.widgetHeight = int(self.charHeight * self.borderPercentage) + 3
+       self.textWidth = self.charWidth * self.textPercentage
+       self.textHeight = self.charHeight * self.textPercentage
+ 
+       self.gridWidth = self.widgetWidth
+       self.gridHeight = self.widgetHeight
+ 
+       self.menu_sb_space=0 # the extra spaces needed by the menu, toolbar and 
statusbar
+ 
+       width = self.rootObject._layout.Char__width
+       height = self.rootObject._layout.Char__height
+       self.panel.SetClientSize(wxSize(int(width)*self.widgetWidth,
+                        int(height)*self.widgetHeight))
+       self.panel.Refresh()
+ 
+ 
+   def drawPage(self, page):
+     self._currentSelection = []
+     self.page = page
+ 
+     try:
+       self.panel = self.page.__panel
+     except AttributeError:
+       self.panel = GridPane(self, self.workspace, wxPoint(10,12))
+ 
+       # Automatically resize workspace
+       EVT_SIZE(self.panel, self.__OnGridSize)
+ 
+       # We are a drop target for Drag-and-Drop
+       self.panel.SetDropTarget(DisplayDropTarget(self))
+ #      self.panel.SetDropTarget(SchemaDropTarget(self))
+ 
+       self.page.__panel = self.panel
+       self.panelColor = self.panel.GetBackgroundColour()
+       self.panelGridColor = wxColour(order(255,self.panelColor.Red()+16)[0],
+                  order(255,self.panelColor.Green()+16)[0],
+                  order(255,self.panelColor.Blue()+16)[0])
+ 
+       page.__pointSize = UIwxpython.getPointSize()
+       self.calcGridSpacing()
+ 
+       page.walk(self.__drawItem)
+ 
+ 
+     EVT_CHAR(self.panel, self.keyTrap)
+     EVT_LEFT_DOWN(self.panel, self.OnLeftDown)
+     EVT_MOTION(self.panel, self.OnMotion)
+     EVT_LEFT_UP(self.panel, self.OnLeftUp)
+     EVT_RIGHT_UP(self.panel, self.OnRightUp)
+ 
+ 
+   def __drawItem(self, object):
+     if self.widgets.has_key(object._type) and \
+        (not hasattr(object, 'hidden') or not object.hidden):
+       if hasattr(object, 'name'):
+         GDebug.printMesg(7, 'Drawing item %s of type %s' % (object.name, 
object._type))
+       else:
+         GDebug.printMesg(7, 'Drawing item of type %s' % (object._type))
+       object._widgetHandler = WidgetHandler(self, object)
+ 
+       cevent = Event('CreateUIWidget',None,
+                    parent=None,
+                    object=object,
+                    container=self.panel,
+                    textWidth=self.textWidth,
+                    textHeight=self.textHeight,
+                    widgetWidth=self.widgetWidth,
+                    widgetHeight=self.widgetHeight,
+                    interface=self,
+                    eventHandler=None,
+                    ui=self,
+                    initialize=0)
+ 
+       object._widget = widget = 
self.widgets[object._type].configuration['baseClass'](cevent)
+ 
+       # TODO: This segfaults us... yay!!!
+       widget.phaseInit(widget._buildObject())
+ 
+       object._widget._object = object
+       object._widgetHandler.initialize(object._widget)
+       self.widgetList.append(object)
+ 
+   def OnSize(self, event):
+     self.notebook.SetSize(wxSize(self.GetClientSize().x-8, 
self.GetClientSize().y - 8))
+ 
+   def OnPageSelected(self, event):
+     p = self._notebookMap[event.GetSelection()]
+     if p != self.page:
+       self.dispatchEvent('ObjectSelected', object=p, 
originator="Forms::LayoutEditor")
+     self._setCurrentPage(p)
+     self.__OnGridSize(None)
+ 
+   def OnLeftDown(self, event):
+     x, y = event.GetPositionTuple()
+     self.handleLeftDown(x,y)
+     event.Skip()
+ 
+ 
+   def handleLeftDown(self, x, y):
+     self.__drawing = 1
+ 
+     # Save starting coordinates for cross-selection box
+     self.__cx = cx = int(x / self.gridWidth)
+     self.__cy = cy = int(y / self.gridHeight)
+ 
+     self.setFeedback ('Col: %s   Row: %s' % (cx, cy))
+ 
+     self.__brush = wxBrush(wxWHITE, style=wxTRANSPARENT)
+ 
+     self.__x = x
+     self.__y = y
+     self.__ox = None
+     self.__oy = None
+ 
+ 
+   # Used by the dragging routines to draw a selection box
+   def xorBox(self, x1, y1, x2, y2, x3=None, y3=None):
+     dc = wxClientDC(self.panel)
+     dc.SetBrush(self.__brush)
+     dc.SetPen(wxGREY_PEN)
+     dc.SetLogicalFunction(wxXOR)
+ 
+     if x3 != None:
+       dc.DrawRectangle(x1,y1,x3-x1,y3-y1)
+ 
+     dc.DrawRectangle(x1,y1,x2-x1,y2-y1)
+ 
+ 
+   def OnMotion(self, event):
+     # draw cross-selection box
+     if self.__drawing and event.LeftIsDown():
+ 
+       if self.__drawing == 1:
+         self.panel.SetCursor(wxCROSS_CURSOR)
+         self.__drawing = 2
+ 
+       x, y = event.GetPositionTuple()
+       cx = int(x / self.gridWidth)
+       cy = int(y / self.gridHeight)
+ 
+       cx1, cx2 = order(self.__cx, cx)
+       cy1, cy2 = order(self.__cy, cy)
+ 
+       self.setFeedback('Col: %s   Row: %s   Width: %s   Height: %s'% (cx1, 
cy1, cx2 - cx1 + 1, cy2 - cy1 + 1))
+ 
+ 
+ 
+       self.xorBox(self.__x, self.__y, x, y, self.__ox, self.__oy)
+ 
+       self.__ox = x
+       self.__oy = y
+ 
+     event.Skip()
+ 
+ 
+   def OnLeftUp(self, event):
+     x, y = event.GetPositionTuple()
+     self.handleLeftUp(x,y)
+     event.Skip()
+ 
+ 
+   def handleLeftUp(self, x, y):
+     selection = []
+ 
+     self.setFeedback('')
+ 
+     if self.__drawing and self.__ox is not None:
+ 
+       self.xorBox(self.__x, self.__y, self.__ox, self.__oy)
+       self.__ox = None
+       self.__oy = None
+ 
+     self.__drawing = 0
+ 
+     # Set x1,y1 to be smaller coordinates, and x2,y2 to be larger
+     x1, x2 = order(int(self.__x / self.gridWidth), int(x / self.gridWidth))
+     y1, y2 = order(int(self.__y / self.gridHeight),int(y / self.gridHeight))
+ 
+ 
+     self.panel.SetCursor(wxSTANDARD_CURSOR)
+     wxSetCursor(wxSTANDARD_CURSOR)
+ 
+ 
+     areaSelected = (x1 <> x2 or y1 <> y2)
+ 
+     if self.mode == 'move':
+       if areaSelected:
+         # We are selecting an area
+         self.page.walk(self.selectWidgetInArea, x1, y1, x2, y2, selection)
+         try:
+           object = selection[-1]
+         except IndexError:
+           object = self.page
+         self.dispatchEvent('ObjectSelected',
+                          object = object,
+                          originator = "Forms::LayoutEditor",
+                          selection = selection)
+       else:
+         self.dispatchEvent('ObjectSelected',
+                          object = self.page,
+                          originator = "Forms::LayoutEditor")
+ 
+     elif self.mode == 'positioning':
+ 
+        if areaSelected:
+          width = x2 - x1 + 1
+          height = y2 - y1 + 1
+        else:
+          width = None
+          height = None
+ 
+        
PrepositioningTimer(self.endPrePositioningTemplate,x1,y1,width,height).Start(100,1)
+ 
+ 
+ 
+   def selectWidgetInArea(self, object, x1, y1, x2, y2, selection):
+     try:
+       if x1 <= object.Char__x <= x2 and \
+          y1 <= object.Char__y <= y2:
+         if object not in selection:
+           selection.append(object)
+     except AttributeError:
+       # Not all child objects have coordinates (x,y)
+       pass
+ 
+ 
+   def OnRightUp(self, event):
+ ##    self.toolbar.resetTool(self.mode)
+     self.mode = 'move'
+     self.dispatchEvent('LayoutEditor:Select')
+ 
+     x, y = event.GetPositionTuple()
+ 
+     x = int(x / self.gridWidth)
+     y = int(y / self.gridHeight)
+ 
+     menu = wxMenu('Layout Editor')
+     form = self._currentObject._type == 'GFForm' and self._currentObject or \
+        self._currentObject.findParentOfType('GFForm')
+     page = self._currentObject._type == 'GFPage' and self._currentObject or \
+        self._currentObject.findParentOfType('GFPage')
+     block = self._currentObject._type == 'GFBlock' and self._currentObject or 
\
+        self._currentObject.findParentOfType('GFBlock')
+ 
+     menu.AppendMenu(wxNewId(), 'Form', PageMenu(self.instance, form, x, y))
+     if page:
+       menu.AppendMenu(wxNewId(), page.name, PageMenu(self.instance, page, x, 
y))
+     if block:
+       menu.AppendMenu(wxNewId(), block.name, PageMenu(self.instance, block, 
x, y))
+ 
+     self.panel.PopupMenu(menu, event.GetPosition())
+ 
+ 
+   def keyTrap(self, event):
+     if event.KeyCode() in (WXK_LEFT, WXK_RIGHT, WXK_UP, WXK_DOWN) and \
+       len(self._currentSelection):
+       if event.AltDown() or event.ControlDown() or event.ShiftDown():
+         # caution: event.MetaDown() is always true on some architectures
+         resize = None
+         if event.KeyCode() == WXK_LEFT:
+           resize = (-1,0)
+         if event.KeyCode() == WXK_RIGHT:
+           resize = (1,0)
+         if event.KeyCode() == WXK_UP:
+           resize = (0,-1)
+         if event.KeyCode() == WXK_DOWN:
+           resize = (0,1)
+         if resize:
+           self.dispatchEvent('BeginUndoGroup')
+           for widget in self._currentSelection:
+             widget._widgetHandler.relativeResize(*resize)
+           self.dispatchEvent('EndUndoGroup')
+       else:
+         pos = None
+         if event.KeyCode() == WXK_LEFT:
+           pos = (-1,0)
+         if event.KeyCode() == WXK_RIGHT:
+           pos = (1,0)
+         if event.KeyCode() == WXK_UP:
+           pos = (0,-1)
+         if event.KeyCode() == WXK_DOWN:
+           pos = (0,1)
+ 
+         if pos:
+           self.dispatchEvent('BeginUndoGroup')
+           for widget in self._currentSelection:
+             if widget._type != 'GFPage':
+               widget._widgetHandler.relativeMove(*pos)
+           self.dispatchEvent('EndUndoGroup')
+ 
+     elif event.KeyCode() == WXK_DELETE and \
+          len(self._currentSelection):
+       self.dispatchEvent('BeginUndoGroup')
+       for object in self._currentSelection:
+         if object._type != 'GFPage':
+           self.dispatchEvent('ObjectDeleted', object=object,
+                              originator=self)
+       self.dispatchEvent('EndUndoGroup')
+     elif event.KeyCode() == WXK_TAB:
+       if event.ShiftDown():
+         object = self._currentObject
+         if hasattr(object,'_widgetHandler') and not object._type == 'GFPage':
+           i = object._parent._children.index(object)
+           lst = object._parent._children[i:] + object._parent._children[:i]
+         else:
+           lst = self.page._children[:]
+         lst.reverse()
+         for newobj in lst:
+           if hasattr(newobj,'_widgetHandler'):
+             self.instance.dispatchEvent('ObjectSelected',
+                                         originator=None,
+                                         object=newobj)
+             break
+       elif not event.ControlDown() and not event.AltDown():
+         object = self._currentObject
+         if hasattr(object,'_widgetHandler') and not object._type == 'GFPage':
+           i = object._parent._children.index(object)
+           lst = object._parent._children[i+1:] + 
object._parent._children[:i+1]
+         else:
+           lst = self.page._children[:]
+         for newobj in lst:
+           if hasattr(newobj,'_widgetHandler'):
+             self.instance.dispatchEvent('ObjectSelected',
+                                         originator=None,
+                                         object=newobj)
+             break
+ 
+ 
+   def zoomIn(self, event):
+     size = UIwxpython.getPointSize()
+     if size < 72:
+       size = size + 1 # int(size * 1.05 + .5)
+       UIwxpython.setPointSize(size)
+       self.calcGridSpacing()
+       self.refreshPage(self.page)
+       self.setFeedback(_('Adjusting base point size to %spt') % size)
+     else:
+       self.setFeedback(_('Cannot adjust point size to more than 72pt'))
+ 
+ 
+   def zoomOut(self, event):
+     size = UIwxpython.getPointSize()
+     if size > 6:
+       size = size - 1 # int(size * -1.05)
+       UIwxpython.setPointSize(size)
+       self.calcGridSpacing()
+       self.refreshPage(self.page)
+       self.setFeedback(_('Adjusting base point size to %spt') % size)
+     else:
+       self.setFeedback(_('Cannot adjust point size to less than 6pt'))
+ 
+ 
+   def beginPrePositioningTemplate(self, event):
+     mode = self.mode
+     self.mode = 'positioning'
+     if mode == 'move':
+       self.dispatchEvent('Cancel:LayoutEditor:Select')
+     elif mode == 'refocus':
+       self.dispatchEvent('Cancel:LayoutEditor:FocusOrder')
+ 
+     ##self.panel.SetCursor(wxCROSS_CURSOR)
+     wxSetCursor(wxCROSS_CURSOR)
+     self.__wizardrunner = event.wizardrunner
+ 
+   def cancelPrePositioningTemplate(self, event=None):
+     if self.mode == 'prepositioning':
+       self.__wizardrunner.cancel()
+     wxSetCursor(wxSTANDARD_CURSOR)
+ 
+   def endPrePositioningTemplate(self, x, y, width=None, height=None):
+     self.mode = 'move'
+     self.dispatchEvent('Cancel:LayoutEditor:Prepositioning')
+     self.dispatchEvent('LayoutEditor:Select')
+     self.__wizardrunner.positioned_run(x=x, y=y, width=width, height=height)
+ 
+ 
+   def beginFocusOrder(self, event):
+     mode = self.mode
+     self.mode = 'refocus'
+     if mode == 'move':
+       event.dispatchAfter('Cancel:LayoutEditor:Select')
+     elif mode == 'positioning':
+       self.__wizardrunner.cancel()
+       # Yes, you are reading this right...
+       # I'm triggering the exact event that
+       # triggered this method. Blame it on
+       # the Tuesday night atmospheric crack
+       # levels.
+       self.dispatchEvent('LayoutEditor:FocusOrder')
+       return
+ 
+     self.reorderfocus.start(self.page)
+ 
+   def endFocusOrder(self, event):
+     self.reorderfocus.end()
+     if self.mode == 'refocus':
+       self.mode = 'move'
+       self.dispatchEvent('LayoutEditor:Select')
+ 
+   def beginSelectMode(self, event=None):
+     mode = self.mode
+     self.mode = 'move'
+     if mode == 'refocus':
+       self.dispatchEvent('Cancel:LayoutEditor:FocusOrder')
+     elif mode == 'positioning':
+       self.dispatchEvent('Cancel:LayoutEditor:Prepositioning')
+ 
+   def cancelSelectMode(self, event=None):
+     if self.mode == 'move':
+       event.dispatchAfter('LayoutEditor:Select')
+ 
+   def endWizard(self, event=None):
+     mode = self.mode
+     self.mode = 'move'
+     if mode == 'refocus':
+       self.dispatchEvent('Cancel:LayoutEditor:FocusOrder')
+     elif mode == 'positioning':
+       self.dispatchEvent('Cancel:LayoutEditor:Prepositioning')
+     self.dispatchEvent('LayoutEditor:Select')
+ 
+ 
+ class PrepositioningTimer(wxTimer):
+   def __init__(self, method, *args, **params):
+     self.__method = method
+     self.__args = args
+     self.__params = params
+     wxTimer.__init__(self)
+ 
+   def Notify(self):
+     self.__method(*self.__args, **self.__params)
+ 
Index: gnue-designer/src/forms/LayoutEditor/renderers/Base/Driver.py
diff -c /dev/null 
gnue-designer/src/forms/LayoutEditor/renderers/Base/Driver.py:1.1.4.1
*** /dev/null   Fri Aug 22 20:04:43 2003
--- gnue-designer/src/forms/LayoutEditor/renderers/Base/Driver.py       Fri Aug 
22 20:04:42 2003
***************
*** 0 ****
--- 1,69 ----
+ #
+ # 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.
+ #
+ # Copyright 2001-2003 Free Software Foundation
+ #
+ # FILE:
+ # renderers/Base/Driver.py
+ #
+ # DESCRIPTION:
+ #
+ # NOTES:
+ #
+ 
+ from wxPython.wx import *
+ 
+ class BaseRenderer:
+   def __init__(self, instance):
+     self.instance = instance
+ 
+     StartupStatus(_('Loading Form renderers'))
+ 
+     self.init()
+ 
+   #
+   # For subclasses
+   #
+   def init(self):
+     pass
+ 
+ 
+   #
+   # Convenience
+   #
+ 
+   #
+   # Set the font in use and
+   # calculate the cell sizing
+   #
+   def resetFont(self):
+     self.font = font = wxSystemSettings_GetFont(wxSYS_OEM_FIXED_FONT)
+ 
+     # Get font extents
+     tmpBitmap = wxEmptyBitmap(100,100)
+     dc = wxMemoryDC()
+     dc.SelectObject(tmpBitmap)
+     dc.SetFont(font)
+     w, h = dc.GetTextExtent('0123456789')
+     self.cell_vert_margin = 2
+     self.cell_horiz_margin = 2
+     self.line_spacing = self.cell_vert_margin * 2
+     self.cell_height = h + self.line_spacing
+     self.cell_width = int(w/10)
+ 
+ 
Index: gnue-designer/src/forms/LayoutEditor/renderers/Base/GridPane.py
diff -c /dev/null 
gnue-designer/src/forms/LayoutEditor/renderers/Base/GridPane.py:1.7.4.1
*** /dev/null   Fri Aug 22 20:04:43 2003
--- gnue-designer/src/forms/LayoutEditor/renderers/Base/GridPane.py     Fri Aug 
22 20:04:42 2003
***************
*** 0 ****
--- 1,90 ----
+ #
+ # Copyright 2001-2003 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.
+ #
+ # FILE:
+ # GridPane.py
+ #
+ # DESCRIPTION:
+ #
+ # NOTES:
+ 
+ from wxPython.wx import *
+ import sys, string
+ from gnue.designer.forms.LayoutEditor.Utils import *
+ from gnue.common.apps import GDebug
+ 
+ 
+ #
+ #
+ #
+ class GridPane(wxSashWindow):
+   def __init__(self, instance, parent, pos):
+     wxSashWindow.__init__(self, parent, -1, pos=pos, 
style=wxWANTS_CHARS|wxSIMPLE_BORDER)
+     self.__showGrids = 1
+     self.__instance = instance
+     EVT_PAINT(self, self.OnPaint)
+ 
+     # TODO: Have the sash events resize the form
+     self.SetSashVisible(wxSASH_RIGHT,1)
+     self.SetSashVisible(wxSASH_BOTTOM,1)
+ 
+     EVT_SASH_DRAGGED(self, self.GetId(), self.SashChanged)
+ 
+   def OnPaint(self, event):
+     if self.__showGrids:
+       dc = wxPaintDC(self)
+       dc.BeginDrawing()
+       w, h = self.GetSizeTuple()
+       dc.SetPen(wxPen(self.__instance.workspace.panelGridColor))
+       for x in range(self.__instance.workspace.widgetWidth,w-3, 
self.__instance.workspace.widgetWidth):
+         dc.DrawLine(x,0,x,h-1)
+ 
+       for y in 
range(self.__instance.workspace.widgetHeight,h-2,self.__instance.workspace.widgetHeight):
+         dc.DrawLine(0,y,w-1,y)
+       dc.EndDrawing()
+     event.Skip()
+ 
+   def SashChanged(self, event):
+     w = event.GetDragRect().width
+     h = event.GetDragRect().height
+ 
+     neww = int(w/float(self.__instance.workspace.widgetWidth)+.5)
+     newh = int(h/float(self.__instance.workspace.widgetHeight)+.5)
+ 
+     layout = self.__instance.instance.rootObject._layout
+ 
+     oldvars = {}
+     newvars = {}
+ 
+     if neww != layout.Char__width:
+       oldvars['Char:width'] = layout.Char__width
+       newvars['Char:width'] = neww
+       layout.Char__width = neww
+     if newh != layout.Char__height:
+       oldvars['Char:height'] = layout.Char__height
+       newvars['Char:height'] = newh
+       layout.Char__height = newh
+ 
+     if oldvars:
+       self.__instance.instance.dispatchEvent('ObjectModified', object=layout,
+                                     originator="Forms::GridPane",
+                                     old=oldvars,
+                                     new=newvars)
+ 
Index: gnue-designer/src/forms/LayoutEditor/renderers/curses/Driver.py
diff -c /dev/null 
gnue-designer/src/forms/LayoutEditor/renderers/curses/Driver.py:1.1.4.1
*** /dev/null   Fri Aug 22 20:04:43 2003
--- gnue-designer/src/forms/LayoutEditor/renderers/curses/Driver.py     Fri Aug 
22 20:04:42 2003
***************
*** 0 ****
--- 1,230 ----
+ #
+ # 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.
+ #
+ # Copyright 2001-2003 Free Software Foundation
+ #
+ # FILE:
+ # curses/Driver.py
+ #
+ # DESCRIPTION:
+ #
+ # NOTES:
+ #
+ 
+ from wxPython.wx import *
+ from gnue.designer.forms.LayoutEditor.renderers.Base import *
+ import string
+ 
+ class Renderer(BaseRenderer):
+ 
+   ##########
+   #
+   # Public methods
+   #
+ 
+   def init(self):
+     self.map = {
+        'GFScrollbar': self.scrollbar,
+        'GFEntry': self.entry,
+        'GFButton': self.button,
+        'GFImage': self.image,
+        'GFLabel': self.label,
+        'GFBox': self.box,
+ 
+     self.resetFont()
+ 
+   def removeWidget(self, object):
+     # We don't need to do anything special
+     # if a widget is removed
+     return
+ 
+   def redrawWidget(self, object):
+     # We don't need to do anything special,
+     # other than recreate the bitmap, if a
+     # widget is redrawn/updated
+     return self.addWidget(object)
+ 
+   def addWidget(self, object):
+     try:
+       func = self.map[object._type]
+     except:
+       func = self.unknown
+ 
+     return func(object)
+ 
+ 
+ 
+   ##########
+   #
+   # Internal methods
+   #
+ 
+ 
+   #
+   # Known objects
+   # Return a wxBitmap
+   #
+   def entry(self, object):
+     return self.simpleTextObject(object, 10, 1, COLOR_TEXTBOX, "", 0)
+ 
+   def button(self, object):
+     # Default the width to the length of
+     # the label if width hasn't been set.
+     try:        width = object.Char__width
+     except:     width = len(object.label)
+ 
+     # Create a label formatted as <Button Name>
+     # and pad it to take up the width
+     label = string.center('<' + object.label[:width-2] + '>', width)
+ 
+     # Use our handy-dandy bitmap creator to do the rest
+     return self.simpleTextObject(object, width, 1, COLOR_BUTTON, text, 0)
+ 
+   def label(self, object):
+ 
+     # Default the width to the length of
+     # the label if width hasn't been set.
+     try:        width = object.Char__width
+     except:     width = len(object.label)
+ 
+     # Get the label alignment, if set
+     try:       alignment = object.alignment
+     except:    alignment = 'left'
+ 
+     # Align the text
+     text = aligners[alignment](object.label[:width],width)
+ 
+     # And use our handy-dandy bitmap creator to do the rest
+     return self.simpleTextObject(object, width, 1, COLOR_LABEL, object.label, 
1)
+ 
+   def scrollbar(self, object):
+     return self.unknown(object)
+ 
+   def box(self, object):
+     return self.unknown(object)
+ 
+   def image(self, object):
+     # We don't support this,
+     # so create an "unknown" object
+     return self.unknown(object)
+ 
+ 
+   #
+   # Unknown/unsupported object
+   # Return a wxBitmap with
+   # cross-hatching
+   #
+   def unknown(self, object):
+     # TODO: something better
+     return self.simpleTextObject(object, 10, 1, COLOR_BACKGROUND, "", 0)
+ 
+ 
+   #
+   # Encapsulate the creation of widgets that are nothing more than
+   # a one-line display of text (w/appropriate colors)
+   #
+   def simpleTextObject(object, text, defw, defh, colors, transparent=0):
+     dc, bitmap = self.createBitmap(object, defw, defh)
+     self.writeText(dc, 0, 0, colors, text, transparent)
+ 
+ 
+   #
+   # Create a bitmap object
+   # using the char-based width/height
+   #
+   def createBitmap(self, object, defw=10, defh=1):
+     # Get the bitmap width and height
+     try:
+       h = object.Char__height * self.heightAdjustment
+     except:
+       h = defw
+ 
+     try:
+       w = object.Char__width * self.heightAdjustment
+     except:
+       w = defw
+ 
+     dc = wxMemoryDC()
+     bitmap = wxEmptyBitmap(w, h)
+     dc.SelectObject(bitmap)
+     dc.SetFont(self.font)
+     return (dc, bitmap)
+ 
+ 
+ 
+   #
+   # Draw text onto the bitmap
+   # Supports background coloring
+   # and multiline-text
+   #
+   def writeText(self, dc, x, y, colors, text, transparent=0):
+ 
+     fgcolor, bgcolor = colors
+     if not transparent:
+       dc.SetBackground(wxBrush(bgcolor))
+       dc.Clear()
+     else:
+       dc.SetBackground(wxTRANSPARENT_BRUSH)
+ 
+     dc.SetTextForeground(fgcolor)
+ 
+     ox = x * self.cell_width + self.cell_horiz_margin
+     oy = x * self.cell_height + self.cell_vert_margin
+ 
+ 
+     for line in text.split('\n'):
+       dc.DrawText(line, ox, oy)
+       oy += self.cell_height
+ 
+ 
+ 
+ WHITE = wxWHITE
+ BLUE = wxBLUE
+ CYAN = wxCYAN
+ BLACK = wxBLACK
+ RED = wxRED
+ 
+ 
+ # These names were copied over
+ # from gnue.common.cursing;
+ # not all are used here.
+ COLOR_BACKGROUND=(WHITE,BLUE)
+ COLOR_TITLEBAR=(WHITE,BLUE)
+ COLOR_TEXTBOX_FOCUS=(BLACK,CYAN)
+ COLOR_TEXTBOX=(BLUE,WHITE)
+ COLOR_MENUBAR=(BLACK,WHITE)
+ COLOR_MENUBAR_FOCUS=(BLUE,WHITE)
+ COLOR_LABEL=(BLACK,WHITE)
+ COLOR_STATUSBAR=(BLACK,WHITE)
+ COLOR_STATUSBAR_FIELD=(BLACK,WHITE)
+ COLOR_DIALOG=(BLACK,WHITE)
+ COLOR_DIALOG_TITLE=(BLACK,WHITE)
+ COLOR_BUTTON=(BLUE,WHITE)
+ COLOR_BUTTON_FOCUS=(WHITE,CYAN)
+ COLOR_SCROLL_BUTTON=(BLACK,WHITE)
+ COLOR_SCROLL_BUTTON_FOCUS=(CYAN,WHITE)
+ COLOR_SCROLL_BACKGROUND=(BLUE,WHITE)
+ COLOR_SCROLL_SLIDER=(WHITE,BLUE)
+ COLOR_SCROLL_SLIDER_FOCUS=(BLACK,CYAN)
+ COLOR_DROPSHADOW=(WHITE,BLACK)
+ 
+ # Convenience mapper for <label>.alignment => python method
+ aligners = {'left':string.ljust,
+             'right':string.rjust,
+             'center':string.center}
+ 
Index: gnue-designer/src/forms/LayoutEditor/renderers/native/Driver.py
diff -c /dev/null 
gnue-designer/src/forms/LayoutEditor/renderers/native/Driver.py:1.1.4.1
*** /dev/null   Fri Aug 22 20:04:43 2003
--- gnue-designer/src/forms/LayoutEditor/renderers/native/Driver.py     Fri Aug 
22 20:04:42 2003
***************
*** 0 ****
--- 1,114 ----
+ #
+ # 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.
+ #
+ # Copyright 2001-2003 Free Software Foundation
+ #
+ # FILE:
+ # native/Driver.py
+ #
+ # DESCRIPTION:
+ #
+ # NOTES:
+ #
+ 
+ from wxPython.wx import *
+ from gnue.designer.forms.LayoutEditor.renderers.Base import *
+ from gnue.forms.uidrivers.wx import UIdriver as UIwxpython
+ from gnue.common.events import Event
+ from WidgetHandler import WidgetHandler
+ 
+ class Renderer(BaseRenderer):
+ 
+   ##########
+   #
+   # Public methods
+   #
+ 
+   def init(self):
+     # Create our own WX GFUserInterface instance
+     self.uidriver = uidriver = UIwxpython.GFUserInterface(self.instance, 0)
+ 
+     # Create a list of all UI widgets
+     self.widgets = {}
+     self.widgets.update(uidriver._supportedWidgets)
+ 
+     # But we don't want a page to act like normal objects...
+     # we have special plans for it (bwahahaha)
+     del self.widgets['GFPage']
+ 
+     self.widgetList = []
+ 
+     self.resetFont()
+ 
+ 
+   def removeWidget(self, object):
+     # We don't need to do anything special
+     # if a widget is removed
+     try:
+       self.widgetList.remove(object)
+     except:
+       pass
+ 
+ 
+   def redrawWidget(self, object):
+     # We don't need to do anything special,
+     # other than recreate the bitmap, if a
+     # widget is redrawn/updated
+     return self.addWidget(object)
+ 
+ 
+   def addWidget(self, object):
+     if self.widgets.has_key(object._type) and \
+        (not hasattr(object, 'hidden') or not object.hidden):
+       if hasattr(object, 'name'):
+         GDebug.printMesg(7, 'Drawing item %s of type %s' % (object.name, 
object._type))
+       else:
+         GDebug.printMesg(7, 'Drawing item of type %s' % (object._type))
+       object._widgetHandler = WidgetHandler(self.layouteditor, object)
+ 
+       cevent = Event('CreateUIWidget',None,
+                    parent=None,
+                    object=object,
+                    container=self.layouteditor.workspace.panel,
+                    textWidth=self.textWidth,
+                    textHeight=self.textHeight,
+                    widgetWidth=self.widgetWidth,
+                    widgetHeight=self.widgetHeight,
+                    interface=self,
+                    eventHandler=None,
+                    ui=self,
+                    initialize=0)
+ 
+       object._widget = widget = 
self.widgets[object._type].configuration['baseClass'](cevent)
+ 
+       # TODO: This segfaults us... yay!!!  (is this fixed???)
+       widget.phaseInit(widget._buildObject())
+ 
+       object._widget._object = object
+       object._widgetHandler.initialize(object._widget)
+       self.widgetList.append(object)
+ 
+ 
+ 
+ 
+   ##########
+   #
+   # Internal methods
+   #
+ 
+ 
Index: gnue-designer/src/forms/LayoutEditor/renderers/native/WidgetHandler.py
diff -c /dev/null 
gnue-designer/src/forms/LayoutEditor/renderers/native/WidgetHandler.py:1.15.4.1
*** /dev/null   Fri Aug 22 20:04:43 2003
--- gnue-designer/src/forms/LayoutEditor/renderers/native/WidgetHandler.py      
Fri Aug 22 20:04:42 2003
***************
*** 0 ****
--- 1,375 ----
+ #
+ # 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.
+ #
+ # Copyright 2001-2003 Free Software Foundation
+ #
+ # FILE:
+ # WidgetHandler.py
+ #
+ # DESCRIPTION:
+ #
+ # NOTES:
+ #  (TODO) This needs to go bye-bye
+ 
+ from wxPython.wx import *
+ import sys, string
+ from gnue.common.apps import GDebug
+ import cPickle
+ 
+ # LayoutEditor support files
+ from gnue.designer.forms.LayoutEditor.WidgetHighlighter import 
WidgetHighlighter
+ from gnue.designer.forms.LayoutEditor.PopupEditor import PopupEditor
+ from gnue.designer.forms.LayoutEditor.Utils import *
+ 
+ #
+ #
+ #
+ class WidgetHandler(wxEvtHandler):
+   def __init__(self, instance, object):
+     wxEvtHandler.__init__(self)
+     self.editor = instance
+     self.object = object
+     self.hasFocus = 0
+     self.highlightBox = WidgetHighlighter(self.editor.panel)
+     self._iMoved = 0
+     self._alreadySelected = 0
+     self._popup_editor = None
+ 
+   def initialize(self, widget):
+     self.widget = widget.widgets[0]
+     self.mainWidget = widget
+     self.selected = 0
+ 
+     self.recalcBoundaries()
+ 
+     for widget in self.mainWidget.widgets:
+       widget.SetCursor (wxSTANDARD_CURSOR)
+ 
+ #      try:
+ #        widget.Enable(0)
+ #      except:
+ #        pass
+ 
+       try:
+         widget.SetEditable(0)
+       except:
+         pass
+ 
+       self.setAllChildren(EVT_KEY_UP, widget, self.editor.keyTrap)
+       self.setAllChildren(EVT_SET_FOCUS, widget, self.focusGainedTrap)
+       self.setAllChildren(EVT_KILL_FOCUS, widget, self.focusLostTrap)
+       self.setAllChildren(EVT_LEFT_UP, widget, self.OnLeftUp)
+       self.setAllChildren(EVT_LEFT_DOWN, widget, self.OnLeftDown)
+       self.setAllChildren(EVT_RIGHT_DOWN, widget, self.OnRightDown)
+       self.setAllChildren(EVT_RIGHT_UP, widget, self.OnRightUp)
+       self.setAllChildren(EVT_MOTION, widget, self.OnMotion)
+       self.setAllChildren(EVT_LEFT_DCLICK, widget, self.onLeftDClick)
+     self.setAllChildren(EVT_KEY_UP, self.highlightBox, self.editor.keyTrap)
+     self.setAllChildren(EVT_SET_FOCUS, self.highlightBox, 
self.focusGainedTrap)
+     self.setAllChildren(EVT_KILL_FOCUS, self.highlightBox, self.focusLostTrap)
+     self.setAllChildren(EVT_LEFT_UP, self.highlightBox, self.OnLeftUp)
+     self.setAllChildren(EVT_LEFT_DOWN, self.highlightBox, self.OnLeftDown)
+     self.setAllChildren(EVT_RIGHT_UP, self.highlightBox, self.OnRightUp)
+     self.setAllChildren(EVT_MOTION, self.highlightBox, self.OnMotion)
+ 
+     self.widget.Refresh()
+ 
+   def recalcBoundaries(self):
+     x1,y1,x2,y2 = (9999999,9999999,0,0)
+ 
+     for widget in self.mainWidget.widgets:
+       tx, ty = widget.GetPositionTuple()
+       tw, th = widget.GetSizeTuple()
+       self.editor.positionMappings[widget] = [tx,ty,tx+tw-1,ty+tw-1,self]
+       if tx < x1:
+         x1 = tx
+       if ty < y1:
+         y1 = ty
+       if tw + tx > x2:
+         x2 = tw + tx
+       if th + ty > y2:
+         y2 = th + ty
+ 
+     self.highlightBox.setBoundary(x1-2,y1-2,x2+2,y2+2)
+     for widget in self.mainWidget.widgets:
+        widget.Refresh()
+ 
+ 
+   def setSelected(self, selected, focused=1):
+     self.selected = selected
+     self.focused = focused
+     self.highlightBox.setSelected(selected, focused)
+ 
+ 
+   def setAllChildren(self, event, widget, trap):
+     try:
+       event(widget, trap)
+     except:
+       pass
+     for child in widget.GetChildren():
+       self.setAllChildren(event, child, trap)
+ 
+   def focusGainedTrap(self, event):
+     self.editor.panel.SetFocus()
+     pass
+ #    event.Skip()
+ 
+   def focusLostTrap(self, event):
+     event.Skip()
+ 
+ 
+   def beginDragDrop(self, event):
+ 
+     # Drag and drop TODO: This needs changed to pull all selected widgets
+ 
+     object = self.object
+ 
+     x,y = event.GetPositionTuple()
+ 
+     data = [ { "Type" : "selectedWidgets",
+                "Attributes": {
+                    'startingX': object.Char__x + int(x/self.editor.gridWidth),
+                    'startingY': object.Char__y + 
int(y/self.editor.gridHeight),
+                    }
+                }]
+ #        "name": dname,
+ #        "table": object.name,
+ #        "database": self.connectionName } }
+ #
+ #
+     do = wxCustomDataObject(wxCustomDataFormat("application/x-gnue-designer"))
+     do.SetData(cPickle.dumps(data,1))
+ 
+ ##    icon = FeedbackBitmap(10,10).icon()
+     dropSource = MoveDropSource(self, self.editor)
+     dropSource.SetData(do)
+     result = dropSource.DoDragDrop(true)
+     event.Skip()
+ 
+ 
+   def OnLeftDown(self, event):
+ 
+     if self.editor.mode == 'move':
+ 
+       self.mouseStartX, self.mouseStartY = event.GetPositionTuple()
+       self._iMoved = 0
+ 
+       if event.ShiftDown():
+         selections = self.editor._currentSelection[:]
+       else:
+         selections = []
+ 
+       if self.object in selections:
+         if event.ShiftDown():
+           del selections[selections.index(self.object)]
+       else:
+         selections.append(self.object)
+ 
+       self.editor._instance.dispatchEvent('ObjectSelected',object=self.object,
+                                              originator="Forms::LayoutEditor",
+                                              selection=selections)
+     else:
+       xo, yo = self.widget.GetPosition()
+       x, y = event.GetPositionTuple()
+       self.editor.handleLeftDown(x+xo,y+yo)
+ 
+     event.Skip()
+ 
+ 
+   def OnLeftUp(self, event):
+     if self.editor.mode == 'move':
+       if self._iMoved:
+         self._iMoved = 0
+     else:
+       xo, yo = self.widget.GetPosition()
+       x, y = event.GetPositionTuple()
+       self.editor.handleLeftUp(x+xo,y+yo)
+ 
+     event.Skip()
+ 
+ 
+   def OnMotion(self, event):
+ 
+     if not self._iMoved and event.LeftIsDown():
+       self._iMoved = 1
+       self.beginDragDrop(event)
+ 
+     event.Skip()
+ 
+ 
+   def OnRightDown(self, event):
+     event.Skip()
+ 
+ 
+   def OnRightUp(self, event):
+     if self.editor.mode == 'move':
+       pt = event.GetPositionTuple()
+       self.editor.dispatchEvent('ObjectSelected',object=self.object, 
originator=None)
+       wxPyTypeCast(event.GetEventObject(),'wxWindow') \
+          .PopupMenu(self.object._popupMenu, pt)
+     event.Skip()
+ 
+ 
+   def _endPopupEditor(self, success, value=""):
+     if success:
+ 
+       try:
+         oldVals = {self.__popupAttr:self.object.__dict__[self.__popupAttr]}
+       except KeyError:
+         oldVals = {self.__popupAttr:None}
+       newVals = {self.__popupAttr: value}
+       self.object.__dict__.update(newVals)
+       self.editor.dispatchEvent('ObjectModified', object=self.object,
+                                   originator="Forms::LayoutEditor",
+                                   old=oldVals,
+                                   new=newVals)
+ 
+       self._popup_editor.Destroy()
+       self._popup_editor = None
+       self.widget.SetLabel(value or "<Unset>")
+       if self.object._type == 'GFLabel':
+         width = len(value) or 10
+         self.widget.SetSize((width * self.editor.gridWidth,
+                             self.widget.GetSize().height))
+         self.recalcBoundaries()
+         self.setSelected(self.selected)
+ 
+ 
+   def onLeftDClick(self, event):
+ 
+     if self.editor.mode == 'move':
+       if self.object._type in ('GFBox','GFLabel'):
+         # Create a popup text editor for the labels
+         if self.object._type == 'GFBox':
+           self.__popupAttr = 'label'
+           x = self.widget.GetPosition().x + (self.editor.gridWidth/2)
+           width = (self.object.Char__width - 2) * self.editor.gridWidth
+         else:
+           self.__popupAttr = 'text'
+           x = self.widget.GetPosition().x
+           width = self.widget.GetSize().width + self.editor.gridWidth
+ 
+         self._popup_editor = PopupEditor(self.editor.workspace,
+             self._endPopupEditor,
+             x + self.editor.panel.GetPosition().x,
+             self.widget.GetPosition().y + self.editor.panel.GetPosition().y,
+             width,
+             self.editor.gridHeight,
+             self.object.__dict__[self.__popupAttr])
+ 
+         self._popup_editor.SetFocus()
+ 
+       else:
+         # Signal the Properties dialog
+         self.editor._instance.dispatchEvent('Show:Tool:objectProperties')
+ 
+ 
+   #
+   # Resize the current widget.  dx and dy are incremental
+   # resize units. (e.g, (-1,0) means make the widget one
+   # unit smaller than it currently is.
+   #
+   def relativeResize(self, dx, dy):
+     if not (dx or dy):
+       return 0
+ 
+     nx = dx * self.editor.gridWidth
+     ny = dy * self.editor.gridHeight
+ 
+     try:
+       self.object.Char__height
+     except: 
+       self.object.Char__height = 1
+ 
+     if (self.object.Char__width + dx < 0 or self.object.Char__height + dy < 
0):
+       return 0
+     else:
+       for widget in self.mainWidget.widgets:
+         x,y = widget.GetSizeTuple()
+         widget.SetSize(wxSize(x + nx,y + ny))
+ 
+       oldVals = {}
+       newVals = {}
+       if dx:
+         oldVals['Char:width'] = self.object.Char__width
+         self.object.Char__width = self.object.Char__width + dx
+         newVals['Char:width'] = self.object.Char__width
+       if dy:
+         oldVals['Char:height'] = self.object.Char__height
+         self.object.Char__height = self.object.Char__height + dy
+         newVals['Char:height'] = self.object.Char__height
+ 
+       self.editor.dispatchEvent('ObjectModified', object=self.object,
+                                   originator="Forms::LayoutEditor",
+                                   old=oldVals,
+                                   new=newVals)
+ 
+       self.recalcBoundaries()
+ 
+ 
+   #
+   # Move the current widget. dx and dy are increments.
+   # (e.g., (-1,-2) means move the object up one unit
+   # and left two units.
+   #
+   def relativeMove(self, dx, dy):
+     if not (dx or dy):
+       return 0
+ 
+     nx = dx * self.editor.gridWidth
+     ny = dy * self.editor.gridHeight
+ 
+     if (self.object.Char__x + dx < 0 or self.object.Char__y + dy < 0):
+       return 0
+     else:
+       for widget in self.mainWidget.widgets:
+         x,y = widget.GetPositionTuple()
+         widget.SetPosition(wxPoint(x + nx,y + ny))
+       oldVals = {}
+       newVals = {}
+       if dx:
+         oldVals['Char:x'] = self.object.Char__x
+         self.object.Char__x += dx
+         newVals['Char:x'] = self.object.Char__x
+       if dy:
+         oldVals['Char:y'] = self.object.Char__y
+         self.object.Char__y +=  dy
+         newVals['Char:y'] = self.object.Char__y
+ 
+       self.editor.dispatchEvent('ObjectModified', object=self.object,
+                                   originator="Forms::LayoutEditor",
+                                   old=oldVals,
+                                   new=newVals)
+ 
+       self.recalcBoundaries()
+ 
+   #
+   # Recursively destroy this widget set
+   #
+   def Destroy(self):
+ 
+     # TODO: Why the fsck can't I Destroy() this thing!?!??!?
+     self.widget.Show(0)
+ 
+     self.editor = None
+     self.object = None
+     self.highlightBox.Destroy()
+     self.highlightBox = None
+     self._popup_editor = None
+     self.widget = None
+     self.mainWidget = None




reply via email to

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