| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423 |
- """Undocumented Module"""
- __all__ = ['findDialog', 'cleanupDialog', 'DirectDialog', 'OkDialog', 'OkCancelDialog', 'YesNoDialog', 'YesNoCancelDialog', 'RetryCancelDialog']
- from panda3d.core import *
- import DirectGuiGlobals as DGG
- from DirectFrame import *
- from DirectButton import *
- import types
- def findDialog(uniqueName):
- """findPanel(string uniqueName)
- Returns the panel whose uniqueName is given. This is mainly
- useful for debugging, to get a pointer to the current onscreen
- panel of a particular type.
- """
- if uniqueName in DirectDialog.AllDialogs:
- return DirectDialog.AllDialogs[uniqueName]
- return None
- def cleanupDialog(uniqueName):
- """cleanupPanel(string uniqueName)
- Cleans up (removes) the panel with the given uniqueName. This
- may be useful when some panels know about each other and know
- that opening panel A should automatically close panel B, for
- instance.
- """
- if uniqueName in DirectDialog.AllDialogs:
- # calling cleanup() will remove it out of the AllDialogs dict
- # This way it will get removed from the dict even it we did
- # not clean it up using this interface (ie somebody called
- # self.cleanup() directly
- DirectDialog.AllDialogs[uniqueName].cleanup()
- class DirectDialog(DirectFrame):
- AllDialogs = {}
- PanelIndex = 0
- def __init__(self, parent = None, **kw):
- """
- DirectDialog(kw)
- Creates a popup dialog to alert and/or interact with user.
- Some of the main keywords that can be used to customize the dialog:
- Keyword Definition
- ------- ----------
- text Text message/query displayed to user
- geom Geometry to be displayed in dialog
- buttonTextList List of text to show on each button
- buttonGeomList List of geometry to show on each button
- buttonImageList List of images to show on each button
- buttonValueList List of values sent to dialog command for
- each button. If value is [] then the
- ordinal rank of the button is used as
- its value
- buttonHotKeyList List of hotkeys to bind to each button.
- Typing hotkey is equivalent to pressing
- the corresponding button.
- suppressKeys Set to true if you wish to suppress keys
- (i.e. Dialog eats key event), false if
- you wish Dialog to pass along key event
- buttonSize 4-tuple used to specify custom size for
- each button (to make bigger then geom/text
- for example)
- pad Space between border and interior graphics
- topPad Extra space added above text/geom/image
- midPad Extra space added between text/buttons
- sidePad Extra space added to either side of
- text/buttons
- buttonPadSF Scale factor used to expand/contract
- button horizontal spacing
- command Callback command used when a button is
- pressed. Value supplied to command
- depends on values in buttonValueList
- Note: Number of buttons on the dialog depends upon the maximum
- length of any button[Text|Geom|Image|Value]List specified.
- Values of None are substituted for lists that are shorter
- than the max length
- """
- # Inherits from DirectFrame
- optiondefs = (
- # Define type of DirectGuiWidget
- ('dialogName', 'DirectDialog_' + repr(DirectDialog.PanelIndex), DGG.INITOPT),
- # Default position is slightly forward in Y, so as not to
- # intersect the near plane, which is incorrectly set to 0
- # in DX for some reason.
- ('pos', (0, 0.1, 0), None),
- ('pad', (0.1, 0.1), None),
- ('text', '', None),
- ('text_align', TextNode.ALeft, None),
- ('text_scale', 0.06, None),
- ('image', None, None),
- ('relief', DGG.RAISED, None),
- ('borderWidth', (0.01, 0.01), None),
- ('buttonTextList', [], DGG.INITOPT),
- ('buttonGeomList', [], DGG.INITOPT),
- ('buttonImageList', [], DGG.INITOPT),
- ('buttonValueList', [], DGG.INITOPT),
- ('buttonHotKeyList', [], DGG.INITOPT),
- ('button_borderWidth', (.01, .01), None),
- ('button_pad', (.01, .01), None),
- ('button_relief', DGG.RAISED, None),
- ('button_text_scale', 0.06, None),
- ('buttonSize', None, DGG.INITOPT),
- ('topPad', 0.06, DGG.INITOPT),
- ('midPad', 0.12, DGG.INITOPT),
- ('sidePad', 0., DGG.INITOPT),
- ('buttonPadSF', 1.1, DGG.INITOPT),
- # Alpha of fade screen behind dialog
- ('fadeScreen', 0, None),
- ('command', None, None),
- ('extraArgs', [], None),
- ('sortOrder', NO_FADE_SORT_INDEX, None),
- )
- # Merge keyword options with default options
- self.defineoptions(kw, optiondefs, dynamicGroups = ("button",))
- # Initialize superclasses
- DirectFrame.__init__(self, parent)
- #if not self['dialogName']:
- # self['dialogName'] = 'DirectDialog_' + repr(DirectDialog.PanelIndex)
- # Clean up any previously existing panel with the same unique
- # name. We don't allow any two panels with the same name to
- # coexist.
- cleanupDialog(self['dialogName'])
- # Store this panel in our map of all open panels.
- DirectDialog.AllDialogs[self['dialogName']] = self
- DirectDialog.PanelIndex += 1
- # Determine number of buttons
- self.numButtons = max(len(self['buttonTextList']),
- len(self['buttonGeomList']),
- len(self['buttonImageList']),
- len(self['buttonValueList']))
- # Create buttons
- self.buttonList = []
- index = 0
- for i in range(self.numButtons):
- name = 'Button' + repr(i)
- try:
- text = self['buttonTextList'][i]
- except IndexError:
- text = None
- try:
- geom = self['buttonGeomList'][i]
- except IndexError:
- geom = None
- try:
- image = self['buttonImageList'][i]
- except IndexError:
- image = None
- try:
- value = self['buttonValueList'][i]
- except IndexError:
- value = i
- self['buttonValueList'].append(i)
- try:
- hotKey = self['buttonHotKeyList'][i]
- except IndexError:
- hotKey = None
- button = self.createcomponent(
- name, (), "button",
- DirectButton, (self,),
- text = text,
- geom = geom,
- image = image,
- suppressKeys = self['suppressKeys'],
- frameSize = self['buttonSize'],
- command = lambda s = self, v = value: s.buttonCommand(v)
- )
- self.buttonList.append(button)
- # Update dialog when everything has been initialised
- self.postInitialiseFuncList.append(self.configureDialog)
- self.initialiseoptions(DirectDialog)
- def configureDialog(self):
- # Set up hot key bindings
- bindList = zip(self.buttonList, self['buttonHotKeyList'],
- self['buttonValueList'])
- for button, hotKey, value in bindList:
- if ((type(hotKey) == types.ListType) or
- (type(hotKey) == types.TupleType)):
- for key in hotKey:
- button.bind('press-' + key + '-', self.buttonCommand,
- extraArgs = [value])
- self.bind('press-' + key + '-', self.buttonCommand,
- extraArgs = [value])
- else:
- button.bind('press-' + hotKey + '-', self.buttonCommand,
- extraArgs = [value])
- self.bind('press-' + hotKey + '-', self.buttonCommand,
- extraArgs = [value])
- # Position buttons and text
- pad = self['pad']
- if self.hascomponent('image0'):
- image = self.component('image0')
- else:
- image = None
- # Get size of text/geom without image (for state 0)
- if image:
- image.reparentTo(hidden)
- bounds = self.stateNodePath[0].getTightBounds()
- if image:
- image.reparentTo(self.stateNodePath[0])
- if bounds is None:
- l = 0
- r = 0
- b = 0
- t = 0
- else:
- l = bounds[0][0]
- r = bounds[1][0]
- b = bounds[0][2]
- t = bounds[1][2]
- # Center text and geom around origin
- # How far is center of text from origin?
- xOffset = -(l+r)*0.5
- zOffset = -(b+t)*0.5
- # Update bounds to reflect text movement
- l += xOffset
- r += xOffset
- b += zOffset
- t += zOffset
- # Offset text and geom to center
- if self['text']:
- self['text_pos'] = (self['text_pos'][0] + xOffset,
- self['text_pos'][1] + zOffset)
- if self['geom']:
- self['geom_pos'] = Point3(self['geom_pos'][0] + xOffset,
- self['geom_pos'][1],
- self['geom_pos'][2] + zOffset)
- if self.numButtons != 0:
- bpad = self['button_pad']
- # Get button size
- if self['buttonSize']:
- # Either use given size
- buttonSize = self['buttonSize']
- bl = buttonSize[0]
- br = buttonSize[1]
- bb = buttonSize[2]
- bt = buttonSize[3]
- else:
- # Or get bounds of union of buttons
- bl = br = bb = bt = 0
- for button in self.buttonList:
- bounds = button.stateNodePath[0].getTightBounds()
- if bounds is None:
- bl = 0
- br = 0
- bb = 0
- bt = 0
- else:
- bl = min(bl, bounds[0][0])
- br = max(br, bounds[1][0])
- bb = min(bb, bounds[0][2])
- bt = max(bt, bounds[1][2])
- bl -= bpad[0]
- br += bpad[0]
- bb -= bpad[1]
- bt += bpad[1]
- # Now resize buttons to match largest
- for button in self.buttonList:
- button['frameSize'] = (bl, br, bb, bt)
- # Must compensate for scale
- scale = self['button_scale']
- # Can either be a Vec3 or a tuple of 3 values
- if (isinstance(scale, Vec3) or
- (type(scale) == types.ListType) or
- (type(scale) == types.TupleType)):
- sx = scale[0]
- sz = scale[2]
- elif ((type(scale) == types.IntType) or
- (type(scale) == types.FloatType)):
- sx = sz = scale
- else:
- sx = sz = 1
- bl *= sx
- br *= sx
- bb *= sz
- bt *= sz
- # Position buttons
- # Calc button width and height
- bHeight = bt - bb
- bWidth = br - bl
- # Add pad between buttons
- bSpacing = self['buttonPadSF'] * bWidth
- bPos = -bSpacing * (self.numButtons - 1)*0.5
- index = 0
- for button in self.buttonList:
- button.setPos(bPos + index * bSpacing, 0,
- b - self['midPad'] - bpad[1] - bt)
- index += 1
- bMax = bPos + bSpacing * (self.numButtons - 1)
- else:
- bpad = 0
- bl = br = bb = bt = 0
- bPos = 0
- bMax = 0
- bpad = (0, 0)
- bHeight = bWidth = 0
- # Resize frame to fit text and buttons
- l = min(bPos + bl, l) - pad[0]
- r = max(bMax + br, r) + pad[0]
- sidePad = self['sidePad']
- l -= sidePad
- r += sidePad
- # reduce bottom by pad, button height and 2*button pad
- b = min(b - self['midPad'] - bpad[1] - bHeight - bpad[1], b) - pad[1]
- t = t + self['topPad'] + pad[1]
- self['frameSize'] = (l, r, b, t)
- self['image_scale'] = (r - l, 1, t - b)
- # Center frame about text and buttons
- self['image_pos'] = ((l+r)*0.5, 0.0, (b+t)*0.5)
- self.resetFrameSize()
- def show(self):
- if self['fadeScreen']:
- base.transitions.fadeScreen(self['fadeScreen'])
- self.setBin('gui-popup', 0)
- NodePath.show(self)
- def hide(self):
- if self['fadeScreen']:
- base.transitions.noTransitions()
- NodePath.hide(self)
- def buttonCommand(self, value, event = None):
- if self['command']:
- self['command'](value, *self['extraArgs'])
- def setMessage(self, message):
- self['text'] = message
- self.configureDialog()
- def cleanup(self):
- # Remove this panel out of the AllDialogs list
- uniqueName = self['dialogName']
- if uniqueName in DirectDialog.AllDialogs:
- del DirectDialog.AllDialogs[uniqueName]
- self.destroy()
- def destroy(self):
- if self['fadeScreen']:
- base.transitions.noTransitions()
- for button in self.buttonList:
- button.destroy()
- DirectFrame.destroy(self)
- class OkDialog(DirectDialog):
- def __init__(self, parent = None, **kw):
- # Inherits from DirectFrame
- optiondefs = (
- # Define type of DirectGuiWidget
- ('buttonTextList', ['OK'], DGG.INITOPT),
- ('buttonValueList', [DGG.DIALOG_OK], DGG.INITOPT),
- )
- # Merge keyword options with default options
- self.defineoptions(kw, optiondefs)
- DirectDialog.__init__(self, parent)
- self.initialiseoptions(OkDialog)
- class OkCancelDialog(DirectDialog):
- def __init__(self, parent = None, **kw):
- # Inherits from DirectFrame
- optiondefs = (
- # Define type of DirectGuiWidget
- ('buttonTextList', ['OK','Cancel'], DGG.INITOPT),
- ('buttonValueList', [DGG.DIALOG_OK, DGG.DIALOG_CANCEL], DGG.INITOPT),
- )
- # Merge keyword options with default options
- self.defineoptions(kw, optiondefs)
- DirectDialog.__init__(self, parent)
- self.initialiseoptions(OkCancelDialog)
- class YesNoDialog(DirectDialog):
- def __init__(self, parent = None, **kw):
- # Inherits from DirectFrame
- optiondefs = (
- # Define type of DirectGuiWidget
- ('buttonTextList', ['Yes', 'No'], DGG.INITOPT),
- ('buttonValueList', [DGG.DIALOG_YES, DGG.DIALOG_NO], DGG.INITOPT),
- )
- # Merge keyword options with default options
- self.defineoptions(kw, optiondefs)
- DirectDialog.__init__(self, parent)
- self.initialiseoptions(YesNoDialog)
- class YesNoCancelDialog(DirectDialog):
- def __init__(self, parent = None, **kw):
- # Inherits from DirectFrame
- optiondefs = (
- # Define type of DirectGuiWidget
- ('buttonTextList', ['Yes', 'No', 'Cancel'], DGG.INITOPT),
- ('buttonValueList', [DGG.DIALOG_YES, DGG.DIALOG_NO, DGG.DIALOG_CANCEL],
- DGG.INITOPT),
- )
- # Merge keyword options with default options
- self.defineoptions(kw, optiondefs)
- DirectDialog.__init__(self, parent)
- self.initialiseoptions(YesNoCancelDialog)
- class RetryCancelDialog(DirectDialog):
- def __init__(self, parent = None, **kw):
- # Inherits from DirectFrame
- optiondefs = (
- # Define type of DirectGuiWidget
- ('buttonTextList', ['Retry','Cancel'], DGG.INITOPT),
- ('buttonValueList', [DGG.DIALOG_RETRY, DGG.DIALOG_CANCEL], DGG.INITOPT),
- )
- # Merge keyword options with default options
- self.defineoptions(kw, optiondefs)
- DirectDialog.__init__(self, parent)
- self.initialiseoptions(RetryCancelDialog)
|