Browse Source

*** empty log message ***

Mark Mine 24 years ago
parent
commit
dba1abc3a4

+ 261 - 55
direct/src/gui/DirectDialog.py

@@ -4,61 +4,152 @@ from DirectButton import *
 
 
 class DirectDialog(DirectFrame):
 class DirectDialog(DirectFrame):
     def __init__(self, parent = guiTop, **kw):
     def __init__(self, parent = guiTop, **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
+            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
+            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
         # Inherits from DirectFrame
         optiondefs = (
         optiondefs = (
             # Define type of DirectGuiWidget
             # Define type of DirectGuiWidget
-            ('pad',             (0.4, 0.4),    None),
-            ('text',            '',            None),
-            ('text_align',      TMALIGNCENTER, None),
-            ('geom',  getDefaultDialogGeom(),  None),
-            ('relief',          None,          None),
-            ('buttons',         [],            INITOPT),
-            ('buttonOffset',    0.2,           None),
-            ('button_pad',      (.1,.1),       None),
-            ('button_relief',   RAISED,        None),
-            ('button_frameSize', (-1,1,-.2,.9),    None),
-            ('command',         None,          None),
-            ('extraArgs',       [],            None),
+            ('pad',               (0.1, 0.1),    None),
+            ('text',              '',            None),
+            ('text_align',        TMALIGNLEFT,   None),
+            ('text_scale',        0.06,          None),
+            ('image',  getDefaultDialogGeom(),   None),
+            ('relief',            None,          None),
+            ('buttonTextList',    [],            INITOPT),
+            ('buttonGeomList',    [],            INITOPT),
+            ('buttonImageList',   [],            INITOPT),
+            ('buttonValueList',   [],            INITOPT),
+            ('button_borderWidth',(.01,.01),     None),
+            ('button_pad',        (.01,.01),     None),
+            ('button_relief',     RAISED,        None),
+            ('button_text_scale'  , 0.06,        None),
+            ('buttonSize',        None,          INITOPT),
+            ('topPad',            0.06,          INITOPT),
+            ('midPad',            0.12,          INITOPT),
+            ('buttonPadSF',       1.05,          INITOPT),
+            ('command',           None,          None),
+            ('extraArgs',         [],            None),
             )
             )
         # Merge keyword options with default options
         # Merge keyword options with default options
         self.defineoptions(kw, optiondefs, dynamicGroups = ("button",))
         self.defineoptions(kw, optiondefs, dynamicGroups = ("button",))
 
 
         # Initialize superclasses
         # Initialize superclasses
         DirectFrame.__init__(self, parent)
         DirectFrame.__init__(self, parent)
-
-        self.numButtons = len(self['buttons'])
+        # Determine number of buttons
+        self.numButtons = max(len(self['buttonTextList']),
+                              len(self['buttonGeomList']),
+                              len(self['buttonImageList']),
+                              len(self['buttonValueList']))
+        # Create buttons
         self.buttonList = []
         self.buttonList = []
-        for button in self['buttons']:
-            name = button + 'Button'
+        index = 0
+        for i in range(self.numButtons):
+            name = 'Button' + `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
             button = self.createcomponent(
             button = self.createcomponent(
                 name, (), "button",
                 name, (), "button",
                 DirectButton, (self,),
                 DirectButton, (self,),
-                text = button,
-                command = lambda s = self, b = button: s.__buttonCommand(b)
+                text = text,
+                geom = geom,
+                image = image,
+                frameSize = self['buttonSize'],
+                command = lambda s = self, v = value: s.buttonCommand(v)
                 )
                 )
             self.buttonList.append(button)
             self.buttonList.append(button)
-            self.numButtons += 1
+        
+        # Update dialog when everything has been initialised
+        self.postInitialiseFuncList.append(self.configureDialog)
         self.initialiseoptions(DirectDialog)
         self.initialiseoptions(DirectDialog)
 
 
+    def configureDialog(self):
         # Position buttons and text
         # Position buttons and text
-        # Get size of text
-        text = self.component('text0')
-        bounds = text.getTightBounds()
         pad = self['pad']
         pad = self['pad']
-        l = bounds[0][0] - pad[0]
-        r = bounds[1][0] + pad[0]
-        b = bounds[0][2] - pad[1]
-        t = bounds[1][2] + pad[1]
-        text.setPos((l+r)/2.0, (b+t)/2.0)
-        # Move buttons
-        if self['button_frameSize']:
-            frameSize = self['button_frameSize']
-            bl = frameSize[0]
-            br = frameSize[1]
-            bb = frameSize[2]
-            bt = frameSize[3]
+        bpad = self['button_pad']
+        image = self.component('image0')
+        # 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])
+        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)/2.0
+        zOffset = -(b+t)/2.0
+        # 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)
+        # 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:
         else:
-            # Get bounds of union of buttons
+            # Or get bounds of union of buttons
             bl = br = bb = bt = 0
             bl = br = bb = bt = 0
             for button in self.buttonList:
             for button in self.buttonList:
                 bounds = button.stateNodePath[0].getTightBounds()
                 bounds = button.stateNodePath[0].getTightBounds()
@@ -66,41 +157,156 @@ class DirectDialog(DirectFrame):
                 br = max(br, bounds[1][0])
                 br = max(br, bounds[1][0])
                 bb = min(bb, bounds[0][2])
                 bb = min(bb, bounds[0][2])
                 bt = max(bt, bounds[1][2])
                 bt = max(bt, bounds[1][2])
-        bWidth = br - bl
-        bSpacing = 1.1 * bWidth
+            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
         bHeight = bt - bb
-        index = 0
-        if self.numButtons == 0:
-            return
-        bPos = bSpacing * (self.numButtons - 1)/2.0
-        for button in self.buttonList:
-            button.setPos(bPos + index * bSpacing, 0,
-                          b - self['buttonOffset'] - bt)
-            index += 1
-        # Resize frame
-        b = b - self['buttonOffset'] - bHeight - pad[1]
-        frame = self.component('geom0')
-        frame.setScale(r - l, 1, t - b)
-        frame.setPos((l+r)/2.0, 0.0, (b+t)/2.0)
+        bWidth = br - bl
+        # Add pad between buttons
+        bSpacing = self['buttonPadSF'] * bWidth
+        if self.numButtons != 0:
+            bPos = -bSpacing * (self.numButtons - 1)/2.0
+            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:
+            bPos = 0
+            bMax = 0
+        # Resize frame to fit text and buttons
+        l = min(bPos + bl, l) - pad[0]
+        r = max(bMax + br, r) + pad[0]
+        # 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['image_scale'] = (r - l, 1, t - b)
+        # Center frame about text and buttons
+        self['image_pos'] = ((l+r)/2.0, 0.0,(b+t)/2.0)
         self.resetFrameSize()
         self.resetFrameSize()
 
 
-    def __buttonCommand(self, button):
+    def buttonCommand(self, value):
         if self['command']:
         if self['command']:
-            self['command'](button)
+            self['command'](value)
         
         
     def destroy(self):
     def destroy(self):
         DirectFrame.destroy(self)
         DirectFrame.destroy(self)
 
 
 
 
+class OKDialog(DirectDialog):
+    def __init__(self, parent = guiTop, **kw):
+        # Inherits from DirectFrame
+        optiondefs = (
+            # Define type of DirectGuiWidget
+            ('buttonTextList',  ['OK'],       INITOPT),
+            ('buttonValueList', [1],          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 = guiTop, **kw):
+        # Inherits from DirectFrame
+        optiondefs = (
+            # Define type of DirectGuiWidget
+            ('buttonTextList',  ['OK','Cancel'],       INITOPT),
+            ('buttonValueList', [1,-1],                INITOPT),
+            )
+        # Merge keyword options with default options
+        self.defineoptions(kw, optiondefs)
+        DirectDialog.__init__(self, parent)
+        self.initialiseoptions(OKCancelDialog)
+
 class YesNoDialog(DirectDialog):
 class YesNoDialog(DirectDialog):
     def __init__(self, parent = guiTop, **kw):
     def __init__(self, parent = guiTop, **kw):
         # Inherits from DirectFrame
         # Inherits from DirectFrame
         optiondefs = (
         optiondefs = (
             # Define type of DirectGuiWidget
             # Define type of DirectGuiWidget
-            ('buttons',       ['Yes', 'No'],       INITOPT),
-            ('text',          'Yes or No?',        None),
+            ('buttonTextList',  ['Yes', 'No'],       INITOPT),
+            ('buttonValueList', [1,0],               INITOPT),
             )
             )
         # Merge keyword options with default options
         # Merge keyword options with default options
         self.defineoptions(kw, optiondefs)
         self.defineoptions(kw, optiondefs)
-        apply(DirectDialog.__init__, (self, parent), kw)
+        DirectDialog.__init__(self, parent)
         self.initialiseoptions(YesNoDialog)
         self.initialiseoptions(YesNoDialog)
+
+class YesNoCancelDialog(DirectDialog):
+    def __init__(self, parent = guiTop, **kw):
+        # Inherits from DirectFrame
+        optiondefs = (
+            # Define type of DirectGuiWidget
+            ('buttonTextList',  ['Yes', 'No', 'Cancel'],  INITOPT),
+            ('buttonValueList', [1,0,-1],                 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 = guiTop, **kw):
+        # Inherits from DirectFrame
+        optiondefs = (
+            # Define type of DirectGuiWidget
+            ('buttonTextList',  ['Retry','Cancel'],   INITOPT),
+            ('buttonValueList', [1,-1],               INITOPT),
+            )
+        # Merge keyword options with default options
+        self.defineoptions(kw, optiondefs)
+        DirectDialog.__init__(self, parent)
+        self.initialiseoptions(RetryCancelDialog)
+
+class TTOkCancelDialog(DirectDialog):
+    def __init__(self, parent = guiTop, **kw):
+        # Inherits from DirectDialog
+        buttons = loader.loadModelOnce(
+            'phase_3/models/gui/dialog_box_buttons_gui')
+        okImageList = (buttons.find('**/ChtBx_OKBtn_UP'),
+                       buttons.find('**/ChtBx_OKBtn_DN'),
+                       buttons.find('**/ChtBx_OKBtn_Rllvr'))
+        okTextList = ('', 'OK', 'OK')
+        cancelImageList = (buttons.find('**/CloseBtn_UP'),
+                           buttons.find('**/CloseBtn_DN'),
+                           buttons.find('**/CloseBtn_Rllvr'))
+        cancelTextList = ('', 'Cancel', 'Cancel')
+        optiondefs = (
+            # Define type of DirectGuiWidget
+            ('buttonTextList',  [okTextList, cancelTextList], INITOPT),
+            ('buttonImageList', [okImageList, cancelImageList], INITOPT),
+            ('buttonValueList', [1,-1],               INITOPT),
+            ('button_pad',      (0,0),                None),
+            ('button_relief',   None,                 None),
+            ('button_text_pos', (0,-0.1),             None),
+            ('buttonSize',      (-.05,.05,-.05,.05),  None),
+            )
+        # Merge keyword options with default options
+        self.defineoptions(kw, optiondefs)
+        DirectDialog.__init__(self, parent)
+        self.initialiseoptions(TTOkCancelDialog)
+

+ 1 - 0
direct/src/gui/DirectGui.py

@@ -15,3 +15,4 @@ from DirectButton import *
 from DirectEntry import *
 from DirectEntry import *
 from DirectLabel import *
 from DirectLabel import *
 from DirectScrolledList import *
 from DirectScrolledList import *
+from DirectDialog import *

+ 8 - 2
direct/src/gui/DirectGuiBase.py

@@ -95,6 +95,8 @@ class DirectGuiBase(PandaObject.PandaObject):
         self.guiId = 'guiObject'
         self.guiId = 'guiObject'
         # List of all active hooks
         # List of all active hooks
         self._hookDict = {}
         self._hookDict = {}
+        # List of all post initialization functions
+        self.postInitialiseFuncList = []
         # To avoid doing things redundantly during initialisation
         # To avoid doing things redundantly during initialisation
         self.fInit = 1
         self.fInit = 1
         # Mapping from each megawidget option to a list of information
         # Mapping from each megawidget option to a list of information
@@ -261,7 +263,8 @@ class DirectGuiBase(PandaObject.PandaObject):
             self.postInitialiseFunc()
             self.postInitialiseFunc()
 
 
     def postInitialiseFunc(self):
     def postInitialiseFunc(self):
-        pass
+        for func in self.postInitialiseFuncList:
+            func()
                     
                     
     def isinitoption(self, option):
     def isinitoption(self, option):
         """
         """
@@ -758,11 +761,14 @@ class DirectGuiWidget(DirectGuiBase, NodePath):
 
 
         # Bind destroy hook
         # Bind destroy hook
         self.bind(DESTROY, self.destroy)
         self.bind(DESTROY, self.destroy)
+
+        # Update frame when everything has been initialized
+        self.postInitialiseFuncList.append(self.frameInitialiseFunc)
             
             
         # Call option initialization functions
         # Call option initialization functions
         self.initialiseoptions(DirectGuiWidget)
         self.initialiseoptions(DirectGuiWidget)
 
 
-    def postInitialiseFunc(self):
+    def frameInitialiseFunc(self):
         # Now allow changes to take effect
         # Now allow changes to take effect
         self.updateFrameStyle()
         self.updateFrameStyle()
         if not self['frameSize']:
         if not self['frameSize']:

+ 2 - 1
direct/src/gui/DirectGuiGlobals.py

@@ -96,7 +96,8 @@ def setDefaultFont(newFont):
 def getDefaultDialogGeom():
 def getDefaultDialogGeom():
     global defaultDialogGeom
     global defaultDialogGeom
     if defaultDialogGeom == None:
     if defaultDialogGeom == None:
-        defaultDialogGeom = loader.loadModelOnce('phase_3/models/props/panel')
+        defaultDialogGeom = loader.loadModelOnce(
+            'phase_3/models/gui/dialog_box_gui')
     return defaultDialogGeom
     return defaultDialogGeom
 
 
 def setDefaultDialogGeom(newDialogGeom):
 def setDefaultDialogGeom(newDialogGeom):

+ 28 - 0
direct/src/gui/DirectGuiTest.py

@@ -96,6 +96,34 @@ de1 = DirectEntry(initialText = 'Hello, how are you?',
                   scale = 0.0707855,
                   scale = 0.0707855,
                   )
                   )
 
 
+# DIRECT DIALOG EXAMPLE
+def printDialogValue(value):
+    print 'Value:', value
+
+simpleDialog = YesNoDialog(text = 'Simple',
+                           command = printDialogValue)
+
+customValues = YesNoDialog(text = 'Simple',
+                           buttonValueList = ['Yes', 'No'],
+                           command = printDialogValue)
+
+
+fancyDialog = YesNoDialog(text = 'Testing Direct Dialog',
+                          geom = smiley,
+                          geom_scale = .1,
+                          geom_pos = (-0.3,0,0),
+                          command = printDialogValue)
+
+toontownDialog = TTOkCancelDialog(text = 'Exit Toontown?',
+                                  command = printDialogValue)
+
+customDialog = DirectDialog(text = 'Pick a number',
+                            buttonTextList = map(str, range(10)),
+                            buttonValueList = range(10),
+                            command = printDialogValue)
+
+
+
 # NOTE: There are some utility functions which help you get size
 # NOTE: There are some utility functions which help you get size
 # of a direct gui widget.  These can be used to position and scale an
 # of a direct gui widget.  These can be used to position and scale an
 # image after you've created the entry.  scale = (width/2, 1, height/2)
 # image after you've created the entry.  scale = (width/2, 1, height/2)

+ 10 - 3
direct/src/gui/OnscreenText.py

@@ -179,7 +179,8 @@ class OnscreenText(PandaObject, NodePath):
         # We'd rather do it here, on the text itself, rather than on
         # We'd rather do it here, on the text itself, rather than on
         # our NodePath, so we have one fewer transforms in the scene
         # our NodePath, so we have one fewer transforms in the scene
         # graph.
         # graph.
-        mat = Mat4.scaleMat(scale[0], 1, scale[1]) * Mat4.translateMat(pos[0], 0, pos[1])
+        mat = Mat4.scaleMat(
+            scale[0], 1, scale[1]) * Mat4.translateMat(pos[0], 0, pos[1])
         textNode.setTransform(mat)
         textNode.setTransform(mat)
 
 
         textNode.setBin('fixed')
         textNode.setBin('fixed')
@@ -259,7 +260,10 @@ class OnscreenText(PandaObject, NodePath):
         Position the onscreen text in 2d screen space
         Position the onscreen text in 2d screen space
         """
         """
         self.pos = (x, y)
         self.pos = (x, y)
-        mat = Mat4.scaleMat(self.scale[0], 1, self.scale[1]) * Mat4.translateMat(self.pos[0], 0, self.pos[1])
+        mat = Mat4.scaleMat(
+            self.scale[0],
+            1,
+            self.scale[1]) * Mat4.translateMat(self.pos[0], 0, self.pos[1])
         self.textNode.setTransform(mat)
         self.textNode.setTransform(mat)
 
 
     def getPos(self):
     def getPos(self):
@@ -278,7 +282,10 @@ class OnscreenText(PandaObject, NodePath):
                 self.scale = (sx, sx)
                 self.scale = (sx, sx)
         else:
         else:
             self.scale = (sx, sy)
             self.scale = (sx, sy)
-        mat = Mat4.scaleMat(self.scale[0], 1, self.scale[1]) * Mat4.translateMat(self.pos[0], 0, self.pos[1])
+        mat = Mat4.scaleMat(
+            self.scale[0],
+            1,
+            self.scale[1]) * Mat4.translateMat(self.pos[0], 0, self.pos[1])
         self.textNode.setTransform(mat)
         self.textNode.setTransform(mat)
 
 
     def getScale(self):
     def getScale(self):