diff --git a/direct/src/gui/DirectGui.py b/direct/src/gui/DirectGui.py index b792ccc4b2..6a528b7437 100644 --- a/direct/src/gui/DirectGui.py +++ b/direct/src/gui/DirectGui.py @@ -24,3 +24,4 @@ from DirectScrollBar import * from DirectScrolledFrame import * from DirectCheckButton import * from DirectOptionMenu import * +from DirectRadioButton import * diff --git a/direct/src/gui/DirectRadioButton.py b/direct/src/gui/DirectRadioButton.py new file mode 100755 index 0000000000..91e7b8f381 --- /dev/null +++ b/direct/src/gui/DirectRadioButton.py @@ -0,0 +1,219 @@ +"""Undocumented Module""" + +__all__ = ['DirectRadioButton'] + +from pandac.PandaModules import * +import DirectGuiGlobals as DGG +from DirectButton import * +from DirectLabel import * + +class DirectRadioButton(DirectButton): + """ + DirectRadioButton(parent) - Create a DirectGuiWidget which responds + to mouse clicks by setting given value to given variable and + execute a callback function (passing that state through) if defined + """ + def __init__(self, parent = None, **kw): + # Inherits from DirectButton + # A Direct Frame can have: + # - A background texture (pass in path to image, or Texture Card) + # - A midground geometry item (pass in geometry) + # - A foreground text Node (pass in text string or Onscreen Text) + # For a direct button: + # Each button has 4 states (ready, press, rollover, disabled) + # The same image/geom/text can be used for all four states or each + # state can have a different text/geom/image + # State transitions happen automatically based upon mouse interaction + # Responds to click event and calls command if None + + self.colors = None + optiondefs = ( + ('indicatorValue', 0, self.setIndicatorValue), + # variable is a list whose value will be set by this radio button + ('variable', [], None), + # value is the value to be set when this radio button is selected + ('value', [], None), + # others is a list of other radio buttons sharing same variable + ('others', [], None), + # boxBorder defines the space created around the check box + ('boxBorder', 0, None), + # boxPlacement maps left, above, right, below + ('boxPlacement', 'left', None), + # boxGeom defines geom to indicate current radio button is selected or not + ('boxGeom', None, None), + ('boxGeomColor', None, None), + ('boxGeomScale', 1.0, None), + ('boxImage', loader.loadModel('models/gui/radio_button_gui'), None), + ('boxImageScale', 1.0, None), + ('boxImageColor', VBase4(1, 1, 1, 1), None), + ('boxRelief', None, None), + ) + # Merge keyword options with default options + self.defineoptions(kw, optiondefs) + # Initialize superclasses + DirectButton.__init__(self, parent) + self.indicator = self.createcomponent("indicator", (), None, + DirectLabel, (self,), + numStates = 2, + image = self['boxImage'], + image_scale = self['boxImageScale'], + image_color = self['boxImageColor'], + geom = self['boxGeom'], + geom_scale = self['boxGeomScale'], + geom_color = self['boxGeomColor'], + state = 'disabled', + text = ('X', 'X'), + relief = self['boxRelief'], + ) + + # Call option initialization functions + self.initialiseoptions(DirectRadioButton) + # After initialization with X giving it the correct size, put back space + if self['boxGeom'] == None: + self.indicator['text'] = (' ', '*') + self.indicator['text_pos'] = (0, -.5) + else: + self.indicator['text'] = (' ', ' ') + + if self['boxGeomColor'] != None and self['boxGeom'] != None: + self.colors = [VBase4(1, 1, 1, 0), self['boxGeomColor']] + self.component('indicator')['geom_color'] = VBase4(1, 1, 1, 0) + + needToCheck = True + if len(self['value']) == len(self['variable']) != 0: + for i in range(len(self['value'])): + if self['variable'][i] != self['value'][i]: + needToCheck = False + break + + if needToCheck: + self.check() + + # Override the resetFrameSize of DirectGuiWidget inorder to provide space for label + def resetFrameSize(self): + self.setFrameSize(fClearFrame = 1) + + def setFrameSize(self, fClearFrame = 0): + + if self['frameSize']: + # Use user specified bounds + self.bounds = self['frameSize'] + frameType = self.frameStyle[0].getType() + ibw = self.indicator['borderWidth'] + else: + # Use ready state to compute bounds + frameType = self.frameStyle[0].getType() + if fClearFrame and (frameType != PGFrameStyle.TNone): + self.frameStyle[0].setType(PGFrameStyle.TNone) + self.guiItem.setFrameStyle(0, self.frameStyle[0]) + # To force an update of the button + self.guiItem.getStateDef(0) + # Clear out frame before computing bounds + self.getBounds() + # Restore frame style if necessary + if (frameType != PGFrameStyle.TNone): + self.frameStyle[0].setType(frameType) + self.guiItem.setFrameStyle(0, self.frameStyle[0]) + + # Ok, they didn't set specific bounds, + # let's add room for the label indicator + # get the difference in height + + ibw = self.indicator['borderWidth'] + indicatorWidth = (self.indicator.getWidth() + (2*ibw[0])) + indicatorHeight = (self.indicator.getHeight() + (2*ibw[1])) + diff = (indicatorHeight + (2*self['boxBorder']) - + (self.bounds[3] - self.bounds[2])) + # If background is smaller then indicator, enlarge background + if diff > 0: + if self['boxPlacement'] == 'left': #left + self.bounds[0] += -(indicatorWidth + (2*self['boxBorder'])) + self.bounds[3] += diff/2 + self.bounds[2] -= diff/2 + elif self['boxPlacement'] == 'below': #below + self.bounds[2] += -(indicatorHeight+(2*self['boxBorder'])) + elif self['boxPlacement'] == 'right': #right + self.bounds[1] += indicatorWidth + (2*self['boxBorder']) + self.bounds[3] += diff/2 + self.bounds[2] -= diff/2 + else: #above + self.bounds[3] += indicatorHeight + (2*self['boxBorder']) + + # Else make space on correct side for indicator + else: + if self['boxPlacement'] == 'left': #left + self.bounds[0] += -(indicatorWidth + (2*self['boxBorder'])) + elif self['boxPlacement'] == 'below': #below + self.bounds[2] += -(indicatorHeight + (2*self['boxBorder'])) + elif self['boxPlacement'] == 'right': #right + self.bounds[1] += indicatorWidth + (2*self['boxBorder']) + else: #above + self.bounds[3] += indicatorHeight + (2*self['boxBorder']) + + # Set frame to new dimensions + if ((frameType != PGFrameStyle.TNone) and + (frameType != PGFrameStyle.TFlat)): + bw = self['borderWidth'] + else: + bw = (0, 0) + # Set frame to new dimensions + self.guiItem.setFrame( + self.bounds[0] - bw[0], + self.bounds[1] + bw[0], + self.bounds[2] - bw[1], + self.bounds[3] + bw[1]) + + # If they didn't specify a position, put it in the center of new area + if not self.indicator['pos']: + bbounds = self.bounds + lbounds = self.indicator.bounds + newpos = [0, 0, 0] + + if self['boxPlacement'] == 'left': #left + newpos[0] += bbounds[0]-lbounds[0] + self['boxBorder'] + ibw[0] + dropValue = (bbounds[3]-bbounds[2]-lbounds[3]+lbounds[2])/2 + self['boxBorder'] + newpos[2] += (bbounds[3]-lbounds[3] + self['boxBorder'] - + dropValue) + elif self['boxPlacement'] == 'right': #right + newpos[0] += bbounds[1]-lbounds[1] - self['boxBorder'] - ibw[0] + dropValue = (bbounds[3]-bbounds[2]-lbounds[3]+lbounds[2])/2 + self['boxBorder'] + newpos[2] += (bbounds[3]-lbounds[3] + self['boxBorder'] + - dropValue) + elif self['boxPlacement'] == 'above': #above + newpos[2] += bbounds[3]-lbounds[3] - self['boxBorder'] - ibw[1] + else: #below + newpos[2] += bbounds[2]-lbounds[2] + self['boxBorder'] + ibw[1] + + self.indicator.setPos(newpos[0], newpos[1], newpos[2]) + + + def commandFunc(self, event): + if len(self['value']) == len(self['variable']) != 0: + for i in range(len(self['value'])): + self['variable'][i] = self['value'][i] + self.check() + + def check(self): + self['indicatorValue'] = 1 + self.setIndicatorValue() + + for other in self['others']: + if other != self: + other.uncheck() + + if self['command']: + # Pass any extra args to command + apply(self['command'], [self['indicatorValue']] + self['extraArgs']) + + def setOthers(self, others): + self['others'] = others + + def uncheck(self): + self['indicatorValue'] = 0 + if self.colors != None: + self.component('indicator')['geom_color'] = self.colors[self['indicatorValue']] + + def setIndicatorValue(self): + self.component('indicator').guiItem.setState(self['indicatorValue']) + if self.colors != None: + self.component('indicator')['image_color'] = self.colors[self['indicatorValue']]