#----------------------------------------------------------------------
# Name: Designer.py
# Purpose: Visual frame designer
#
# Author: Riaan Booysen
#
# Created: 1999
# RCS-ID: $Id: Designer.py,v 1.45 2007/07/02 15:01:16 riaan Exp $
# Copyright: (c) 1999 - 2007 Riaan Booysen
# Licence: GPL
#----------------------------------------------------------------------
print 'importing Views.Designer'
import copy, os, pprint, math
import wx
import Preferences, Utils, Help
from Preferences import IS
from Utils import _
import CtrlAlign, CtrlSize
import sourceconst
from InspectableViews import InspectableObjectView
import SelectionTags
from PropEdit import Enumerations
[wxID_CTRLPARENT, wxID_EDITCUT, wxID_EDITCOPY, wxID_EDITPASTE, wxID_EDITDELETE,
wxID_SHOWINSP, wxID_SHOWEDTR, wxID_CTRLHELP, wxID_EDITALIGN, wxID_EDITSIZE,
wxID_EDITRECREATE, wxID_EDITSNAPGRID, wxID_EDITRELAYOUT, wxID_EDITRELAYOUTSEL,
wxID_EDITRELAYOUTDESGN, wxID_EDITCREATEORDER, wxID_EDITFITINSIDESIZER,
wxID_FINDININDEX, wxID_EDITFITSIZER,
] = Utils.wxNewIds(19)
[wxID_EDITMOVELEFT, wxID_EDITMOVERIGHT, wxID_EDITMOVEUP, wxID_EDITMOVEDOWN,
wxID_EDITWIDTHINC, wxID_EDITWIDTHDEC, wxID_EDITHEIGHTINC, wxID_EDITHEIGHTDEC,
] = Utils.wxNewIds(8)
[wxID_EDITSELECTLEFT, wxID_EDITSELECTRIGHT, wxID_EDITSELECTUP, wxID_EDITSELECTDOWN,
] = Utils.wxNewIds(4)
# XXX When opening a frame with a connected menubar, the frame is not selected
# XXX in the inspector
class DesignerView(wx.Frame, InspectableObjectView, Utils.FrameRestorerMixin):
""" Frame Designer for design-time creation/manipulation of visual controls
on frames. """
viewName = 'Designer'
viewTitle = _('Designer')
docked = False
collectionMethod = sourceconst.init_ctrls
supportsParentView = True
def setupArgs(self, ctrlName, params, dontEval, parent=None, compClass=None, evalDct={}, doId=True):
""" Create a dictionary of parameters for the constructor of the
control from a dictionary of string/source parameters.
"""
args = InspectableObjectView.setupArgs(self, ctrlName, params, dontEval, evalDct=evalDct)
if compClass:
prnt = compClass.windowParentName
wId = compClass.windowIdName
doId = not compClass.suppressWindowId
else:
prnt = 'parent'
wId = 'id'
doId = True
# Determine parent
if parent:
args[prnt] = parent
else:
srcPrnt = args[prnt]
if srcPrnt == 'None':
args[prnt] = None
elif srcPrnt == 'self':
try:
args[prnt] = self
except AttributeError, name:
# XXX This isn't right
if self.objects.has_key(name):
pass
elif self.model.objectCollections.has_key(name):
pass
else:
raise
else:
dot = srcPrnt.find('.')
if dot != -1:
srcPrnt = srcPrnt[dot + 1:]
else: raise Exception, _('Component name illegal %s')%srcPrnt
args[prnt] = self.objects[srcPrnt][1]
# hack to allow stock ids to set the button
if wId in args and args[wId] in Enumerations.wxStockIds:
args[wId] = getattr(wx, args[wId].split('.')[1])
elif doId:
args[wId] = wx.NewId()
return args
defPos = wx.DefaultPosition
def __init__(self, parent, inspector, model, compPal, CompanionClass,
dataView):
self.controllerView = self
self.objectNamespace = DesignerNamespace(self)
args = self.setupArgs(model.main, model.mainConstr.params,
CompanionClass.handledConstrParams, parent, CompanionClass,
model.specialAttrs)
style=wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, parent, -1, args.get('title', ''),
args.get('pos', CompanionClass.defFramePos),
args.get('size', CompanionClass.defFrameSize),
style=CompanionClass.defFrameStyle)
InspectableObjectView.__init__(self, inspector, model, compPal)
self.controllerView = self
if model.dialogLook:
self.SetBackgroundColour(
wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE))
self.SetIcon(IS.load('Images/Icons/Designer.ico'))
self.Bind(wx.EVT_MOVE, self.OnFramePos)
self.pageIdx = -1
self.dataView = dataView
self.dataView.controllerView = self
self.sizersView = None
#self.controllerView = self
self.saveOnClose = True
self.confirmCancel = False
self.ctrlEvtHandler = DesignerControlsEvtHandler(self)
self.companion = CompanionClass(self.model.main, self, self)
self.companion.id = Utils.windowIdentifier(self.model.main, '')
self.companion.control = self
self.mainMultiDrag = None
self.lastSize = (-1, -1)
# the objects dict has the following structure:
# key = componentname
# value = list of companion, control, deltaConstr, deltaProps, deltaEvents
# Note that the frame itself is defined as the blank string name
self.objects[''] = [self.companion, self, None]
self.objectOrder.append('')
self.SetName(self.model.main)
self.companion.initDesignTimeControl()
self.active = True
self.destroying = False
self.selection = None
self.multiSelection = []
# flags controlling behaviour in resize event
self.vetoResize = False
self.forceResize = False
self.deletingCtrl = False
#self.objectNamespace = DesignerNamespace(self)
# XXX Move this definition into actions
self.menu = wx.Menu()
self.menu.Append(wxID_CTRLPARENT, _('Up'))
self.menu.AppendSeparator()
self.menu.Append(wxID_EDITCUT, _('Cut'))
self.menu.Append(wxID_EDITCOPY, _('Copy'))
self.menu.Append(wxID_EDITPASTE, _('Paste'))
self.menu.Append(wxID_EDITDELETE, _('Delete'))
self.menu.AppendSeparator()
self.menu.Append(wxID_EDITRECREATE, _('Recreate'))
self.menu.Append(wxID_EDITRELAYOUTSEL, _('Relayout selection'))
self.menu.Append(wxID_EDITRELAYOUTDESGN, _('Relayout Designer'))
self.menu.AppendSeparator()
self.menu.Append(wxID_EDITFITSIZER, _('Fit sizer'))
#self.menu.Append(wxID_EDITFITINSIDESIZER, 'Fit sizer')
self.menu.AppendSeparator()
self.menu.Append(wxID_EDITSNAPGRID, _('Snap to grid'))
self.menu.Append(wxID_EDITALIGN, _('Align...'))
self.menu.Append(wxID_EDITSIZE, _('Size...'))
self.menu.AppendSeparator()
Utils.appendMenuItem(self.menu, wxID_FINDININDEX,
_('Find in index...'), Preferences.keyDefs['HelpFind'], '',
_('Pops up a text input for starting a search of the help indexes'))
self.menu.AppendSeparator()
self.menu.Append(wxID_EDITCREATEORDER, _('Creation/Tab order...'))
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
self.Bind(wx.EVT_MENU, self.OnControlDelete, id=wxID_EDITDELETE)
self.Bind(wx.EVT_MENU, self.OnInspector, id=wxID_SHOWINSP)
self.Bind(wx.EVT_MENU, self.OnEditor, id=wxID_SHOWEDTR)
self.Bind(wx.EVT_MENU, self.OnCtrlHelp, id=wxID_CTRLHELP)
self.Bind(wx.EVT_MENU, self.OnAlignSelected, id=wxID_EDITALIGN)
self.Bind(wx.EVT_MENU, self.OnSizeSelected, id=wxID_EDITSIZE)
self.Bind(wx.EVT_MENU, self.OnSelectParent, id=wxID_CTRLPARENT)
self.Bind(wx.EVT_MENU, self.OnCutSelected, id=wxID_EDITCUT)
self.Bind(wx.EVT_MENU, self.OnCopySelected, id=wxID_EDITCOPY)
self.Bind(wx.EVT_MENU, self.OnPasteSelected, id=wxID_EDITPASTE)
self.Bind(wx.EVT_MENU, self.OnRecreateSelected, id=wxID_EDITRECREATE)
self.Bind(wx.EVT_MENU, self.OnRelayoutSelection, id=wxID_EDITRELAYOUTSEL)
self.Bind(wx.EVT_MENU, self.OnRelayoutDesigner, id=wxID_EDITRELAYOUTDESGN)
self.Bind(wx.EVT_MENU, self.OnSnapToGrid, id=wxID_EDITSNAPGRID)
self.Bind(wx.EVT_MENU, self.OnCreationOrder, id=wxID_EDITCREATEORDER)
self.Bind(wx.EVT_MENU, self.OnFindInIndex, id=wxID_FINDININDEX)
self.Bind(wx.EVT_MENU, self.OnFitSizer, id=wxID_EDITFITSIZER)
#self.Bind(wx.EVT_MENU, self.OnFitInsideSizer, id=wxID_EDITFITINSIDESIZER)
self.Bind(wx.EVT_MENU, self.OnMoveLeft, id=wxID_EDITMOVELEFT)
self.Bind(wx.EVT_MENU, self.OnMoveRight, id=wxID_EDITMOVERIGHT)
self.Bind(wx.EVT_MENU, self.OnMoveUp, id=wxID_EDITMOVEUP)
self.Bind(wx.EVT_MENU, self.OnMoveDown, id=wxID_EDITMOVEDOWN)
self.Bind(wx.EVT_MENU, self.OnWidthInc, id=wxID_EDITWIDTHINC)
self.Bind(wx.EVT_MENU, self.OnWidthDec, id=wxID_EDITWIDTHDEC)
self.Bind(wx.EVT_MENU, self.OnHeightInc, id=wxID_EDITHEIGHTINC)
self.Bind(wx.EVT_MENU, self.OnHeightDec, id=wxID_EDITHEIGHTDEC)
self.Bind(wx.EVT_MENU, self.OnSelectLeft, id=wxID_EDITSELECTLEFT)
self.Bind(wx.EVT_MENU, self.OnSelectRight, id=wxID_EDITSELECTRIGHT)
self.Bind(wx.EVT_MENU, self.OnSelectUp, id=wxID_EDITSELECTUP)
self.Bind(wx.EVT_MENU, self.OnSelectDown, id=wxID_EDITSELECTDOWN)
# Key bindings
accLst = []
for name, wId in (('Delete', wxID_EDITDELETE),
('Inspector', wxID_SHOWINSP),
('Editor', wxID_SHOWEDTR),
('ContextHelp', wxID_CTRLHELP),
('Escape', wxID_CTRLPARENT),
('Copy', wxID_EDITCOPY),
('Paste', wxID_EDITPASTE),
('MoveLeft', wxID_EDITMOVELEFT),
('MoveRight', wxID_EDITMOVERIGHT),
('MoveUp', wxID_EDITMOVEUP),
('MoveDown', wxID_EDITMOVEDOWN),
('WidthInc', wxID_EDITWIDTHINC),
('WidthDec', wxID_EDITWIDTHDEC),
('HeightInc', wxID_EDITHEIGHTINC),
('HeightDec', wxID_EDITHEIGHTDEC),
('SelectLeft', wxID_EDITSELECTLEFT),
('SelectRight', wxID_EDITSELECTRIGHT),
('SelectUp', wxID_EDITSELECTUP),
('SelectDown', wxID_EDITSELECTDOWN),
('HelpFind', wxID_FINDININDEX),
):
tpe, key, code = Preferences.keyDefs[name]
accLst.append((tpe, key, wId))
self.SetAcceleratorTable(wx.AcceleratorTable(accLst))
def generateMenu(self):
return Utils.duplicateMenu(self.menu)
def saveCtrls(self, definedCtrls, module=None):
""" Generate source code for Designer """
if not module:
module = self.model.getModule()
# Remove all collection methods
for oc in self.model.identifyCollectionMethods():
if len(oc) > len('_init_coll_') and oc[:11] == '_init_coll_':
## module = self.model.getModule()
module.removeMethod(self.model.main, oc)
# Update all size and pos parameters possibly updated externally
for compn, ctrl, prnt in self.objects.values():
compn.updatePosAndSize()
if self.sizersView and self.sizersView.objects:
collDeps = ['%sself.%s()'%(sourceconst.bodyIndent,
sourceconst.init_sizers)]
else:
collDeps = None
# Generate code
InspectableObjectView.saveCtrls(self, definedCtrls, module, collDeps)
# Regenerate window ids
companions = [i[0] for i in self.objects.values()]
self.model.writeWindowIds(self.collectionMethod, companions)
def renameCtrlAndParentRefs(self, oldName, newName, children=()):
# rename other ctrl references like parent
for ctrl in self.objectOrder:
# Notify
self.objects[ctrl][0].renameCtrlRefs(oldName, newName)
# Rename childrens' parents
if ctrl in children:
self.objects[ctrl][2] = newName
# also do collections
for coll in self.collEditors.values():
coll.companion.renameCtrlRefs(oldName, newName)
def renameCtrl(self, oldName, newName):
""" Rename control, references to control and update parent tree """
prel, pref = self.buildParentRelationship()
# rename other ctrl references like parent
children = pref[oldName].keys()
self.renameCtrlAndParentRefs(oldName, newName, children)
InspectableObjectView.renameCtrl(self, oldName, newName)
if self.sizersView:
self.sizersView.designerRenameNotify(oldName, newName)
selName = self.inspector.containment.selectedName()
if selName == oldName:
selName = newName
self.refreshContainment(selName)
if self.selection.name == oldName:
self.selection.name = newName
def renameFrame(self, oldName, newName):
""" Hook that also updates the Model and window ids of the
Frame when it's name changes """
self.SetName(newName)
# propagate rename to model
self.model.renameMain(oldName, newName)
# update window ids in designer and data
InspectableObjectView.renameFrame(self, oldName, newName)
self.dataView.renameFrame(oldName, newName)
if self.sizersView:
self.sizersView.renameFrame(oldName, newName)
# update window ids in collection items
collEditors = self.collEditors.values() + \
self.dataView.collEditors.values()
if self.sizersView:
collEditors.extend(self.sizersView.collEditors.values())
for collEditor in collEditors:
collEditor.renameFrame(oldName, newName)
# propagate rename to inspector
selName = self.inspector.containment.selectedName()
if selName == oldName: selName = ''
self.refreshContainment(selName)
def refreshCtrl(self):
""" Model View method that is called when the Designer should
create itself from source
"""
if self.destroying or self.opened: return
# Delete previous
comps = {}
# Create selection if none is defined
if not self.selection:
self.selection = \
SelectionTags.SingleSelectionGroup(self, self.inspector, self)
self.model.editor.statusBar.setHint(_('Creating frame'))
try:
objCol = self.model.objectCollections[self.collectionMethod]
objCol.indexOnCtrlName()
self.model.editor.statusBar.progress.SetValue(20)
stepsDone = 20.0
# Initialise the design time controls and
# companion with default values
# initObjectsAndCompanions(creators, props, events)
self.inspector.vetoSelect = True
try:
# init main construtor
self.companion.setConstr(self.model.mainConstr)
ctrlCompn = self.companion
deps = {}
depLnks = {}
self.initObjProps(objCol.propertiesByName, '', objCol.creators[0], deps, depLnks)
self.initObjEvts(objCol.eventsByName, '', objCol.creators[0])
if len(objCol.creators) > 1:
self.initObjectsAndCompanions(objCol.creators[1:], objCol, deps, depLnks)
# Track progress
step = (90 - stepsDone) / len(objCol.creators)
stepsDone = stepsDone + step
self.model.editor.statusBar.progress.SetValue(int(stepsDone))
self.finaliseDepLinks(depLnks)
self.OnRelayoutDesigner(None)
if len(depLnks):
wx.LogWarning(pprint.pformat(depLnks))
wx.LogWarning(_('These links were not resolved (Details...)'))
finally:
self.inspector.vetoSelect = False
self.model.editor.statusBar.progress.SetValue(80)
self.refreshContainment()
self.model.editor.statusBar.progress.SetValue(0)
self.model.editor.statusBar.setHint(_('Designer refreshed'))
self.opened = True
except:
self.model.editor.statusBar.progress.SetValue(0)
#self.model.editor.statusBar.setHint('Error opening the Designer', 'Error')
raise
def refreshModel(self):
""" Update model with streamed out controls """
# Make source r/w
self.model.views['Source'].disableSource(False)
if self.saveOnClose:
oldData = self.model.data
module = self.model.getModule()
# Stream out everything to Module & update model
otherRefs = self.dataView.objectOrder[:]
if self.sizersView:
otherRefs.extend(self.sizersView.objectOrder[:])
self.saveCtrls(otherRefs, module)
self.dataView.saveCtrls([], module)
if self.sizersView:
self.sizersView.saveCtrls([], module)
self.model.refreshFromModule()
# Close data view before updates
self.dataView.deleteFromNotebook('Source', 'Data')
if self.sizersView:
self.sizersView.deleteFromNotebook('Source', 'Sizers')
# Update state (if changed)
newData = self.model.data
self.model.modified = self.model.modified or newData != oldData
self.model.editor.updateModulePage(self.model)
# Update other views
InspectableObjectView.refreshModel(self)
# Put the cursor somewhere (ideally at the first generated event)
module = self.model.getModule()
if module:
self.model.views['Source'].GotoLine(module.classes[\
self.model.main].methods['__init__'].start)
self.model.editor.setStatus(_('Designer session Posted.'))
else:
self.dataView.deleteFromNotebook('Source', 'Data')
if self.sizersView:
self.sizersView.deleteFromNotebook('Source', 'Sizers')
self.model.editor.setStatus(_('Designer session Cancelled.'), 'Warning')
def initSelection(self):
""" Create a selection group """
self.selection = SelectionTags.SingleSelectionGroup(self, self.inspector, self)
def loadControl(self, CtrlClass, CtrlCompanion, ctrlName, params):
""" Create and register given control and companion.
See also: newControl
"""
args = self.setupArgs(ctrlName, params, CtrlCompanion.handledConstrParams,
compClass=CtrlCompanion, evalDct=self.model.specialAttrs)
parent = Utils.ctrlNameFromSrcRef(params[CtrlCompanion.windowParentName])
# Create control and companion
companion = CtrlCompanion(ctrlName, self, None, CtrlClass)
self.addObject(ctrlName, companion,
companion.designTimeControl(None, None, args), parent)
return ctrlName
def newControl(self, parent, CtrlClass, CtrlCompanion, position = None, size = None):
""" At design time, when adding a new ctrl from the palette, create and
register given control and companion.
See also: loadControl
"""
self.checkHost(CtrlCompanion)
ctrlName = self.newObjName(CtrlClass.__name__)
companion = CtrlCompanion(ctrlName, self, parent, CtrlClass)
params = companion.designTimeSource('wx.Point(%d, %d)' % (position.x, position.y))
parentName, params[companion.windowParentName] = self.getParentNames(parent)
self.addObject(ctrlName, companion,
companion.designTimeControl(position, size), parentName)
if not companion.suppressWindowId:
params[companion.windowIdName] = companion.id
companion.persistConstr(Utils.getWxPyNameForClass(CtrlClass), params)
self.refreshContainment()
return ctrlName
def initObjCreator(self, constrPrs):
# decorate class_name if it's a factory constructor
if not constrPrs.class_name and constrPrs.factory:
factoryObj, factoryMeth = constrPrs.factory
if factoryObj in self.dataView.objects:
constrPrs.class_name = self.dataView.objects[factoryObj][0].factory(factoryMeth)
elif factoryObj in self.objects:
constrPrs.class_name = self.objects[factoryObj][0].factory(factoryMeth)
else:
raise Exception, _('%s not found')%factoryObj
InspectableObjectView.initObjCreator(self, constrPrs)
def initSizers(self, sizersView):
self.sizersView = sizersView
self.sizersView.controllerView = self
def getParentNames(self, parent):
if parent.GetName() != self.GetName():
return parent.GetName(), 'self.'+parent.GetName()
else:
return '', 'self'
def removeEvent(self, name):
# XXX Remove event!
self.inspector.eventUpdate(name, True)
def getObjectsOfClass(self, theClass):
""" Overridden to also add objects from the other views """
results = InspectableObjectView.getObjectsOfClass(self, theClass)
otherResults = {}
for objName in self.dataView.objects.keys():
if isinstance(self.dataView.objects[objName][1], theClass):
otherResults['self.'+objName] = self.dataView.objects[objName][1]
if self.sizersView:
for objName in self.sizersView.objects.keys():
if isinstance(self.sizersView.objects[objName][1], theClass):
otherResults['self.'+objName] = self.sizersView.objects[objName][1]
results.update(otherResults)
return results
def getAllObjects(self):
""" Overridden to also add objects from other views """
results = InspectableObjectView.getAllObjects(self)
for objName in self.dataView.objects.keys():
results[Utils.srcRefFromCtrlName(objName)] = \
self.dataView.objects[objName][1]
if self.sizersView:
for objName in self.sizersView.objects.keys():
results[Utils.srcRefFromCtrlName(objName)] = \
self.sizersView.objects[objName][1]
return results
def selectParent(self, ctrl):
""" Change the selection to the parent of the currently selected control. """
if self.selection or self.multiSelection:
if self.multiSelection:
self.clearMultiSelection()
self.assureSingleSelection()
if ctrl and ctrl != self:
parentName, dummy = self.getParentNames(ctrl.GetParent())
self.inspector.containment.selectName(parentName)
def deleteCtrl(self, name, parentRef = None):
""" Delete a control, update selection and parent tree """
ctrlInfo = self.objects[name]
if ctrlInfo[1] == self:
wx.MessageBox(_("Can't delete frame"), style=wx.OK | wx.ICON_ERROR, parent=self)
return
parRel = None
# build relationship, this will only happen for the first call
if not parentRef:
# select parent so long, pretty soon won't be able to ask who
# the parent is
parentName, dummy = self.getParentNames(ctrlInfo[1].GetParent())
self.selectParent(ctrlInfo[1])
parRel, parRef = self.buildParentRelationship()
else:
parRef = parentRef
# notify other components of deletion
self.notifyAction(ctrlInfo[0], 'delete')
# delete all children
children = parRef[name]
for child in children.keys():
self.deleteCtrl(child, parRef)
InspectableObjectView.deleteCtrl(self, name)
ctrlInfo[1].Destroy()
if parRel is not None:
self.refreshContainment(parentName)
def selectNone(self):
if self.selection:
self.selection.selectNone()
elif self.multiSelection:
for sel in self.multiSelection:
sel.selectNone()
sel.destroy()
self.multiSelection = []
self.assureSingleSelection()
def notifyAction(self, compn, action):
InspectableObjectView.notifyAction(self, compn, action)
self.dataView.notifyAction(compn, action)
if self.sizersView:
self.sizersView.notifyAction(compn, action)
def close(self):
self.Close()
def focus(self):
self.restore()
def getSizerConnectList(self):
if self.sizersView:
return self.sizersView.sizerConnectList
else:
return None
ignoreWindows = [wx.ToolBar, wx.StatusBar]
def connectToolBar(self, toolBar):
parRel, parRef = self.buildParentRelationship()
children = parRef['']
for childName in children.keys():
childCompn, childCtrl = self.objects[childName][:2]
if not childCtrl.__class__ in self.ignoreWindows:
pos = childCtrl.GetPosition()
childCtrl.SetPosition( (pos.x, pos.y + toolBar.GetSize().y) )
def disconnectToolBar(self, toolBar):
parRel, parRef = self.buildParentRelationship()
children = parRef['']
for childName in children.keys():
childCompn, childCtrl = self.objects[childName][:2]
if not childCtrl.__class__ in self.ignoreWindows:
pos = childCtrl.GetPosition()
childCtrl.SetPosition( (pos.x, pos.y - toolBar.GetSize().y) )
def checkChildCtrlClick(self, ctrlName, ctrl, companion, clickPos):
""" Check whether the click on the control actually falls
within a region occupied by one of it's children.
The click is then transfered to the child. """
selCtrl, selCompn, selPos = ctrl, companion, clickPos
if companion.container:
parent = ctrl
else:
parent = ctrl.GetParent()
# Hack: Shortcut intersection tests if click was directly in a proxy
# container
if wx.Platform == '__WXGTK__' and hasattr(ctrl, 'proxyContainer'):
return selCtrl, selCompn, selPos
# Workaround toolbar offset bug
offset = [0, 0]
if parent == self:
tb = self.GetToolBar()
if tb:
offset[1] = tb.GetSize().y #* -1
# XXX Is this going to become to slow for frames with many ctrls?
parRel, parRef = self.buildParentRelationship()
if ctrl == self:
officialParent = ''
children = parRef['']
else:
officialParent = ctrlName
children = parRef[ctrlName]
for childName in children.keys():
childCompn, childCtrl = self.objects[childName][:2]
pos = childCtrl.GetPosition()
sze = childCtrl.GetSize()
realParent = childCtrl.GetParent()
# Compensate for BlankWindowPages's offset
if realParent != self.objects[officialParent][1]:
offset[0] += realParent.GetPosition().x
offset[1] += realParent.GetPosition().y
# Check for intersection
if childCtrl.IsShown() and realParent.IsShown() and \
wx.IntersectRect(wx.Rect(clickPos.x - offset[0],
clickPos.y - offset[1], 1, 1),
wx.Rect(pos.x, pos.y, max(sze.x, 1),
max(sze.y, 1))) is not None:
#print clickPos, offset, pos, sze
selCtrl = childCtrl
selCompn = childCompn
selPos = wx.Point(clickPos.x - offset[0] - pos.x,
clickPos.y - offset[1] - pos.y)
break
return selCtrl, selCompn, selPos
def clearMultiSelection(self):
""" Destroys multi selection groups """
for sel in self.multiSelection:
sel.destroy()
self.multiSelection = []
def assureSingleSelection(self):
""" Assure that a valid single selection exists """
if not self.selection:
self.selection = SelectionTags.SingleSelectionGroup(self, self.inspector, self)
def flattenParentRelationship(self, rel, lst):
""" Add all items in a nested dictionary into a single list """
for itm in rel.keys():
lst.append(itm)
self.flattenParentRelationship(rel[itm], lst)
def expandNamesToContainers(self, ctrlNames):
""" Expand set of names to include the names of all their children """
exp = ctrlNames[:]
rel, ref = self.buildParentRelationship()
for ctrl in ctrlNames:
children = []
self.flattenParentRelationship(ref[ctrl], children)
exp.extend(children)
return exp
def collapseNamesToContainers(self, ctrlNames):
""" Collapse set of names to exclude the names of all their children """
def hasParentInList(item, list):
return intem in list
exp = ctrlNames[:]
colLst = [name for name in ctrlNames
if self.objects[name][2] not in ctrlNames]
return colLst
def buildSizerInfo(self, sizer, res):
sp = sizer.GetPosition()
ss = sizer.GetSize()
res.append( (wx.Rect(sp.x, sp.y, ss.width, ss.height), sizer) )
if sizer.__class__.__name__ == 'BlankSizer':
return
c = sizer.GetChildren()
for sc in c:
if sc.IsSizer():
self.buildSizerInfo(sc.GetSizer(), res)
else:
sp = sc.GetPosition()
ss = sc.GetSize()
res.append( (wx.Rect(sp.x, sp.y, ss.width, ss.height), sc) )
def selectControlByPos(self, ctrl, pos, multiSelect):
""" Handle selection of a control from a users click of creation
of a new one if a component was selected on the palette.
Some ctrls do not register clicks, the click is then
picked up from the parent which checks if a click
intersects any child regions. For efficiency this
is only applied for 2 levels.
Also handles single and multiple selection logic.
"""
# Patch to workaround SizerItem identity problem
def _contains(d, k):
for key in d:
if str(k) == str(key):
return True
return False
def _get(d, k):
for key in d:
if str(k) == str(key):
return d[key]
raise KeyError, k
self.vetoResize = True
try:
if ctrl == self:
companion = self.companion
else:
companion = self.objects[ctrl.GetName()][0]
ctrlName = companion.name
selCtrl, selCompn, selPos = \
self.checkChildCtrlClick(ctrlName, ctrl, companion, pos)
# Component on palette selected, create it
if self.compPal.selection:
if selCompn.container:
parent = selCtrl
pos = selPos
else:
parent = selCtrl.GetParent()
screenPos = selCtrl.ClientToScreen(selPos)
pos = parent.ScreenToClient(screenPos)
# Workaround toolbar offset bug
if parent == self:
tb = self.GetToolBar()
if tb:
pos.y = pos.y - tb.GetSize().y
# Granularise position
pos = wx.Point(SelectionTags.granularise(pos.x),
SelectionTags.granularise(pos.y))
CtrlClass, CtrlCompanion = self.compPal.selection[1:3]
destSizer, destSizerCmpn = None, None
parentSzr = parent.GetSizer()
if parentSzr:
# build a mapping from sizers to companions
sizerCompns = {}
view = self.model.views['Sizers']#CtrlCompanion.host]
for name, vals in view.objects.items():
compn = vals[0]
sizerCompns[compn.control] = compn
items = compn.control.GetChildren()
for idx in range(len(items)):
si = items[idx]
if si.IsSizer() and si.GetSizer().__class__.__name__=='BlankSizer':
sizerCompns[si.GetSizer()] = (compn.collections['Items'], idx)#compn.collections['Items'].textConstrLst[idx]
else:
sizerCompns[si] = (compn.collections['Items'], idx)
res = []
self.buildSizerInfo(parentSzr, res)
res.reverse() # find deepest regions first
for rect, s in res:
if wx.IntersectRect(rect, wx.Rect(pos.x, pos.y, 1, 1)):
#if s in sizerCompns:
if _contains(sizerCompns, s):
destSizer = s
#destSizerCmpn = sizerCompns[s]
destSizerCmpn = _get(sizerCompns, s)
break
else:
# sizer item
print 'err', s
if CtrlCompanion.host == 'Sizers':
# create sizer
view = self.model.views[CtrlCompanion.host]
ctrlName = view.OnSelectOrAdd()
if ctrlName is not None:
compn, sizer = view.objects[ctrlName][:2]
ctrlSzr = selCompn.GetSizer(None)
if destSizer is not None:
# sizer dropped on sizer item
if type(destSizerCmpn) is type(()):
destSizerCmpn, sizerItemIdx = destSizerCmpn
tcl = destSizerCmpn.textConstrLst[sizerItemIdx]
if tcl.params[0] == 'None':
tcl.method = 'AddSizer'
tcl.params[0] = 'self.%s'%ctrlName
destSizerCmpn.recreateSizers()
collEditView = SelectionTags.openCollEditorForSizerItems(
self.inspector, destSizerCmpn.parentCompanion,
destSizerCmpn.designer, destSizerCmpn.parentCompanion.control)
if collEditView is not None:
collEditView.refreshCtrl()
if collEditView.frame:
collEditView.frame.selectObject(sizerItemIdx)
return
else:
collEditView = SelectionTags.openCollEditorForSizerItems(
self.inspector, destSizerCmpn.parentCompanion,
destSizerCmpn.designer, destSizerCmpn.parentCompanion.control)
if collEditView is not None:
ci = collEditView.companion.appendItem(
method='AddSizer',
srcParams={0: 'self.%s'%ctrlName})
collEditView.refreshCtrl()
collEditView.selectObject(
collEditView.frame.itemList.GetItemCount() -1)
return
# sizer dropped on sizer
else:
collEditView = SelectionTags.openCollEditorForSizerItems(
self.inspector, destSizerCmpn,
destSizerCmpn.designer, destSizer)
if collEditView is not None:
ci = collEditView.companion.appendItem(
method='AddSizer',
srcParams={0: 'self.%s'%ctrlName})
collEditView.refreshCtrl()
collEditView.selectObject(
collEditView.frame.itemList.GetItemCount() -1)
return
# no sizer on the parent ctrl, link this new sizer to it
if ctrlSzr is None:
selCompn.SetSizer(sizer)
selCompn.persistProp('Sizer', 'SetSizer', 'self.%s'%compn.name)
return
# parent control already has a sizer, add this sizer as a sizer item
else:
collEditView = SelectionTags.openCollEditorForSizerItems(
self.inspector, selCompn)
if collEditView is not None:
ci = collEditView.companion.appendItem(
method='AddSizer',
srcParams={0: 'self.%s'%ctrlName})
collEditView.refreshCtrl()
collEditView.selectObject(
collEditView.frame.itemList.GetItemCount() -1)
return
if CtrlCompanion.host in ('Data', 'Sizers'):
view = self.model.views[CtrlCompanion.host]
view.focus()
view.OnSelectOrAdd()
return
# create ctrl
ctrlName = self.newControl(parent, CtrlClass, CtrlCompanion, pos)
self.compPal.selectNone()
view = self.model.views[CtrlCompanion.host]
compn, sizer = view.objects[ctrlName][:2]
ctrlSzr = selCompn.GetSizer(None)
if ctrlSzr is not None:
if destSizer is not None:
# ctrl dropped on sizer item
if type(destSizerCmpn) is type(()):
destSizerCmpn, sizerItemIdx = destSizerCmpn
tcl = destSizerCmpn.textConstrLst[sizerItemIdx]
tcl.method = 'AddWindow'
tcl.params[0] = 'self.%s'%ctrlName
if tcl.params[1] and tcl.params[1][0] != '(' and tcl.params[1][-1] != ')':
tcl.params[1] = '0'
destSizerCmpn.recreateSizers()
collEditView = SelectionTags.openCollEditorForSizerItems(
self.inspector, destSizerCmpn.parentCompanion,
destSizerCmpn.designer, destSizerCmpn.parentCompanion.control)
if collEditView is not None:
collEditView.refreshCtrl()
collEditView.selectObject(sizerItemIdx)
return
# ctrl dropped on sizer
collEditView = SelectionTags.openCollEditorForSizerItems(
self.inspector, destSizerCmpn,
destSizerCmpn.designer, destSizer)
if collEditView is not None:
ci = collEditView.companion.appendItem(
srcParams={0: 'self.%s'%ctrlName})
collEditView.refreshCtrl()
collEditView.selectObject(
collEditView.frame.itemList.GetItemCount() -1)
return
collEditView = SelectionTags.openCollEditorForSizerItems(
self.inspector, selCompn)
if collEditView is not None:
ci = collEditView.companion.appendItem(srcParams={0: 'self.%s'%ctrlName})
collEditView.refreshCtrl()
collEditView.selectObject(collEditView.frame.itemList.GetItemCount() -1)
else:
prntCtrlSzr = parent.GetSizer()
if prntCtrlSzr is not None:
if destSizer is not None:
# ctrl dropped on sizer item with ctrl, append to items
if type(destSizerCmpn) is type(()):
destSizerCmpn, sizerItemIdx = destSizerCmpn
collEditView = SelectionTags.openCollEditorForSizerItems(
self.inspector, destSizerCmpn.parentCompanion,
destSizerCmpn.designer, prntCtrlSzr)#destSizer)
if collEditView is not None:
ci = collEditView.companion.appendItem(
srcParams={0: 'self.%s'%ctrlName})
collEditView.refreshCtrl()
collEditView.selectObject(
collEditView.frame.itemList.GetItemCount() -1)
return
if self.selection:
ctrl = self.objects[ctrlName][1]
self.selection.selectCtrl(ctrl, self.objects[ctrlName][0])
# Select ctrl
else:
if self.selection or self.multiSelection:
# Multi selection
if multiSelect:
# Verify that it's a legal multi selection
# They must have the same parent
if self.selection:
if selCtrl.GetParent() != self.selection.selection.GetParent():
return
elif self.multiSelection:
if selCtrl.GetParent() != self.multiSelection[0].selection.GetParent():
return
if not self.multiSelection:
# don't select if multiselecting single selection
if selCtrl == self.selection.selection:
return
newSelection = SelectionTags.MultiSelectionGroup(self,
self.inspector, self)
newSelection.assign(self.selection)
self.selection.destroy()
self.selection = None
self.multiSelection = [newSelection]
# Check that this is not a de-selection
# don't deselect if there's only one
if len(self.multiSelection) > 1:
for selIdx in range(len(self.multiSelection)):
if self.multiSelection[selIdx].selection == ctrl:
self.multiSelection[selIdx].destroy()
del self.multiSelection[selIdx]
# Change to single selection if 2nd last one
# deselected
if len(self.multiSelection) == 1:
self.selection = SelectionTags.SingleSelectionGroup(self,
self.inspector, self)
self.selection.assign(self.multiSelection[0])
self.selection.selectCtrl(self.multiSelection[0].selection,
self.multiSelection[0].selCompn)
self.clearMultiSelection()
return
newSelection = SelectionTags.MultiSelectionGroup(self,
self.inspector, self)
newSelection.selectCtrl(selCtrl, selCompn)
self.multiSelection.append(newSelection)
# Single selection
else:
# Deselect multiple selection or start multiple drag
if self.multiSelection:
for sel in self.multiSelection:
if selCtrl == sel.selection:
sel.moveCapture(selCtrl, selCompn, selPos)
self.mainMultiDrag = selCtrl
others = self.multiSelection[:]
others.remove(sel)
for capSel in others:
capSel.moveCapture(capSel.selection, capSel.selCompn, selPos)
return
self.clearMultiSelection()
self.assureSingleSelection()
self.selection.selectCtrl(selCtrl, selCompn)
self.selection.moveCapture(selCtrl, selCompn, selPos)
return
finally:
self.vetoResize = False
def OnFramePos(self, event):
""" Called when frame is repositioned """
# self.assureSingleSelection()
# self.selection.selectCtrl(self, self.companion)
if self.selection and self.selection.selection == self:
self.inspector.constructorUpdate('Position')
self.inspector.propertyUpdate('Position')
event.Skip()
def OnCloseWindow(self, event):
""" When the Designer closes, the code generation process is started.
General Inspector and Designer clean-up """
if not self.saveOnClose and self.confirmCancel and wx.MessageBox(
_('Cancel Designer session?'), _('Cancel'),
wx.YES_NO | wx.ICON_WARNING, parent=None) == wx.NO:
self.saveOnClose = True
self.confirmCancel = False
return
if self.IsIconized():
self.Iconize(False)
# XXX Should handle errors more gracefully here
self.destroying = True
self.vetoResize = True
try:
if self.selection:
self.selection.destroy()
self.selection = None
if self.multiSelection:
for sel in self.multiSelection:
sel.destroy()
self.multiSelection = None
self.inspector.cleanup()
self.inspector.containment.cleanup()
# generate source
self.refreshModel()
except:
self.destroying = False
self.vetoResize = False
raise
self.menu.Destroy()
self.cleanup()
self.Show(False)
self.Destroy()
del self.model.views['Designer']
del self.companion
self.destroy()
event.Skip()
def OnRightDown(self, event):
""" Store popup position of the menu relative to the control that
triggered the event """
ctrl = event.GetEventObject()
screenPos = ctrl.ClientToScreen(wx.Point(event.GetX(), event.GetY()))
parentPos = self.ScreenToClient(screenPos)
self.popx = parentPos.x
self.popy = parentPos.y
def OnEditor(self, event):
""" Bring Editor to the front """
self.model.editor.restore()
self.model.editor.modules[self.model.filename].focus()
def OnInspector(self, event):
""" Bring Inspector to the front """
self.inspector.restore()
if self.inspector.pages.GetSelection() > 3:
self.inspector.pages.SetSelection(0)
def OnControlDelete(self, event):
""" Delete the currently selected controls """
if self.deletingCtrl: return
self.deletingCtrl = True
try:
ctrls = []
if self.selection:
if self.selection.isProxySelection():
wx.LogError(_('Nothing to delete'))
return
ctrls = [self.selection.name]
elif self.multiSelection:
ctrls = [sel.name for sel in self.multiSelection]
#map(self.deleteCtrl, ctrls)
for ctrlName in ctrls:
self.deleteCtrl(ctrlName)
finally:
self.deletingCtrl = False
def OnCtrlHelp(self, event):
""" Show help for the selected control """
if self.inspector.selCmp:
Help.showCtrlHelp(self.inspector.selCmp.GetClass())
def OnAlignSelected(self, event=None):
""" Show alignment dialog for multi selections"""
if self.multiSelection:
dlg = CtrlAlign.ControlAlignmentFrame(self, self.multiSelection)
try: dlg.ShowModal()
finally: dlg.Destroy()
def OnSizeSelected(self, event=None):
""" Show size dialog for multi selections"""
if self.multiSelection:
dlg = CtrlSize.ControlSizeFrame(self, self.multiSelection)
try: dlg.ShowModal()
finally: dlg.Destroy()
def OnSelectParent(self, event=None):
""" Select parent of the selected control """
if self.selection:
self.selectParent(self.selection.selection)
elif self.multiSelection:
self.selectParent(self.multiSelection[0].selection)
#---Clipboard operations--------------------------------------------------------
def OnCutSelected(self, event):
""" Cut current selection to the clipboard """
if self.selection:
if self.selection.isProxySelection():
wx.LogError(_('Nothing to cut'))
return
else:
ctrls = [self.selection.name]
#self.selectParent(self.selection.selection)
elif self.multiSelection:
ctrls = [sel.name for sel in self.multiSelection]
output = []
self.cutCtrls(ctrls, [], output)
Utils.writeTextToClipboard(os.linesep.join(output))
self.refreshContainment()
def OnCopySelected(self, event):
""" Copy current selection to the clipboard """
if self.selection:
if self.selection.isProxySelection():
wx.LogError(_('Nothing to copy'))
return
else:
ctrls = [self.selection.name]
elif self.multiSelection:
ctrls = [sel.name for sel in self.multiSelection]
output = []
self.copyCtrls(ctrls, [], output)
Utils.writeTextToClipboard(os.linesep.join(output))
def OnPasteSelected(self, event):
""" Paste current clipboard contents into the current selection """
if self.selection:
# If the selection is not a container, select it's parent (a container)
if not self.selection.selCompn.container:
self.selectParent(self.selection.selection)
pasted = self.pasteCtrls(self.selection.name,
str(Utils.readTextFromClipboard()).split(os.linesep))
if len(pasted):
self.refreshContainment()
pasted = self.collapseNamesToContainers(pasted)
# Single control pasted, select it
if len(pasted) == 1:
if self.selection.isProxySelection():
self.selection.selection.linkToNewestControl()
self.objects[pasted[0]][1].Reparent(self.selection.selection)
self.selection.selectCtrl(self.objects[pasted[0]][1],
self.objects[pasted[0]][0])
# Multiple controls pasted, select them
else:
if self.selection.isProxySelection():
# Undo the pasting
for ctrlName in pasted:
self.deleteCtrl(ctrlName)
self.selection.selectNone()
self.inspector.cleanup()
wx.LogError(_('Only 1 control can be pasted into this container'))
else:
self.selection.destroy()
self.selection = None
self.multiSelection = []
for ctrlName in pasted:
selCompn, selCtrl, prnt = self.objects[ctrlName]
newSelection = SelectionTags.MultiSelectionGroup(self,
self.inspector, self)
newSelection.selectCtrl(selCtrl, selCompn)
self.multiSelection.append(newSelection)
def OnRecreateSelected(self, event):
""" Recreate the current selection by cutting and pasting it.
The clipboard is not disturbed.
This is useful for applying changes to constructor parameters """
if self.selection and self.selection.selection != self:
output = []
ctrlName = self.selection.name
# XXX Boa should be able to tell me this
parent = self.selection.selection.GetParent()
parentName, dummy = self.getParentNames(parent)
self.cutCtrls([ctrlName], [], output)
self.pasteCtrls(parentName, output)
self.refreshContainment()
self.inspector.containment.selectName(ctrlName)
#---Moving/Sizing selections with the keyboard----------------------------------
def getSelAsList(self):
if self.selection:
return [self.selection]
elif self.multiSelection:
return self.multiSelection
else:
return []
def moveUpdate(self, sel):
sel.setSelection(True)
sel.resizeCtrl()
def OnMoveLeft(self, event):
for sel in self.getSelAsList():
if sel.selection != self:
sel.position.x = sel.position.x - 1
sel.startPos.x = sel.startPos.x - 1
self.moveUpdate(sel)
def OnMoveRight(self, event):
for sel in self.getSelAsList():
if sel.selection != self:
sel.position.x = sel.position.x + 1
sel.startPos.x = sel.startPos.x + 1
self.moveUpdate(sel)
def OnMoveUp(self, event):
for sel in self.getSelAsList():
if sel.selection != self:
sel.position.y = sel.position.y - 1
sel.startPos.y = sel.startPos.y - 1
self.moveUpdate(sel)
def OnMoveDown(self, event):
for sel in self.getSelAsList():
if sel.selection != self:
sel.position.y = sel.position.y + 1
sel.startPos.y = sel.startPos.y + 1
self.moveUpdate(sel)
def sizeUpdate(self, sel):
sel.resizeCtrl()
sel.setSelection(True)
def OnWidthInc(self, event):
sel = self.selection
if sel and sel.selection != self:
sel.size.x = sel.size.x + 1
self.sizeUpdate(sel)
def OnWidthDec(self, event):
sel = self.selection
if sel and sel.selection != self and sel.size.x > 0:
sel.size.x = sel.size.x - 1
self.sizeUpdate(sel)
def OnHeightInc(self, event):
sel = self.selection
if sel and sel.selection != self:
sel.size.y = sel.size.y + 1
self.sizeUpdate(sel)
def OnHeightDec(self, event):
sel = self.selection
if sel and sel.selection != self and sel.size.y > 0:
sel.size.y = sel.size.y - 1
self.sizeUpdate(sel)
#---Cursor selection------------------------------------------------------------
def selectInDimentionDirection(self, selctrl, dim, dir):
def compSides(selctrl, ctrl, dim, dir):
selpos, selsize = selctrl.GetPosition(), selctrl.GetSize()
pos, size = ctrl.GetPosition(), ctrl.GetSize()
selMidPoint = wx.Point(selpos.x + selsize.x/2, selpos.y + selsize.y/2)
ctrlMidPoint = wx.Point(pos.x + size.x/2, pos.y + size.y/2)
if (dim, dir) == ('x', 1):
return (wx.Point(selpos.x + selsize.x, selpos.y), selMidPoint,
wx.Point(selpos.x + selsize.x, selpos.y + selsize.y),
wx.Point(pos.x, pos.y), ctrlMidPoint,
wx.Point(pos.x, pos.y + size.y) )
if (dim, dir) == ('x', -1):
return (wx.Point(selpos.x, selpos.y), selMidPoint,
wx.Point(selpos.x, selpos.y + selsize.y),
wx.Point(pos.x + size.x, pos.y), ctrlMidPoint,
wx.Point(pos.x + size.x, pos.y + size.y) )
if (dim, dir) == ('y', 1):
return (wx.Point(selpos.x, selpos.y + selsize.y), selMidPoint,
wx.Point(selpos.x + selsize.x, selpos.y + selsize.y),
wx.Point(pos.x, pos.y), ctrlMidPoint,
wx.Point(pos.x + size.x, pos.y) )
if (dim, dir) == ('y', -1):
return (wx.Point(selpos.x, selpos.y), selMidPoint,
wx.Point(selpos.x + selsize.x, selpos.y),
wx.Point(pos.x, pos.y + size.y), ctrlMidPoint,
wx.Point(pos.x + size.x, pos.y + size.y) )
dims = ['x', 'y']
otherdim = dims[not dims.index(dim)]
parentName, dummy = self.getParentNames(selctrl.GetParent())
selName = selctrl.GetName()
distLo = -1
nearestCtrl = None
for objName in self.objects.keys():
ctrl, parent = self.objects[objName][1:3]
if parent == parentName and objName != selName:
pos1p, pos0p, pos2p, cpos1p, cpos0p, cpos2p = compSides(selctrl, ctrl, dim, dir)
pos, otherpos1, otherpos2 = getattr(pos1p, dim), \
getattr(pos1p, otherdim), getattr(pos2p, otherdim)
pos0, otherpos0 = getattr(pos0p, dim), getattr(pos0p, otherdim)
cpos, cotherpos1, cotherpos2 = getattr(cpos1p, dim), \
getattr(cpos1p, otherdim), getattr(cpos2p, otherdim)
cpos0, cotherpos0 = getattr(cpos0p, dim), getattr(cpos0p, otherdim)
dpos, dotherpos1, dotherpos2 = cpos - pos, \
cotherpos1 - otherpos1, cotherpos2 - otherpos2
dpos0, dotherpos0 = cpos0 - pos0, cotherpos0 - otherpos0
if (abs(dpos) >= min(abs(dotherpos1), abs(dotherpos2)) and \
(not dpos or dpos/abs(dpos) == dir)) or \
(abs(dpos0) >= abs(dotherpos0) and \
(not dpos0 or dpos0/abs(dpos0) == dir)):
dist = min(math.sqrt(dpos*dpos+dotherpos1*dotherpos1),
math.sqrt(dpos0*dpos0+dotherpos0*dotherpos0),
math.sqrt(dpos*dpos+dotherpos2*dotherpos2))
if distLo == -1 or dist < distLo:
distLo = dist
nearestCtrl = ctrl
if nearestCtrl:
self.inspector.containment.selectName(nearestCtrl.GetName())
def OnSelectLeft(self, event):
sel = self.selection
if sel and sel.selection != self:
self.selectInDimentionDirection(sel.selection, 'x', -1)
def OnSelectRight(self, event):
sel = self.selection
if sel and sel.selection != self:
self.selectInDimentionDirection(sel.selection, 'x', 1)
def OnSelectUp(self, event):
sel = self.selection
if sel and sel.selection != self:
self.selectInDimentionDirection(sel.selection, 'y', -1)
def OnSelectDown(self, event):
sel = self.selection
if sel and sel.selection != self:
self.selectInDimentionDirection(sel.selection, 'y', 1)
#-------------------------------------------------------------------------------
def OnSnapToGrid(self, event):
for sel in self.getSelAsList():
if sel.selection != self:
sel.position.x = SelectionTags.granularise(sel.position.x)
sel.position.y = SelectionTags.granularise(sel.position.y)
sel.startPos.x = sel.position.x
sel.startPos.y = sel.position.y
self.moveUpdate(sel)
def relayoutCtrl(self, ctrl):
self.forceResize = True # cleared by the event
sizer = ctrl.GetSizer()
if sizer:
sizer.Layout()
wx.PostEvent(ctrl, wx.SizeEvent(ctrl.GetSize(), ctrl.GetId()))
wx.CallAfter(ctrl.Refresh)
def OnRelayoutSelection(self, event):
# for ctrl in [sel.selection for sel in self.getSelAsList()]:
for sel in self.getSelAsList():
self.relayoutCtrl(sel.selection)
def OnRelayoutDesigner(self, event):
self.relayoutCtrl(self)
def OnFitSizer(self, event):
for sel in self.getSelAsList():
sizer = sel.selection.GetSizer()
if sizer:
sizer.Fit(sel.selection)
def OnCreationOrder(self, event):
sel = self.selection
if sel:
selName = sel.selection.GetName()
if selName == self.GetName():
selName = ''
self.showCreationOrderDlg(selName)
def OnFindInIndex(self, event):
self.model.editor.OnHelpFindIndex(event)
#---Inspector session-----------------------------------------------------------
def doPost(self, inspector):
self.saveOnClose = True
self.Close()
def doCancel(self, inspector):
self.saveOnClose = False
self.confirmCancel = True
self.Close()
class DesignerNamespace:
def __init__(self, designer):
self._designer = designer
def __getattr__(self, name):
designer = self.__dict__['_designer']
if designer.objects.has_key(name):
#return designer.objects[name][1]
obj = designer.objects[name]
if isinstance(obj[1], wx._core._wxPyDeadObject):
obj[0].parent = designer.objects[obj[2]][1]
obj[1] = obj[0].designTimeControl(wx.DefaultPosition, wx.DefaultSize)
obj[0].control = obj[1]
return obj[1]
elif designer.dataView.objects.has_key(name):
return designer.dataView.objects[name][1]
elif designer.sizersView and \
designer.sizersView.objects.has_key(name):
return designer.sizerView.objects[name][1]
else:
raise AttributeError, name
class DesignerControlsEvtHandler(wx.EvtHandler):
def __init__(self, designer):
wx.EvtHandler.__init__(self)
self.designer = designer
self.drawGridMethods = {'lines' : self.drawGrid_intersectingLines,
'dots' : self.drawGrid_dots,
'bitmap': self.drawGrid_bitmap,
'grid' : self.drawGrid_grid}
self._points = (0, 0), []
def connectEvts(self, ctrl, connectChildren=False):
ctrls = [ctrl]
if connectChildren:
ctrls.extend(ctrl.GetChildren())
for ctrl in ctrls:
ctrl.Bind(wx.EVT_MOTION, self.OnMouseOver)
ctrl.Bind(wx.EVT_LEFT_DOWN, self.OnControlSelect)
ctrl.Bind(wx.EVT_LEFT_UP, self.OnControlRelease)
ctrl.Bind(wx.EVT_LEFT_DCLICK, self.OnControlDClick)
ctrl.Bind(wx.EVT_SIZE, self.OnControlResize)
ctrl.Bind(wx.EVT_MOVE, self.OnControlMove)
if isinstance(ctrl, (wx.Panel, wx.ScrolledWindow)) or \
ctrl.__class__ == DesignerView:
ctrl.Bind(wx.EVT_PAINT, self.OnPaint)
def OnMouseOver(self, event):
if event.Dragging():
dsgn = self.designer
pos = event.GetPosition()
ctrl = event.GetEventObject()
if dsgn.selection:
dsgn.selection.moving(ctrl, pos)
elif dsgn.multiSelection:
for sel in dsgn.multiSelection:
sel.moving(ctrl, pos, dsgn.mainMultiDrag)
event.Skip()
def getCtrlAndPosFromEvt(self, event):
pos = event.GetPosition()
ctrl = event.GetEventObject()
# XXX only here for when testing
if not ctrl:
ctrl = self.designer
else:
if hasattr(ctrl, '_composite_child'):
pos = ctrl.ClientToScreen(pos)
ctrl = ctrl.GetParent()
pos = ctrl.ScreenToClient(pos)
return ctrl, pos
def OnControlSelect(self, event):
""" Control is clicked. Either select it or add control from palette """
dsgn = self.designer
ctrl, pos = self.getCtrlAndPosFromEvt(event)
dsgn.selectControlByPos(ctrl, pos, event.ShiftDown())
event.Skip()
def OnControlRelease(self, event):
""" A select or drag operation is ended """
dsgn = self.designer
if dsgn.selection:
dsgn.selection.moveRelease()
elif dsgn.multiSelection:
for sel in dsgn.multiSelection:
sel.moveRelease()
dsgn.mainMultiDrag = None
event.Skip()
def OnControlResize(self, event):
""" Control is resized, emulate native wxWidgets layout behaviour """
dsgn = self.designer
try:
if dsgn.vetoResize:
return
if event.GetId() == dsgn.GetId():
if event.GetSize().Get() == dsgn.lastSize and not dsgn.forceResize:
return
dsgn.lastSize = event.GetSize().Get()
if dsgn.selection:
dsgn.selection.selectCtrl(dsgn, dsgn.companion)
elif dsgn.multiSelection:
dsgn.clearMultiSelection()
dsgn.assureSingleSelection()
dsgn.selection.selectCtrl(dsgn, dsgn.companion)
return
# Compensate for autolayout=False and 1 ctrl on frame behaviour
# Needed because incl selection tags there are actually 5 ctrls
if not dsgn.GetAutoLayout() and not dsgn.companion.dialogLayout:
# Count children
c = 0
ctrl = None
for ctrlLst in dsgn.objects.values():
if len(ctrlLst) > 2 and ctrlLst[2] == '' and \
(ctrlLst[1].__class__ not in dsgn.ignoreWindows):
c = c + 1
ctrl = ctrlLst[1]
if c == 1:
s = dsgn.GetClientSize()
ctrl.SetDimensions(0, 0, s.x, s.y)
if dsgn.selection:
s, p = dsgn.selection.size, dsgn.selection.position
dsgn.selection.sizeFromCtrl()
dsgn.selection.setSelection()
if (s, p) != (dsgn.selection.size, dsgn.selection.position):
dsgn.selection.sizeUpdate()
dsgn.selection.positionUpdate()
finally:
dsgn.forceResize = False
dsgn.Refresh()
event.Skip()
def OnControlDClick(self, event):
dsgn = self.designer
if dsgn.selection:
#ctrl = event.GetEventObject()
ctrl, pos = self.getCtrlAndPosFromEvt(event)
dsgn.selectControlByPos(ctrl, pos, event.ShiftDown())
if ctrl == dsgn:
companion = dsgn.companion
ctrlName = ''
else:
ctrlName = ctrl.GetName()
companion = dsgn.objects[ctrlName][0]
selCtrl, selCompn, selPos = \
dsgn.checkChildCtrlClick(ctrlName, ctrl, companion,
event.GetPosition())
selCompn.defaultAction()
dsgn.selection.moveRelease()
def OnControlMove(self, event):
ctrl = event.GetEventObject()
# Prevent infinite event loop by not sending siz events to statusbar
# Only applies to sizered statusbars
if ctrl and not isinstance(ctrl, wx.StatusBar):
parent = ctrl.GetParent()
if parent:
wx.PostEvent(parent, wx.SizeEvent( parent.GetSize() ))
event.Skip()
#---Grid drawing----------------------------------------------------------------
def _drawLines(self, dc, col, loglFunc, sze, sg):
""" Draw horizontal and vertical lines
"""
pen1 = wx.Pen(col)
dc.SetPen(pen1)
dc.SetLogicalFunction(loglFunc)
lines = []
for y in range(sze.y / sg + 1):
lines.append( (0, y * sg, sze.x, y * sg) )
for x in range(sze.x / sg + 1):
lines.append( (x * sg, 0, x * sg, sze.y) )
dc.DrawLineList(lines)
def drawGrid_intersectingLines(self, dc, sze, sg):
""" Cute hack to draw dots by intersecting lines
"""
bgCol = dc.GetBackground().GetColour()
xorBgCol = wx.Colour(255^bgCol.Red(), 255^bgCol.Green(), 255^bgCol.Blue())
self._drawLines(dc, xorBgCol, wx.COPY, sze, sg)
self._drawLines(dc, wx.WHITE, wx.XOR, sze, sg)
darken = 15
def drawGrid_grid(self, dc, sze, sg):
""" The default method, drawing horizontal and vertical grid lines.
"""
bgCol = dc.GetBackground().GetColour()
darkerBgCol = wx.Colour(max(bgCol.Red() -self.darken, 0),
max(bgCol.Green() -self.darken, 0),
max(bgCol.Blue() -self.darken, 0))
self._drawLines(dc, darkerBgCol, wx.COPY, sze, sg)
def drawGrid_dots(self, dc, sze, sg):
""" The slowest method, drawing each dot of the grid individually
"""
pen1 = wx.Pen(wx.BLACK)
dc.SetPen(pen1)
(szex, szey), points = self._points
if (szex, szey) != (sze.x, sze.y):
points = []
for y in range(sze.y / sg + 1):
for x in range(sze.x / sg + 1):
points.append( (x * sg, y * sg) )
self._points = (szex, szey), points
dc.DrawPointList(points)
def drawGrid_bitmap(self, dc, sze, sg):
""" This should be the most efficient method, when the granularity is
changed, a new (possibly +-32x32) bitmap should be created with
transparent background and black grid points. This can then be
blitted over background
"""
pass
def updateDCProps(self, dc, sizer, validCol):
if sizer.__class__.__name__ == 'BlankSizer':
pen = wx.Pen(wx.RED)
brush = wx.Brush(wx.RED, wx.FDIAGONAL_HATCH)
else:
pen = wx.Pen(validCol, 3, wx.SOLID)
brush = wx.TRANSPARENT_BRUSH
dc.SetPen(pen)
dc.SetBrush(brush)
def drawSizerInfo(self, dc, sizer, yoffset=0):
self.updateDCProps(dc, sizer, Preferences.dsHasSizerCol)
sp = sizer.GetPosition()
ss = sizer.GetSize()
dc.DrawRectangle(sp.x, sp.y+yoffset, ss.width, ss.height)
c = sizer.GetChildren()
for sc in c:
if sc.IsSizer():
self.drawSizerInfo(dc, sc.GetSizer())
else:
self.updateDCProps(dc, sizer, Preferences.dsInSizerCol)
sp = sc.GetPosition()
ss = sc.GetSize()
dc.DrawRectangle(sp.x, sp.y+yoffset, ss.width, ss.height)
def OnPaint(self, event):
# XXX Paint event fired after destruction, should remove EVT ?
ctrl = event.GetEventObject()
if ctrl:
dc = wx.PaintDC(ctrl)
# sze = ctrl.GetClientSize()
sze = ctrl.GetSize()
sg = Preferences.dsGridSize
# Workaround toolbar offset bug
yoffset = 0
if ctrl == self.designer:
tb = self.designer.GetToolBar()
if tb:
yoffset = tb.GetSize().y
drawGrid = self.drawGridMethods[Preferences.drawGridMethod]
dc.BeginDrawing()
try:
if Preferences.drawDesignerGrid:
drawGrid(dc, sze, sg)
sizer = ctrl.GetSizer()
if sizer:
self.drawSizerInfo(dc, sizer, yoffset)
finally:
dc.EndDrawing()
event.Skip()
|