| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413 |
- from ShowBaseGlobal import *
- import GuiGlobals
- import PandaObject
- import Button
- import Label
- import OnscreenText
- import types
- def findPanel(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 OnscreenPanel.AllPanels.has_key(uniqueName):
- return OnscreenPanel.AllPanels[uniqueName]
- return None
- def cleanupPanel(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 OnscreenPanel.AllPanels.has_key(uniqueName):
- # calling cleanup() will remove it out of the AllPanels 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
- OnscreenPanel.AllPanels[uniqueName].cleanup()
- class OnscreenPanel(PandaObject.PandaObject, NodePath):
- """OnscreenPanel:
- This class defines the basic interface to a user-interface panel
- that pops up within the Panda window, overlaying whatever graphics
- we may have already.
- """
- AllPanels = {}
- def __init__(self, panelName):
- self.panelName = panelName
- self.panelSetup = 0
-
- # initialize our NodePath essence.
- NodePath.__init__(self, aspect2d.attachNewNode(panelName))
- NodePath.hide(self)
-
- def makePanel(self,
- rect = (-0.5, 0.5, -0.5, 0.5),
- bg = (1, 1, 1, 1),
- geom = GuiGlobals.getDefaultPanel(),
- geomRect = (-0.5, 0.5, -0.5, 0.5),
- drawOrder = 0,
- font = GuiGlobals.getDefaultFont(),
- support3d = 0):
- """makePanel()
- Initializes the geometry to render the panel with the
- specified parameters. This should only be called once, and
- generally by the __init__ function.
- The parameters are as follows:
- rect: the (left, right, bottom, top) of the panel on the
- screen. This is in aspect2d coordinates. The panel
- will be set up in its own coordinate system so that (0,
- 0) is the center of the panel.
- bg: the (r, g, b, a) background color of the panel.
- geom: the model to use as the background panel geometry.
- Normally you can safely let this default.
- geomRect: the (left, right, bottom, top) rectangle around
- the background panel geometry as it is modeled. This is
- used to compute how the panel should be scaled to make
- it fit the rectangle specified by rect, above.
- drawOrder: the drawing order of this panel with respect to
- all other things in the 'fixed' bin within render2d.
- Buttons and text created within the panel via
- makeButton() and makeText() will by default be given a
- drawOrder slightly higher than this. Normally you can
- safely let this default, unless you really expect this
- panel to overlay some other panels.
- font: the default font for buttons and text created within
- the panel via makeButton() and makeText().
- support3d: if this is set true, the panel will be set up so
- that 3-d geometry (like a floating head) may be safely
- parented to the panel.
- """
- assert not self.panelSetup
- # Clean up any previously existing panel with the same unique
- # name. We don't allow any two panels with the same name to
- # coexist.
- uniqueName = self.getUniqueName()
- cleanupPanel(uniqueName)
- # Store this panel in our map of all open panels.
- OnscreenPanel.AllPanels[uniqueName] = self
-
- self.panelSetup = 1
- self.panelDrawOrder = drawOrder
- self.panelFont = font
- self.panelButtons = []
- self.panelText = []
- if geom == None:
- # If 'geom' is None, it means not to have a background
- # panel at all.
- self.panelGeom = None
-
- elif isinstance(geom, types.StringType):
- # If 'geom' is a string, it's the name of a model to load.
- self.panelGeom = loader.loadModelCopy(geom)
- self.panelGeom.reparentTo(self)
- else:
- # Otherwise, it's a model to instance.
- self.panelGeom = geom.instanceTo(self)
- centerX = (rect[0] + rect[1]) / 2.0
- centerY = (rect[2] + rect[3]) / 2.0
- NodePath.setPos(self, centerX, 0, centerY)
- self.setBin('fixed', self.panelDrawOrder)
- self.panelRegion = None
- if self.panelGeom != None:
- # Scale and position the geometry to fill up our desired
- # rectangle.
- gCenterX = (geomRect[0] + geomRect[1]) / 2.0
- gCenterY = (geomRect[2] + geomRect[3]) / 2.0
- self.panelGeom.setPos(-gCenterX, 0, -gCenterY)
- self.panelGeom.setScale((rect[1] - rect[0]) / (geomRect[1] - geomRect[0]), 1,
- (rect[3] - rect[2]) / (geomRect[3] - geomRect[2]))
- if bg[3] != 1:
- self.panelGeom.setTransparency(1)
- self.panelGeom.setColor(bg[0], bg[1], bg[2], bg[3])
- if support3d:
- # If we're supposed to support 3-d geometry in front of
- # the panel, set a few extra attributes to ensure the
- # panel geometry fills up the depth buffer as it goes,
- # making it safe to put 3-d geometry in front of it.
- dw = DepthWriteTransition()
- self.panelGeom.setY(100)
- self.panelGeom.arc().setTransition(dw, 1)
- # Set up the panel as its own mouse region so mouse clicks on
- # the panel don't inadvertently drive the toon around. This
- # must be done after the panelGeom has been scaled
- # appropriately, above.
- self.geomRect = geomRect
- self.panelRegion = MouseWatcherRegion(uniqueName, 0, 0, 0, 0)
- self.panelRegion.setRelative(self.panelGeom,
- geomRect[0], geomRect[1],
- geomRect[2], geomRect[3])
- self.panelRegion.setSort(self.panelDrawOrder)
- def cleanup(self):
- """cleanup(self):
- Removes the panel and frees all the resources associated with
- it. This must be called to safely remove the panel from the
- screen.
- The return value is true if the panel was cleaned up, or false
- if it had already been cleaned up.
- """
- if not self.panelSetup:
- return 0
- self.hide()
-
- for button in self.panelButtons:
- button.cleanup()
- del self.panelButtons
- for text in self.panelText:
- text.cleanup()
- del self.panelText
- if not self.isEmpty():
- self.removeNode()
- # Remove this panel out of the AllPanels list
- uniqueName = self.getUniqueName()
- if OnscreenPanel.AllPanels.has_key(uniqueName):
- del OnscreenPanel.AllPanels[uniqueName]
- self.panelSetup = 0
- return 1
- def show(self):
- """show(self):
- Show everything and hang hooks
- """
- if not self.panelSetup:
- return 0
- NodePath.show(self)
- # show the buttons that are meant to be shown
- for button in self.panelButtons:
- if button.panelManage:
- button.manage(self)
- if button.func != None:
- if (button.event != None):
- self.accept(button.event, button.func, [button.button])
- else:
- self.accept(button.button.getDownRolloverEvent(),
- button.func, [button.button])
- button.startBehavior()
- if self.panelRegion != None:
- base.mouseWatcherNode.addRegion(self.panelRegion)
-
- def hide(self):
- """hide(self):
- Hide everything and remove hooks
- """
- if not self.panelSetup:
- return 0
- NodePath.hide(self)
- # hide the shown buttons and remove all hooks
- for button in self.panelButtons:
- if (button.event != None):
- self.ignore(button.event)
- else:
- self.ignore(button.button.getDownRolloverEvent())
- if button.panelManage:
- button.unmanage()
- if self.panelRegion != None:
- base.mouseWatcherNode.removeRegion(self.panelRegion)
- def makeButton(self, name,
- func = None,
- manage = 1,
- label = None,
- labels = None,
- scale = 0.1,
- width = None,
- align = None,
- drawOrder = None,
- font = None,
- pos = (0, 0),
- geomRect = None,
- supportInactive = 0,
- inactive = 0,
- upStyle = Label.ButtonUp,
- litStyle = Label.ButtonLit,
- downStyle = Label.ButtonDown,
- inactiveStyle = Label.ButtonInactive,
- event = None):
- """makeButton(self, ...)
- Creates a button on the panel. The return value is the button
- itself. The position of the button is relative to the panel,
- where (0, 0) is the center.
- The button will automatically be managed (i.e. made visible)
- unless manage is set to 0.
- If func is specified, it is the name of a function that will
- be called when the button is clicked. In this case, a hook
- will automatically be assigned for the button, and removed
- when cleanup() is called.
- """
- assert self.panelSetup
- if (label == None) and (labels == None):
- label = name
- if drawOrder == None:
- drawOrder = self.panelDrawOrder + 10
- if font == None:
- font = self.panelFont
- buttonName = self.getUniqueName() + '-' + name
-
- button = Button.Button(buttonName,
- label = label,
- labels = labels,
- scale = scale,
- width = width,
- align = align,
- drawOrder = drawOrder,
- font = font,
- pos = pos,
- geomRect = geomRect,
- supportInactive = supportInactive,
- inactive = inactive,
- upStyle = upStyle,
- litStyle = litStyle,
- downStyle = downStyle,
- inactiveStyle = inactiveStyle,
- event = event)
- self.panelButtons.append(button)
-
- button.panelManage = manage
- button.func = func
-
- return button
- def makeText(self, text = '',
- style = OnscreenText.Plain,
- pos = (0, 0),
- scale = None,
- fg = None,
- bg = None,
- shadow = None,
- frame = None,
- align = None,
- wordwrap = None,
- drawOrder = None,
- font = None,
- parent = None,
- mayChange = 0):
- """makeText(self, ...)
- Creates some text on the panel. The return value is an
- OnscreenText object. The position of the text is relative to
- the panel, where (0, 0) is the center.
- The text need not be further managed by the derived class. It
- will automatically be removed when cleanup() is called.
-
- """
- assert self.panelSetup
- if drawOrder == None:
- drawOrder = self.panelDrawOrder + 10
- if font == None:
- font = self.panelFont
- if parent == None:
- parent = self
- text = OnscreenText.OnscreenText(text,
- style = style,
- pos = pos,
- scale = scale,
- fg = fg,
- bg = bg,
- shadow = shadow,
- frame = frame,
- align = align,
- wordwrap = wordwrap,
- drawOrder = drawOrder,
- font = font,
- parent = parent,
- mayChange = mayChange)
-
- self.panelText.append(text)
- return text
- def getUniqueName(self):
- """getUniqueName(self):
- Returns a name unique to this panel. If no two instances of
- the same panel will ever be in existence at once, this can
- simply be the panel name. If, for some reason, you want to
- define a panel type that can have multiple instances, you
- should redefine this function to return a unique name for each
- instance.
- """
-
- return self.panelName
- def setPos(self, x, y, z):
- """setPos(self, x, y, z)
- Repositions the panel onscreen, taking all of the panel's
- managed buttons along with it.
-
- """
- assert self.panelSetup
- NodePath.setPos(self, x, y, z)
- for button in self.panelButtons:
- if button.managed:
- button.unmanage()
- button.manage(self)
- if self.panelRegion != None:
- self.panelRegion.setRelative(self.panelGeom,
- self.geomRect[0], self.geomRect[1],
- self.geomRect[2], self.geomRect[3])
|