def generateOtherPlayerGui(self): for avId in self.doId2Frame.keys(): self.avId2otherPlayerAvIds2otherPlayerHeadsFrame[avId] = {} headNumber = -1 frame = self.doId2Frame[avId][0] otherPlayerHeadsFrame = DirectFrame(relief=None, scale=0.85, parent=frame) otherPlayerHeadsFrame['image'] = frame['image'] otherPlayerHeadsFrame['image_color'] = frame['image_color'] otherPlayerHeadsFrame[ 'image_scale'] = self.otherPlayerHeadHolderTransforms['scale'] otherPlayerHeadsFrame.setPos( self.otherPlayerHeadHolderTransforms['pos']) otherPlayerHeadsFrame.setBin('gui-popup', 70) self.frameList.append(otherPlayerHeadsFrame) for otherAvId in self.doId2Frame.keys(): if otherAvId != avId: headNumber += 1 otherAv = base.cr.doId2do.get(otherAvId) headFrame = otherPlayerHeadsFrame.attachNewNode( 'otherPlayerHeadFrame') headFrame.setPosHprScale( self.otherPlayerHeadXValues[headNumber], 5, -0.1, 180, 0, 0, 0.2, 0.2, 0.2) headFrame.setColorScale(self.state2Color[0]) head = ToonGlobals.generateGuiHead(otherAv) head.reparentTo(headFrame) self.avId2otherPlayerAvIds2otherPlayerHeadsFrame[avId][ otherAvId] = headFrame
def generate(self, gender, head, headtype, color, doId, name, valueLabel = 1): gui = loader.loadModel("phase_3/models/gui/pick_a_toon_gui.bam") bg = gui.find('**/av-chooser_Square_UP') container = DirectFrame(relief=None, scale=0.3, parent=base.a2dTopLeft) container['image'] = bg container['image_color'] = self.frameColors[len(self.frameList)] container.setBin('gui-popup', 60) container.setPos(self.framePositions[len(self.frameList)]) headframe = container.attachNewNode('head') headframe.setPosHprScale(0, 5, -0.1, 180, 0, 0, 0.24, 0.24, 0.24) toon = ToonHead(None) toon.generateHead(gender, head, headtype) r, g, b = color color = (r, g, b, 1.0) toon.setHeadColor(color) toon.setDepthWrite(1) toon.setDepthTest(1) toon.reparentTo(headframe) nameLbl = DirectLabel(text=name, text_wordwrap=7.0, parent=container, text_scale=0.13, text_fg=(1,1,1,1), text_shadow=(0,0,0,1), relief=None, pos=(0, 0, 0.25)) if valueLabel: someValueToBroadcast = DirectLabel(text="0", parent=container, text_scale=0.15, text_fg=(1,1,1,1), text_shadow=(0,0,0,1), relief=None, pos=(0.26, 0, -0.28)) self.frameList.append(container) if valueLabel: self.doId2Frame[doId] = tuple((container, headframe, toon, nameLbl, someValueToBroadcast)) else: self.doId2Frame[doId] = tuple((container, headframe, toon, nameLbl))
class LoadingScreen(): """Show a directWaitbar to display the current loading state of the application""" def __init__(self): # a fill panel so the player doesn't see how everything # gets loaded in the background self.frameMain = DirectFrame( image="gui/MenuBackground.png", image_scale=(1.7778, 1, 1), #image_pos=(0, 0, 0.25), frameSize=( base.a2dLeft, base.a2dRight, base.a2dTop, base.a2dBottom), frameColor=(0,0,0,0)) self.frameMain.setTransparency(True) self.frameMain.setBin("fixed", 6000) self.frameMain.setDepthWrite(False) self.logo = DirectFrame( image="Logo.png", image_scale=0.25, image_pos=(0, 0, 0.55), frameSize=( base.a2dLeft, base.a2dRight, base.a2dTop, base.a2dBottom), frameColor=(0,0,0,0)) self.logo.reparentTo(self.frameMain) # the text Loading... self.lblLoading = DirectLabel( scale=0.10, pos=(0, 0, -0.15), frameColor=(0, 0, 0, 0), text=_("Loading..."), text_align=TextNode.ACenter, text_fg=(1, 1, 1, 1)) self.lblLoading.reparentTo(self.frameMain) self.stop() def start(self): self.frameMain.show() base.graphicsEngine.renderFrame() base.graphicsEngine.renderFrame() def stop(self): self.frameMain.hide()
def generateOtherPlayerGui(self): for avId in self.doId2Frame.keys(): self.avId2otherPlayerAvIds2otherPlayerHeadsFrame[avId] = {} headNumber = -1 frame = self.doId2Frame[avId][0] otherPlayerHeadsFrame = DirectFrame(relief=None, scale=0.85, parent=frame) otherPlayerHeadsFrame['image'] = frame['image'] otherPlayerHeadsFrame['image_color'] = frame['image_color'] otherPlayerHeadsFrame[ 'image_scale'] = self.otherPlayerHeadHolderTransforms['scale'] otherPlayerHeadsFrame.setPos( self.otherPlayerHeadHolderTransforms['pos']) otherPlayerHeadsFrame.setBin('gui-popup', 70) self.frameList.append(otherPlayerHeadsFrame) for otherAvId in self.doId2Frame.keys(): if otherAvId != avId: headNumber += 1 otherAv = base.cr.doId2do.get(otherAvId) gender = otherAv.getGender() head, color = otherAv.getHeadStyle() animal = otherAv.getAnimal() headFrame = otherPlayerHeadsFrame.attachNewNode( 'otherPlayerHeadFrame') headFrame.setPosHprScale( self.otherPlayerHeadXValues[headNumber], 5, -0.1, 180, 0, 0, 0.2, 0.2, 0.2) headFrame.setColorScale(self.state2Color[0]) toon = ToonHead(None) toon.generateHead(gender, animal, head) r, g, b, _ = color color = (r, g, b, 1.0) toon.setHeadColor(color) toon.setDepthWrite(1) toon.setDepthTest(1) toon.reparentTo(headFrame) self.avId2otherPlayerAvIds2otherPlayerHeadsFrame[avId][ otherAvId] = headFrame
def generate(self, gender, head, headtype, color, doId, name, valueLabel = 1): gui = loader.loadModel('phase_3/models/gui/pick_a_toon_gui.bam') bg = gui.find('**/av-chooser_Square_UP') container = DirectFrame(relief=None, scale=0.3, parent=base.a2dTopLeft) container['image'] = bg container['image_color'] = self.frameColors[len(self.frameList)] container.setBin('gui-popup', 60) container.setPos(self.framePositions[len(self.frameList)]) headframe = container.attachNewNode('head') headframe.setPosHprScale(0, 5, -0.1, 180, 0, 0, 0.24, 0.24, 0.24) toon = ToonHead(None) toon.generateHead(gender, head, headtype) r, g, b = color color = (r, g, b, 1.0) toon.setHeadColor(color) toon.setDepthWrite(1) toon.setDepthTest(1) toon.reparentTo(headframe) nameLbl = DirectLabel(text=name, text_wordwrap=7.0, parent=container, text_scale=0.13, text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 1), relief=None, pos=(0, 0, 0.25)) if valueLabel: someValueToBroadcast = DirectLabel(text='0', parent=container, text_scale=0.15, text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 1), relief=None, pos=(0.26, 0, -0.28)) self.frameList.append(container) if valueLabel: self.doId2Frame[doId] = tuple((container, headframe, toon, nameLbl, someValueToBroadcast)) else: self.doId2Frame[doId] = tuple((container, headframe, toon, nameLbl)) return
def generateOtherPlayerGui(self): for avId in self.doId2Frame.keys(): self.avId2otherPlayerAvIds2otherPlayerHeadsFrame[avId] = {} headNumber = -1 frame = self.doId2Frame[avId][0] otherPlayerHeadsFrame = DirectFrame(relief=None, scale=0.85, parent=frame) otherPlayerHeadsFrame['image'] = frame['image'] otherPlayerHeadsFrame['image_color'] = frame['image_color'] otherPlayerHeadsFrame['image_scale'] = self.otherPlayerHeadHolderTransforms['scale'] otherPlayerHeadsFrame.setPos(self.otherPlayerHeadHolderTransforms['pos']) otherPlayerHeadsFrame.setBin('gui-popup', 70) self.frameList.append(otherPlayerHeadsFrame) for otherAvId in self.doId2Frame.keys(): if otherAvId != avId: headNumber += 1 otherAv = base.cr.doId2do.get(otherAvId) gender = otherAv.getGender() head, color = otherAv.getHeadStyle() animal = otherAv.getAnimal() headFrame = otherPlayerHeadsFrame.attachNewNode('otherPlayerHeadFrame') headFrame.setPosHprScale(self.otherPlayerHeadXValues[headNumber], 5, -0.1, 180, 0, 0, 0.2, 0.2, 0.2) headFrame.setColorScale(self.state2Color[0]) toon = ToonHead(None) toon.generateHead(gender, animal, head) r, g, b, _ = color color = (r, g, b, 1.0) toon.setHeadColor(color) toon.setDepthWrite(1) toon.setDepthTest(1) toon.reparentTo(headFrame) self.avId2otherPlayerAvIds2otherPlayerHeadsFrame[avId][otherAvId] = headFrame return
class FinalScoreGUI: notify = directNotify.newCategory('FinalScoreGUI') def __init__(self): self.finalScoreBg = None self.finalScoreTitle = None self.finalScoreNameLbl = None self.finalScorePointLbl = None self.finalScoreContainer = None self.finalScores = [] return def load(self): font = CIGlobals.getToonFont() box = DGG.getDefaultDialogGeom() self.finalScoreContainer = DirectFrame() self.finalScoreBg = OnscreenImage(image=box, color=(1, 1, 0.75, 1), scale=(1.9, 1.4, 1.4), parent=self.finalScoreContainer) self.finalScoreTitle = OnscreenText(text='Waiting for final scores...', pos=(0, 0.5, 0), font=font, scale=0.12, parent=self.finalScoreContainer) self.finalScoreNameLbl = OnscreenText(text='', scale=0.095, pos=(-0.85, 0.3, 0), font=font, align=TextNode.ALeft, parent=self.finalScoreContainer) self.finalScorePointLbl = OnscreenText(text='', scale=0.095, pos=(0.85, 0.3, 0), font=font, align=TextNode.ARight, parent=self.finalScoreContainer) self.finalScoreContainer.hide() self.finalScoreContainer.setBin('gui-popup', 60) del font del box def unload(self): if self.finalScoreContainer: self.finalScoreContainer.destroy() self.finalScoreContainer = None if self.finalScoreBg: self.finalScoreBg.destroy() self.finalScoreBg = None if self.finalScoreTitle: self.finalScoreTitle.destroy() self.finalScoreTitle = None if self.finalScoreNameLbl: self.finalScoreNameLbl.destroy() self.finalScoreNameLbl = None if self.finalScorePointLbl: self.finalScorePointLbl.destroy() self.finalScorePointLbl = None return def showFinalScores(self): self.finalScoreContainer.show() base.transitions.fadeScreen(0.5) def hideFinalScores(self): base.transitions.noTransitions() self.finalScoreContainer.hide() def handleFinalScores(self, avIdList, scoreList): for avId in avIdList: score = scoreList[avIdList.index(avId)] scoreObj = FinalScore(avId, score) self.finalScores.append(scoreObj) self.finalScores.sort(key=lambda x: x.score, reverse=True) for scoreObj in self.finalScores: name = base.cr.doId2do.get(scoreObj.avId).getName() self.finalScoreNameLbl['text'] += name + '\n' self.finalScorePointLbl['text'] += str(scoreObj.score) + ' Points\n' self.finalScoreTitle['text'] = 'Final Scores'
class Transitions: # These may be reassigned before the fade or iris transitions are # actually invoked to change the models that will be used. IrisModelName = "models/misc/iris" FadeModelName = "models/misc/fade" def __init__(self, loader, model=None, scale=3.0, pos=Vec3(0, 0, 0)): self.transitionIval = None self.letterboxIval = None self.iris = None self.fade = None self.letterbox = None self.fadeModel = model self.imagePos = pos if model: self.alphaOff = Vec4(1, 1, 1, 0) self.alphaOn = Vec4(1, 1, 1, 1) model.setTransparency(1) self.lerpFunc = LerpColorScaleInterval else: self.alphaOff = Vec4(0, 0, 0, 0) self.alphaOn = Vec4(0, 0, 0, 1) self.lerpFunc = LerpColorInterval self.irisTaskName = "irisTask" self.fadeTaskName = "fadeTask" self.letterboxTaskName = "letterboxTask" def __del__(self): if self.fadeModel: self.fadeModel.removeNode() self.fadeModel = None ################################################## # Fade ################################################## # We can set a custom model for the fade before using it for the first time def setFadeModel(self, model, scale=1.0): self.fadeModel = model # We have to change some default parameters for a custom fadeModel self.alphaOn = Vec4(1, 1, 1, 1) # Reload fade if its already been created if self.fade: self.fade.destroy() self.fade = None self.loadFade() def loadFade(self): if self.fade is None: # We create a DirectFrame for the fade polygon, instead of # simply loading the polygon model and using it directly, # so that it will also obscure mouse events for objects # positioned behind it. self.fade = DirectFrame( parent=hidden, guiId='fade', relief=None, image=self.fadeModel, image_scale=(4, 2, 2), state=DGG.NORMAL, ) if not self.fadeModel: # No fade model was given, so we make this the fade model. self.fade["relief"] = DGG.FLAT self.fade["frameSize"] = (-2, 2, -1, 1) self.fade["frameColor"] = (0, 0, 0, 1) self.fade.setTransparency(TransparencyAttrib.MAlpha) self.fade.setBin('unsorted', 0) self.fade.setColor(0, 0, 0, 0) def getFadeInIval(self, t=0.5, finishIval=None): """ Returns an interval without starting it. This is particularly useful in cutscenes, so when the cutsceneIval is escaped out of we can finish the fade immediately """ #self.noTransitions() masad: this creates a one frame pop, is it necessary? self.loadFade() transitionIval = Sequence( Func(self.fade.reparentTo, aspect2d, DGG.FADE_SORT_INDEX), Func(self.fade.showThrough ), # in case aspect2d is hidden for some reason self.lerpFunc( self.fade, t, self.alphaOff, # self.alphaOn, ), Func(self.fade.detachNode), name=self.fadeTaskName, ) if finishIval: transitionIval.append(finishIval) return transitionIval def getFadeOutIval(self, t=0.5, finishIval=None): """ Create a sequence that lerps the color out, then parents the fade to hidden """ self.noTransitions() self.loadFade() transitionIval = Sequence( Func(self.fade.reparentTo, aspect2d, DGG.FADE_SORT_INDEX), Func(self.fade.showThrough ), # in case aspect2d is hidden for some reason self.lerpFunc( self.fade, t, self.alphaOn, # self.alphaOff, ), name=self.fadeTaskName, ) if finishIval: transitionIval.append(finishIval) return transitionIval def fadeIn(self, t=0.5, finishIval=None): """ Play a fade in transition over t seconds. Places a polygon on the aspect2d plane then lerps the color from black to transparent. When the color lerp is finished, it parents the fade polygon to hidden. """ gsg = base.win.getGsg() if gsg: # If we're about to fade in from black, go ahead and # preload all the textures etc. base.graphicsEngine.renderFrame() render.prepareScene(gsg) render2d.prepareScene(gsg) if (t == 0): # Fade in immediately with no lerp #print "transitiosn: fadeIn 0.0" self.noTransitions() self.loadFade() self.fade.detachNode() else: # Create a sequence that lerps the color out, then # parents the fade to hidden self.transitionIval = self.getFadeInIval(t, finishIval) self.transitionIval.start() def fadeOut(self, t=0.5, finishIval=None): """ Play a fade out transition over t seconds. Places a polygon on the aspect2d plane then lerps the color from transparent to full black. When the color lerp is finished, it leaves the fade polygon covering the aspect2d plane until you fadeIn or call noFade. lerp """ if (t == 0): # Fade out immediately with no lerp self.noTransitions() self.loadFade() self.fade.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) self.fade.setColor(self.alphaOn) elif ConfigVariableBool('no-loading-screen', False): if finishIval: self.transitionIval = finishIval self.transitionIval.start() else: # Create a sequence that lerps the color out, then # parents the fade to hidden self.transitionIval = self.getFadeOutIval(t, finishIval) self.transitionIval.start() def fadeOutActive(self): return self.fade and self.fade.getColor()[3] > 0 def fadeScreen(self, alpha=0.5): """ Put a semitransparent screen over the camera plane to darken out the world. Useful for drawing attention to a dialog box for instance """ #print "transitiosn: fadeScreen" self.noTransitions() self.loadFade() self.fade.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) self.fade.setColor(self.alphaOn[0], self.alphaOn[1], self.alphaOn[2], alpha) def fadeScreenColor(self, color): """ Put a semitransparent screen over the camera plane to darken out the world. Useful for drawing attention to a dialog box for instance """ #print "transitiosn: fadeScreenColor" self.noTransitions() self.loadFade() self.fade.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) self.fade.setColor(color) def noFade(self): """ Removes any current fade tasks and parents the fade polygon away """ #print "transitiosn: noFade" if self.transitionIval: self.transitionIval.pause() self.transitionIval = None if self.fade: # Make sure to reset the color, since fadeOutActive() is looking at it self.fade.setColor(self.alphaOff) self.fade.detachNode() def setFadeColor(self, r, g, b): self.alphaOn.set(r, g, b, 1) self.alphaOff.set(r, g, b, 0) ################################################## # Iris ################################################## def loadIris(self): if self.iris == None: self.iris = loader.loadModel(self.IrisModelName) self.iris.setPos(0, 0, 0) def irisIn(self, t=0.5, finishIval=None): """ Play an iris in transition over t seconds. Places a polygon on the aspect2d plane then lerps the scale of the iris polygon up so it looks like we iris in. When the scale lerp is finished, it parents the iris polygon to hidden. """ self.noTransitions() self.loadIris() if (t == 0): self.iris.detachNode() else: self.iris.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) self.transitionIval = Sequence( LerpScaleInterval(self.iris, t, scale=0.18, startScale=0.01), Func(self.iris.detachNode), name=self.irisTaskName, ) if finishIval: self.transitionIval.append(finishIval) self.transitionIval.start() def irisOut(self, t=0.5, finishIval=None): """ Play an iris out transition over t seconds. Places a polygon on the aspect2d plane then lerps the scale of the iris down so it looks like we iris out. When the scale lerp is finished, it leaves the iris polygon covering the aspect2d plane until you irisIn or call noIris. """ self.noTransitions() self.loadIris() self.loadFade() # we need this to cover up the hole. if (t == 0): self.iris.detachNode() self.fadeOut(0) else: self.iris.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) self.transitionIval = Sequence( LerpScaleInterval(self.iris, t, scale=0.01, startScale=0.18), Func(self.iris.detachNode), # Use the fade to cover up the hole that the iris would leave Func(self.fadeOut, 0), name=self.irisTaskName, ) if finishIval: self.transitionIval.append(finishIval) self.transitionIval.start() def noIris(self): """ Removes any current iris tasks and parents the iris polygon away """ if self.transitionIval: self.transitionIval.pause() self.transitionIval = None if self.iris != None: self.iris.detachNode() # Actually we need to remove the fade too, # because the iris effect uses it. self.noFade() def noTransitions(self): """ This call should immediately remove any and all transitions running """ self.noFade() self.noIris() # Letterbox is not really a transition, it is a screen overlay # self.noLetterbox() ################################################## # Letterbox ################################################## def loadLetterbox(self): if not self.letterbox: # We create a DirectFrame for the fade polygon, instead of # simply loading the polygon model and using it directly, # so that it will also obscure mouse events for objects # positioned behind it. self.letterbox = NodePath("letterbox") # Allow fade in and out of the bars self.letterbox.setTransparency(1) # Allow DirectLabels to be parented to the letterbox sensibly self.letterbox.setBin('unsorted', 0) # Allow a custom look to the letterbox graphic. # TODO: This model isn't available everywhere. We should # pass it in as a parameter. button = loader.loadModel('models/gui/toplevel_gui', okMissing=True) barImage = None if button: barImage = button.find('**/generic_button') self.letterboxTop = DirectFrame( parent=self.letterbox, guiId='letterboxTop', relief=DGG.FLAT, state=DGG.NORMAL, frameColor=(0, 0, 0, 1), borderWidth=(0, 0), frameSize=(-1, 1, 0, 0.2), pos=(0, 0, 0.8), image=barImage, image_scale=(2.25, 1, .5), image_pos=(0, 0, .1), image_color=(0.3, 0.3, 0.3, 1), sortOrder=0, ) self.letterboxBottom = DirectFrame( parent=self.letterbox, guiId='letterboxBottom', relief=DGG.FLAT, state=DGG.NORMAL, frameColor=(0, 0, 0, 1), borderWidth=(0, 0), frameSize=(-1, 1, 0, 0.2), pos=(0, 0, -1), image=barImage, image_scale=(2.25, 1, .5), image_pos=(0, 0, .1), image_color=(0.3, 0.3, 0.3, 1), sortOrder=0, ) # masad: always place these at the bottom of render self.letterboxTop.setBin('sorted', 0) self.letterboxBottom.setBin('sorted', 0) self.letterbox.reparentTo(render2d, -1) self.letterboxOff(0) def noLetterbox(self): """ Removes any current letterbox tasks and parents the letterbox polygon away """ if self.letterboxIval: self.letterboxIval.pause() self.letterboxIval = None if self.letterbox: self.letterbox.stash() def letterboxOn(self, t=0.25, finishIval=None): """ Move black bars in over t seconds. """ self.noLetterbox() self.loadLetterbox() self.letterbox.unstash() if (t == 0): self.letterboxBottom.setPos(0, 0, -1) self.letterboxTop.setPos(0, 0, 0.8) else: self.letterboxIval = Sequence( Parallel( LerpPosInterval( self.letterboxBottom, t, pos=Vec3(0, 0, -1), #startPos = Vec3(0, 0, -1.2), ), LerpPosInterval( self.letterboxTop, t, pos=Vec3(0, 0, 0.8), # startPos = Vec3(0, 0, 1), ), ), name=self.letterboxTaskName, ) if finishIval: self.letterboxIval.append(finishIval) self.letterboxIval.start() def letterboxOff(self, t=0.25, finishIval=None): """ Move black bars away over t seconds. """ self.noLetterbox() self.loadLetterbox() self.letterbox.unstash() if (t == 0): self.letterbox.stash() else: self.letterboxIval = Sequence( Parallel( LerpPosInterval( self.letterboxBottom, t, pos=Vec3(0, 0, -1.2), # startPos = Vec3(0, 0, -1), ), LerpPosInterval( self.letterboxTop, t, pos=Vec3(0, 0, 1), # startPos = Vec3(0, 0, 0.8), ), ), Func(self.letterbox.stash), Func(messenger.send, 'letterboxOff'), name=self.letterboxTaskName, ) if finishIval: self.letterboxIval.append(finishIval) self.letterboxIval.start()
class panda3dIOClass( DirectObject.DirectObject ): # set gui key to None if you want to call toggleConsole from outside this class gui_key = PANDA3D_CONSOLE_TOGGLE_KEY autocomplete_key = PANDA3D_CONSOLE_AUTOCOMPLETE_KEY autohelp_key = PANDA3d_CONSOLE_AUTOHELP_KEY # change size of text and number of characters on one line # scale of frame ( must be small (0.0x) scale = PANDA3D_CONSOLE_SCALE # to define a special font, if loading fails the default font is used (without warning) font = PANDA3D_CONSOLE_FONT fontWidth = PANDA3D_CONSOLE_FONT_WIDTH # frame position and size (vertical & horizontal) h_pos = PANDA3D_CONSOLE_HORIZONTAL_POS h_size = PANDA3D_CONSOLE_HORIZONTAL_SIZE # v_size + v_pos should not exceed 2.0, else parts of the interface will not be visible # space above the frame ( must be below 2.0, best between 0.0 and 1.0 ) v_pos = PANDA3D_CONSOLE_VERTICAL_POS # vertical size of the frame ( must be at max 2.0, best between 0.5 and 2.0 ) v_size = PANDA3D_CONSOLE_VERTICAL_SIZE linelength = int((h_size/scale - 5) / fontWidth) print "max number of characters on a length:", linelength numlines = int(v_size/scale - 5) defaultTextColor = (0.0,0.0,0.0,1.0) autoCompleteColor = (0.9,0.4,0.2,1.0) def __init__( self, parent ): self.parent = parent # line wrapper self.linewrap = textwrap.TextWrapper() self.linewrap.width = self.linelength # calculate window size left = (self.h_pos) / self.scale right = (self.h_pos + self.h_size) / self.scale bottom = (self.v_pos) / self.scale top = (self.v_pos + self.v_size) /self.scale # panda3d interface self.consoleFrame = DirectFrame ( relief = DGG.GROOVE , frameColor = (200, 200, 200, 0.5) , scale=self.scale , frameSize = (0, self.h_size / self.scale, 0, self.v_size / self.scale) ) # vardis 27-02-2009: Added special cull bin in order to render on top of everything CullBinManager.getGlobalPtr().addBin(PanoConstants.CONSOLE_CULL_BIN_NAME, CullBinManager.BTUnsorted, PanoConstants.CONSOLE_CULL_BIN_VAL) self.consoleFrame.setBin("fixed", PanoConstants.RENDER_ORDER_CONSOLE) self.windowEvent( base.win ) # try to load the defined font fixedWidthFont = loader.loadFont(parent.game.getResources().getResourceFullPath(PanoConstants.RES_TYPE_FONTS, self.font)) # if font is not valid use default font if not fixedWidthFont.isValid(): if self.font is None: print "pandaInteractiveConsole.py :: could not load the defined font %s" % str(self.font) fixedWidthFont = DGG.getDefaultFont() # text entry line self.consoleEntry = DirectEntry ( self.consoleFrame , text = "" , command = self.onEnterPress , width = self.h_size/self.scale - 2 , pos = (1, 0, 1.5) , initialText = "" , numLines = 1 , focus = 1 , entryFont = fixedWidthFont) # output lines self.consoleOutputList = list() for i in xrange( self.numlines ): label = OnscreenText( parent = self.consoleFrame , text = "" , pos = (1, -i+3+self.numlines) , align=TextNode.ALeft , mayChange=1 , scale=1.0 , fg = self.defaultTextColor ) label.setFont( fixedWidthFont ) self.consoleOutputList.append( label ) # list of the last commands of the user self.userCommandList = list() self.userCommandListLength = 100 for i in xrange(self.userCommandListLength): self.userCommandList.append('') self.userCommandPos = 0 # buffer for data self.textBuffer = list() self.textBufferLength = 1000 for i in xrange(self.textBufferLength): self.textBuffer.append(['', DEFAULT_COLOR]) self.textBufferPos = self.textBufferLength-self.numlines # toggle the window at least once to activate the events self.toggleConsole() self.toggleConsole() self.help() def help( self ): # output some info text about this module infoTxt = """ ------ Panda3dConsole ------ - press F1 to toggle it on/off - use the usual copy, cut & paste keys - page_up : scrolls up - page_down : scrolls down - arrow_up : previous command - arrow_down : next command - BUGS : if you paste a to long text, the entry blocks FIX : use cut to remove the whole line""" #for line in infoTxt.split('\n'): # self.write( line, color=DEFAULT_COLOR ) return infoTxt # write a string to the panda3d console def write( self, printString, color=defaultTextColor ): # remove not printable characters (which can be input by console input) printString = re.sub( r'[^%s]' % re.escape(string.printable[:95]), "", printString) splitLines = self.linewrap.wrap(printString) for line in splitLines: self.textBuffer.append( [line, color] ) self.textBuffer.pop(0) self.updateOutput() def updateOutput( self ): for lineNumber in xrange(self.numlines): lineText, color = self.textBuffer[lineNumber + self.textBufferPos] self.consoleOutputList[lineNumber].setText( lineText ) self.consoleOutputList[lineNumber]['fg'] = color # toggle the gui console def toggleConsole( self ): self.consoleFrame.toggleVis() hidden = self.consoleFrame.isHidden() self.consoleEntry['focus'] != hidden if hidden: self.ignoreAll() # self.accept( self.gui_key, self.toggleConsole ) else: self.ignoreAll() self.accept( 'page_up', self.scroll, [-5] ) self.accept( 'page_up-repeat', self.scroll, [-5] ) self.accept( 'page_down', self.scroll, [5] ) self.accept( 'page_down-repeat', self.scroll, [5] ) self.accept( 'window-event', self.windowEvent) self.accept( 'arrow_up' , self.scrollCmd, [ 1] ) self.accept( 'arrow_down', self.scrollCmd, [-1] ) # self.accept( self.gui_key, self.toggleConsole ) self.accept( self.autocomplete_key, self.autocomplete ) self.accept( self.autohelp_key, self.autohelp ) # accept v, c and x, where c & x copy's the whole console text #messenger.toggleVerbose() #for osx use ('meta') if sys.platform == 'darwin': self.accept( 'meta', self.unfocus ) self.accept( 'meta-up', self.focus ) self.accept( 'meta-c', self.copy ) self.accept( 'meta-x', self.cut ) self.accept( 'meta-v', self.paste ) #for windows use ('control') if sys.platform == 'win32' or sys.platform == 'linux2': self.accept( 'control', self.unfocus ) self.accept( 'control-up', self.focus ) self.accept( 'control-c', self.copy ) self.accept( 'control-x', self.cut ) self.accept( 'control-v', self.paste ) def autocomplete( self ): currentText = self.consoleEntry.get() currentPos = self.consoleEntry.guiItem.getCursorPosition() newText = self.parent.autocomplete( currentText, currentPos ) if newText != currentText: self.consoleEntry.set( newText ) self.consoleEntry.setCursorPosition( len(newText) ) def autohelp( self ): currentText = self.consoleEntry.get() currentPos = self.consoleEntry.guiItem.getCursorPosition() self.parent.autohelp( currentText, currentPos ) def focus( self ): self.consoleEntry['focus'] = 1 def unfocus( self ): self.consoleEntry['focus'] = 0 def copy( self ): copy = self.consoleEntry.get() clipboard.setText( copy ) def paste( self ): oldCursorPos = self.consoleEntry.guiItem.getCursorPosition() clipboardText = clipboard.getText() # compose new text line oldText = self.consoleEntry.get() newText = oldText[0:oldCursorPos] + clipboardText + oldText[oldCursorPos:] clipboardTextLines = newText.split(os.linesep) for i in xrange( len(clipboardTextLines)-1 ): currentLine = clipboardTextLines[i] # we only want printable characters currentLine = re.sub( r'[^' + re.escape(string.printable[:95]) + ']', "", currentLine) # set new text and position self.consoleEntry.set( currentLine ) self.onEnterPress( currentLine ) currentLine = clipboardTextLines[-1] currentLine = re.sub( r'[^' + re.escape(string.printable[:95]) + ']', "", currentLine) self.consoleEntry.set( currentLine ) self.consoleEntry.setCursorPosition( len(self.consoleEntry.get()) ) self.focus() def cut( self ): clipboard.setText( self.consoleEntry.get() ) self.consoleEntry.enterText('') self.focus() def scroll( self, step ): self.textBufferPos += step self.textBufferPos = min( self.textBufferLength-self.numlines, max( 0, self.textBufferPos ) ) self.updateOutput() def scrollCmd( self, step ): oldCmdPos = self.userCommandPos self.userCommandPos += step self.userCommandPos = min( self.userCommandListLength-1, max( 0, self.userCommandPos ) ) self.userCommandList[oldCmdPos] = self.consoleEntry.get() newCmd = self.userCommandList[self.userCommandPos] self.consoleEntry.set( newCmd ) self.consoleEntry.setCursorPosition( len(newCmd) ) def onEnterPress( self, textEntered ): # set to last message self.textBufferPos = self.textBufferLength-self.numlines # clear line self.consoleEntry.enterText('') self.focus() # add text entered to user command list & remove oldest entry self.userCommandList.insert( 1, textEntered ) self.userCommandList[0] = '' self.userCommandList.pop( -1 ) self.userCommandPos = 0 # call our parent self.parent.push( textEntered ) def windowEvent( self, window ): """ This is a special callback. It is called when the panda window is modified. """ wp = window.getProperties() width = wp.getXSize() / float(wp.getYSize()) height = wp.getYSize() / float(wp.getXSize()) if width > height: height = 1.0 else: width = 1.0 # aligned to center consolePos = Vec3(-self.h_size/2, 0, -self.v_size/2) # aligned to left bottom #consolePos = Vec3(-width+self.h_pos, 0, -height+self.v_pos) # aligned to right top #consolePos = Vec3(width-self.h_size, 0, height-self.v_size) # set position self.consoleFrame.setPos( consolePos )
class DeathNotifications(DirectObject): MESSAGE_LIFE = 5 MAX_NUM_MESSAGES = 10 def __init__(self): self.textNodes = [] self.rootFrame = DirectFrame(pos = (-0.05, 0, -0.25), frameColor = (0, 0, 0, 0), frameSize = (0, 1, 0, 1), parent = base.a2dTopRight) self.rootFrame.setBin('fixed', GUIOrder.ORDER[GUIOrder.CHAT]) self.displayFrame = DirectFrame(pos = (0, 0, 0), frameColor = (0, 0, 0, 0), frameSize = (0, 1, 0, 0.42), parent = self.rootFrame) self.accept(PlayerDeathEvent.EventName, self.OnPlayerDeathEvent) def OnPlayerDeathEvent(self, event): player = event.GetPlayer() attacker = event.GetAttacker() wasHS = event.WasHeadshot() if(not attacker.currentItem): itemName = '???' else: itemName = attacker.currentItem.GetName() self.AddMessage(victimName = player.GetPlayerState().GetValue(PlayerState.NAME), attackerName = attacker.GetPlayerState().GetValue(PlayerState.NAME), itemName = itemName, attackerColor = Globals.TEAM_COLORS[attacker.GetPlayerState().GetValue(PlayerState.TEAM)], victimColor = Globals.TEAM_COLORS[player.GetPlayerState().GetValue(PlayerState.TEAM)]) def AddMessage(self, victimName, attackerName, itemName, attackerColor = Globals.COLOR_WHITE, victimColor = Globals.COLOR_WHITE): parent = self.displayFrame.attachNewNode('messageParent') attackerTextNode = TextNode('attackerTextNode') attackerTextNode.setText(attackerName) attackerTextNode.setTextColor(attackerColor) attackerTextNode.setShadow(0.05, 0.05) attackerTextNode.setShadowColor(Globals.COLOR_BLACK) attackerTextNodePath = parent.attachNewNode(attackerTextNode) attackerTextNodePath.setScale(Settings.CHAT_HEIGHT) attackerTextNodePath.setPos(Vec3(-attackerTextNode.calcWidth('%s [%s] %s' % (attackerName, itemName, victimName)) * Settings.CHAT_HEIGHT, 0, 0)) itemNameTextNode = TextNode('itemNameTextNode') itemNameTextNode.setText('[%s]' % (itemName)) itemNameTextNode.setTextColor(Globals.COLOR_WHITE) itemNameTextNode.setShadow(0.05, 0.05) itemNameTextNode.setShadowColor(Globals.COLOR_BLACK) itemNameTextNodePath = parent.attachNewNode(itemNameTextNode) itemNameTextNodePath.setScale(Settings.CHAT_HEIGHT) itemNameTextNodePath.setPos(Vec3(-attackerTextNode.calcWidth('[%s] %s' % (itemName, victimName)) * Settings.CHAT_HEIGHT, 0, 0)) victimTextNode = TextNode('prefixMessage') victimTextNode.setText(victimName) victimTextNode.setTextColor(victimColor) victimTextNode.setShadow(0.05, 0.05) victimTextNode.setShadowColor(Globals.COLOR_BLACK) victimTextNodePath = parent.attachNewNode(victimTextNode) victimTextNodePath.setScale(Settings.CHAT_HEIGHT) victimTextNodePath.setPos(Vec3(-attackerTextNode.calcWidth(victimName) * Settings.CHAT_HEIGHT, 0, 0)) taskMgr.remove('HideMessageLog') taskMgr.doMethodLater(DeathNotifications.MESSAGE_LIFE, self.RemoveMessage, 'RemoveMessage', extraArgs = [parent]) self.textNodes.append(parent) if(len(self.textNodes) > DeathNotifications.MAX_NUM_MESSAGES): self.RemoveMessage(self.textNodes[0]) self.RedrawMessages() def RedrawMessages(self): n = len(self.textNodes) for i, textNode in enumerate(self.textNodes): LerpPosInterval(textNode, 0.5, (0, 0, -(n-i) * (Settings.CHAT_HEIGHT + 0.01))).start() def RemoveMessage(self, textNode): if(textNode in self.textNodes): self.textNodes.remove(textNode) textNode.removeNode() def Destroy(self): taskMgr.remove('HideMessageLog') self.rootFrame.destroy() self.entryFrame.destroy() self.chatarea.destroy() self.typeText.destroy() self.displayFrame.destroy() self.ignoreAll()
class LaffOMeter(DirectFrame): deathColor = Vec4(0.58039216, 0.80392157, 0.34117647, 1.0) def __init__(self, forRender=False): DirectFrame.__init__(self, relief=None, sortOrder=50, parent=base.a2dBottomLeft) self.initialiseoptions(LaffOMeter) self.container = DirectFrame(parent=self, relief=None) self.container.setBin('gui-popup', 60) if forRender: self.container.setY(0) self.setLightOff() self.setFogOff() self.setMaterialOff() self.hide(CIGlobals.ShadowCameraBitmask) self.forRender = forRender def generate(self, r, g, b, animal, maxHP=50, initialHP=50): self.maxHP = maxHP self.initialHP = initialHP self.color = (r, g, b, 1) gui = loader.loadModel("phase_3/models/gui/laff_o_meter.bam") if animal == "rabbit": animal = "bunny" headmodel = gui.find('**/' + animal + 'head') self.container['image'] = headmodel self.container['image_color'] = self.color if animal == 'monkey': self.setPos(0.153, 0.0, 0.13) else: self.setPos(0.133, 0, 0.13) self.resetFrameSize() self.setScale(0.075) self.frown = DirectFrame(parent=self.container, relief=None, image=gui.find('**/frown')) self.smile = DirectFrame(parent=self.container, relief=None, image=gui.find('**/smile')) self.eyes = DirectFrame(parent=self.container, relief=None, image=gui.find('**/eyes')) self.openSmile = DirectFrame(parent=self.container, relief=None, image=gui.find('**/open_smile')) self.tooth1 = DirectFrame(parent=self.openSmile, relief=None, image=gui.find('**/tooth_1')) self.tooth2 = DirectFrame(parent=self.openSmile, relief=None, image=gui.find('**/tooth_2')) self.tooth3 = DirectFrame(parent=self.openSmile, relief=None, image=gui.find('**/tooth_3')) self.tooth4 = DirectFrame(parent=self.openSmile, relief=None, image=gui.find('**/tooth_4')) self.tooth5 = DirectFrame(parent=self.openSmile, relief=None, image=gui.find('**/tooth_5')) self.tooth6 = DirectFrame(parent=self.openSmile, relief=None, image=gui.find('**/tooth_6')) self.teethList = [ self.tooth6, self.tooth5, self.tooth4, self.tooth3, self.tooth2, self.tooth1 ] if self.forRender: self.container['image_pos'] = (0, 0.01, 0) for tooth in self.teethList: tooth.setDepthWrite(False) self.eyes.setDepthWrite(False) self.smile.setDepthWrite(False) self.openSmile.setDepthWrite(False) self.frown.setDepthWrite(False) self.fractions = [0.0, 0.166666, 0.333333, 0.5, 0.666666, 0.833333] self.currentHealthLbl = DirectLabel(text=str(self.initialHP), parent=self.eyes, pos=(-0.425, 0, 0.05), scale=0.4, relief=None) self.maxHealthLbl = DirectLabel(text=str(self.maxHP), parent=self.eyes, pos=(0.425, 0, 0.05), scale=0.4, relief=None) if self.forRender: self.currentHealthLbl.setY(-0.01) self.maxHealthLbl.setY(-0.01) self.updateMeter(self.initialHP) gui.removeNode() return def start(self): taskMgr.add(self.updateMeterTask, "updateMeterTask") def updateMeterTask(self, task): if hasattr(base, 'localAvatar'): if str(base.localAvatar.getHealth() ) != self.currentHealthLbl['text']: self.updateMeter(base.localAvatar.getHealth()) else: return task.done return task.cont def updateMeter(self, health): self.adjustFace(health) def adjustFace(self, health): self.frown.hide() self.smile.hide() self.openSmile.hide() self.eyes.hide() for tooth in self.teethList: tooth.hide() if health <= 0: self.frown.show() self.container['image_color'] = self.deathColor elif health >= self.maxHP: self.smile.show() self.eyes.show() self.container['image_color'] = self.color else: self.openSmile.show() self.eyes.show() self.maxHealthLbl.show() self.currentHealthLbl.show() self.container['image_color'] = self.color self.adjustTeeth(health) self.animatedEffect(health - self.initialHP) self.adjustText(health) def animatedEffect(self, delta): if delta == 0: return name = 'effect' if delta > 0: ToontownIntervals.start( ToontownIntervals.getPulseLargerIval(self.container, name)) else: ToontownIntervals.start( ToontownIntervals.getPulseSmallerIval(self.container, name)) def adjustTeeth(self, health): for i in xrange(len(self.teethList)): if health > self.maxHP * self.fractions[i]: self.teethList[i].show() else: self.teethList[i].hide() def adjustText(self, health): if self.maxHealthLbl['text'] != str( self.maxHP) or self.currentHealthLbl['text'] != str(health): self.currentHealthLbl['text'] = str(health) def stop(self): taskMgr.remove("updateMeterTask") def disable(self): if not hasattr(self, 'frown'): notify.warning("Won't disable LaffOMeter, no var named frown.") return self.frown.destroy() self.smile.destroy() self.eyes.destroy() self.openSmile.destroy() self.tooth1.destroy() self.tooth2.destroy() self.tooth3.destroy() self.tooth4.destroy() self.tooth5.destroy() self.tooth6.destroy() del self.frown del self.smile del self.eyes del self.openSmile del self.tooth1 del self.tooth2 del self.tooth3 del self.tooth4 del self.tooth5 del self.tooth6 self.container["image"] = None return def delete(self): self.container.destroy() del self.container return
class OptionsMenu(DirectObject): def __init__(self): """Default constructor""" # create a main frame as big as the window self.frameMain = DirectFrame( # set framesize the same size as the window frameSize=(base.a2dLeft, base.a2dRight, base.a2dTop, base.a2dBottom), image="LogoTextGlow.png", image_scale=(1.06 / 2.0, 1, 0.7 / 2.0), image_pos=(0, 0, 0.7), # position center pos=(0, 0, 0), # set tramsparent background color frameColor=(0, 0, 0, 0)) self.frameMain.setTransparency(1) self.frameMain.setBin("fixed", 100) sliderscale = 0.5 buttonScale = 0.25 textscale = 0.1 checkboxscale = 0.05 left = -0.5 right = 0.5 self.sliderTextspeed = DirectSlider( scale=sliderscale, pos=(left, 0, 0.2), range=(0.2, 0.01), scrollSize=0.01, text=_("Textspeed %0.1f%%") % (base.textWriteSpeed * 10), text_scale=textscale, text_align=TextNode.ACenter, text_pos=(0.0, 0.15), text_fg=(1, 1, 1, 1), thumb_frameColor=(0.65, 0.65, 0.0, 1), thumb_relief=DGG.FLAT, frameColor=(0.15, 0.15, 0.15, 1), value=base.textWriteSpeed, command=self.sliderTextspeed_ValueChanged) self.sliderTextspeed.reparentTo(self.frameMain) self.cbParticles = DirectCheckButton( text=_(" Enable Particles"), text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 0.35), pos=(left, 0, -0.0), scale=checkboxscale, frameColor=(0, 0, 0, 0), command=self.cbParticles_CheckedChanged, rolloverSound=None, clickSound=None, pressEffect=False, boxPlacement="below", boxBorder=0.8, boxRelief=DGG.FLAT, indicator_scale=1.5, indicator_text_fg=(0.65, 0.65, 0.0, 1), indicator_text_shadow=(0, 0, 0, 0.35), indicator_frameColor=(0.15, 0.15, 0.15, 1), indicatorValue=base.particleMgrEnabled) self.cbParticles.indicator['text'] = (' ', 'x') self.cbParticles.indicator['text_pos'] = (0, 0.1) #self.cbParticles.indicator.setX(self.cbParticles.indicator, -0.5) #self.cbParticles.indicator.setZ(self.cbParticles.indicator, -0.1) #self.cbParticles.setFrameSize() self.cbParticles.setTransparency(1) self.cbParticles.reparentTo(self.frameMain) volume = base.musicManager.getVolume() self.sliderVolume = DirectSlider( scale=sliderscale, pos=(left, 0, -0.35), range=(0, 1), scrollSize=0.01, text=_("Volume %d%%") % volume * 100, text_scale=textscale, text_align=TextNode.ACenter, text_pos=(.0, 0.15), text_fg=(1, 1, 1, 1), thumb_frameColor=(0.65, 0.65, 0.0, 1), thumb_relief=DGG.FLAT, frameColor=(0.15, 0.15, 0.15, 1), value=volume, command=self.sliderVolume_ValueChanged) self.sliderVolume.reparentTo(self.frameMain) self.lblControltype = DirectLabel(text=_("Control type"), text_fg=(1, 1, 1, 1), text_shadow=(0, 0, 0, 0.35), frameColor=(0, 0, 0, 0), scale=textscale / 2, pos=(right, 0, 0.27)) self.lblControltype.setTransparency(1) self.lblControltype.reparentTo(self.frameMain) selectedControlType = 0 if base.controlType == "MouseAndKeyboard": selectedControlType = 1 self.controltype = DirectOptionMenu( pos=(right, 0, 0.18), text_fg=(1, 1, 1, 1), scale=0.1, items=[_("Keyboard"), _("Keyboard + Mouse")], initialitem=selectedControlType, frameColor=(0.15, 0.15, 0.15, 1), popupMarker_frameColor=(0.65, 0.65, 0.0, 1), popupMarker_relief=DGG.FLAT, highlightColor=(0.65, 0.65, 0.0, 1), relief=DGG.FLAT, command=self.controlType_Changed) self.controltype.reparentTo(self.frameMain) b = self.controltype.getBounds() xPos = right - ((b[1] - b[0]) / 2.0 * 0.1) self.controltype.setX(xPos) setItems(self.controltype) self.controltype.setItems = setItems self.controltype.showPopupMenu = showPopupMenu self.controltype.popupMarker.unbind(DGG.B1PRESS) self.controltype.popupMarker.bind(DGG.B1PRESS, showPopupMenu) self.controltype.unbind(DGG.B1PRESS) self.controltype.bind(DGG.B1PRESS, showPopupMenuExtra, [self.controltype]) isChecked = not base.AppHasAudioFocus img = None if base.AppHasAudioFocus: img = "AudioSwitch_on.png" else: img = "AudioSwitch_off.png" self.cbVolumeMute = DirectCheckBox( text=_("Mute Audio"), text_scale=0.5, text_align=TextNode.ACenter, text_pos=(0.0, 0.65), text_fg=(1, 1, 1, 1), pos=(right, 0, -0.35), scale=0.21 / 2.0, command=self.cbVolumeMute_CheckedChanged, rolloverSound=None, clickSound=None, relief=None, pressEffect=False, isChecked=isChecked, image=img, image_scale=0.5, checkedImage="AudioSwitch_off.png", uncheckedImage="AudioSwitch_on.png") self.cbVolumeMute.setTransparency(1) self.cbVolumeMute.setImage() self.cbVolumeMute.reparentTo(self.frameMain) sensitivity = base.mouseSensitivity self.sliderSensitivity = DirectSlider( scale=sliderscale, pos=(right, 0, -0.075), range=(0.5, 2), scrollSize=0.01, text=_("Mouse Sensitivity %0.1fx") % sensitivity, text_scale=textscale, text_align=TextNode.ACenter, text_pos=(.0, 0.15), text_fg=(1, 1, 1, 1), thumb_frameColor=(0.65, 0.65, 0.0, 1), thumb_relief=DGG.FLAT, frameColor=(0.15, 0.15, 0.15, 1), value=sensitivity, command=self.sliderSensitivity_ValueChanged) self.sliderSensitivity.reparentTo(self.frameMain) if base.controlType == "Gamepad": self.sliderSensitivity.hide() # create the back button self.btnBack = DirectButton( scale=buttonScale, # position on the window pos=(0, 0, base.a2dBottom + 0.15), frameColor=(0, 0, 0, 0), # text properties text=_("Back"), text_scale=0.5, text_fg=(1, 1, 1, 1), text_pos=(0.0, -0.15), text_shadow=(0, 0, 0, 0.35), text_shadowOffset=(-0.05, -0.05), # sounds that should be played rolloverSound=None, clickSound=None, pressEffect=False, relief=None, # the event which is thrown on clickSound command=lambda: base.messenger.send("options_back")) self.btnBack.setTransparency(1) self.btnBack.reparentTo(self.frameMain) self.hide() def show(self, enableResume=False): self.frameMain.show() def hide(self): self.frameMain.hide() def cbVolumeMute_CheckedChanged(self, checked): if checked: base.disableAllAudio() else: base.enableAllAudio() def sliderVolume_ValueChanged(self): volume = round(self.sliderVolume["value"], 2) self.sliderVolume["text"] = _("Volume %d%%") % int(volume * 100) base.sfxManagerList[0].setVolume(volume) base.musicManager.setVolume(volume) def sliderSensitivity_ValueChanged(self): sensitivity = round(self.sliderSensitivity["value"], 2) self.sliderSensitivity["text"] = _( "Mouse Sensitivity %0.1fx") % sensitivity base.mouseSensitivity = sensitivity def sliderTextspeed_ValueChanged(self): newSpeed = round(self.sliderTextspeed["value"], 2) displaySpeed = 1.0 / newSpeed self.sliderTextspeed["text"] = _("Textspeed %0.1f%%") % displaySpeed base.textWriteSpeed = newSpeed def cbParticles_CheckedChanged(self, unchecked): if unchecked: base.enableParticles() else: base.disableParticles() def controlType_Changed(self, arg): if arg == _("Keyboard"): self.sliderSensitivity.hide() base.controlType = "Gamepad" elif arg == _("Keyboard + Mouse"): self.sliderSensitivity.show() base.controlType = "MouseAndKeyboard"
class RewardPanel(DirectFrame): notify = directNotify.newCategory('RewardPanel') def __init__(self, panelData): dialogBox = loader.loadModel('phase_3/models/gui/dialog_box_gui.bam') DirectFrame.__init__(self, relief=None, geom=dialogBox, geom_color=CIGlobals.DialogColor, geom_scale=(1.75, 1, 0.75 * 1.1), geom_pos=Point3(0, 0, -0.05), pos=(0, 0, 0.661)) self.initialiseoptions(RewardPanel) self.setScale(0.8) # The data for the reward panel inside of a RPToonData object. self.panelData = panelData # Top wood panel saying Reward Panel gagShopNodes = loader.loadModel( 'phase_4/models/gui/gag_shop_purchase_gui.bam') # Original pos: (-0.02, 0, 0.3) scale = (1.55, 1, 1) self.titlePanel = OnscreenImage( parent=self, image=gagShopNodes.find('**/Goofys_Sign'), pos=(0, 0, 0.3), hpr=(1, 0, 0), scale=(1.3, 1, 0.9)) self.avatarNamePanel = DirectFrame(parent=self.titlePanel, pos=(0, 0.005, 0)) self.avatarText = OnscreenText(parent=self.avatarNamePanel, text='', font=CIGlobals.getMickeyFont(), fg=(0.698, 0.13, 0.13, 1), mayChange=1, scale=(0.1, 0.13, 0.1)) self.panelContentsTitle = OnscreenText(parent=self, text=GagPanelName, font=CIGlobals.getMickeyFont(), pos=(0, 0.24, 0), fg=(0.3725, 0.619, 0.627, 1), mayChange=1) self.playerInfo = DirectFrame(parent=self, relief=None, pos=(-0.5, 0, 0)) self.playerInfo.setBin('gui-popup', 0) self.bonusText = OnscreenText(parent=self.playerInfo, text='2X Cog Office Bonus!', font=CIGlobals.getToonFont(), pos=(0, 0.15, 0), scale=(0.055, 0.055, 0.055), align=TextNode.ACenter) self.bonusText.hide() ################################################################################## # GUI Elements relating to the Favorite Gag/Gag Popup Used for showing Gag Unlock# ################################################################################## self.favoriteGagText = OnscreenText(parent=self.playerInfo, text=FavoriteGag, font=CIGlobals.getMickeyFont(), pos=FavoriteGagTitlePos, fg=(1, 0.2, 0.2, 1), sort=0) glow = loader.loadModel('phase_4/models/minigames/particleGlow.bam') self.favoriteGagGlow = OnscreenImage(parent=self.playerInfo, image=glow, pos=FavoriteGagPos, color=GagGlowColor, scale=(0.8, 0.8, 0.8)) self.favoriteGagGlow.setBin('gui-popup', 10) # particleGlow.bam uses a material since it's normally part of render, not render2d. # Since render2d is still fixed-function, we have to explicitly enable shader generation # to correctly display the glow in render2d. self.favoriteGagGlow.setShaderAuto() invIcons = loader.loadModel('phase_3.5/models/gui/inventory_icons.bam') gag = invIcons.find( GagGlobals.InventoryIconByName.get(GagGlobals.Foghorn)) self.favoriteGag = OnscreenImage(parent=self.playerInfo, image=gag, pos=FavoriteGagPos, scale=(1.65, 1.65, 1.65)) self.favoriteGag.setBin('gui-popup', 20) self.favoriteGagName = OnscreenText(parent=self.playerInfo, text=GagGlobals.Foghorn, font=CIGlobals.getToonFont(), pos=FavoriteGagNamePos, mayChange=1) ################################################################################ # GUI elements showing gag experience on the right-side of the gag exp panel # ################################################################################ self.gagExpFrame = DirectFrame(parent=self, relief=None, pos=(0.085, 0, 0.15)) self.trackLabels = [] self.trackIncLabels = [] self.trackBars = [] self.trackBarsOffset = 0 for i in range(len(GagGlobals.TrackNameById.values())): track = GagGlobals.TrackNameById.values()[i] color = GagGlobals.TrackColorByName.get(track) label = DirectLabel(parent=self.gagExpFrame, relief=None, text=track.upper(), text_scale=0.05, text_align=TextNode.ARight, pos=(0.13, 0, -0.09 * i), text_pos=(0, -0.02)) incrementLabel = DirectLabel(parent=self.gagExpFrame, relief=None, text='', text_scale=0.05, text_align=TextNode.ALeft, pos=(0.65, 0, -0.09 * i), text_pos=(0, -0.02)) progressBar = DirectWaitBar( parent=self.gagExpFrame, relief=DGG.SUNKEN, frameSize=(-1, 1, -0.15, 0.15), borderWidth=(0.02, 0.02), scale=0.25, frameColor=(color[0] * 0.7, color[1] * 0.7, color[2] * 0.7, 1), barColor=(color[0], color[1], color[2], 1), text='0/0', text_scale=0.18, text_fg=(0, 0, 0, 1), text_align=TextNode.ACenter, text_pos=(0, -0.05), pos=(0.4, 0, -0.09 * i)) self.trackLabels.append(label) self.trackIncLabels.append(incrementLabel) self.trackBars.append(progressBar) ################################################################################ # GUI elements showing progress updates on quests # ################################################################################ self.questFrame = DirectFrame(parent=self, relief=None) self.questPosters = [] self.congratsLeft = OnscreenText(parent=self.playerInfo, pos=(-0.1, 0.125, -0.1), text='', scale=0.06, align=TextNode.ARight) self.congratsLeft.setR(-30) self.congratsRight = OnscreenText(parent=self.playerInfo, pos=(0.1, 0.125, 0.1), text='', scale=0.06, align=TextNode.ALeft) self.congratsRight.setR(30) glow.removeNode() invIcons.removeNode() gagShopNodes.removeNode() dialogBox.removeNode() def __getAvatarTextScale(self): totalWidth = self.avatarText.node().getWidth() panelWidth = 9.2 defaultTextScale = 1.0 scale = min(defaultTextScale, defaultTextScale / (totalWidth / panelWidth)) return (scale, scale, scale) def enterOff(self): pass def exitOff(self): pass def setPanelData(self, panelData): self.panelData = panelData self.avatarText['text'] = self.panelData.avatarName self.avatarNamePanel.setScale(self.__getAvatarTextScale()) # Let's set the data for our gag experience here. for i in range(len(self.trackLabels)): track = self.panelData.getTrackByName( GagGlobals.TrackNameById.values()[i]) bar = self.trackBars[i] bar['text'] = '%d/%d' % (track.exp, track.maxExp) # When the maximum experience of a track isn't 0, we know it isn't unlocked. if track.maxExp == -1: bar.hide() self.trackIncLabels[i]['text'] = '' self.trackIncLabels[i].show() def __chooseRewardShot(self, av): shotChoices = [(0, 8, av.getHeight() * 0.66, 179, 15, 0), (5.2, 5.45, av.getHeight() * 0.66, 131.5, 3.6, 0)] shot = random.choice(shotChoices) return shot def getQuestsProgressInterval(self): avatar = self.panelData.avatar intervals = [] def toggleFavoriteGagItems(visible): for item in [ self.favoriteGag, self.favoriteGagGlow, self.favoriteGagText, self.favoriteGagName ]: if not visible: item.hide() else: item.show() def setupQuestPosters(): questManager = avatar.questManager numQuests = len(questManager.quests.values()) yPos = 0.47 displayData = { 1: [[Point3(0.0, 0.0, yPos)], 0.88], 2: [[Point3(-0.42, 0.0, yPos), Point3(0.45, 0.0, yPos)], 0.88], 3: [[ Point3(-0.57, 0.0, yPos), Point3(0.0, 0.0, yPos), Point3(0.57, 0.0, yPos) ], 0.70], 4: [[ Point3(-0.32, 0.0, 0.62), Point3(-0.32, 0.0, 0.30), Point3(0.32, 0.0, 0.62), Point3(0.32, 0.0, 0.30) ], 0.52] } # A full frame is a frame showing two quests at once. howManyFullFrames = math.ceil(numQuests / 2.0) howManyRemainderFrames = (numQuests - howManyFullFrames) for i, quest in enumerate(questManager.quests.values()): poster = QuestGlobals.generatePoster(quest, parent=self.questFrame) poster.setScale(displayData.get(numQuests)[1]) poster.setPos(displayData.get(numQuests)[0][i]) poster.show() self.questPosters.append(poster) intervals.append(Func(self.gagExpFrame.hide)) intervals.append(Func(self.playerInfo.show)) intervals.append(Func(self.panelContentsTitle.setText, QuestsPanelName)) intervals.append(Func(toggleFavoriteGagItems, False)) intervals.append(Func(setupQuestPosters)) #intervals.append(Func(self.playerInfo.initialiseoptions, DirectFrame)) return intervals def getGagExperienceInterval(self): avatar = self.panelData.avatar intervals = [] shot = self.__chooseRewardShot(avatar) intervals.append(Func(base.camera.reparentTo, avatar)) intervals.append(Func(base.camera.setPosHpr, *shot)) intervals.append(Func(self.congratsLeft.hide)) intervals.append(Func(self.congratsRight.hide)) intervals.append(Func(self.panelContentsTitle.setText, GagPanelName)) intervals.append(Func(self.setFavoriteGag, self.panelData.favoriteGag)) intervals.append(Func(self.gagExpFrame.show)) intervals.append(Func(self.playerInfo.show)) intervals.append(Wait(1.0)) for i in range(len(self.trackLabels)): track = self.panelData.getTrackByName( GagGlobals.TrackNameById.values()[i]) intervals.extend(self.getTrackIntervalList(track, i)) return intervals def getNextExpValue(self, newValue, track): if newValue < track.maxExp or track.maxExp == 0: return track.maxExp else: levels = GagGlobals.TrackExperienceAmounts[track.name] index = levels.index(track.maxExp) if index + 1 < len(levels): return levels[index + 1] return -1 def incrementExp(self, trackIndex, track, newValue): bar = self.trackBars[trackIndex] nextExp = GagGlobals.getMaxExperienceValue(newValue, track.name) oldValue = bar['value'] color = GagGlobals.TrackColorByName.get(track.name) bar['text'] = '%d/%d' % (newValue, nextExp) bar['range'] = nextExp if not nextExp == -1 else newValue bar['value'] = newValue bar['barColor'] = (color[0], color[1], color[2], 1) def resetBarColor(self, trackIndex): color = GagGlobals.TrackColorByName.get( GagGlobals.TrackNameById.values()[trackIndex]) self.trackBars[trackIndex]['barColor'] = (color[0] * 0.8, color[1] * 0.8, color[2] * 0.8, 1) def showTrackIncLabel(self, trackIndex, track, increment): label = self.trackIncLabels[trackIndex] # Only show increments when that track is unlocked. if track.exp != -1: label['text'] = '+%d' % increment label.show() def getTrackIntervalList(self, track, trackIndex): tickDelay = 1.0 / 60 intervalList = [] intervalList.append( Func(self.showTrackIncLabel, trackIndex, track, track.increment)) barTime = 2.0 if track.exp > 0 else 0.25 numTicks = int(math.ceil(barTime / tickDelay)) for i in range(numTicks): t = (i + 1) / float(numTicks) newValue = int(track.exp + t * track.increment + 0.5) intervalList.append( Func(self.incrementExp, trackIndex, track, newValue)) intervalList.append(Wait(tickDelay)) intervalList.append(Func(self.resetBarColor, trackIndex)) intervalList.append(Wait(0.2)) if track.maxExp > 0 and (track.maxExp != GagGlobals.MaxedTrackExperiences.get(track.name) \ and (track.exp + track.increment) >= track.maxExp): gagIndex = GagGlobals.TrackExperienceAmounts.get(track.name).index( track.maxExp) + 1 newGag = GagGlobals.TrackGagNamesByTrackName.get( track.name)[gagIndex] intervalList.append( self.getShowGagUnlockedInterval(track.name, newGag)) return intervalList def getShowGagUnlockedInterval(self, track, gagName): seq = Sequence( Func(self.gagExpFrame.hide), Func(self.panelContentsTitle.setText, 'Gag Unlocked!'), Func(self.playerInfo.show), Func(self.setFavoriteGag, gagName), Func(self.favoriteGagName.setY, -0.35), Func(self.favoriteGagText.setY, 0.105), Func(self.favoriteGagText.setText, 'New %s Gag' % track), Func(self.bonusText.hide), Func(self.playerInfo.setPos, 0, 0, 0), Func(self.playerInfo.initialiseoptions, DirectFrame)) seq.append(self.getCongratsInterval()) seq.append(Wait(1.0)) seq.append(self.getHideGagUnlockedInterval()) seq.append(Func(self.gagExpFrame.show)) seq.append(Wait(0.5)) return seq def getHideGagUnlockedInterval(self): def correctPositioning(guiElement, pos): guiElement['pos'] = pos seq = Sequence( Func(self.panelContentsTitle.setText, GagPanelName), Func(self.setFavoriteGag, self.panelData.favoriteGag), Func(self.playerInfo.setX, -0.5), Func(correctPositioning, self.favoriteGagName, FavoriteGagNamePos), Func(self.favoriteGagText.setText, FavoriteGag), Func(correctPositioning, self.favoriteGagText, FavoriteGagTitlePos), Func(self.congratsLeft.hide), Func(self.congratsRight.hide)) return seq def __getRandomCongratsPair(self): msgs = list(NewGagCongratsMessages) msg = msgs[random.randint(0, len(msgs) - 1)] msgs.remove(msg) return (msg, msgs[random.randint(0, len(msgs) - 1)]) def getCongratsInterval(self): msgs = self.__getRandomCongratsPair() self.congratsLeft['text'] = msgs[0] self.congratsRight['text'] = msgs[1] sfx = loader.loadSfx('phase_3/audio/sfx/GUI_balloon_popup.ogg') sfx.setLoop(False) sfx.setVolume(1.0) def makeSequence(text): seq = Sequence(Wait(1.0), Func(text.show)) seq.append(Func(sfx.play)) seq.append( CIGlobals.makePulseEffectInterval(text, 1.0, 0.01, 1.05, 0.5, 0.25)) seq.append(Func(sfx.stop)) return seq return Sequence(makeSequence(self.congratsLeft), makeSequence(self.congratsRight)) def setFavoriteGag(self, gagName): invIcons = loader.loadModel('phase_3.5/models/gui/inventory_icons.bam') gag = invIcons.find(GagGlobals.InventoryIconByName.get(gagName)) self.favoriteGagName.setText(gagName) self.favoriteGag['image'] = gag invIcons.removeNode() def destroy(self): if self.titlePanel: self.titlePanel.destroy() if self.avatarText: self.avatarText.destroy() if self.avatarNamePanel: self.avatarNamePanel.destroy() if self.panelContentsTitle: self.panelContentsTitle.destroy() if self.favoriteGag: self.favoriteGag.destroy() if self.favoriteGagGlow: self.favoriteGagGlow.destroy() if self.favoriteGagName: self.favoriteGagName.destroy() if self.playerInfo: self.playerInfo.destroy() if self.trackLabels: for label in self.trackLabels: label.destroy() if self.trackIncLabels: for label in self.trackIncLabels: label.destroy() if self.trackBars: for bar in self.trackBars: bar.destroy() if self.congratsLeft: self.congratsLeft.destroy() if self.congratsRight: self.congratsRight.destroy() if self.gagExpFrame: self.gagExpFrame.destroy() if self.panelData: self.panelData = None del self.titlePanel del self.avatarText del self.avatarNamePanel del self.panelContentsTitle del self.favoriteGag del self.favoriteGagGlow del self.favoriteGagName del self.playerInfo del self.trackLabels del self.trackIncLabels del self.trackBars del self.gagExpFrame del self.congratsLeft del self.congratsRight del self.panelData DirectFrame.destroy(self)
class GuiFrame(DirectObject, HasKeybinds): #should be able to show/hide, do conditional show hide #position where you want #parent to other frames TEXT_MAGIC_NUMBER = .833333333334 #5/6 ?!? DRAW_ORDER={ 'frame':('unsorted',0), 'frame_bg':('unsorted', 0), 'items':('unsorted', 0), 'title':('unsorted', 0), 'border':('unsorted', 0), } def __init__(self, title, shortcut = None, # XXX obsolete, but needs a non deco replacement x = 0, y = .1, width = .2, height = .8, #scale = .05, # there is some black magic here :/ bdr_thickness = 2, bdr_color = (.1, .1, .1, 1), bg_color = (.7, .7, .7, .5), text_color = (0, 0, 0, 1), text_font = TextNode.getDefaultFont(), #text_h = .05, # do not use directly text_height_mm = 4, items = tuple(), ): #item_w_pad = 1 #item_h_pad = 1 self.title = title self.do_xywh(x, y, width, height) self.bdr_thickness = bdr_thickness # FIXME ?? self.bdr_color = bdr_color self.bg_color = bg_color self.text_color = text_color self.text_font = text_font self.text_height_mm = text_height_mm #set up variables self.__winx__ = base.win.getXSize() self.__winy__ = base.win.getYSize() self.__ar__ = base.camLens.getAspectRatio() self.__was_dragging__ = False self.__first_item__ = None self.__add_head__ = None self.items = OrderedDict() # ordered dict to allow sequential addition #self.BT = buttonThrower if buttonThrower else base.buttonThrowers[0].node() self.BT = base.buttonThrowers[0].node() # get our aspect ratio, and pixels per mm self.pixels_per_mm = render.getPythonTag('system_data')['max_ppmm'] self.getWindowData() self.accept('window-event', self.getWindowData) #set the text height using the above data self.setTextHeight() # get the root for all frames in the scene self.frameRoot = aspect2d.find('frameRoot') if not self.frameRoot: self.frameRoot = aspect2d.attachNewNode('frameRoot') # create the parent node for this frame #parent = self.frameRoot.find('frame-*') #if not parent: #parent = self.frameRoot self.frame = self.frameRoot.attachNewNode('frame-%s-%s'%(title, id(self))) self.frame.setBin(*self.DRAW_ORDER['frame']) # background l,r,b,t = 0, self.width, 0, self.height self.frame_bg = DirectFrame(parent=self.frame, frameColor=self.bg_color, pos=LVecBase3f(self.x, 0, self.y), frameSize=(l,r,b,t), state=DGG.NORMAL, # FIXME framesize is >_< suppressMouse=1) self.frame_bg.setBin(*self.DRAW_ORDER['frame_bg']) # border self.__make_border__(self.frame_bg, self.bdr_thickness, self.bdr_color, l, r, b, t) # setup for items self.itemsParent = self.frame_bg.attachNewNode('items parent') # title self.title_button = self.__create_item__(title, self.title_toggle_vis) # add any items that we got for item in items: self.__create_item__(*item) # FIXME when we call frame adjust we will loose the record of any data items # dragging self.title_button.bind(DGG.B1PRESS, self.__startDrag) self.title_button.bind(DGG.B1RELEASE, self.__stopDrag) # raise if we click the frame background self.frame_bg.bind(DGG.B1PRESS, self.raise_) #self.frame_bg.bind(DGG.B1RELEASE, self.__stopDrag) # this can cause problems w/ was dragging # toggle vis if shortcut: self.accept(shortcut, self.toggle_vis) # adjust the frame self.frame_adjust() @property def text_s(self): return self.text_h * self.TEXT_MAGIC_NUMBER def setTextHeight(self): h_units = 2 * base.a2dTop units_per_pixel = h_units / self.__winy__ text_h = self.text_height_mm * self.pixels_per_mm * units_per_pixel self.text_h = text_h def do_xywh(self, x, y, w, h): """ makes negative wneg xidths and heights work as well as negative x and y (bottom right is 0) """ if x < 0: x = 1 + x if y < 0: y = 1 + y if w < 0: x, w = x + w, -w if h < 0: y, h = y + h, -h self.x = self.fix_x(x) # for top left self.y = self.fix_y(y) # for top left self.width = self.fix_w(w) self.height = self.fix_h(h) def getWindowData(self, window=None): x = base.win.getXSize() y = base.win.getYSize() if x != self.__winx__ or y != self.__winy__: self.__ar__ = base.camLens.getAspectRatio() # w/h self.__winx__ = x self.__winy__ = y self.frame_adjust() def raise_(self, *args): """ function that raises windows call FIRST inside any function that should raise """ self.frame.reparentTo(self.frameRoot) # self.frame doesn't move so no wrt def frame_adjust(self): # FIXME sometimes this fails to call, also calls too often at startup self.setTextHeight() MI = self.getMaxItems() # does not count title >_< LI = len(self.items) DI = MI - LI if DI >= 0: for i in range(DI+1): self.__create_item__(' blank') else: for i in range(-(DI+1)): k,v = self.items.popitem() # remove the last nodes in order v.removeNode() # FIXME consider keeping these around? for k,b in self.items.items(): if k == 'title': if self.frame_bg.isHidden(): x, y, z = self.frame_bg.getPos() self.title_button.setPos(LVecBase3f(x, y , z-self.text_h)) else: self.title_button.setPos(LVecBase3f(0, 0, -self.text_h)) elif k == self.__first_item__: b.setPos(LVecBase3f(0, 0, -(self.text_h * 2))) else: b.setPos(LVecBase3f(0, 0, -self.text_h)) b['frameSize'] = 0, self.width, 0, self.text_h b['text_scale'] = self.text_s, self.text_s b['text_pos'] = 0, self.text_h - self.TEXT_MAGIC_NUMBER * self.text_s def getWindowSize(self, event=None): # TODO see if we really need this self.__winx__ = base.win.getXSize() self.__winy__ = base.win.getYSize() m = max(self.__winx__, self.__winy__) self.__xscale__ = self.__winx__ / m self.__yscale__ = self.__winy__ / m # put origin in top left and positive down and right @staticmethod def fix_x(x): return (x - .5) * 2 # TODO * base.a2dLeft? @staticmethod def fix_y(y): return (y - .5) * -2 # TODO * base.a2dTop? @staticmethod def fix_w(n): return n * 2 @staticmethod def fix_h(n): return -n * 2 def add_item(self, text, command = None, args = tuple()): args = list(args) if text[0] != ' ': text = ' '+text items = list(self.items) last_slot = len(self.items) if self.__add_head__ == last_slot: print('all slots are full, cannot add item to %s'%self) return None button = self.items[items[self.__add_head__]] button['text'] = text button['command'] = command button['extraArgs'] = args + button['extraArgs'] # blank buttons always have [self,id] self.__add_head__ += 1 def __create_item__(self, text, command = None, args = tuple()): args = list(args) #if not len(self.items): #parent = self.frame if len(self.items) <= 1: parent = self.itemsParent #everyone else parents off 2nd text else: parent = list(self.items.values())[-1] if command != None: def cmd(*args): """ any item should raise """ self.raise_() command(*args) else: cmd = self.raise_ b = DirectButton( parent=parent, frameColor=(1,1,1,.0), # a = 0 => no border overlap frameSize=(0, self.width, 0, self.text_h), text=' '+text, # hack to keep spacing from border text_font=self.text_font, text_fg=self.text_color, text_scale=self.text_s, text_pos=(0, self.text_h - self.TEXT_MAGIC_NUMBER * self.text_s), command=cmd, relief=DGG.FLAT, text_align=TextNode.ALeft, ) b.setPos(LVecBase3f(0, 0, -self.text_h)) b.setName('DirectButton-'+text) if not len(self.items): self.items['title'] = b b.setBin(*self.DRAW_ORDER['title']) else: b['extraArgs'] = args+[self, id(b)] b.node().setPythonTag('id', id(b)) b.setBin(*self.DRAW_ORDER['items']) if len(self.items) is 1: # the first item that is not the title b.setPos(LVecBase3f(0, 0, -(self.text_h * 2))) self.__first_item__ = id(b) self.items[id(b)] = b if text == ' blank': if self.__add_head__ is None: self.__add_head__ = 1 return b def del_all(self): if self.__first_item__ != None: for id_, button in self.items.items(): if id_ != 'title': button['text'] = ' blank' button['command'] = None button['extraArgs'] = [self, id_] self.__add_head__ = 1 def del_item(self, text): # FIXME uniqueness problems #d = self.itemsParent.find('*%s*'%text) if text[0] != ' ': text = ' '+text d = [i for i in self.items.values() if i.getName().count(text)] try: self.__del_item__(d[0].getPythonTag('id')) except IndexError: print('that item does not seem to exist') # if we have a name then there shouldn't be key errors def __del_item__(self, index): """ I have no idea how this is going to work """ out = self.items[index] p = out.getParent() if out.getNumChildren(): # avoid the printing of the AssertionError :/ c = out.getChild(0) c.reparentTo(p) if index == self.__first_item__: # XXX is fails, ints from id != c.setPos(LVecBase3f(out.getPos())) id_ = c.getPythonTag('id') self.__first_item__ = id_ out.setPos(LVecBase3f(0, 0, -self.text_h)) self.items.pop(index) parent = list(self.items.values())[-1] out['text'] = ' del blank' #out['command'] = None out['extraArgs'] = [self, index] out.reparentTo(parent) self.items[index] = out if self.__add_head__ > 1: # title is always at 0 self.__add_head__ -= 1 @classmethod def __make_border__(cls, parent, thickness, color, l, r , b, t): moveto_drawto = ( ((l,0,t), (l,0,b)), ((r,0,t), (r,0,b)), ((l,0,b), (r,0,b)), ((l,0,t), (r,0,t)), ) for moveto, drawto in moveto_drawto: Border = LineSegs() Border.setThickness(thickness) Border.setColor(*color) Border.moveTo(*moveto) Border.drawTo(*drawto) b = parent.attachNewNode(Border.create()) b.setBin(*cls.DRAW_ORDER['border']) def getMaxItems(self): return int(abs(self.height / self.text_h) - 1) @event_callback def toggle_vis(self): if self.frame_bg.isHidden(): self.frame_bg.show() self.raise_() else: self.frame_bg.hide() def title_toggle_vis(self): if not self.__was_dragging__: self.toggle_vis() if self.frame_bg.isHidden(): self.title_button.wrtReparentTo(self.frame) self.title_button['frameColor'] = (1, 1, 1, .5) # TODO else: self.title_button.wrtReparentTo(self.frame_bg) self.title_button['frameColor'] = (1, 1, 1, 0) # TODO else: self.__was_dragging__ = False def __startDrag(self, crap): self.raise_() self._ox, self._oy = base.mouseWatcherNode.getMouse() taskMgr.add(self.__drag,'dragging %s'%self.title) self.origBTprefix=self.BT.getPrefix() self.BT.setPrefix('dragging frame') def __drag(self, task): if base.mouseWatcherNode.hasMouse(): x, y = base.mouseWatcherNode.getMouse() if x != self._ox or y != self._oy: m_old = aspect2d.getRelativePoint(render2d, Point3(self._ox, self._oy, 0)) m_new = aspect2d.getRelativePoint(render2d, Point3(x, y, 0)) dx, dy, _ = m_new - m_old self.setPos(self.x + dx, self.y + dy) self._ox = x self._oy = y self.__was_dragging__ = True return task.cont def __stopDrag(self,crap): taskMgr.remove('dragging %s'%self.title) self.BT.setPrefix(self.origBTprefix) def setPos(self, x, y): """ actually sets the title button position since it is really the parent node """ self.x = x self.y = y #- self.text_h # FIXME is hard :/ self.frame_bg.setPos(LVecBase3f(x, 0, y)) if self.frame_bg.isHidden(): self.title_button.setPos(LVecBase3f(x, 0, y - self.text_h)) def __enter__(self): #load the position #load other saved state pass def __exit__(self): #save the position! #save other state pass
class GuiUnitInfo: def __init__(self, offset, parent, unit_type, default_hp, hp, default_ap, ap): self.offset = offset self.frame = DirectFrame( relief = DGG.FLAT , scale = 1 , frameSize = (-0.5, 0.5, 0, -0.5) , parent = parent ) self.frame.setBillboardPointEye() self.frame.setLightOff() self.frame.setBin("fixed", 40) self.frame.setDepthTest(False) self.frame.setDepthWrite(False) fixedWidthFont = loader.loadFont(GUI_FONT)#@UndefinedVariable #fixedWidthFont.setPixelsPerUnit(60) #fixedWidthFont.setRenderMode(fontt.RMSolid) if not fixedWidthFont.isValid(): print "pandaInteractiveConsole.py :: could not load the defined font %s" % str(self.font) fixedWidthFont = DGG.getDefaultFont() self.label = OnscreenText( parent = self.frame , text = "" , pos = (offset.getX(),offset.getZ()+0.1) , align=TextNode.ACenter , mayChange=True , scale=0.1 , fg = (1,0,0,1) #, shadow = (0, 0, 0, 1) #, frame = (200,0,0,1) ) self.label.setFont( fixedWidthFont ) #self.label.setLightOff() self.all_icons = {} self.visible_icons = {} self.addIcon("overwatch") self.addIcon("set_up") self.ap_bar = DirectWaitBar(parent = self.frame , text = "" , range = default_ap , value = ap , pos = (offset.getX()+0.08,0,offset.getZ()-0.27) , barColor = (0,0,1,1) , frameColor = (0,0,0.5,0.2) , scale = (0.3,0.5,0.3)) self.hp_bar = DirectWaitBar(parent = self.frame , text = "" , range = default_hp , value = hp , pos = (offset.getX()+0.08,0,offset.getZ()-0.2) , barColor = (0,1,0,1) , frameColor = (1,0,0,0.9) , scale = (0.3,0.5,0.3)) self.insignia = OnscreenImage(parent = self.frame ,image = "unit_" + unit_type + "_big_transparent_32.png" #,pos = (offset.getX(),0,offset.getZ()+0.14) , pos = (offset.getX() - 0.31,0,offset.getZ()-0.23) ,scale = 0.09) self.insignia.setTransparency(TransparencyAttrib.MAlpha) def addIcon(self, name): self.all_icons[name] = OnscreenImage(parent = self.frame ,image = name + "_icon.png" #,pos = offset + (0,0,-0.1) ,scale = 0.08) self.all_icons[name].setTransparency(TransparencyAttrib.MAlpha) self.all_icons[name].hide() def write(self, text): text = "" self.label.setText(text) def redraw(self): return def remove(self): self.frame.remove() def reparentTo(self, parent): self.frame.reparentTo(parent) def hide(self): self.label.hide() def show(self): self.label.show() def refreshBars(self, hp, ap): self.ap_bar['value'] = ap self.hp_bar['value'] = hp self.ap_bar.setValue() self.hp_bar.setValue() def refreshIcons(self): count = len(self.visible_icons) start_pos = (1 - count) * 0.25 / 2 for icon in self.all_icons: if icon in self.visible_icons: self.visible_icons[icon].setPos(self.offset + (start_pos, 0, -0.08)) self.visible_icons[icon].show() start_pos += 0.21 else: self.all_icons[icon].hide() def hideOverwatch(self): if "overwatch" in self.visible_icons: self.visible_icons.pop("overwatch") self.refreshIcons() def showOverwatch(self): self.visible_icons["overwatch"] = self.all_icons["overwatch"] self.refreshIcons() def hideSetUp(self): if "set_up" in self.visible_icons: self.visible_icons.pop("set_up") self.refreshIcons() def showSetUp(self): self.visible_icons["set_up"] = self.all_icons["set_up"] self.refreshIcons()
class ChatBox(DirectObject): MESSAGE_LIFE = 10 MAX_NUM_MESSAGES = 15 (TYPE_GLOBAL, TYPE_TEAM, TYPE_CONSOLE) = range(3) messageTypeToPrefix = { TYPE_GLOBAL : 'Global:', TYPE_TEAM : 'Team:', TYPE_CONSOLE : 'Console' } def __init__(self): self.textNodes = [] self.messageType = None self.rootFrame = DirectFrame(pos = (0.03, 0, 0.2), frameColor = (0, 0, 0, 0), frameSize = (0, 1, 0, 1), parent = base.a2dBottomLeft) self.rootFrame.setBin('fixed', GUIOrder.ORDER[GUIOrder.CHAT]) self.entryFrame = DirectFrame(pos = (0, 0, 0), frameColor = (0, 0, 0, 0.1), frameSize = (0, 1, 0, 0.1), parent = self.rootFrame) self.chatarea = DirectEntry(width = 27, scale = Settings.CHAT_HEIGHT, pos = (0, 0, 0), frameColor = (0, 0, 0, 0), text_fg = (1, 1, 1, 1), numLines = 1, cursorKeys = 1, rolloverSound = None, clickSound = None, focus = 0, command = self.OnChatEntered, parent = self.entryFrame) self.typeText = OnscreenText(text = '', pos = (0, Settings.CHAT_HEIGHT + 0.01), scale = Settings.CHAT_HEIGHT, fg = (1, 1, 1, 1), mayChange = True, align = TextNode.ALeft, parent = self.entryFrame) self.displayFrame = DirectFrame(pos = (0, 0, 0.1), frameColor = (0, 0, 0, 0), frameSize = (0, 1, 0, 0.42), parent = self.rootFrame) self.chatarea.enterText('') self.entryFrame.hide() self.chatarea['focus'] = 0 self.chatarea.setFocus() def OnChatEntered(self, enteredText): enteredText = enteredText.strip() self.Hide() if(len(enteredText) > 0): ChatEnteredEvent(self.messageType, enteredText).Fire() def AddMessage(self, prefix, prefixColor, message): parent = self.displayFrame.attachNewNode('messageParent') prefixTextNode = TextNode('prefixMessage') prefixTextNode.setText(prefix) prefixTextNode.setTextColor(prefixColor) prefixTextNode.setShadow(0.05, 0.05) prefixTextNode.setShadowColor(Globals.COLOR_BLACK) prefixTextNodePath = parent.attachNewNode(prefixTextNode) prefixTextNodePath.setScale(Settings.CHAT_HEIGHT) messageTextNode = TextNode('prefixMessage') messageTextNode.setText(message) messageTextNode.setTextColor(1, 1, 1, 1) messageTextNode.setShadow(0.05, 0.05) messageTextNode.setShadowColor(Globals.COLOR_BLACK) messageTextNodePath = parent.attachNewNode(messageTextNode) messageTextNodePath.setScale(Settings.CHAT_HEIGHT) messageTextNodePath.setPos(Vec3(prefixTextNode.calcWidth(prefix) * Settings.CHAT_HEIGHT, 0, 0)) taskMgr.remove('HideMessageLog') taskMgr.doMethodLater(ChatBox.MESSAGE_LIFE, self.HideMessageLog, 'HideMessageLog') self.ShowMessageLog() self.textNodes.append(parent) if(len(self.textNodes) > ChatBox.MAX_NUM_MESSAGES): self.RemoveMessage(self.textNodes[0]) self.RedrawMessages() def RedrawMessages(self): n = len(self.textNodes) for i, textNode in enumerate(self.textNodes): LerpPosInterval(textNode, 0.5, (0, 0, (n-i) * (Settings.CHAT_HEIGHT + 0.01))).start() def RemoveMessage(self, textNode): self.textNodes.remove(textNode) textNode.removeNode() def HideMessageLog(self, task = None): self.displayFrame.hide() def ShowMessageLog(self): self.displayFrame.show() def Hide(self): self.chatarea.enterText('') self.entryFrame.hide() self.chatarea['focus'] = 0 self.chatarea.setFocus() self.HideMessageLog() ChatCloseEvent().Fire() def Show(self, messageType): self.messageType = messageType self.entryFrame.show() self.chatarea['focus'] = 1 self.chatarea.setFocus() self.typeText.setText(ChatBox.GetPrefix(self.messageType)) self.ShowMessageLog() ChatOpenEvent().Fire() def EnableKeyboardListening(self): self.acceptOnce('escape', self.Hide) def DisableKeyboardListening(self): self.ignoreAll() @staticmethod def GetPrefix(messageType): return ChatBox.messageTypeToPrefix[messageType] def Destroy(self): taskMgr.remove('HideMessageLog') self.rootFrame.destroy() self.entryFrame.destroy() self.chatarea.destroy() self.typeText.destroy() self.displayFrame.destroy() self.ignoreAll()
class GuiFrame(DirectObject, HasKeybinds): #should be able to show/hide, do conditional show hide #position where you want #parent to other frames TEXT_MAGIC_NUMBER = .833333333334 #5/6 ?!? DRAW_ORDER = { 'frame': ('unsorted', 0), 'frame_bg': ('unsorted', 0), 'items': ('unsorted', 0), 'title': ('unsorted', 0), 'border': ('unsorted', 0), } def __init__( self, title, shortcut=None, # XXX obsolete, but needs a non deco replacement x=0, y=.1, width=.2, height=.8, #scale = .05, # there is some black magic here :/ bdr_thickness=2, bdr_color=(.1, .1, .1, 1), bg_color=(.7, .7, .7, .5), text_color=(0, 0, 0, 1), text_font=TextNode.getDefaultFont(), #text_h = .05, # do not use directly text_height_mm=4, items=tuple(), ): #item_w_pad = 1 #item_h_pad = 1 self.title = title self.do_xywh(x, y, width, height) self.bdr_thickness = bdr_thickness # FIXME ?? self.bdr_color = bdr_color self.bg_color = bg_color self.text_color = text_color self.text_font = text_font self.text_height_mm = text_height_mm #set up variables self.__winx__ = base.win.getXSize() self.__winy__ = base.win.getYSize() self.__ar__ = base.camLens.getAspectRatio() self.__was_dragging__ = False self.__first_item__ = None self.__add_head__ = None self.items = OrderedDict() # ordered dict to allow sequential addition #self.BT = buttonThrower if buttonThrower else base.buttonThrowers[0].node() self.BT = base.buttonThrowers[0].node() # get our aspect ratio, and pixels per mm self.pixels_per_mm = render.getPythonTag('system_data')['max_ppmm'] self.getWindowData() self.accept('window-event', self.getWindowData) #set the text height using the above data self.setTextHeight() # get the root for all frames in the scene self.frameRoot = aspect2d.find('frameRoot') if not self.frameRoot: self.frameRoot = aspect2d.attachNewNode('frameRoot') # create the parent node for this frame #parent = self.frameRoot.find('frame-*') #if not parent: #parent = self.frameRoot self.frame = self.frameRoot.attachNewNode('frame-%s-%s' % (title, id(self))) self.frame.setBin(*self.DRAW_ORDER['frame']) # background l, r, b, t = 0, self.width, 0, self.height self.frame_bg = DirectFrame( parent=self.frame, frameColor=self.bg_color, pos=LVecBase3f(self.x, 0, self.y), frameSize=(l, r, b, t), state=DGG.NORMAL, # FIXME framesize is >_< suppressMouse=1) self.frame_bg.setBin(*self.DRAW_ORDER['frame_bg']) # border self.__make_border__(self.frame_bg, self.bdr_thickness, self.bdr_color, l, r, b, t) # setup for items self.itemsParent = self.frame_bg.attachNewNode('items parent') # title self.title_button = self.__create_item__(title, self.title_toggle_vis) # add any items that we got for item in items: self.__create_item__( *item ) # FIXME when we call frame adjust we will loose the record of any data items # dragging self.title_button.bind(DGG.B1PRESS, self.__startDrag) self.title_button.bind(DGG.B1RELEASE, self.__stopDrag) # raise if we click the frame background self.frame_bg.bind(DGG.B1PRESS, self.raise_) #self.frame_bg.bind(DGG.B1RELEASE, self.__stopDrag) # this can cause problems w/ was dragging # toggle vis if shortcut: self.accept(shortcut, self.toggle_vis) # adjust the frame self.frame_adjust() @property def text_s(self): return self.text_h * self.TEXT_MAGIC_NUMBER def setTextHeight(self): h_units = 2 * base.a2dTop units_per_pixel = h_units / self.__winy__ text_h = self.text_height_mm * self.pixels_per_mm * units_per_pixel self.text_h = text_h def do_xywh(self, x, y, w, h): """ makes negative wneg xidths and heights work as well as negative x and y (bottom right is 0) """ if x < 0: x = 1 + x if y < 0: y = 1 + y if w < 0: x, w = x + w, -w if h < 0: y, h = y + h, -h self.x = self.fix_x(x) # for top left self.y = self.fix_y(y) # for top left self.width = self.fix_w(w) self.height = self.fix_h(h) def getWindowData(self, window=None): x = base.win.getXSize() y = base.win.getYSize() if x != self.__winx__ or y != self.__winy__: self.__ar__ = base.camLens.getAspectRatio() # w/h self.__winx__ = x self.__winy__ = y self.frame_adjust() def raise_(self, *args): """ function that raises windows call FIRST inside any function that should raise """ self.frame.reparentTo( self.frameRoot) # self.frame doesn't move so no wrt def frame_adjust( self ): # FIXME sometimes this fails to call, also calls too often at startup self.setTextHeight() MI = self.getMaxItems() # does not count title >_< LI = len(self.items) DI = MI - LI if DI >= 0: for i in range(DI + 1): self.__create_item__(' blank') else: for i in range(-(DI + 1)): k, v = self.items.popitem() # remove the last nodes in order v.removeNode() # FIXME consider keeping these around? for k, b in self.items.items(): if k == 'title': if self.frame_bg.isHidden(): x, y, z = self.frame_bg.getPos() self.title_button.setPos(LVecBase3f(x, y, z - self.text_h)) else: self.title_button.setPos(LVecBase3f(0, 0, -self.text_h)) elif k == self.__first_item__: b.setPos(LVecBase3f(0, 0, -(self.text_h * 2))) else: b.setPos(LVecBase3f(0, 0, -self.text_h)) b['frameSize'] = 0, self.width, 0, self.text_h b['text_scale'] = self.text_s, self.text_s b['text_pos'] = 0, self.text_h - self.TEXT_MAGIC_NUMBER * self.text_s def getWindowSize(self, event=None): # TODO see if we really need this self.__winx__ = base.win.getXSize() self.__winy__ = base.win.getYSize() m = max(self.__winx__, self.__winy__) self.__xscale__ = self.__winx__ / m self.__yscale__ = self.__winy__ / m # put origin in top left and positive down and right @staticmethod def fix_x(x): return (x - .5) * 2 # TODO * base.a2dLeft? @staticmethod def fix_y(y): return (y - .5) * -2 # TODO * base.a2dTop? @staticmethod def fix_w(n): return n * 2 @staticmethod def fix_h(n): return -n * 2 def add_item(self, text, command=None, args=tuple()): args = list(args) if text[0] != ' ': text = ' ' + text items = list(self.items) last_slot = len(self.items) if self.__add_head__ == last_slot: print('all slots are full, cannot add item to %s' % self) return None button = self.items[items[self.__add_head__]] button['text'] = text button['command'] = command button['extraArgs'] = args + button[ 'extraArgs'] # blank buttons always have [self,id] self.__add_head__ += 1 def __create_item__(self, text, command=None, args=tuple()): args = list(args) #if not len(self.items): #parent = self.frame if len(self.items) <= 1: parent = self.itemsParent #everyone else parents off 2nd text else: parent = list(self.items.values())[-1] if command != None: def cmd(*args): """ any item should raise """ self.raise_() command(*args) else: cmd = self.raise_ b = DirectButton( parent=parent, frameColor=(1, 1, 1, .0), # a = 0 => no border overlap frameSize=(0, self.width, 0, self.text_h), text=' ' + text, # hack to keep spacing from border text_font=self.text_font, text_fg=self.text_color, text_scale=self.text_s, text_pos=(0, self.text_h - self.TEXT_MAGIC_NUMBER * self.text_s), command=cmd, relief=DGG.FLAT, text_align=TextNode.ALeft, ) b.setPos(LVecBase3f(0, 0, -self.text_h)) b.setName('DirectButton-' + text) if not len(self.items): self.items['title'] = b b.setBin(*self.DRAW_ORDER['title']) else: b['extraArgs'] = args + [self, id(b)] b.node().setPythonTag('id', id(b)) b.setBin(*self.DRAW_ORDER['items']) if len(self.items) is 1: # the first item that is not the title b.setPos(LVecBase3f(0, 0, -(self.text_h * 2))) self.__first_item__ = id(b) self.items[id(b)] = b if text == ' blank': if self.__add_head__ is None: self.__add_head__ = 1 return b def del_all(self): if self.__first_item__ != None: for id_, button in self.items.items(): if id_ != 'title': button['text'] = ' blank' button['command'] = None button['extraArgs'] = [self, id_] self.__add_head__ = 1 def del_item(self, text): # FIXME uniqueness problems #d = self.itemsParent.find('*%s*'%text) if text[0] != ' ': text = ' ' + text d = [i for i in self.items.values() if i.getName().count(text)] try: self.__del_item__(d[0].getPythonTag('id')) except IndexError: print('that item does not seem to exist') # if we have a name then there shouldn't be key errors def __del_item__(self, index): """ I have no idea how this is going to work """ out = self.items[index] p = out.getParent() if out.getNumChildren(): # avoid the printing of the AssertionError :/ c = out.getChild(0) c.reparentTo(p) if index == self.__first_item__: # XXX is fails, ints from id != c.setPos(LVecBase3f(out.getPos())) id_ = c.getPythonTag('id') self.__first_item__ = id_ out.setPos(LVecBase3f(0, 0, -self.text_h)) self.items.pop(index) parent = list(self.items.values())[-1] out['text'] = ' del blank' #out['command'] = None out['extraArgs'] = [self, index] out.reparentTo(parent) self.items[index] = out if self.__add_head__ > 1: # title is always at 0 self.__add_head__ -= 1 @classmethod def __make_border__(cls, parent, thickness, color, l, r, b, t): moveto_drawto = ( ((l, 0, t), (l, 0, b)), ((r, 0, t), (r, 0, b)), ((l, 0, b), (r, 0, b)), ((l, 0, t), (r, 0, t)), ) for moveto, drawto in moveto_drawto: Border = LineSegs() Border.setThickness(thickness) Border.setColor(*color) Border.moveTo(*moveto) Border.drawTo(*drawto) b = parent.attachNewNode(Border.create()) b.setBin(*cls.DRAW_ORDER['border']) def getMaxItems(self): return int(abs(self.height / self.text_h) - 1) @event_callback def toggle_vis(self): if self.frame_bg.isHidden(): self.frame_bg.show() self.raise_() else: self.frame_bg.hide() def title_toggle_vis(self): if not self.__was_dragging__: self.toggle_vis() if self.frame_bg.isHidden(): self.title_button.wrtReparentTo(self.frame) self.title_button['frameColor'] = (1, 1, 1, .5) # TODO else: self.title_button.wrtReparentTo(self.frame_bg) self.title_button['frameColor'] = (1, 1, 1, 0) # TODO else: self.__was_dragging__ = False def __startDrag(self, crap): self.raise_() self._ox, self._oy = base.mouseWatcherNode.getMouse() taskMgr.add(self.__drag, 'dragging %s' % self.title) self.origBTprefix = self.BT.getPrefix() self.BT.setPrefix('dragging frame') def __drag(self, task): if base.mouseWatcherNode.hasMouse(): x, y = base.mouseWatcherNode.getMouse() if x != self._ox or y != self._oy: m_old = aspect2d.getRelativePoint( render2d, Point3(self._ox, self._oy, 0)) m_new = aspect2d.getRelativePoint(render2d, Point3(x, y, 0)) dx, dy, _ = m_new - m_old self.setPos(self.x + dx, self.y + dy) self._ox = x self._oy = y self.__was_dragging__ = True return task.cont def __stopDrag(self, crap): taskMgr.remove('dragging %s' % self.title) self.BT.setPrefix(self.origBTprefix) def setPos(self, x, y): """ actually sets the title button position since it is really the parent node """ self.x = x self.y = y #- self.text_h # FIXME is hard :/ self.frame_bg.setPos(LVecBase3f(x, 0, y)) if self.frame_bg.isHidden(): self.title_button.setPos(LVecBase3f(x, 0, y - self.text_h)) def __enter__(self): #load the position #load other saved state pass def __exit__(self): #save the position! #save other state pass
class PlacerTool3D(DirectFrame): ORIGINAL_SCALE = (1.0, 1.0, 1.0) MINIMIZED_SCALE = (0.85, 1.0, 0.15) ORIG_DRAG_BUTTON_POS = (0.37, 0.0, 0.37) MINI_DRAG_BUTTON_POS = (0.37, 0.0, 0.03) ORIG_MINI_BUTTON_POS = (0.29, 0.0, 0.37) MINI_MINI_BUTTON_POS = (0.29, 0.0, 0.03) ORIG_NAME_POS = (-0.39, 0.0, 0.27) MINI_NAME_POS = (-0.39, 0.0, 0.0) def __init__(self, target, increment=0.01, hprIncrement=1.0, parent=aspect2d, pos=(0.0, 0.0, 0.0)): DirectFrame.__init__(self, parent) self.target = target self.increment = increment self.minimized = False self.mainFrame = DirectFrame( parent=self, relief=None, geom=DGG.getDefaultDialogGeom(), geom_color=(1, 1, 0.75, 1), geom_scale=self.ORIGINAL_SCALE, pos=pos, ) # Arrow gui (preload) gui = loader.loadModel('phase_3/models/gui/tt_m_gui_mat_mainGui.bam') # Set Bins self.mainFrame.setBin('gui-popup', 0) # Name name = self.target.getName() self.nameLabel = TTLabel(self.mainFrame, text='Target: %s' % name, pos=self.ORIG_NAME_POS, text_align=TextNode.ALeft, text_wordwrap=13) # Pos pos = self.target.getPos() self.posLabel = TTLabel(self.mainFrame, text='Position: ', pos=(-0.39, 0.0, 0.055), text_align=TextNode.ALeft) self.xPosSpinner = PlacerToolSpinner(self.mainFrame, value=pos[0], pos=(-0.085, 0.0, 0.06), increment=increment, callback=self.handleXChange) self.yPosSpinner = PlacerToolSpinner(self.mainFrame, value=pos[1], pos=(0.1, 0.0, 0.06), increment=increment, callback=self.handleYChange) self.zPosSpinner = PlacerToolSpinner(self.mainFrame, value=pos[2], pos=(0.28, 0.0, 0.06), increment=increment, callback=self.handleZChange) # hpr hpr = self.target.getHpr() self.hprLabel = TTLabel(self.mainFrame, text='HPR: ', pos=(-0.39, 0.0, -0.19), text_align=TextNode.ALeft) self.hSpinner = PlacerToolSpinner(self.mainFrame, value=hpr[0], pos=(-0.085, 0.0, -0.195), increment=hprIncrement, callback=self.handleHChange) self.pSpinner = PlacerToolSpinner(self.mainFrame, value=hpr[1], pos=(0.1, 0.0, -0.195), increment=hprIncrement, callback=self.handlePChange) self.rSpinner = PlacerToolSpinner(self.mainFrame, value=hpr[2], pos=(0.28, 0.0, -0.195), increment=hprIncrement, callback=self.handleRChange) # scale scale = [round(s, 3) for s in self.target.getScale()] self.scaleLabel = TTLabel(self.mainFrame, text='Scale: ', pos=(-0.39, 0.0, -0.4), text_align=TextNode.ALeft) self.sxSpinner = PlacerToolSpinner(self.mainFrame, value=hpr[0], pos=(-0.085, 0.0, -0.4), increment=increment, callback=self.handleSxChange) self.sySpinner = PlacerToolSpinner(self.mainFrame, value=hpr[1], pos=(0.1, 0.0, -0.4), increment=increment, callback=self.handleSyChange) self.szSpinner = PlacerToolSpinner(self.mainFrame, value=hpr[2], pos=(0.28, 0.0, -0.4), increment=increment, callback=self.handleSzChange) gui.removeNode() gui = loader.loadModel('phase_3/models/gui/tt_m_gui_mat_nameShop') thumb = gui.find('**/tt_t_gui_mat_namePanelCircle') self.dragButton = DirectButton(self.mainFrame, relief=None, image=thumb, image_scale=(0.5, 0.5, 0.5), pos=self.ORIG_DRAG_BUTTON_POS) self.minimizeButton = DirectButton(self.mainFrame, relief=None, image=thumb, image_scale=(0.5, 0.5, 0.5), image_color=(0.0, 0.0, 0.65, 1.0), pos=self.ORIG_MINI_BUTTON_POS, command=self.toggleMinimize, extraArgs=[]) self.dragButton.bind(DGG.B1PRESS, self.onPress) if target is not None: self.setTarget(target) def destroy(self): self.target = None messenger.send('placer-destroyed', [self]) DirectFrame.destroy(self) def setTarget(self, target): self.target = target name = self.target.getName() scale = [round(s, 3) for s in self.target.getScale()] x, y, z = self.target.getPos() h, p, r = self.target.getHpr() sx, sy, sz = self.target.getScale() self.nameLabel['text'] = 'Target: %s' % name self.xPosSpinner.setValue(x) self.yPosSpinner.setValue(y) self.zPosSpinner.setValue(z) self.hSpinner.setValue(h) self.pSpinner.setValue(p) self.rSpinner.setValue(r) self.sxSpinner.setValue(sx) self.sySpinner.setValue(sy) self.szSpinner.setValue(sz) def handleXChange(self, value): self.changeTargetPos(0, value) def handleYChange(self, value): self.changeTargetPos(1, value) def handleZChange(self, value): self.changeTargetPos(2, value) def handleHChange(self, value): self.changeTargetHpr(0, value) def handlePChange(self, value): self.changeTargetHpr(1, value) def handleRChange(self, value): self.changeTargetHpr(2, value) def handleSxChange(self, value): self.changeTargetScale(0, value) def handleSyChange(self, value): self.changeTargetScale(1, value) def handleSzChange(self, value): self.changeTargetScale(2, value) def changeTargetPos(self, index, value): pos = self.target.getPos() pos[index] = float(value) self.target.setPos(pos) def changeTargetHpr(self, index, value): hpr = self.target.getHpr() hpr[index] = float(value) self.target.setHpr(hpr) def changeTargetScale(self, index, value): pos = self.target.getScale() pos[index] = float(value) self.target.setScale(pos) def toggleMinimize(self): if self.minimized: self.maximize() else: self.minimize() def minimize(self): self.minimized = True self.mainFrame['geom_scale'] = self.MINIMIZED_SCALE self.nameLabel.setPos(self.MINI_NAME_POS) self.dragButton.setPos(self.MINI_DRAG_BUTTON_POS) self.minimizeButton.setPos(self.MINI_MINI_BUTTON_POS) self.posLabel.hide() self.xPosSpinner.hide() self.yPosSpinner.hide() self.zPosSpinner.hide() self.hprLabel.hide() self.hSpinner.hide() self.pSpinner.hide() self.rSpinner.hide() self.scaleLabel.hide() self.setPos(0, 0, 0) def maximize(self): self.minimized = False self.mainFrame['geom_scale'] = self.ORIGINAL_SCALE self.nameLabel.setPos(self.ORIG_NAME_POS) self.dragButton.setPos(self.ORIG_DRAG_BUTTON_POS) self.minimizeButton.setPos(self.ORIG_MINI_BUTTON_POS) self.posLabel.show() self.xPosSpinner.show() self.yPosSpinner.show() self.zPosSpinner.show() self.hprLabel.show() self.hSpinner.show() self.pSpinner.show() self.rSpinner.show() self.scaleLabel.show() self.setPos(0, 0, 0) def onPress(self, e=None): self.accept('mouse1-up', self.onRelease) taskMgr.add(self.mouseMoverTask, '%s-mouseMoverTask' % self.id) def onRelease(self, e=None): self.ignore('mouse1-up') taskMgr.remove('%s-mouseMoverTask' % self.id) def mouseMoverTask(self, task): if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() buttonPos = self.dragButton.getPos() newPos = (mpos[0] - buttonPos[0] / 2 - 0.02, 0, mpos[1] - buttonPos[2]) self.setPos(render2d, newPos) return task.cont
class QuestPoster(DirectFrame): notify = directNotify.newCategory('QuestPoster') def __init__(self, quest, parent = aspect2d, **kw): self.quest = quest # Let's begin building the quest poster. bookModel = loader.loadModel('phase_3.5/models/gui/stickerbook_gui.bam') questCard = bookModel.find('**/questCard') optiondefs = (('relief', None, None), ('image', questCard, None), ('image_scale', (0.8, 1.0, 0.58), None), ('state', DGG.NORMAL, None)) self.defineoptions(kw, optiondefs) DirectFrame.__init__(self, relief = None) self.initialiseoptions(QuestPoster) self.questFrame = DirectFrame(parent = self, relief = None) # Quest title text self.headline = DirectLabel(parent = self.questFrame, relief = None, text = self.quest.getName(), text_font = CIGlobals.getMinnieFont(), text_fg = QuestGlobals.TEXT_COLOR, text_scale = 0.05, text_align = TextNode.ACenter, text_wordwrap = 25.0, textMayChange = 1, pos = (0, 0, 0.23)) # Quest information self.questInfo = DirectLabel(parent = self.questFrame, relief = None, text = '', text_font = CIGlobals.getToonFont(), text_fg = QuestGlobals.TEXT_COLOR, text_scale = 0.04, text_align = TextNode.ACenter, text_wordwrap = TEXT_WORDWRAP, textMayChange = 1, pos = (QuestGlobals.DEFAULT_INFO_POS)) self.questInfo.hide() self.questInfo02 = DirectLabel(parent = self.questFrame, relief = None, text = '', text_font = CIGlobals.getToonFont(), text_fg = QuestGlobals.TEXT_COLOR, text_scale = 0.04, text_align = TextNode.ACenter, text_wordwrap = TEXT_WORDWRAP, textMayChange = 1, pos = (QuestGlobals.DEFAULT_INFO2_POS)) self.questInfo02.hide() self.locationInfo = DirectLabel(parent = self.questFrame, relief = None, text = 'N/A', text_font = CIGlobals.getToonFont(), text_fg = QuestGlobals.TEXT_COLOR, text_scale = TEXT_SCALE, text_align = TextNode.ACenter, text_wordwrap = TEXT_WORDWRAP, textMayChange = 1, pos = (0, 0, -0.115)) self.locationInfo.hide() # C'mon Brian this one is obvious self.rewardText = DirectLabel(parent = self.questFrame, relief = None, text = '', text_fg = QuestGlobals.REWARD_RED, text_scale = 0.0425, text_align = TextNode.ALeft, text_wordwrap = 17.0, textMayChange = 1, pos = (-0.36, 0, -0.26)) self.rewardText.hide() self.lPictureFrame = DirectFrame(parent = self.questFrame, relief = None, image = bookModel.find('**/questPictureFrame'), image_scale = QuestGlobals.IMAGE_SCALE_SMALL, text = '', text_pos = (0, -0.11), text_fg = QuestGlobals.TEXT_COLOR, text_scale = TEXT_SCALE, text_align = TextNode.ACenter, text_wordwrap = 11.0, pos = (QuestGlobals.DEFAULT_LEFT_PICTURE_POS), textMayChange = 1) self.lPictureFrame.hide() self.rPictureFrame = DirectFrame(parent = self.questFrame, relief = None, image = bookModel.find('**/questPictureFrame'), image_scale = QuestGlobals.IMAGE_SCALE_SMALL, text = '', text_pos = (0, -0.11), text_fg = QuestGlobals.TEXT_COLOR, text_scale = TEXT_SCALE, text_align = TextNode.ACenter, text_wordwrap = 11.0, textMayChange = 1, pos = (QuestGlobals.DEFAULT_RIGHT_PICTURE_POS)) self.rPictureFrame['image_color'] = Vec4(*QuestGlobals.GREEN) self.rPictureFrame.hide() self.lQuestIcon = DirectFrame(parent = self.lPictureFrame, relief = None, text = ' ', text_font = CIGlobals.getSuitFont(), text_pos = (0, -0.03), text_fg = QuestGlobals.TEXT_COLOR, text_scale = 0.13, text_align = TextNode.ACenter, text_wordwrap = 13.0, textMayChange = 1) self.lQuestIcon.setColorOff(-1) self.rQuestIcon = DirectFrame(parent = self.rPictureFrame, relief = None, text = ' ', text_font = CIGlobals.getSuitFont(), text_pos = (0, -0.03), text_fg = QuestGlobals.TEXT_COLOR, text_scale = 0.13, text_align = TextNode.ACenter, text_wordwrap = 13.0, textMayChange = 1) self.rQuestIcon.setColorOff(-1) head = SuitBank.PennyPincher.getHead().generate() head.setDepthTest(True) head.setDepthWrite(True) head.setScale(0.25) for part in head.getChildren(): part.setDepthTest(True) part.setDepthWrite(True) self.fitGeometry(head, fFlip = 1) self.rQuestIcon['geom'] = head self.rQuestIcon['geom_scale'] = QuestGlobals.IMAGE_SCALE_SMALL self.rQuestIcon['geom_pos'] = Point3(0, 10, -0.05) self.rQuestIcon['geom_hpr'] = Point3(180, 0, 0) self.rQuestIcon.initialiseoptions(DirectFrame) self.auxText = DirectLabel(parent = self.questFrame, relief = None, text = 'Recover', text_font = CIGlobals.getToonFont(), text_scale = QuestGlobals.QPauxText, text_fg = QuestGlobals.TEXT_COLOR, text_align = TextNode.ACenter, pos = (QuestGlobals.DEFAULT_AUX_POS), textMayChange=1) self.auxText.hide() self.middleText = DirectLabel(parent = self.questFrame, relief = None, text = 'from:', text_font = CIGlobals.getToonFont(), text_scale = QuestGlobals.QPauxText, text_fg = QuestGlobals.TEXT_COLOR, text_align = TextNode.ACenter, pos = (QuestGlobals.DEFAULT_MIDDLE_POS), textMayChange=1) self.middleText.hide() self.questProgress = DirectWaitBar(parent = self.questFrame, relief = DGG.SUNKEN, frameSize=(-0.95, 0.95, -0.1, 0.12), borderWidth = (0.025, 0.025), scale = 0.2, frameColor = (0.945, 0.875, 0.706, 1.0), barColor=(0.5, 0.7, 0.5, 1), text='0/0', text_font = CIGlobals.getToonFont(), text_scale = 0.19, text_fg = (0.05, 0.14, 0.4, 1), text_align = TextNode.ACenter, text_pos = (0, -0.05), #-0.02 pos = (0, 0, -0.2425)) self.questProgress.hide() rewardFrameGeom = loader.loadModel('phase_4/models/gui/gag_shop_purchase_gui.bam') self.rewardFrame = DirectFrame(parent = self.questFrame, relief = None, geom = rewardFrameGeom.find('**/Goofys_Sign'), geom_scale = (0.615, 0, 0.4), pos = (-0.01, 0, -0.25) ) jellybeanJar = QuestGlobals.getFilmIcon() self.lRewardFrame = DirectFrame(parent = self.rewardFrame, relief = None, geom = jellybeanJar, geom_scale = QuestGlobals.TP_ACCESS_SCALE, sortOrder = 1, pos = (QuestGlobals.LEFT_TP_ACCESS_POS)) self.lRewardFrame.setBin('gui-popup', 30) self.lRewardAmt = DirectFrame(parent = self.questFrame, relief = None, geom = rewardFrameGeom.find('**/Char_Pnl'), geom_scale = (0.15, 0, 0.1275), text = '#1', text_font = CIGlobals.getToonFont(), text_scale = 0.04, text_fg = (0, 0, 0, 1), text_align = TextNode.ACenter, text_pos = (0, -0.01), sortOrder = 2, pos = (-0.285, 0, -0.255)) self.lRewardAmt.setBin('gui-popup', 40) self.rRewardFrame = DirectFrame(parent = self.rewardFrame, relief = None, geom = QuestGlobals.getJBIcon(), geom_scale = QuestGlobals.JB_JAR_SCALE, pos = QuestGlobals.RIGHT_JB_JAR_POS) self.rRewardAmt = DirectFrame(parent = self.questFrame, relief = None, geom = rewardFrameGeom.find('**/Char_Pnl'), geom_scale = (0.15, 0, 0.1275), text = '25', text_font = CIGlobals.getToonFont(), text_scale = 0.04, text_fg = (0, 0, 0, 1), text_align = TextNode.ACenter, text_pos = (0, -0.01), pos = (0.2725, 0, -0.255)) self.rRewardAmt.setBin('gui-popup', 40) rewardFrameGeom.removeNode() # This is the rotated text on the side. self.sideInfo = DirectLabel(parent = self.questFrame, relief = None, text = QuestGlobals.JUST_FOR_FUN, text_fg = (0.0, 0.439, 1.0, 1.0), text_shadow = (0, 0, 0, 1), pos = (-0.2825, 0, 0.2), scale = 0.03) self.sideInfo.setR(-30) self.sideInfo.hide() bookModel.removeNode() self.laffMeter = None self.hide() return def handleIcon(self, objective, geom, scale, icon): isHead = True if type(geom) == ToonHead else geom.getName() == ('%sHead' % CIGlobals.Suit) if isHead: geom.setDepthWrite(1) geom.setDepthTest(1) self.fitGeometry(geom, fFlip = 1) if isinstance(objective, VisitNPCObjective) and icon == self.rQuestIcon: icon.setPos(icon.getX(), icon.getY(), icon.getZ() + 0.05) icon.setH(180) elif isinstance(objective, CogObjective): icon.setScale(QuestGlobals.IMAGE_SCALE_SMALL) icon.setPos(icon.getX(), icon.getY(), icon.getZ() - 0.04) if icon == self.lQuestIcon: icon.setH(180) icon['geom'] = geom icon['geom_scale'] = QuestGlobals.IMAGE_SCALE_SMALL else: icon['geom'] = geom icon['geom_scale'] = scale def update(self): objective = self.quest.getCurrentObjective() objective.updateInfo() # Let's setup the quest info. self.questInfo.setPos(self.quest.getInfoPos()) self.questInfo['text'] = self.quest.getInfoText() self.questInfo02.setPos(self.quest.getInfo02Pos()) self.questInfo02['text'] = self.quest.getInfo02Text() # Let's move the picture frames to the positions we want them in. self.lPictureFrame.setPos(self.quest.getLeftPicturePos()) self.rPictureFrame.setPos(self.quest.getRightPicturePos()) editLeftAtr = isinstance(objective, VisitNPCObjective) or isinstance(objective, CogObjective) if editLeftAtr and objective.getDidEditLeft() or not editLeftAtr: geom = self.quest.getLeftIconGeom() scale = self.quest.getLeftIconScale() icon = self.lQuestIcon self.handleIcon(objective, geom, scale, icon) self.handleIcon(objective, self.quest.getRightIconGeom(), self.quest.getRightIconScale(), self.rQuestIcon) else: geom = self.quest.getRightIconGeom() scale = self.quest.getRightIconScale() icon = self.rQuestIcon self.handleIcon(objective, geom, scale, icon) self.handleIcon(objective, self.quest.getLeftIconGeom(), self.quest.getLeftIconScale(), self.lQuestIcon) if self.questInfo02['text'] == '': self.rPictureFrame.hide() self.questInfo02.hide() else: self.rPictureFrame.show() self.questInfo02.show() self.middleText['text'] = self.quest.getMiddleText() if not self.middleText['text'] == '': self.middleText.show() self.questInfo.show() self.lPictureFrame.show() # Let's set the location text. self.locationInfo['text'] = self.quest.getLocationText() self.locationInfo['text_pos'] = (0, self.quest.getLocationY()) self.locationInfo.show() # Let's set the progress bar up. self.questProgress['text'] = self.quest.getProgressText() if len(self.questProgress['text']) > 0 and not objective.finished(): self.questProgress.show() self.questProgress['range'] = objective.getNeededAmount() self.questProgress['value'] = objective.getProgress() & pow(2, 16) - 1 else: self.questProgress.hide() # Let's setup the aux text. self.auxText.setPos(self.quest.getAuxPos()) self.auxText['text'] = self.quest.getAuxText() self.auxText.show() maxHP = base.localAvatar.getMaxHealth() # Let's setup the rewards. for i in xrange(0, len(self.quest.getRewards())): reward = self.quest.getRewards()[i] frame = self.lRewardFrame if (i == 0) else self.rRewardFrame info = self.lRewardAmt if (i == 0) else self.rRewardAmt rType = reward.getType() if(rType == RewardType.JELLYBEANS): frame['pos'] = QuestGlobals.LEFT_JB_JAR_POS if (i == 0) else QuestGlobals.RIGHT_JB_JAR_POS frame['geom'] = QuestGlobals.getJBIcon() frame['geom_scale'] = QuestGlobals.JB_JAR_SCALE info['text'] = str(reward.getModifier()) elif(rType == RewardType.TELEPORT_ACCESS or rType == RewardType.GAG_FRAME): frame['pos'] = QuestGlobals.LEFT_TP_ACCESS_POS if(i == 0) else QuestGlobals.RIGHT_TP_ACCESS_POS frame['geom'] = QuestGlobals.getTPAccessIcon() if(rType == RewardType.TELEPORT_ACCESS) else QuestGlobals.getFilmIcon() frame['geom_scale'] = QuestGlobals.TP_ACCESS_SCALE info['text'] = 'N/A' if(rType == RewardType.TELEPORT_ACCESS) else '#%s' % (str(reward.getModifier())) elif(rType == RewardType.LAFF_POINTS): frame.initialiseoptions(DirectFrame) r, g, b, _ = base.localAvatar.getHeadColor() pos = QuestGlobals.LEFT_LAFF_METER_POS if(i == 0) else QuestGlobals.RIGHT_LAFF_METER_POS # Create the laff meter with the new health. hp = maxHP + reward.getModifier() laffMeter = LaffOMeter() laffMeter.generate(r, g, b, base.localAvatar.getAnimal(), maxHP = hp, initialHP = hp) # Let's position the laff meter. frame['geom'] = laffMeter frame['geom_scale'] = QuestGlobals.LAFF_METER_SCALE frame.setPos(pos) info['text'] = '+%s' % (str(reward.getModifier())) laffMeter.destroy() laffMeter = None # Hide or show the other reward depending on if there's 2 rewards. if(len(self.quest.getRewards()) == 1): self.rRewardFrame.hide() self.rRewardAmt.hide() else: self.rRewardFrame.show() self.rRewardAmt.show() if objective.finished(): self.setColor(Vec4(*QuestGlobals.LIGHT_GREEN)) self.sideInfo['text'] = 'Completed!' self.sideInfo.show() self.questInfo.initialiseoptions(DirectLabel) self.questInfo02.initialiseoptions(DirectLabel) self.locationInfo.initialiseoptions(DirectLabel) self.lPictureFrame.initialiseoptions(DirectFrame) self.rPictureFrame.initialiseoptions(DirectFrame) self.lQuestIcon.initialiseoptions(DirectFrame) self.rQuestIcon.initialiseoptions(DirectFrame) self.auxText.initialiseoptions(DirectLabel) self.middleText.initialiseoptions(DirectLabel) self.sideInfo.initialiseoptions(DirectLabel) self.lPictureFrame['image_color'] = self.quest.getPictureFrameColor() self.rPictureFrame['image_color'] = self.quest.getPictureFrameColor() def fitGeometry(self, geom, fFlip = 0, dimension = 0.8): p1 = Point3() p2 = Point3() geom.calcTightBounds(p1, p2) if fFlip: t = p1[0] p1.setX(-p2[0]) p2.setX(-t) d = p2 - p1 biggest = max(d[0], d[2]) s = dimension / biggest mid = (p1 + d / 2.0) * s geomXform = hidden.attachNewNode('geomXform') for child in geom.getChildren(): child.reparentTo(geomXform) geomXform.setPosHprScale(-mid[0], -mid[1] + 1, -mid[2], 180, 0, 0, s, s, s) geomXform.reparentTo(geom) def destroy(self): self._deleteGeoms() DirectFrame.destroy(self) def _deleteGeoms(self): for icon in (self.lQuestIcon, self.rQuestIcon): geom = icon['geom'] if geom and hasattr(geom, 'delete'): geom.delete() def getQuest(self): return self.quest
class OptionsMenu(DirectObject): def __init__(self): """Default constructor""" # create a main frame as big as the window self.frameMain = DirectFrame( # set framesize the same size as the window frameSize = (base.a2dLeft, base.a2dRight, base.a2dTop, base.a2dBottom), image = "LogoTextGlow.png", image_scale = (1.06/2.0, 1, 0.7/2.0), image_pos = (0, 0, 0.7), # position center pos = (0, 0, 0), # set tramsparent background color frameColor = (0, 0, 0, 0)) self.frameMain.setTransparency(1) self.frameMain.setBin("fixed", 100) sliderscale = 0.5 buttonScale = 0.25 textscale = 0.1 checkboxscale = 0.05 left = -0.5 right = 0.5 self.sliderTextspeed = DirectSlider( scale = sliderscale, pos = (left, 0, 0.2), range = (0.2,0.01), scrollSize = 0.01, text = _("Textspeed %0.1f%%")%(base.textWriteSpeed * 10), text_scale = textscale, text_align = TextNode.ACenter, text_pos = (0.0, 0.15), text_fg = (1,1,1,1), thumb_frameColor = (0.65, 0.65, 0.0, 1), thumb_relief = DGG.FLAT, frameColor = (0.15, 0.15, 0.15, 1), value = base.textWriteSpeed, command = self.sliderTextspeed_ValueChanged) self.sliderTextspeed.reparentTo(self.frameMain) self.cbParticles = DirectCheckButton( text = _(" Enable Particles"), text_fg = (1, 1, 1, 1), text_shadow = (0, 0, 0, 0.35), pos = (left, 0, -0.0), scale = checkboxscale, frameColor = (0,0,0,0), command = self.cbParticles_CheckedChanged, rolloverSound = None, clickSound = None, pressEffect = False, boxPlacement = "below", boxBorder = 0.8, boxRelief = DGG.FLAT, indicator_scale = 1.5, indicator_text_fg = (0.65, 0.65, 0.0, 1), indicator_text_shadow = (0, 0, 0, 0.35), indicator_frameColor = (0.15, 0.15, 0.15, 1), indicatorValue = base.particleMgrEnabled ) self.cbParticles.indicator['text'] = (' ', 'x') self.cbParticles.indicator['text_pos'] = (0, 0.1) #self.cbParticles.indicator.setX(self.cbParticles.indicator, -0.5) #self.cbParticles.indicator.setZ(self.cbParticles.indicator, -0.1) #self.cbParticles.setFrameSize() self.cbParticles.setTransparency(1) self.cbParticles.reparentTo(self.frameMain) volume = base.musicManager.getVolume() self.sliderVolume = DirectSlider( scale = sliderscale, pos = (left, 0, -0.35), range = (0,1), scrollSize = 0.01, text = _("Volume %d%%")%volume*100, text_scale = textscale, text_align = TextNode.ACenter, text_pos = (.0, 0.15), text_fg = (1,1,1,1), thumb_frameColor = (0.65, 0.65, 0.0, 1), thumb_relief = DGG.FLAT, frameColor = (0.15, 0.15, 0.15, 1), value = volume, command = self.sliderVolume_ValueChanged) self.sliderVolume.reparentTo(self.frameMain) self.lblControltype = DirectLabel( text = _("Control type"), text_fg = (1, 1, 1, 1), text_shadow = (0, 0, 0, 0.35), frameColor = (0, 0, 0, 0), scale = textscale/2, pos = (right, 0, 0.27)) self.lblControltype.setTransparency(1) self.lblControltype.reparentTo(self.frameMain) selectedControlType = 0 if base.controlType == "MouseAndKeyboard": selectedControlType = 1 self.controltype = DirectOptionMenu( pos = (right, 0, 0.18), text_fg = (1, 1, 1, 1), scale = 0.1, items = [_("Keyboard"),_("Keyboard + Mouse")], initialitem = selectedControlType, frameColor = (0.15, 0.15, 0.15, 1), popupMarker_frameColor = (0.65, 0.65, 0.0, 1), popupMarker_relief = DGG.FLAT, highlightColor = (0.65, 0.65, 0.0, 1), relief = DGG.FLAT, command=self.controlType_Changed) self.controltype.reparentTo(self.frameMain) b = self.controltype.getBounds() xPos = right - ((b[1] - b[0]) / 2.0 * 0.1) self.controltype.setX(xPos) setItems(self.controltype) self.controltype.setItems = setItems self.controltype.showPopupMenu = showPopupMenu self.controltype.popupMarker.unbind(DGG.B1PRESS) self.controltype.popupMarker.bind(DGG.B1PRESS, showPopupMenu) self.controltype.unbind(DGG.B1PRESS) self.controltype.bind(DGG.B1PRESS, showPopupMenuExtra, [self.controltype]) isChecked = not base.AppHasAudioFocus img = None if base.AppHasAudioFocus: img = "AudioSwitch_on.png" else: img = "AudioSwitch_off.png" self.cbVolumeMute = DirectCheckBox( text = _("Mute Audio"), text_scale = 0.5, text_align = TextNode.ACenter, text_pos = (0.0, 0.65), text_fg = (1,1,1,1), pos = (right, 0, -0.35), scale = 0.21/2.0, command = self.cbVolumeMute_CheckedChanged, rolloverSound = None, clickSound = None, relief = None, pressEffect = False, isChecked = isChecked, image = img, image_scale = 0.5, checkedImage = "AudioSwitch_off.png", uncheckedImage = "AudioSwitch_on.png") self.cbVolumeMute.setTransparency(1) self.cbVolumeMute.setImage() self.cbVolumeMute.reparentTo(self.frameMain) sensitivity = base.mouseSensitivity self.sliderSensitivity = DirectSlider( scale = sliderscale, pos = (right, 0, -0.075), range = (0.5,2), scrollSize = 0.01, text = _("Mouse Sensitivity %0.1fx")%sensitivity, text_scale = textscale, text_align = TextNode.ACenter, text_pos = (.0, 0.15), text_fg = (1,1,1,1), thumb_frameColor = (0.65, 0.65, 0.0, 1), thumb_relief = DGG.FLAT, frameColor = (0.15, 0.15, 0.15, 1), value = sensitivity, command = self.sliderSensitivity_ValueChanged) self.sliderSensitivity.reparentTo(self.frameMain) if base.controlType == "Gamepad": self.sliderSensitivity.hide() # create the back button self.btnBack = DirectButton( scale = buttonScale, # position on the window pos = (0, 0, base.a2dBottom + 0.15), frameColor = (0,0,0,0), # text properties text = _("Back"), text_scale = 0.5, text_fg = (1,1,1,1), text_pos = (0.0, -0.15), text_shadow = (0, 0, 0, 0.35), text_shadowOffset = (-0.05, -0.05), # sounds that should be played rolloverSound = None, clickSound = None, pressEffect = False, relief = None, # the event which is thrown on clickSound command = lambda: base.messenger.send("options_back")) self.btnBack.setTransparency(1) self.btnBack.reparentTo(self.frameMain) self.hide() def show(self, enableResume=False): self.frameMain.show() def hide(self): self.frameMain.hide() def cbVolumeMute_CheckedChanged(self, checked): if checked: base.disableAllAudio() else: base.enableAllAudio() def sliderVolume_ValueChanged(self): volume = round(self.sliderVolume["value"], 2) self.sliderVolume["text"] = _("Volume %d%%") % int(volume * 100) base.sfxManagerList[0].setVolume(volume) base.musicManager.setVolume(volume) def sliderSensitivity_ValueChanged(self): sensitivity = round(self.sliderSensitivity["value"], 2) self.sliderSensitivity["text"] = _("Mouse Sensitivity %0.1fx") % sensitivity base.mouseSensitivity = sensitivity def sliderTextspeed_ValueChanged(self): newSpeed = round(self.sliderTextspeed["value"], 2) displaySpeed = 1.0 / newSpeed self.sliderTextspeed["text"] = _("Textspeed %0.1f%%")%displaySpeed base.textWriteSpeed = newSpeed def cbParticles_CheckedChanged(self, unchecked): if unchecked: base.enableParticles() else: base.disableParticles() def controlType_Changed(self, arg): if arg == _("Keyboard"): self.sliderSensitivity.hide() base.controlType = "Gamepad" elif arg == _("Keyboard + Mouse"): self.sliderSensitivity.show() base.controlType = "MouseAndKeyboard"
class Menu(DirectObject): def __init__(self): self.accept("window-event", self.recalcAspectRatio) self.frameMain = DirectFrame( # size of the frame frameSize = (base.a2dLeft, base.a2dRight, base.a2dTop, base.a2dBottom), # position of the frame image = "LogoTextGlow.png", image_scale = (1.06, 1, 0.7), image_pos = (0, 0, 0.25), pos = (0, 0, 0), # tramsparent bg color frameColor = (0, 0, 0, 0), sortOrder = 0) self.frameMain.setTransparency(1) self.frameMain.setBin("fixed", 100) btnGeom = None self.btnStart = self.createButton(_("Start"), btnGeom, -0.6, self.btnStart_Click) self.btnStart.reparentTo(self.frameMain) self.btnOptions = self.createButton(_("Options"), btnGeom, 0, self.btnOptions_Click) self.btnOptions.reparentTo(self.frameMain) self.btnQuit = self.createButton(_("Quit"), btnGeom, 0.6, self.btnQuit_Click) self.btnQuit.reparentTo(self.frameMain) self.recalcAspectRatio(base.win) # hide all buttons at startup self.hide() def show(self): self.frameMain.show() self.recalcAspectRatio(base.win) def hide(self): self.frameMain.hide() def recalcAspectRatio(self, window): """get the new aspect ratio to resize the mainframe""" screenResMultiplier = window.getXSize() / window.getYSize() self.frameMain["frameSize"] = ( base.a2dLeft, base.a2dRight, base.a2dTop, base.a2dBottom) self.btnQuit["text_scale"] = (0.5*screenResMultiplier, 0.5, 0.5) self.btnStart["text_scale"] = (0.5*screenResMultiplier, 0.5, 0.5) def createButton(self, text, btnGeom, xPos, command): btn = DirectButton( scale = (0.25, 0.25, 0.25), # some temp text text = text, text_scale = (0.5, 0.5, 0.5), # set the alignment to right text_align = TextNode.ACenter, # put the text on the right side of the button text_pos = (0, -0.15), # set the text color to black text_fg = (1,1,1,1), text_shadow = (0.3, 0.3, 0.1, 1), text_shadowOffset = (0.05, 0.05), # set the buttons images #geom = btnGeom, relief = 1, frameColor = (0,0,0,0), pressEffect = False, pos = (xPos, 0, -0.65), command = command, rolloverSound = None, clickSound = None) btn.setTransparency(1) return btn def btnStart_Click(self): base.messenger.send("menu_start") def btnOptions_Click(self): base.messenger.send("menu_options") def btnQuit_Click(self): base.messenger.send("menu_quit")
class Transitions: # These may be reassigned before the fade or iris transitions are # actually invoked to change the models that will be used. IrisModelName = "models/misc/iris" FadeModelName = "models/misc/fade" def __init__(self, loader, model=None, scale=3.0, pos=Vec3(0, 0, 0)): self.transitionIval = None self.letterboxIval = None self.iris = None self.fade = None self.letterbox = None self.fadeModel = model self.imagePos = pos if model: self.alphaOff = Vec4(1, 1, 1, 0) self.alphaOn = Vec4(1, 1, 1, 1) model.setTransparency(1) self.lerpFunc = LerpColorScaleInterval else: self.alphaOff = Vec4(0, 0, 0, 0) self.alphaOn = Vec4(0, 0, 0, 1) self.lerpFunc = LerpColorInterval self.irisTaskName = "irisTask" self.fadeTaskName = "fadeTask" self.letterboxTaskName = "letterboxTask" def __del__(self): if self.fadeModel: self.fadeModel.removeNode() self.fadeModel = None ################################################## # Fade ################################################## # We can set a custom model for the fade before using it for the first time def setFadeModel(self, model, scale=1.0): self.fadeModel = model # We have to change some default parameters for a custom fadeModel self.alphaOn = Vec4(1, 1, 1, 1) # Reload fade if its already been created if self.fade: self.fade.destroy() self.fade = None self.loadFade() def loadFade(self): if self.fade is None: # We create a DirectFrame for the fade polygon, instead of # simply loading the polygon model and using it directly, # so that it will also obscure mouse events for objects # positioned behind it. self.fade = DirectFrame( parent = hidden, guiId = 'fade', relief = None, image = self.fadeModel, image_scale = (4, 2, 2), state = DGG.NORMAL, ) if not self.fadeModel: # No fade model was given, so we make this the fade model. self.fade["relief"] = DGG.FLAT self.fade["frameSize"] = (-2, 2, -1, 1) self.fade["frameColor"] = (0, 0, 0, 1) self.fade.setTransparency(TransparencyAttrib.MAlpha) self.fade.setBin('unsorted', 0) self.fade.setColor(0,0,0,0) def getFadeInIval(self, t=0.5, finishIval=None): """ Returns an interval without starting it. This is particularly useful in cutscenes, so when the cutsceneIval is escaped out of we can finish the fade immediately """ #self.noTransitions() masad: this creates a one frame pop, is it necessary? self.loadFade() transitionIval = Sequence(Func(self.fade.reparentTo, aspect2d, DGG.FADE_SORT_INDEX), Func(self.fade.showThrough), # in case aspect2d is hidden for some reason self.lerpFunc(self.fade, t, self.alphaOff, # self.alphaOn, ), Func(self.fade.detachNode), name = self.fadeTaskName, ) if finishIval: transitionIval.append(finishIval) return transitionIval def getFadeOutIval(self, t=0.5, finishIval=None): """ Create a sequence that lerps the color out, then parents the fade to hidden """ self.noTransitions() self.loadFade() transitionIval = Sequence(Func(self.fade.reparentTo,aspect2d,DGG.FADE_SORT_INDEX), Func(self.fade.showThrough), # in case aspect2d is hidden for some reason self.lerpFunc(self.fade, t, self.alphaOn, # self.alphaOff, ), name = self.fadeTaskName, ) if finishIval: transitionIval.append(finishIval) return transitionIval def fadeIn(self, t=0.5, finishIval=None): """ Play a fade in transition over t seconds. Places a polygon on the aspect2d plane then lerps the color from black to transparent. When the color lerp is finished, it parents the fade polygon to hidden. """ gsg = base.win.getGsg() if gsg: # If we're about to fade in from black, go ahead and # preload all the textures etc. base.graphicsEngine.renderFrame() render.prepareScene(gsg) render2d.prepareScene(gsg) if (t == 0): # Fade in immediately with no lerp #print "transitiosn: fadeIn 0.0" self.noTransitions() self.loadFade() self.fade.detachNode() else: # Create a sequence that lerps the color out, then # parents the fade to hidden self.transitionIval = self.getFadeInIval(t, finishIval) self.transitionIval.start() def fadeOut(self, t=0.5, finishIval=None): """ Play a fade out transition over t seconds. Places a polygon on the aspect2d plane then lerps the color from transparent to full black. When the color lerp is finished, it leaves the fade polygon covering the aspect2d plane until you fadeIn or call noFade. lerp """ if (t == 0): # Fade out immediately with no lerp self.noTransitions() self.loadFade() self.fade.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) self.fade.setColor(self.alphaOn) elif ConfigVariableBool('no-loading-screen', False): if finishIval: self.transitionIval = finishIval self.transitionIval.start() else: # Create a sequence that lerps the color out, then # parents the fade to hidden self.transitionIval = self.getFadeOutIval(t,finishIval) self.transitionIval.start() def fadeOutActive(self): return self.fade and self.fade.getColor()[3] > 0 def fadeScreen(self, alpha=0.5): """ Put a semitransparent screen over the camera plane to darken out the world. Useful for drawing attention to a dialog box for instance """ #print "transitiosn: fadeScreen" self.noTransitions() self.loadFade() self.fade.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) self.fade.setColor(self.alphaOn[0], self.alphaOn[1], self.alphaOn[2], alpha) def fadeScreenColor(self, color): """ Put a semitransparent screen over the camera plane to darken out the world. Useful for drawing attention to a dialog box for instance """ #print "transitiosn: fadeScreenColor" self.noTransitions() self.loadFade() self.fade.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) self.fade.setColor(color) def noFade(self): """ Removes any current fade tasks and parents the fade polygon away """ #print "transitiosn: noFade" if self.transitionIval: self.transitionIval.pause() self.transitionIval = None if self.fade: # Make sure to reset the color, since fadeOutActive() is looking at it self.fade.setColor(self.alphaOff) self.fade.detachNode() def setFadeColor(self, r, g, b): self.alphaOn.set(r, g, b, 1) self.alphaOff.set(r, g, b, 0) ################################################## # Iris ################################################## def loadIris(self): if self.iris == None: self.iris = loader.loadModel(self.IrisModelName) self.iris.setPos(0, 0, 0) def irisIn(self, t=0.5, finishIval=None): """ Play an iris in transition over t seconds. Places a polygon on the aspect2d plane then lerps the scale of the iris polygon up so it looks like we iris in. When the scale lerp is finished, it parents the iris polygon to hidden. """ self.noTransitions() self.loadIris() if (t == 0): self.iris.detachNode() else: self.iris.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) self.transitionIval = Sequence(LerpScaleInterval(self.iris, t, scale = 0.18, startScale = 0.01), Func(self.iris.detachNode), name = self.irisTaskName, ) if finishIval: self.transitionIval.append(finishIval) self.transitionIval.start() def irisOut(self, t=0.5, finishIval=None): """ Play an iris out transition over t seconds. Places a polygon on the aspect2d plane then lerps the scale of the iris down so it looks like we iris out. When the scale lerp is finished, it leaves the iris polygon covering the aspect2d plane until you irisIn or call noIris. """ self.noTransitions() self.loadIris() self.loadFade() # we need this to cover up the hole. if (t == 0): self.iris.detachNode() self.fadeOut(0) else: self.iris.reparentTo(aspect2d, DGG.FADE_SORT_INDEX) self.transitionIval = Sequence(LerpScaleInterval(self.iris, t, scale = 0.01, startScale = 0.18), Func(self.iris.detachNode), # Use the fade to cover up the hole that the iris would leave Func(self.fadeOut, 0), name = self.irisTaskName, ) if finishIval: self.transitionIval.append(finishIval) self.transitionIval.start() def noIris(self): """ Removes any current iris tasks and parents the iris polygon away """ if self.transitionIval: self.transitionIval.pause() self.transitionIval = None if self.iris != None: self.iris.detachNode() # Actually we need to remove the fade too, # because the iris effect uses it. self.noFade() def noTransitions(self): """ This call should immediately remove any and all transitions running """ self.noFade() self.noIris() # Letterbox is not really a transition, it is a screen overlay # self.noLetterbox() ################################################## # Letterbox ################################################## def loadLetterbox(self): if not self.letterbox: # We create a DirectFrame for the fade polygon, instead of # simply loading the polygon model and using it directly, # so that it will also obscure mouse events for objects # positioned behind it. self.letterbox = NodePath("letterbox") # Allow fade in and out of the bars self.letterbox.setTransparency(1) # Allow DirectLabels to be parented to the letterbox sensibly self.letterbox.setBin('unsorted', 0) # Allow a custom look to the letterbox graphic. # TODO: This model isn't available everywhere. We should # pass it in as a parameter. button = loader.loadModel('models/gui/toplevel_gui', okMissing = True) barImage = None if button: barImage = button.find('**/generic_button') self.letterboxTop = DirectFrame( parent = self.letterbox, guiId = 'letterboxTop', relief = DGG.FLAT, state = DGG.NORMAL, frameColor = (0, 0, 0, 1), borderWidth = (0, 0), frameSize = (-1, 1, 0, 0.2), pos = (0, 0, 0.8), image = barImage, image_scale = (2.25,1,.5), image_pos = (0,0,.1), image_color = (0.3,0.3,0.3,1), sortOrder = 0, ) self.letterboxBottom = DirectFrame( parent = self.letterbox, guiId = 'letterboxBottom', relief = DGG.FLAT, state = DGG.NORMAL, frameColor = (0, 0, 0, 1), borderWidth = (0, 0), frameSize = (-1, 1, 0, 0.2), pos = (0, 0, -1), image = barImage, image_scale = (2.25,1,.5), image_pos = (0,0,.1), image_color = (0.3,0.3,0.3,1), sortOrder = 0, ) # masad: always place these at the bottom of render self.letterboxTop.setBin('sorted',0) self.letterboxBottom.setBin('sorted',0) self.letterbox.reparentTo(render2d, -1) self.letterboxOff(0) def noLetterbox(self): """ Removes any current letterbox tasks and parents the letterbox polygon away """ if self.letterboxIval: self.letterboxIval.pause() self.letterboxIval = None if self.letterbox: self.letterbox.stash() def letterboxOn(self, t=0.25, finishIval=None): """ Move black bars in over t seconds. """ self.noLetterbox() self.loadLetterbox() self.letterbox.unstash() if (t == 0): self.letterboxBottom.setPos(0, 0, -1) self.letterboxTop.setPos(0, 0, 0.8) else: self.letterboxIval = Sequence(Parallel( LerpPosInterval(self.letterboxBottom, t, pos = Vec3(0, 0, -1), #startPos = Vec3(0, 0, -1.2), ), LerpPosInterval(self.letterboxTop, t, pos = Vec3(0, 0, 0.8), # startPos = Vec3(0, 0, 1), ), ), name = self.letterboxTaskName, ) if finishIval: self.letterboxIval.append(finishIval) self.letterboxIval.start() def letterboxOff(self, t=0.25, finishIval=None): """ Move black bars away over t seconds. """ self.noLetterbox() self.loadLetterbox() self.letterbox.unstash() if (t == 0): self.letterbox.stash() else: self.letterboxIval = Sequence(Parallel( LerpPosInterval(self.letterboxBottom, t, pos = Vec3(0, 0, -1.2), # startPos = Vec3(0, 0, -1), ), LerpPosInterval(self.letterboxTop, t, pos = Vec3(0, 0, 1), # startPos = Vec3(0, 0, 0.8), ), ), Func(self.letterbox.stash), Func(messenger.send,'letterboxOff'), name = self.letterboxTaskName, ) if finishIval: self.letterboxIval.append(finishIval) self.letterboxIval.start()
class Menu(DirectObject): def __init__(self): self.accept("window-event", self.recalcAspectRatio) self.frameMain = DirectFrame( # size of the frame frameSize=(base.a2dLeft, base.a2dRight, base.a2dTop, base.a2dBottom), # position of the frame image="LogoTextGlow.png", image_scale=(1.06, 1, 0.7), image_pos=(0, 0, 0.25), pos=(0, 0, 0), # tramsparent bg color frameColor=(0, 0, 0, 0), sortOrder=0, ) self.frameMain.setTransparency(1) self.frameMain.setBin("fixed", 100) btnGeom = None self.btnStart = self.createButton(_("Start"), btnGeom, -0.6, self.btnStart_Click) self.btnStart.reparentTo(self.frameMain) self.btnOptions = self.createButton(_("Options"), btnGeom, 0, self.btnOptions_Click) self.btnOptions.reparentTo(self.frameMain) self.btnQuit = self.createButton(_("Quit"), btnGeom, 0.6, self.btnQuit_Click) self.btnQuit.reparentTo(self.frameMain) self.recalcAspectRatio(base.win) # hide all buttons at startup self.hide() def show(self): self.frameMain.show() self.recalcAspectRatio(base.win) def hide(self): self.frameMain.hide() def recalcAspectRatio(self, window): """get the new aspect ratio to resize the mainframe""" screenResMultiplier = window.getXSize() / window.getYSize() self.frameMain["frameSize"] = (base.a2dLeft, base.a2dRight, base.a2dTop, base.a2dBottom) self.btnQuit["text_scale"] = (0.5 * screenResMultiplier, 0.5, 0.5) self.btnStart["text_scale"] = (0.5 * screenResMultiplier, 0.5, 0.5) def createButton(self, text, btnGeom, xPos, command): btn = DirectButton( scale=(0.25, 0.25, 0.25), # some temp text text=text, text_scale=(0.5, 0.5, 0.5), # set the alignment to right text_align=TextNode.ACenter, # put the text on the right side of the button text_pos=(0, -0.15), # set the text color to black text_fg=(1, 1, 1, 1), text_shadow=(0.3, 0.3, 0.1, 1), text_shadowOffset=(0.05, 0.05), # set the buttons images # geom = btnGeom, relief=1, frameColor=(0, 0, 0, 0), pressEffect=False, pos=(xPos, 0, -0.65), command=command, rolloverSound=None, clickSound=None, ) btn.setTransparency(1) return btn def btnStart_Click(self): base.messenger.send("menu_start") def btnOptions_Click(self): base.messenger.send("menu_options") def btnQuit_Click(self): base.messenger.send("menu_quit")