def __init__(self): self.itemFrame = DirectScrolledFrame( text="Inventory", text_scale=0.25, text_pos=(0, 0.75, 0), text_bg=(1, 1, 1, 1), # make the frame occupy the whole window frameSize=(-0.6, 0.6, -0.8, 0.8), pos=(-0.7, 0, 0), # make the canvas as big as the frame canvasSize=(-0.6, 0.6, -0.8, 0.8), # set the frames color to white frameColor=(1, 1, 1, 1)) self.itemList = [] self.craftFrame = DirectFrame( text="Crafting", text_scale=0.25, text_pos=(0, 0.75, 0), text_bg=(1, 1, 1, 1), # make the frame occupy the whole window frameSize=(-0.6, 0.6, -0.8, 0.8), pos=(0.7, 0, 0), # set the frames color to white frameColor=(1, 1, 1, 1)) self.craftDrop = DirectFrame(text="drop ore", text_scale=0.1, pos=(0, 0.4, 0), frameSize=(-0.25, 0.25, -0.25, 0.25), frameColor=(1, 0, 0, 1)) self.craftDrop.reparentTo(self.craftFrame)
def create_device_menu(self): self.current_panel = None self.buttons = {} self.devices_frame = DirectScrolledFrame( frameSize=VBase4( 0, base.a2dLeft*-0.75, base.a2dBottom - base.a2dTop, 0, ), frameColor=VBase4(0, 0, 0.25, 1.0), canvasSize=VBase4( 0, base.a2dLeft*-0.75, 0, 0, ), scrollBarWidth=0.08, manageScrollBars=True, autoHideScrollBars=True, pos=(base.a2dLeft, 0, base.a2dTop), parent=base.aspect2d, ) self.devices_frame.setCanvasSize()
def __init__(self): self.defaultBtnMap = base.loader.loadModel("gui/button_map") self.buttonGeom = (self.defaultBtnMap.find("**/button_ready"), self.defaultBtnMap.find("**/button_click"), self.defaultBtnMap.find("**/button_rollover"), self.defaultBtnMap.find("**/button_disabled")) defaultFont = loader.loadFont('gui/eufm10.ttf') self.logFrame = DirectScrolledFrame( canvasSize=(0, base.a2dRight * 2, -5, 0), frameSize=(0, base.a2dRight * 2, (base.a2dBottom + .2) * 2, 0), frameColor=(0.1, 0.1, 0.1, 1)) self.logFrame.reparentTo(base.a2dTopLeft) # create the info and server debug output self.textscale = 0.1 self.txtinfo = OnscreenText(scale=self.textscale, pos=(0.1, -0.1), text="", align=TextNode.ALeft, fg=(0.1, 1.0, 0.15, 1), bg=(0, 0, 0, 0), shadow=(0, 0, 0, 1), shadowOffset=(-0.02, -0.02)) self.txtinfo.setTransparency(1) self.txtinfo.reparentTo(self.logFrame.getCanvas()) # create a close Server button self.btnBackPos = Vec3(0.4, 0, 0.2) self.btnBackScale = 0.25 self.btnBack = DirectButton( # Scale and position scale=self.btnBackScale, pos=self.btnBackPos, # Text text="Quit Server", text_scale=0.45, text_pos=(0, -0.1), text_fg=(0.82, 0.85, 0.87, 1), text_shadow=(0, 0, 0, 1), text_shadowOffset=(-0.02, -0.02), text_font=defaultFont, # Frame geom=self.buttonGeom, frameColor=(0, 0, 0, 0), relief=0, pressEffect=False, # Functionality command=self.back, rolloverSound=None, clickSound=None) self.btnBack.setTransparency(1) self.btnBack.reparentTo(base.a2dBottomLeft) # catch window resizes and recalculate the aspectration self.accept("window-event", self.recalcAspectRatio) self.accept("addLog", self.addLog)
def __init__(self, frame_size=(1, 1.5), frame_color=(0.2, 0.2, 0.2, 0.8), pos=(0, 0, 0), item_v_padding=0.02, item_h_padding=0.04, item_scale=1, item_side_ratio=0.2, item_background=(0.3, 0.3, 0.3, 1), item_background_active=(0.6, 0.6, 0.6, 1), command=lambda: None): self.f_x, self.f_y = frame_size self.c_x = self.f_x self.c_y = self.f_y self.item_v_padding = item_v_padding self.item_h_padding = item_h_padding self.item_scale = item_scale self.item_background = item_background self.item_background_active = item_background_active self.frame = DirectScrolledFrame( frameSize=(-self.f_x / 2, self.f_x / 2, -self.f_y / 2, self.f_y / 2), canvasSize=(-self.c_x / 2, self.c_x / 2, -self.c_y / 2, self.c_y / 2), frameColor=frame_color, pos=pos, scrollBarWidth=(0), manageScrollBars=False, state=DGG.NORMAL) self.frame.verticalScroll.destroy() self.frame.horizontalScroll.destroy() self.frame.bind(DGG.WITHIN, self._start_listening) self.frame.bind(DGG.WITHOUT, self._stop_listening) self.canvas = self.frame.getCanvas() self.i_x = self.f_x * (1 - item_h_padding) self.i_y = self.f_y * item_side_ratio self.i_size = (-self.i_x / 2, self.i_x / 2, -self.i_y / 2, self.i_y / 2) self.i_start = self.c_y / 2 + self.i_y / 2 self.active_item = None self.item_list = [] self.value_list = [] self.start_mY = None self.old_mY = None self.m_diff = 0 self.is_scrolling = False self.command = command
def __init__(self): self.itemFrame = DirectScrolledFrame( text = "Inventory", text_scale = 0.25, text_pos = (0, 0.75, 0), text_bg = (1,1,1,1), # make the frame occupy the whole window frameSize = (-1.2, 1.2, -0.8, 0.8), # make the canvas as big as the frame canvasSize = (-1.2, 1.2, -0.8, 0.8), # set the frames color to white frameColor = (1, 1, 1, 1)) self.itemList = []
def __init__(self, parent=None, scale=0.05, limitText=1, frameSize=(0, 1.3, 0.2, 0.697), pos=(0, 0, 0.1)): self.__scale = scale self.__frameSize = frameSize self.__canvasSize = (frameSize[0], frameSize[2] - 0.01, frameSize[2], frameSize[3]) self.__limitText = limitText self.__countLine = [] self.dsf = DirectScrolledFrame( parent=parent, canvasSize=self.__canvasSize, frameSize=self.__frameSize, pos=pos, frameColor=COR_OPACITY_03_PRETO, autoHideScrollBars=1, scrollBarWidth=0.05, borderWidth=(0, 0), verticalScroll_value=1, verticalScroll_decButton_frameColor=(1, 1, 1, 0.3), verticalScroll_decButton_rolloverSound=None, verticalScroll_decButton_clickSound=None, verticalScroll_incButton_frameColor=(1, 1, 1, 0.3), verticalScroll_incButton_rolloverSound=None, verticalScroll_incButton_clickSound=None, verticalScroll_thumb_frameColor=(1, 1, 1, 0.3), verticalScroll_thumb_rolloverSound=None, verticalScroll_thumb_clickSound=None, ) self.__textoHeight = scale self.__canvasHeight = self.dsf.getHeight() self.__canvas = self.dsf.getCanvas()
def __init__(self): self.itemFrame = DirectScrolledFrame( text="Inventory", text_scale=0.25, text_pos=(0, 0.75, 0), text_bg=(1, 1, 1, 1), # make the frame occupy the whole window frameSize=(-0.6, 0.6, -0.8, 0.8), pos=(-0.7, 0, 0), # make the canvas as big as the frame canvasSize=(-0.6, 0.6, -0.8, 0.8), # set the frames color to white frameColor=(1, 1, 1, 1), ) self.itemList = [] self.craftFrame = DirectFrame( text="Crafting", text_scale=0.25, text_pos=(0, 0.75, 0), text_bg=(1, 1, 1, 1), # make the frame occupy the whole window frameSize=(-0.6, 0.6, -0.8, 0.8), pos=(0.7, 0, 0), # set the frames color to white frameColor=(1, 1, 1, 1), ) self.craftDrop = DirectFrame( text="drop ore", text_scale=0.1, pos=(0, 0.4, 0), frameSize=(-0.25, 0.25, -0.25, 0.25), frameColor=(1, 0, 0, 1), ) self.craftDrop.reparentTo(self.craftFrame)
def __init__( self, pos=(0, 0, 0), parent=None, frameSize=(1, 1), treeStructure=DirectTreeItem(), ): if parent is None: parent = aspect2d self.treeStructure = treeStructure self.treeStructureNodes = dict() self.highlightedNodes = list() self.frameWidth = frameSize[0] #0.8 self.frameHeight = frameSize[1] #1.5 self.itemIndent = 0.05 self.itemScale = 0.03 self.itemTextScale = 1.2 self.verticalSpacing = 0.0375 self.__createTreeLines() self.childrenFrame = DirectScrolledFrame( parent=parent, pos=pos, relief=DGG.GROOVE, state=DGG.NORMAL, # to create a mouse watcher region manageScrollBars=0, enableEdit=0, #suppressMouse=1, sortOrder=1000, frameColor=(0, 0, 0, .7), borderWidth=(0.005, 0.005), frameSize=(0, self.frameWidth, 0, self.frameHeight), canvasSize=(0, self.frameWidth - self.itemScale * 2, 0, self.frameHeight), verticalScroll_frameSize=[0, self.itemScale, 0, 1], horizontalScroll_frameSize=[0, 1, 0, self.itemScale], ) self.childrenCanvas = self.childrenFrame.getCanvas().attachNewNode( 'myCanvas') self.childrenCanvas.setX(0.05) self.childrenCanvas.setZ(self.frameHeight - 1) # some fix to have the list in the window self.accept(EVENT_DIRECTTREE_REFRESH, self.update)
def loadFormationSelectionFrame(manager): """Loads all formations files in the same directory as this .py file and builds a UI element with buttons for each formation. Formations are .csv files where the nth line is the x, y, z coordinate of the nth drone.""" manager = manager formations = [ ] # a list of formations, which are lists consisting of the name and the positions as a numpy array # load all .txt files in the formations folder directory = os.path.dirname( os.path.abspath(__file__) ) # the directory this.py file is in, which also contains the formation files for file in os.listdir(directory): if file.endswith(".csv"): path = os.path.join(directory, file) formations.append(_loadFormation(path)) # size and position of the buttons and the scrollable frame buttonSize = (-8, 8, -.2, .8) buttonDistance = 0.15 scrolledFrame = DirectScrolledFrame(frameColor=(.2, .2, .2, 1), canvasSize=(-.7, .7, -buttonDistance * len(formations), 0), frameSize=(-.9, .9, -.5, .5), pos=(.8, 0, -.7), scale=.5) canvas = scrolledFrame.getCanvas() # add a button for each formation for i in range(0, len(formations)): button = DirectButton(text=formations[i][0], scale=.1, frameSize=buttonSize, command=manager.applyFormation, extraArgs=[formations[i]]) button.reparentTo(canvas) button.setPos(0.15, 0, -(i + 0.75) * buttonDistance) print("{} formations loaded.".format(len(formations)))
def __init__(self): self.itemFrame = DirectScrolledFrame( text="Inventory", text_scale=0.25, text_pos=(0, 0.75, 0), text_bg=(1, 1, 1, 1), # make the frame occupy the whole window frameSize=(-1.2, 1.2, -0.8, 0.8), # make the canvas as big as the frame canvasSize=(-1.2, 1.2, -0.8, 0.8), # set the frames color to white frameColor=(1, 1, 1, 1), ) self.itemList = []
def __init__(self, parent=None, scale=.05, limitText=1, frameSize=(0, 1.3, .2, .697), pos=(0, 0, .1)): self.__scale = scale self.__frameSize = frameSize self.__canvasSize = (frameSize[0], frameSize[2] - .01, frameSize[2], frameSize[3]) self.__limitText = limitText self.__countLine = [] self.dsf = DirectScrolledFrame( parent=parent, canvasSize=self.__canvasSize, frameSize=self.__frameSize, pos=pos, frameColor=COR_OPACITY_03_PRETO, autoHideScrollBars=1, scrollBarWidth=0.05, borderWidth=(0, 0), verticalScroll_value=1, verticalScroll_decButton_frameColor=(1, 1, 1, 0.3), verticalScroll_decButton_rolloverSound=None, verticalScroll_decButton_clickSound=None, verticalScroll_incButton_frameColor=(1, 1, 1, 0.3), verticalScroll_incButton_rolloverSound=None, verticalScroll_incButton_clickSound=None, verticalScroll_thumb_frameColor=(1, 1, 1, 0.3), verticalScroll_thumb_rolloverSound=None, verticalScroll_thumb_clickSound=None) self.__textoHeight = scale self.__canvasHeight = self.dsf.getHeight() self.__canvas = self.dsf.getCanvas()
def __init__(self, pos=(0,0,0), parent=None, frameSize=(1,1), treeStructure=DirectTreeItem(),): if parent is None: parent = aspect2d self.treeStructure = treeStructure self.treeStructureNodes = dict() self.highlightedNodes = list() self.frameWidth = frameSize[0] #0.8 self.frameHeight = frameSize[1] #1.5 self.itemIndent = 0.05 self.itemScale = 0.03 self.itemTextScale = 1.2 self.verticalSpacing = 0.0375 self.__createTreeLines() self.childrenFrame = DirectScrolledFrame( parent=parent,pos=pos, relief=DGG.GROOVE, state=DGG.NORMAL, # to create a mouse watcher region manageScrollBars=0, enableEdit=0, #suppressMouse=1, sortOrder=1000, frameColor=(0,0,0,.7), borderWidth=(0.005,0.005), frameSize =(0, self.frameWidth, 0, self.frameHeight), canvasSize=(0, self.frameWidth-self.itemScale*2, 0, self.frameHeight), verticalScroll_frameSize = [0,self.itemScale,0,1], horizontalScroll_frameSize = [0,1,0,self.itemScale], ) self.childrenCanvas=self.childrenFrame.getCanvas().attachNewNode('myCanvas') self.childrenCanvas.setX(0.05) self.childrenCanvas.setZ(self.frameHeight-1) # some fix to have the list in the window self.accept(EVENT_DIRECTTREE_REFRESH, self.update)
class HostMenu(DirectObject): def __init__(self): self.defaultBtnMap = base.loader.loadModel("gui/button_map") self.buttonGeom = (self.defaultBtnMap.find("**/button_ready"), self.defaultBtnMap.find("**/button_click"), self.defaultBtnMap.find("**/button_rollover"), self.defaultBtnMap.find("**/button_disabled")) defaultFont = loader.loadFont('gui/eufm10.ttf') self.logFrame = DirectScrolledFrame( canvasSize=(0, base.a2dRight * 2, -5, 0), frameSize=(0, base.a2dRight * 2, (base.a2dBottom + .2) * 2, 0), frameColor=(0.1, 0.1, 0.1, 1)) self.logFrame.reparentTo(base.a2dTopLeft) # create the info and server debug output self.textscale = 0.1 self.txtinfo = OnscreenText(scale=self.textscale, pos=(0.1, -0.1), text="", align=TextNode.ALeft, fg=(0.1, 1.0, 0.15, 1), bg=(0, 0, 0, 0), shadow=(0, 0, 0, 1), shadowOffset=(-0.02, -0.02)) self.txtinfo.setTransparency(1) self.txtinfo.reparentTo(self.logFrame.getCanvas()) # create a close Server button self.btnBackPos = Vec3(0.4, 0, 0.2) self.btnBackScale = 0.25 self.btnBack = DirectButton( # Scale and position scale=self.btnBackScale, pos=self.btnBackPos, # Text text="Quit Server", text_scale=0.45, text_pos=(0, -0.1), text_fg=(0.82, 0.85, 0.87, 1), text_shadow=(0, 0, 0, 1), text_shadowOffset=(-0.02, -0.02), text_font=defaultFont, # Frame geom=self.buttonGeom, frameColor=(0, 0, 0, 0), relief=0, pressEffect=False, # Functionality command=self.back, rolloverSound=None, clickSound=None) self.btnBack.setTransparency(1) self.btnBack.reparentTo(base.a2dBottomLeft) # catch window resizes and recalculate the aspectration self.accept("window-event", self.recalcAspectRatio) self.accept("addLog", self.addLog) def show(self): self.logFrame.show() self.btnBack.show() def hide(self): self.logFrame.hide() self.btnBack.hide() def back(self): self.hide() base.messenger.send("stop_server") self.addLog("Quit Server!") def addLog(self, text): self.txtinfo.appendText(text + "\n") textbounds = self.txtinfo.getTightBounds() self.logFrame["canvasSize"] = (0, textbounds[1].getX(), textbounds[0].getZ(), 0) def recalcAspectRatio(self, window): """get the new aspect ratio to resize the mainframe""" # set the mainframe size to the window borders again self.logFrame["frameSize"] = (0, base.a2dRight * 2, (base.a2dBottom + .2) * 2, 0)
class DirectTree(DirectObject): def __init__(self, pos=(0,0,0), parent=None, frameSize=(1,1), treeStructure=DirectTreeItem(),): if parent is None: parent = aspect2d self.treeStructure = treeStructure self.treeStructureNodes = dict() self.highlightedNodes = list() self.frameWidth = frameSize[0] #0.8 self.frameHeight = frameSize[1] #1.5 self.itemIndent = 0.05 self.itemScale = 0.03 self.itemTextScale = 1.2 self.verticalSpacing = 0.0375 self.__createTreeLines() self.childrenFrame = DirectScrolledFrame( parent=parent,pos=pos, relief=DGG.GROOVE, state=DGG.NORMAL, # to create a mouse watcher region manageScrollBars=0, enableEdit=0, #suppressMouse=1, sortOrder=1000, frameColor=(0,0,0,.7), borderWidth=(0.005,0.005), frameSize =(0, self.frameWidth, 0, self.frameHeight), canvasSize=(0, self.frameWidth-self.itemScale*2, 0, self.frameHeight), verticalScroll_frameSize = [0,self.itemScale,0,1], horizontalScroll_frameSize = [0,1,0,self.itemScale], ) self.childrenCanvas=self.childrenFrame.getCanvas().attachNewNode('myCanvas') self.childrenCanvas.setX(0.05) self.childrenCanvas.setZ(self.frameHeight-1) # some fix to have the list in the window self.accept(EVENT_DIRECTTREE_REFRESH, self.update) def destroy(self): self.treeStructure = DirectTreeItem() self.render() self.childrenFrame.destroy() #del self.treeStructureNodes def __createLine(self, length=1, color=(1,1,1,1), endColor=None): LS=LineSegs() LS.setColor(*color) LS.moveTo(0,0,0) LS.drawTo(length*1,0,0) node=LS.create() if endColor: LS.setVertexColor(1,*endColor) return node def __createTreeLines(self): # create horisontal tree line color=(1,0,0,.9) self.horizontalTreeLine=NodePath(self.__createLine( self.itemIndent+self.itemScale*.5, color,endColor=(1,1,1,.1))) self.horizontalTreeLine.setTwoSided(0,100) self.horizontalTreeLine.setTransparency(1) # create vertical tree line self.verticalTreeLine=NodePath(self.__createLine( self.verticalSpacing,color)) self.verticalTreeLine.setR(90) self.verticalTreeLine.setTwoSided(0,100) self.verticalTreeLine.setTransparency(1) def render(self): ''' traverse the tree and update the visuals according to it ''' for treeItem in self.treeStructure.getRec(): # create nodes that have no visual elements if not treeItem in self.treeStructureNodes: treeNode = self.childrenCanvas.attachNewNode('') hor=self.horizontalTreeLine.instanceUnderNode(treeNode,'') vert=self.verticalTreeLine.instanceUnderNode(treeNode,'') vert.setZ(0.007) hor.setPos(-1.5*self.itemIndent,0,self.itemScale*.25) vert.setX(-.5*self.itemIndent) nodeButton = DirectButton( parent=treeNode, scale=self.itemScale, relief=DGG.FLAT, text_scale=self.itemTextScale, text_align=TextNode.ALeft, text=treeItem.name, rolloverSound=None, #clickSound=None, ) nodeButton.bind(DGG.B1PRESS,treeItem.button1press) nodeButton.bind(DGG.B2PRESS,treeItem.button2press) nodeButton.bind(DGG.B3PRESS,treeItem.button3press) #treeButton = None #if len(treeItem.childrens) > 0: treeButton = DirectButton( parent=nodeButton, frameColor=(1,1,1,1), frameSize=(-.4,.4,-.4,.4), pos=(-.5*self.itemIndent/self.itemScale,0,.25), text='', text_pos=(-.1,-.22), text_scale=(1.6,1), text_fg=(0,0,0,1), enableEdit=0, command=treeItem.setOpen, sortOrder=1000, rolloverSound=None, #clickSound=None, ) self.treeStructureNodes[treeItem] = [treeNode, nodeButton, treeButton, hor, vert] # destroy nodes no more used for treeItem in self.treeStructureNodes.keys()[:]: #treeItem = self.treeStructureNodes[treeName] if treeItem not in self.treeStructure.getRec(): treeNode, nodeButton, treeButton, hor, vert = self.treeStructureNodes[treeItem] #nodeButton['text']='' nodeButton.unbind(DGG.B1PRESS) nodeButton.unbind(DGG.B2PRESS) nodeButton.unbind(DGG.B3PRESS) #nodeButton.detachNode() #nodeButton.removeNode() nodeButton.destroy() if treeButton: #treeButton['text']='' #treeButton['command']=None treeButton.detachNode() treeButton.removeNode() hor.detachNode() hor.removeNode() vert.detachNode() vert.removeNode() treeItem.destroy() #treeNode.detachNode() treeNode.removeNode() #treeNode.destroy() del self.treeStructureNodes[treeItem] frameHeight = len(self.treeStructureNodes) * self.verticalSpacing self.childrenFrame['canvasSize'] = (0, self.frameWidth-self.itemScale*2, 0, frameHeight) self.childrenCanvas.setZ(frameHeight-1) def highlight(self, selectedTreeNodes): for treeNode in self.highlightedNodes: treeNode.highlighted = False self.highlightedNodes = selectedTreeNodes for treeNode in self.highlightedNodes: treeNode.highlighted = True self.update() def update(self): ''' update the tree, updating the positions and hidden status of childrens ''' idx = 0 for treeItem in self.treeStructure.getRec(): # show or hide the items treeNode, nodeButton, treeButton, hor, vert = self.treeStructureNodes[treeItem] if treeItem.getShow(): treeNode.show() vert.show() if treeItem.parent: # dont show the horizontal line on the parent hor.show() else: hor.hide() idx += 1 else: treeNode.hide() hor.hide() vert.hide() if len(treeItem.childrens) > 0: treeButton.show() else: treeButton.hide() if treeItem.highlighted: nodeButton['text_fg'] = (1,0,0,1) else: nodeButton['text_fg'] = (0,0,0,1) # update the vertical position of the node treeNode.setPos(treeItem.getDepth()*self.itemIndent,0,1-idx*self.verticalSpacing) # if the tree element has a treebutton (if it has childrens), update the +/- if treeButton: # update the text for the open/close button tag = ['+','-'][treeItem.open] treeButton['text']=tag # calculate length to the last children with the same depth as this treeitem # this gives the length of the vertical line c = -1; i = 0; treeItemDepth = treeItem.getDepth() for recItem in treeItem.getRec(): if recItem.getShow(): c+=1 if recItem.getDepth() == treeItemDepth+1: i = c vert.setSz(i)
def __init__(self): ShowBase.__init__(self) self.setBackgroundColor(0, 0, 0) # make the font look nice at a big scale DGG.getDefaultFont().setPixelsPerUnit(100) # Store our mapping, with some sensible defaults. In a real game, you # will want to load these from a configuration file. self.mapping = InputMapping() self.mapping.mapAxis("Move forward", InputDevice.Axis.left_y) self.mapping.mapAxis("Move backward", InputDevice.Axis.left_y) self.mapping.mapAxis("Move left", InputDevice.Axis.left_x) self.mapping.mapAxis("Move right", InputDevice.Axis.left_x) self.mapping.mapButton("Jump", GamepadButton.face_a()) self.mapping.mapButton("Use", GamepadButton.face_b()) self.mapping.mapButton("Break", GamepadButton.face_x()) self.mapping.mapButton("Fix", GamepadButton.face_y()) # The geometry for our basic buttons maps = loader.loadModel("models/button_map") self.buttonGeom = ( maps.find("**/ready"), maps.find("**/click"), maps.find("**/hover"), maps.find("**/disabled")) # Change the default dialog skin. DGG.setDefaultDialogGeom("models/dialog.png") # create a sample title self.textscale = 0.1 self.title = DirectLabel( scale=self.textscale, pos=(base.a2dLeft + 0.05, 0.0, base.a2dTop - (self.textscale + 0.05)), frameColor=VBase4(0, 0, 0, 0), text="Button Mapping", text_align=TextNode.ALeft, text_fg=VBase4(1, 1, 1, 1), text_shadow=VBase4(0, 0, 0, 0.75), text_shadowOffset=Vec2(0.05, 0.05)) self.title.setTransparency(1) # Set up the list of actions that we can map keys to # create a frame that will create the scrollbars for us # Load the models for the scrollbar elements thumbMaps = loader.loadModel("models/thumb_map") thumbGeom = ( thumbMaps.find("**/thumb_ready"), thumbMaps.find("**/thumb_click"), thumbMaps.find("**/thumb_hover"), thumbMaps.find("**/thumb_disabled")) incMaps = loader.loadModel("models/inc_map") incGeom = ( incMaps.find("**/inc_ready"), incMaps.find("**/inc_click"), incMaps.find("**/inc_hover"), incMaps.find("**/inc_disabled")) decMaps = loader.loadModel("models/dec_map") decGeom = ( decMaps.find("**/dec_ready"), decMaps.find("**/dec_click"), decMaps.find("**/dec_hover"), decMaps.find("**/dec_disabled")) # create the scrolled frame that will hold our list self.lstActionMap = DirectScrolledFrame( # make the frame occupy the whole window frameSize=VBase4(base.a2dLeft, base.a2dRight, 0.0, 1.55), # make the canvas as big as the frame canvasSize=VBase4(base.a2dLeft, base.a2dRight, 0.0, 0.0), # set the frames color to white frameColor=VBase4(0, 0, 0.25, 0.75), pos=(0, 0, -0.8), verticalScroll_scrollSize=0.2, verticalScroll_frameColor=VBase4(0.02, 0.02, 0.02, 1), verticalScroll_thumb_relief=1, verticalScroll_thumb_geom=thumbGeom, verticalScroll_thumb_pressEffect=False, verticalScroll_thumb_frameColor=VBase4(0, 0, 0, 0), verticalScroll_incButton_relief=1, verticalScroll_incButton_geom=incGeom, verticalScroll_incButton_pressEffect=False, verticalScroll_incButton_frameColor=VBase4(0, 0, 0, 0), verticalScroll_decButton_relief=1, verticalScroll_decButton_geom=decGeom, verticalScroll_decButton_pressEffect=False, verticalScroll_decButton_frameColor=VBase4(0, 0, 0, 0),) # creat the list items idx = 0 self.listBGEven = base.loader.loadModel("models/list_item_even") self.listBGOdd = base.loader.loadModel("models/list_item_odd") self.actionLabels = {} for action in self.mapping.actions: mapped = self.mapping.formatMapping(action) item = self.__makeListItem(action, mapped, idx) item.reparentTo(self.lstActionMap.getCanvas()) idx += 1 # recalculate the canvas size to set scrollbars if necesary self.lstActionMap["canvasSize"] = ( base.a2dLeft+0.05, base.a2dRight-0.05, -(len(self.mapping.actions)*0.1), 0.09) self.lstActionMap.setCanvasSize()
def __init__(self, parent=None, **kwargs): optiondefs = ( ('frameSize', (-0.5, 0.5, -0.5, 0.5), None), ('tabClickOffsetColor', Vec4(0.1, 0.1, 0.1, 0), None), ('tabRolloverOffsetColor', Vec4(0.1, 0.1, 0.1, 0), None), ('tabInactiveColor', Vec4(0.2, 0.2, 0.2, 1), None), ('tabUnselectedColor', Vec4(0.7, 0.7, 0.7, 1), None), ('tabSelectedColor', Vec4(0.4, 0.7, 1.0, 1), None), ('tab_scale', 0.05, None), ('tab_frameSize', (0, 5, 0, 2), None), ('tab_geom_scale', 1, None), ('tabHighlightFrameTexture', None, None), ('tabFrameTexture', None, None), ('tabHighlightGeom', None, None), ('tabGeom', None, None), ) # Button colours: Selected, unselected, rollover-offset, clicked-offset, inactive if "scrollFrameConstructor" in kwargs: self.scrollFrameConstructor = kwargs["scrollFrameConstructor"] del kwargs["scrollFrameConstructor"] else: self.scrollFrameConstructor = None #type(DirectScrolledFrame) if "pageChangeCallback" in kwargs: self.pageChangeCallback = kwargs["pageChangeCallback"] del kwargs["pageChangeCallback"] else: self.pageChangeCallback = None #type(DirectScrolledFrame) viewingArgs = {} for key, arg in list(kwargs.items()): if key.startswith("scroll_"): key = key[7:] viewingArgs[key] = arg for key in viewingArgs: del kwargs["scroll_" + key] if not "canvasSize" in viewingArgs: viewingArgs["canvasSize"] = (0, 0, 0, 0) self.defineoptions(kwargs, optiondefs) DirectFrame.__init__(self, parent) if self.scrollFrameConstructor is not None: self.viewingArea = self.scrollFrameConstructor(parent=self, **viewingArgs) else: self.viewingArea = DirectScrolledFrame(parent=self, **viewingArgs) self.pages = [] self.pageButtons = [] self.currentPageIndex = -1 self.tabArgs = {} for key, arg in self._constructorKeywords.items(): if key.startswith("tab_") and \ not key.endswith("highlightGeom") and \ not key.endswith("unselectedColor") and \ not key.endswith("selectedColor") and \ not key.endswith("highlightFrameTexture") and \ not key.endswith("highlightGeom"): self.tabArgs[key[4:]] = arg[0] self.addPage(DirectFrame(), "<stand-in>") self.initialiseoptions(TabbedFrame)
def __init__( self, pos=(-.5, .5), title='Title', curSize=(1, 1), maxSize=(1, 1), minSize=(.5, .5), backgroundColor=(1, 1, 1, 1), borderColor=(1, 1, 1, 1), titleColor=(1, 1, 1, 1), borderSize=0.04, titleSize=0.06, closeButton=False, windowParent=aspect2d, preserve=True, preserveWhole=True, ): self.preserve = preserve self.preserveWhole = preserveWhole self.windowParent = windowParent self.windowPos = pos DirectFrame.__init__( self, parent=windowParent, pos=(self.windowPos[0], 0, self.windowPos[1]), frameColor=(0, 0, 0, 0), frameTexture=loader.loadTexture(DIRECTORY + 'transparent.png')) self.setTransparency(True) # the title part of the window, drag around to move the window self.headerHeight = titleSize h = -self.headerHeight self.windowHeaderLeft = DirectButton( parent=self, frameTexture=DEFAULT_TITLE_GEOM_LEFT, frameSize=(-.5, .5, -.5, .5), borderWidth=(0, 0), relief=DGG.FLAT, frameColor=titleColor, ) self.windowHeaderCenter = DirectButton( parent=self, frameTexture=DEFAULT_TITLE_GEOM_CENTER, frameSize=(-.5, .5, -.5, .5), borderWidth=(0, 0), relief=DGG.FLAT, frameColor=titleColor, ) if closeButton: rightTitleGeom = DEFAULT_TITLE_GEOM_RIGHT_CLOSE command = self.destroy else: rightTitleGeom = DEFAULT_TITLE_GEOM_RIGHT command = None self.windowHeaderRight = DirectButton(parent=self, frameTexture=rightTitleGeom, frameSize=(-.5, .5, -.5, .5), borderWidth=(0, 0), relief=DGG.FLAT, frameColor=titleColor, command=command) self.windowHeaderLeft.setTransparency(True) self.windowHeaderCenter.setTransparency(True) self.windowHeaderRight.setTransparency(True) self.windowHeaderLeft.bind(DGG.B1PRESS, self.startWindowDrag) self.windowHeaderCenter.bind(DGG.B1PRESS, self.startWindowDrag) self.windowHeaderRight.bind(DGG.B1PRESS, self.startWindowDrag) # this is not handled correctly, if a window is dragged which has been # created before another it will not be released # check the bugfixed startWindowDrag function #self.windowHeader.bind(DGG.B1RELEASE,self.stopWindowDrag) text = TextNode('WindowTitleTextNode') text.setText(title) text.setAlign(TextNode.ACenter) text.setTextColor(0, 0, 0, 1) text.setShadow(0.05, 0.05) text.setShadowColor(1, 1, 1, 1) self.textNodePath = self.attachNewNode(text) self.textNodePath.setScale(self.headerHeight * 0.8) # the content part of the window, put stuff beneath # contentWindow.getCanvas() to put it into it self.maxVirtualSize = maxSize self.minVirtualSize = minSize self.resizeSize = borderSize self.contentWindow = DirectScrolledFrame( parent=self, pos=(0, 0, -self.headerHeight), canvasSize=(0, self.maxVirtualSize[0], 0, self.maxVirtualSize[1]), frameColor=( 0, 0, 0, 0), # defines the background color of the resize-button relief=DGG.FLAT, borderWidth=(0, 0), verticalScroll_frameSize=[0, self.resizeSize, 0, 1], horizontalScroll_frameSize=[0, 1, 0, self.resizeSize], # resize the scrollbar according to window size verticalScroll_resizeThumb=False, horizontalScroll_resizeThumb=False, # define the textures for the scrollbars verticalScroll_frameTexture=VERTICALSCROLL_FRAMETEXTURE, verticalScroll_incButton_frameTexture= VERTICALSCROLL_INCBUTTON_FRAMETEXTURE, verticalScroll_decButton_frameTexture= VERTICALSCROLL_DECBUTTON_FRAMETEXTURE, verticalScroll_thumb_frameTexture=VERTICALSCROLL_TUMB_FRAMETEXTURE, horizontalScroll_frameTexture=HORIZONTALSCROLL_FRAMETEXTURE, horizontalScroll_incButton_frameTexture= HORIZONTALSCROLL_INCBUTTON_FRAMETEXTURE, horizontalScroll_decButton_frameTexture= HORIZONTALSCROLL_DECBUTTON_FRAMETEXTURE, horizontalScroll_thumb_frameTexture= HORIZONTALSCROLL_TUMB_FRAMETEXTURE, # make all flat, so the texture is as we want it verticalScroll_relief=DGG.FLAT, verticalScroll_thumb_relief=DGG.FLAT, verticalScroll_decButton_relief=DGG.FLAT, verticalScroll_incButton_relief=DGG.FLAT, horizontalScroll_relief=DGG.FLAT, horizontalScroll_thumb_relief=DGG.FLAT, horizontalScroll_decButton_relief=DGG.FLAT, horizontalScroll_incButton_relief=DGG.FLAT, # colors verticalScroll_frameColor=borderColor, verticalScroll_incButton_frameColor=borderColor, verticalScroll_decButton_frameColor=borderColor, verticalScroll_thumb_frameColor=borderColor, horizontalScroll_frameColor=borderColor, horizontalScroll_incButton_frameColor=borderColor, horizontalScroll_decButton_frameColor=borderColor, horizontalScroll_thumb_frameColor=borderColor, ) self.contentWindow.setTransparency(True) # background color self.backgroundColor = DirectFrame( parent=self.contentWindow.getCanvas(), frameSize=(0, self.maxVirtualSize[0], 0, self.maxVirtualSize[1]), frameColor=backgroundColor, relief=DGG.FLAT, borderWidth=(.01, .01), ) self.backgroundColor.setTransparency(True) # Add a box self.box = boxes.VBox(parent=self.getCanvas()) # is needed for some nicer visuals of the resize button (background) self.windowResizeBackground = DirectButton( parent=self, frameSize=(-.5, .5, -.5, .5), borderWidth=(0, 0), scale=(self.resizeSize, 1, self.resizeSize), relief=DGG.FLAT, frameColor=backgroundColor, ) # the resize button of the window self.windowResize = DirectButton( parent=self, frameSize=(-.5, .5, -.5, .5), borderWidth=(0, 0), scale=(self.resizeSize, 1, self.resizeSize), relief=DGG.FLAT, frameTexture=DEFAULT_RESIZE_GEOM, frameColor=borderColor, ) self.windowResize.setTransparency(True) self.windowResize.bind(DGG.B1PRESS, self.startResizeDrag) self.windowResize.bind(DGG.B1RELEASE, self.stopResizeDrag) # offset then clicking on the resize button from the mouse to the resizebutton # position, required to calculate the position / scaling self.offset = None self.taskName = "resizeTask-%s" % str(hash(self)) # do sizing of the window (minimum) #self.resize( Vec3(0,0,0), Vec3(0,0,0) ) # maximum #self.resize( Vec3(100,0,-100), Vec3(0,0,0) ) self.resize(Vec3(curSize[0], 0, -curSize[1]), Vec3(0, 0, 0))
def __init__( self, pos = ( -.5, .5), title = 'Title', curSize = ( 1, 1), maxSize = ( 1, 1 ), minSize = ( .5, .5 ), backgroundColor = ( 1, 1, 1, 1 ), borderColor = ( 1, 1, 1, 1 ), titleColor = ( 1, 1, 1, 1 ), borderSize = 0.04, titleSize = 0.06, closeButton = False, windowParent = aspect2d, preserve = True, preserveWhole = True, ): self.preserve = preserve self.preserveWhole = preserveWhole self.windowParent = windowParent self.windowPos = pos DirectFrame.__init__( self, parent = windowParent, pos = ( self.windowPos[0], 0, self.windowPos[1] ), frameColor = ( 0, 0, 0, 0 ), frameTexture = loader.loadTexture( DIRECTORY+'transparent.png' ) ) self.setTransparency(True) # the title part of the window, drag around to move the window self.headerHeight = titleSize h = -self.headerHeight self.windowHeaderLeft = DirectButton( parent = self, frameTexture = DEFAULT_TITLE_GEOM_LEFT, frameSize = ( -.5, .5, -.5, .5 ), borderWidth = ( 0, 0 ), relief = DGG.FLAT, frameColor = titleColor, ) self.windowHeaderCenter = DirectButton( parent = self, frameTexture = DEFAULT_TITLE_GEOM_CENTER, frameSize = ( -.5, .5, -.5, .5 ), borderWidth = ( 0, 0 ), relief = DGG.FLAT, frameColor = titleColor, ) if closeButton: rightTitleGeom = DEFAULT_TITLE_GEOM_RIGHT_CLOSE command = self.destroy else: rightTitleGeom = DEFAULT_TITLE_GEOM_RIGHT command = None self.windowHeaderRight = DirectButton( parent = self, frameTexture = rightTitleGeom, frameSize = ( -.5, .5, -.5, .5 ), borderWidth = ( 0, 0 ), relief = DGG.FLAT, frameColor = titleColor, command = command ) self.windowHeaderLeft.setTransparency(True) self.windowHeaderCenter.setTransparency(True) self.windowHeaderRight.setTransparency(True) self.windowHeaderLeft.bind( DGG.B1PRESS, self.startWindowDrag ) self.windowHeaderCenter.bind( DGG.B1PRESS, self.startWindowDrag ) self.windowHeaderRight.bind( DGG.B1PRESS, self.startWindowDrag ) # this is not handled correctly, if a window is dragged which has been # created before another it will not be released # check the bugfixed startWindowDrag function #self.windowHeader.bind(DGG.B1RELEASE,self.stopWindowDrag) text = TextNode('WindowTitleTextNode') text.setText(title) text.setAlign(TextNode.ACenter) text.setTextColor( 0, 0, 0, 1 ) text.setShadow(0.05, 0.05) text.setShadowColor( 1, 1, 1, 1 ) self.textNodePath = self.attachNewNode(text) self.textNodePath.setScale(self.headerHeight*0.8) # the content part of the window, put stuff beneath # contentWindow.getCanvas() to put it into it self.maxVirtualSize = maxSize self.minVirtualSize = minSize self.resizeSize = borderSize self.contentWindow = DirectScrolledFrame( parent = self, pos = ( 0, 0, -self.headerHeight ), canvasSize = ( 0, self.maxVirtualSize[0], 0, self.maxVirtualSize[1] ), frameColor = ( 0, 0, 0, 0), # defines the background color of the resize-button relief = DGG.FLAT, borderWidth = (0, 0), verticalScroll_frameSize = [0, self.resizeSize, 0, 1], horizontalScroll_frameSize = [0, 1, 0, self.resizeSize], # resize the scrollbar according to window size verticalScroll_resizeThumb = False, horizontalScroll_resizeThumb = False, # define the textures for the scrollbars verticalScroll_frameTexture = VERTICALSCROLL_FRAMETEXTURE, verticalScroll_incButton_frameTexture = VERTICALSCROLL_INCBUTTON_FRAMETEXTURE, verticalScroll_decButton_frameTexture = VERTICALSCROLL_DECBUTTON_FRAMETEXTURE, verticalScroll_thumb_frameTexture = VERTICALSCROLL_TUMB_FRAMETEXTURE, horizontalScroll_frameTexture = HORIZONTALSCROLL_FRAMETEXTURE, horizontalScroll_incButton_frameTexture = HORIZONTALSCROLL_INCBUTTON_FRAMETEXTURE, horizontalScroll_decButton_frameTexture = HORIZONTALSCROLL_DECBUTTON_FRAMETEXTURE, horizontalScroll_thumb_frameTexture = HORIZONTALSCROLL_TUMB_FRAMETEXTURE, # make all flat, so the texture is as we want it verticalScroll_relief = DGG.FLAT, verticalScroll_thumb_relief = DGG.FLAT, verticalScroll_decButton_relief = DGG.FLAT, verticalScroll_incButton_relief = DGG.FLAT, horizontalScroll_relief = DGG.FLAT, horizontalScroll_thumb_relief = DGG.FLAT, horizontalScroll_decButton_relief = DGG.FLAT, horizontalScroll_incButton_relief = DGG.FLAT, # colors verticalScroll_frameColor = borderColor, verticalScroll_incButton_frameColor = borderColor, verticalScroll_decButton_frameColor = borderColor, verticalScroll_thumb_frameColor = borderColor, horizontalScroll_frameColor = borderColor, horizontalScroll_incButton_frameColor = borderColor, horizontalScroll_decButton_frameColor = borderColor, horizontalScroll_thumb_frameColor = borderColor, ) self.contentWindow.setTransparency(True) # background color self.backgroundColor = DirectFrame( parent = self.contentWindow.getCanvas(), frameSize = ( 0, self.maxVirtualSize[0], 0, self.maxVirtualSize[1] ), frameColor = backgroundColor, relief = DGG.FLAT, borderWidth = ( .01, .01), ) self.backgroundColor.setTransparency(True) # Add a box self.box = boxes.VBox(parent = self.getCanvas()) # is needed for some nicer visuals of the resize button (background) self.windowResizeBackground = DirectButton( parent = self, frameSize = ( -.5, .5, -.5, .5 ), borderWidth = ( 0, 0 ), scale = ( self.resizeSize, 1, self.resizeSize ), relief = DGG.FLAT, frameColor = backgroundColor, ) # the resize button of the window self.windowResize = DirectButton( parent = self, frameSize = ( -.5, .5, -.5, .5 ), borderWidth = ( 0, 0 ), scale = ( self.resizeSize, 1, self.resizeSize ), relief = DGG.FLAT, frameTexture = DEFAULT_RESIZE_GEOM, frameColor = borderColor, ) self.windowResize.setTransparency(True) self.windowResize.bind(DGG.B1PRESS,self.startResizeDrag) self.windowResize.bind(DGG.B1RELEASE,self.stopResizeDrag) # offset then clicking on the resize button from the mouse to the resizebutton # position, required to calculate the position / scaling self.offset = None self.taskName = "resizeTask-%s" % str(hash(self)) # do sizing of the window (minimum) #self.resize( Vec3(0,0,0), Vec3(0,0,0) ) # maximum #self.resize( Vec3(100,0,-100), Vec3(0,0,0) ) self.resize( Vec3(curSize[0], 0, -curSize[1]), Vec3(0,0,0))
def __init__(self, winned=False): self._is_shown = False self._read_coordinates = False self._winned = winned self._opened_num = None self._main_fr = DirectFrame( parent=base.a2dTopLeft, # noqa: F821 frameSize=(-0.37, 0.38, -0.6, 0.6), state=DGG.NORMAL, pos=(0.37, 0, -1), frameTexture="gui/tex/paper1.png", ) self._main_fr.setTransparency(TransparencyAttrib.MAlpha) self._main_fr.hide() self._fr = DirectScrolledFrame( parent=self._main_fr, frameSize=(-0.35, 0.3, -0.46, 0.5), frameColor=(0, 0, 0, 0), canvasSize=(-0.31, 0.3, -3, 1.5), state=DGG.NORMAL, pos=(0, 0, -0.1), verticalScroll_frameSize=(-0.003, 0.003, -0.5, 0.5), verticalScroll_frameColor=(0.46, 0.41, 0.37, 1), verticalScroll_thumb_frameColor=(0.31, 0.26, 0.22, 1), verticalScroll_incButton_relief=None, verticalScroll_decButton_relief=None, horizontalScroll_relief=None, horizontalScroll_thumb_relief=None, horizontalScroll_incButton_relief=None, horizontalScroll_decButton_relief=None, ) DirectLabel( # Journal parent=self._main_fr, text=base.labels.JOURNAL[0], # noqa: F821 text_font=base.cursive_font, # noqa: F821 text_scale=0.053, text_bg=(0, 0, 0, 0), text_fg=(0, 0, 0.25, 1), frameSize=(0.1, 0.1, 0.1, 0.1), pos=(-0.34, 0, 0.52), text_align=TextNode.ALeft, ) DirectButton( parent=self._main_fr, text="<", text_scale=0.06, text_bg=(0, 0, 0, 0), text_fg=(0, 0, 0.25, 1), pos=(-0.15, 0, 0.45), frameSize=(-0.2, 0.2, -0.2, 0.2), relief=None, command=self._open_page, extraArgs=[-1], ) DirectButton( parent=self._main_fr, text=">", text_scale=0.06, text_bg=(0, 0, 0, 0), text_fg=(0, 0, 0.25, 1), pos=(0.15, 0, 0.45), frameSize=(-0.2, 0.2, -0.2, 0.2), relief=None, command=self._open_page, extraArgs=[1], ) self._page_title = DirectLabel( parent=self._main_fr, text="", text_scale=0.043, text_font=base.cursive_font, # noqa: F821 text_fg=(0, 0, 0.25, 1), frameSize=(-0.02, 0.02, -3.5, 0.5), frameColor=(0, 0, 0, 0), pos=(0, 0, 0.45), ) self._page_text = DirectLabel( parent=self._fr.getCanvas(), text="", text_scale=0.045, text_font=base.cursive_font, # noqa: F821 text_align=TextNode.ALeft, text_fg=(0, 0, 0.25, 1), frameSize=(-0.02, 0.02, -3.5, 0.5), frameColor=(0, 0, 0, 0), pos=(-0.27, 0, 1.45), ) self._pages = [] self._open_snd = loader.loadSfx("sounds/GUI/journal.ogg") # noqa: F821 self._page_snd = loader.loadSfx("sounds/GUI/journal_page.ogg") # noqa: F821 self._close_snd = loader.loadSfx("sounds/GUI/journal_close.ogg") # noqa: F821
def __init__(self, parent=None, frameSize=(.8,1.2), buttonTextColor=(1,1,1,1), font=None, itemScale=.045, itemTextScale=0.85, itemTextZ=0, command=None, contextMenu=None, autoFocus=0, colorChange=1, colorChangeDuration=1, newItemColor=globals.colors['guiblue1'], rolloverColor=globals.colors['guiyellow'], suppressMouseWheel=1, modifier='control'): self.mode = None self.focusButton=None self.command=command self.contextMenu=contextMenu self.autoFocus=autoFocus self.colorChange=colorChange self.colorChangeDuration=colorChangeDuration*.5 self.newItemColor=newItemColor self.rolloverColor=rolloverColor self.rightClickTextColors=(Vec4(0,1,0,1),Vec4(0,35,100,1)) self.font=font if font: self.fontHeight=font.getLineHeight() else: self.fontHeight=TextNode.getDefaultFont().getLineHeight() self.fontHeight*=1.2 # let's enlarge font height a little self.xtraSideSpace=.2*self.fontHeight self.itemTextScale=itemTextScale self.itemTextZ=itemTextZ self.buttonTextColor=buttonTextColor self.suppressMouseWheel=suppressMouseWheel self.modifier=modifier self.buttonsList=[] self.numItems=0 self.__eventReceivers={} # DirectScrolledFrame to hold items self.itemScale=itemScale self.itemVertSpacing=self.fontHeight*self.itemScale self.frameWidth,self.frameHeight=frameSize # I set canvas' Z size smaller than the frame to avoid the auto-generated vertical slider bar self.childrenFrame = DirectScrolledFrame( parent=parent,pos=(-self.frameWidth*.5,0,.5*self.frameHeight), relief=DGG.GROOVE, state=DGG.NORMAL, # to create a mouse watcher region frameSize=(0, self.frameWidth, -self.frameHeight, 0), frameColor=(0,0,0,.7), canvasSize=(0, 0, -self.frameHeight*.5, 0), borderWidth=(0.01,0.01), manageScrollBars=0, enableEdit=0, suppressMouse=0, sortOrder=1000 ) # the real canvas is "self.childrenFrame.getCanvas()", # but if the frame is hidden since the beginning, # no matter how I set the canvas Z pos, the transform would be resistant, # so just create a new node under the canvas to be my canvas self.canvas=self.childrenFrame.getCanvas().attachNewNode('myCanvas') # slider background SliderBG=DirectFrame( parent=self.childrenFrame,frameSize=(-.025,.025,-self.frameHeight,0), frameColor=(0,0,0,.7), pos=(-.03,0,0),enableEdit=0, suppressMouse=0) # slider thumb track sliderTrack = DirectFrame( parent=SliderBG, relief=DGG.FLAT, #state=DGG.NORMAL, frameColor=(1,1,1,.2), frameSize=(-.015,.015,-self.frameHeight+.01,-.01), enableEdit=0, suppressMouse=0) # page up self.pageUpRegion=DirectFrame( parent=SliderBG, relief=DGG.FLAT, state=DGG.NORMAL, frameColor=(1,.8,.2,.1), frameSize=(-.015,.015,0,0), enableEdit=0, suppressMouse=0) self.pageUpRegion.setAlphaScale(0) self.pageUpRegion.bind(DGG.B1PRESS,self.__startScrollPage,[-1]) self.pageUpRegion.bind(DGG.WITHIN,self.__continueScrollUp) self.pageUpRegion.bind(DGG.WITHOUT,self.__suspendScrollUp) # page down self.pageDnRegion=DirectFrame( parent=SliderBG, relief=DGG.FLAT, state=DGG.NORMAL, frameColor=(1,.8,.2,.1), frameSize=(-.015,.015,0,0), enableEdit=0, suppressMouse=0) self.pageDnRegion.setAlphaScale(0) self.pageDnRegion.bind(DGG.B1PRESS,self.__startScrollPage,[1]) self.pageDnRegion.bind(DGG.WITHIN,self.__continueScrollDn) self.pageDnRegion.bind(DGG.WITHOUT,self.__suspendScrollDn) self.pageUpDnSuspended=[0,0] # slider thumb self.vertSliderThumb=DirectButton(parent=SliderBG, relief=DGG.FLAT, frameColor=(1,1,1,.6), frameSize=(-.015,.015,0,0), enableEdit=0, suppressMouse=0, rolloverSound=None, clickSound=None) self.vertSliderThumb.bind(DGG.B1PRESS,self.__startdragSliderThumb) self.vertSliderThumb.bind(DGG.WITHIN,self.__enteringThumb) self.vertSliderThumb.bind(DGG.WITHOUT,self.__exitingThumb) self.oldPrefix=base.buttonThrowers[0].node().getPrefix() self.sliderThumbDragPrefix='draggingSliderThumb-' # GOD & I DAMN IT !!! # These things below don't work well if the canvas has a lot of buttons. # So I end up checking the mouse region every frame by myself using a continuous task. # self.accept(DGG.WITHIN+self.childrenFrame.guiId,self.__enteringFrame) # self.accept(DGG.WITHOUT+self.childrenFrame.guiId,self.__exitingFrame) self.isMouseInRegion=False self.mouseOutInRegionCommand=(self.__exitingFrame,self.__enteringFrame) taskMgr.doMethodLater(.2,self.__getFrameRegion,'getFrameRegion')
class CraftInventory(DirectObject): def __init__(self): self.itemFrame = DirectScrolledFrame( text="Inventory", text_scale=0.25, text_pos=(0, 0.75, 0), text_bg=(1, 1, 1, 1), # make the frame occupy the whole window frameSize=(-0.6, 0.6, -0.8, 0.8), pos=(-0.7, 0, 0), # make the canvas as big as the frame canvasSize=(-0.6, 0.6, -0.8, 0.8), # set the frames color to white frameColor=(1, 1, 1, 1)) self.itemList = [] self.craftFrame = DirectFrame( text="Crafting", text_scale=0.25, text_pos=(0, 0.75, 0), text_bg=(1, 1, 1, 1), # make the frame occupy the whole window frameSize=(-0.6, 0.6, -0.8, 0.8), pos=(0.7, 0, 0), # set the frames color to white frameColor=(1, 1, 1, 1)) self.craftDrop = DirectFrame(text="drop ore", text_scale=0.1, pos=(0, 0.4, 0), frameSize=(-0.25, 0.25, -0.25, 0.25), frameColor=(1, 0, 0, 1)) self.craftDrop.reparentTo(self.craftFrame) def show(self): self.itemFrame.show() self.craftFrame.show() def hide(self): self.itemFrame.hide() self.craftFrame.hide() def __makeItem(self, item): obj = DirectLabel( text=str(item.giveLoot()) + "x " + item.giveType(), text_scale=0.5, text_pos=(0, -1, 0), image=("item.png", "item_hover.png", "item.png"), #normal, hover, disabled scale=0.16, numStates=2, state=DGG.NORMAL, relief=DGG.GROOVE) obj.setTransparency(True) obj["activeState"] = 0 obj.reparentTo(self.itemFrame.getCanvas()) obj.bind(DGG.B1PRESS, self.dragStart, [obj]) obj.bind(DGG.B1RELEASE, self.dragStop) obj.bind(DGG.ENTER, self.inObject, [obj]) obj.bind(DGG.EXIT, self.outObject, [obj]) return obj def updateList(self, items): for item in self.itemList: item.destroy() i = 1 j = 0 pad = 0.2 numItemsPerRow = 2 itemWidth = 0.32 itemHeight = 0.32 #left = -(itemWidth * (numItemsPerRow/2.0)) - 0.16 left = self.itemFrame.getX() # + (itemWidth + 0.16) xStep = itemWidth + 0.13 yStep = -(itemHeight + 0.13) top = 0.8 - (0.16 + pad) for item in items: self.itemList.append(self.__makeItem(item)) x = left + i * xStep y = top + j * yStep self.itemList[-1].setPos(x, 0.0, y) if i == numItemsPerRow: i = 0 j += 1 i += 1 if i == 1: j -= 1 height = ((j) * -yStep) - 0.16 # resize the canvas. This will make the scrollbars dis-/appear, # dependent on if the canvas is bigger than the frame size. self.itemFrame["canvasSize"] = (-0.6, 0.6, -height, 0.8) def inObject(self, element, event): # Can be used to highlight objects element["activeState"] = 1 element.setActiveState() #print "over object" def outObject(self, element, event): # Can be used to unhighlight objects #element["state"] = 0 element["activeState"] = 0 element.setActiveState() def dragStart(self, element, event): print "start drag" taskMgr.remove('dragDropTask') vWidget2render2d = element.getPos(render2d) vMouse2render2d = Point3(event.getMouse()[0], 0, event.getMouse()[1]) editVec = Vec3(vWidget2render2d - vMouse2render2d) t = taskMgr.add(self.dragTask, 'dragDropTask') element.reparentTo(aspect2d) t.element = element t.editVec = editVec t.elementStartPos = element.getPos() def dragTask(self, state): mwn = base.mouseWatcherNode if mwn.hasMouse(): vMouse2render2d = Point3(mwn.getMouse()[0], 0, mwn.getMouse()[1]) newPos = vMouse2render2d + state.editVec state.element.setPos(render2d, newPos) return Task.cont def dragStop(self, event): print "stop drag with:", event isInArea = False t = taskMgr.getTasksNamed('dragDropTask')[0] #for dropArea in self.dropAreas: # if self.isInBounds(event.getMouse(), dropArea["frameSize"], dropArea.getPos(render)): # print "inside Area:", dropArea["text"], dropArea.getPos(render) # isInArea = True # t.element.setPos(dropArea.getPos(render)) # t.element.setX(t.element.getX() * self.ratio) # #t.element.setX(t.element.getX() - t.element.getWidth() / 2.0) # break if not isInArea: t.element.setPos(t.elementStartPos) t.element.reparentTo(self.itemFrame.getCanvas()) taskMgr.remove('dragDropTask') def isInBounds(self, location, bounds, posShift=None): x = 0 if posShift is None else posShift.getX() y = 0 if posShift is None else posShift.getZ() left = x + bounds[0] right = x + bounds[1] bottom = y + bounds[2] top = y + bounds[3] # are we outside of the bounding box from the left if location[0] < left: return False # are we outside of the bounding box from the right if location[0] > right: return False # are we outside of the bounding box from the bottom if location[1] < bottom: return False # are we outside of the bounding box from the top if location[1] > top: return False # the location is inside the bbox return True
class MappingGUIDemo(ShowBase): def __init__(self): ShowBase.__init__(self) self.setBackgroundColor(0, 0, 0) # make the font look nice at a big scale DGG.getDefaultFont().setPixelsPerUnit(100) # Store our mapping, with some sensible defaults. In a real game, you # will want to load these from a configuration file. self.mapping = InputMapping() self.mapping.mapAxis("Move forward", InputDevice.Axis.left_y) self.mapping.mapAxis("Move backward", InputDevice.Axis.left_y) self.mapping.mapAxis("Move left", InputDevice.Axis.left_x) self.mapping.mapAxis("Move right", InputDevice.Axis.left_x) self.mapping.mapButton("Jump", GamepadButton.face_a()) self.mapping.mapButton("Use", GamepadButton.face_b()) self.mapping.mapButton("Break", GamepadButton.face_x()) self.mapping.mapButton("Fix", GamepadButton.face_y()) # The geometry for our basic buttons maps = loader.loadModel("models/button_map") self.buttonGeom = (maps.find("**/ready"), maps.find("**/click"), maps.find("**/hover"), maps.find("**/disabled")) # Change the default dialog skin. DGG.setDefaultDialogGeom("models/dialog.png") # create a sample title self.textscale = 0.1 self.title = DirectLabel(scale=self.textscale, pos=(base.a2dLeft + 0.05, 0.0, base.a2dTop - (self.textscale + 0.05)), frameColor=VBase4(0, 0, 0, 0), text="Button Mapping", text_align=TextNode.ALeft, text_fg=VBase4(1, 1, 1, 1), text_shadow=VBase4(0, 0, 0, 0.75), text_shadowOffset=Vec2(0.05, 0.05)) self.title.setTransparency(1) # Set up the list of actions that we can map keys to # create a frame that will create the scrollbars for us # Load the models for the scrollbar elements thumbMaps = loader.loadModel("models/thumb_map") thumbGeom = (thumbMaps.find("**/thumb_ready"), thumbMaps.find("**/thumb_click"), thumbMaps.find("**/thumb_hover"), thumbMaps.find("**/thumb_disabled")) incMaps = loader.loadModel("models/inc_map") incGeom = (incMaps.find("**/inc_ready"), incMaps.find("**/inc_click"), incMaps.find("**/inc_hover"), incMaps.find("**/inc_disabled")) decMaps = loader.loadModel("models/dec_map") decGeom = (decMaps.find("**/dec_ready"), decMaps.find("**/dec_click"), decMaps.find("**/dec_hover"), decMaps.find("**/dec_disabled")) # create the scrolled frame that will hold our list self.lstActionMap = DirectScrolledFrame( # make the frame occupy the whole window frameSize=VBase4(base.a2dLeft, base.a2dRight, 0.0, 1.55), # make the canvas as big as the frame canvasSize=VBase4(base.a2dLeft, base.a2dRight, 0.0, 0.0), # set the frames color to white frameColor=VBase4(0, 0, 0.25, 0.75), pos=(0, 0, -0.8), verticalScroll_scrollSize=0.2, verticalScroll_frameColor=VBase4(0.02, 0.02, 0.02, 1), verticalScroll_thumb_relief=1, verticalScroll_thumb_geom=thumbGeom, verticalScroll_thumb_pressEffect=False, verticalScroll_thumb_frameColor=VBase4(0, 0, 0, 0), verticalScroll_incButton_relief=1, verticalScroll_incButton_geom=incGeom, verticalScroll_incButton_pressEffect=False, verticalScroll_incButton_frameColor=VBase4(0, 0, 0, 0), verticalScroll_decButton_relief=1, verticalScroll_decButton_geom=decGeom, verticalScroll_decButton_pressEffect=False, verticalScroll_decButton_frameColor=VBase4(0, 0, 0, 0), ) # creat the list items idx = 0 self.listBGEven = base.loader.loadModel("models/list_item_even") self.listBGOdd = base.loader.loadModel("models/list_item_odd") self.actionLabels = {} for action in self.mapping.actions: mapped = self.mapping.formatMapping(action) item = self.__makeListItem(action, mapped, idx) item.reparentTo(self.lstActionMap.getCanvas()) idx += 1 # recalculate the canvas size to set scrollbars if necesary self.lstActionMap["canvasSize"] = (base.a2dLeft + 0.05, base.a2dRight - 0.05, -(len(self.mapping.actions) * 0.1), 0.09) self.lstActionMap.setCanvasSize() def closeDialog(self, action, newInputType, newInput): """Called in callback when the dialog is closed. newInputType will be "button" or "axis", or None if the remapping was cancelled.""" self.dlgInput = None if newInputType is not None: # map the event to the given action if newInputType == "axis": self.mapping.mapAxis(action, newInput) else: self.mapping.mapButton(action, newInput) # actualize the label in the list that shows the current # event for the action self.actionLabels[action]["text"] = self.mapping.formatMapping( action) # cleanup for bt in base.buttonThrowers: bt.node().setSpecificFlag(True) bt.node().setButtonDownEvent("") for bt in base.deviceButtonThrowers: bt.node().setSpecificFlag(True) bt.node().setButtonDownEvent("") taskMgr.remove("checkControls") # Now detach all the input devices. for device in self.attachedDevices: base.detachInputDevice(device) self.attachedDevices.clear() def changeMapping(self, action): # Create the dialog window self.dlgInput = ChangeActionDialog(action, button_geom=self.buttonGeom, command=self.closeDialog) # Attach all input devices. devices = base.devices.getDevices() for device in devices: base.attachInputDevice(device) self.attachedDevices = devices # Disable regular button events on all button event throwers, and # instead broadcast a generic event. for bt in base.buttonThrowers: bt.node().setSpecificFlag(False) bt.node().setButtonDownEvent("keyListenEvent") for bt in base.deviceButtonThrowers: bt.node().setSpecificFlag(False) bt.node().setButtonDownEvent("deviceListenEvent") self.accept("keyListenEvent", self.dlgInput.buttonPressed) self.accept("deviceListenEvent", self.dlgInput.buttonPressed) # As there are no events thrown for control changes, we set up a task # to check if the controls were moved # This list will help us for checking which controls were moved self.axisStates = {None: {}} # fill it with all available controls for device in devices: for axis in device.axes: if device not in self.axisStates.keys(): self.axisStates.update({device: {axis.axis: axis.value}}) else: self.axisStates[device].update({axis.axis: axis.value}) # start the task taskMgr.add(self.watchControls, "checkControls") def watchControls(self, task): # move through all devices and all it's controls for device in self.attachedDevices: if device.device_class == InputDevice.DeviceClass.mouse: # Ignore mouse axis movement, or the user can't even navigate # to the OK/Cancel buttons! continue for axis in device.axes: # if a control got changed more than the given dead zone if self.axisStates[device][axis.axis] + DEAD_ZONE < axis.value or \ self.axisStates[device][axis.axis] - DEAD_ZONE > axis.value: # set the current state in the dict self.axisStates[device][axis.axis] = axis.value # Format the axis for being displayed. if axis.axis != InputDevice.Axis.none: #label = axis.axis.name.replace('_', ' ').title() self.dlgInput.axisMoved(axis.axis) return task.cont def __makeListItem(self, action, event, index): def dummy(): pass if index % 2 == 0: bg = self.listBGEven else: bg = self.listBGOdd item = DirectFrame(text=action, geom=bg, geom_scale=(base.a2dRight - 0.05, 1, 0.1), frameSize=VBase4(base.a2dLeft + 0.05, base.a2dRight - 0.05, -0.05, 0.05), frameColor=VBase4(1, 0, 0, 0), text_align=TextNode.ALeft, text_scale=0.05, text_fg=VBase4(1, 1, 1, 1), text_pos=(base.a2dLeft + 0.3, -0.015), text_shadow=VBase4(0, 0, 0, 0.35), text_shadowOffset=Vec2(-0.05, -0.05), pos=(0.05, 0, -(0.10 * index))) item.setTransparency(True) lbl = DirectLabel( text=event, text_fg=VBase4(1, 1, 1, 1), text_scale=0.05, text_pos=Vec2(0, -0.015), frameColor=VBase4(0, 0, 0, 0), ) lbl.reparentTo(item) lbl.setTransparency(True) self.actionLabels[action] = lbl buttonScale = 0.15 btn = DirectButton(text="Change", geom=self.buttonGeom, scale=buttonScale, text_scale=0.25, text_align=TextNode.ALeft, text_fg=VBase4(0.898, 0.839, 0.730, 1.0), text_pos=Vec2(-0.9, -0.085), relief=1, pad=Vec2(0.01, 0.01), frameColor=VBase4(0, 0, 0, 0), frameSize=VBase4(-1.0, 1.0, -0.25, 0.25), pos=(base.a2dRight - (0.898 * buttonScale + 0.3), 0, 0), pressEffect=False, command=self.changeMapping, extraArgs=[action]) btn.setTransparency(True) btn.reparentTo(item) return item
def __init__(self): ShowBase.__init__(self) self.setBackgroundColor(0, 0, 0) # make the font look nice at a big scale DGG.getDefaultFont().setPixelsPerUnit(100) # Store our mapping, with some sensible defaults. In a real game, you # will want to load these from a configuration file. self.mapping = InputMapping() self.mapping.mapAxis("Move forward", InputDevice.Axis.left_y) self.mapping.mapAxis("Move backward", InputDevice.Axis.left_y) self.mapping.mapAxis("Move left", InputDevice.Axis.left_x) self.mapping.mapAxis("Move right", InputDevice.Axis.left_x) self.mapping.mapButton("Jump", GamepadButton.face_a()) self.mapping.mapButton("Use", GamepadButton.face_b()) self.mapping.mapButton("Break", GamepadButton.face_x()) self.mapping.mapButton("Fix", GamepadButton.face_y()) # The geometry for our basic buttons maps = loader.loadModel("models/button_map") self.buttonGeom = (maps.find("**/ready"), maps.find("**/click"), maps.find("**/hover"), maps.find("**/disabled")) # Change the default dialog skin. DGG.setDefaultDialogGeom("models/dialog.png") # create a sample title self.textscale = 0.1 self.title = DirectLabel(scale=self.textscale, pos=(base.a2dLeft + 0.05, 0.0, base.a2dTop - (self.textscale + 0.05)), frameColor=VBase4(0, 0, 0, 0), text="Button Mapping", text_align=TextNode.ALeft, text_fg=VBase4(1, 1, 1, 1), text_shadow=VBase4(0, 0, 0, 0.75), text_shadowOffset=Vec2(0.05, 0.05)) self.title.setTransparency(1) # Set up the list of actions that we can map keys to # create a frame that will create the scrollbars for us # Load the models for the scrollbar elements thumbMaps = loader.loadModel("models/thumb_map") thumbGeom = (thumbMaps.find("**/thumb_ready"), thumbMaps.find("**/thumb_click"), thumbMaps.find("**/thumb_hover"), thumbMaps.find("**/thumb_disabled")) incMaps = loader.loadModel("models/inc_map") incGeom = (incMaps.find("**/inc_ready"), incMaps.find("**/inc_click"), incMaps.find("**/inc_hover"), incMaps.find("**/inc_disabled")) decMaps = loader.loadModel("models/dec_map") decGeom = (decMaps.find("**/dec_ready"), decMaps.find("**/dec_click"), decMaps.find("**/dec_hover"), decMaps.find("**/dec_disabled")) # create the scrolled frame that will hold our list self.lstActionMap = DirectScrolledFrame( # make the frame occupy the whole window frameSize=VBase4(base.a2dLeft, base.a2dRight, 0.0, 1.55), # make the canvas as big as the frame canvasSize=VBase4(base.a2dLeft, base.a2dRight, 0.0, 0.0), # set the frames color to white frameColor=VBase4(0, 0, 0.25, 0.75), pos=(0, 0, -0.8), verticalScroll_scrollSize=0.2, verticalScroll_frameColor=VBase4(0.02, 0.02, 0.02, 1), verticalScroll_thumb_relief=1, verticalScroll_thumb_geom=thumbGeom, verticalScroll_thumb_pressEffect=False, verticalScroll_thumb_frameColor=VBase4(0, 0, 0, 0), verticalScroll_incButton_relief=1, verticalScroll_incButton_geom=incGeom, verticalScroll_incButton_pressEffect=False, verticalScroll_incButton_frameColor=VBase4(0, 0, 0, 0), verticalScroll_decButton_relief=1, verticalScroll_decButton_geom=decGeom, verticalScroll_decButton_pressEffect=False, verticalScroll_decButton_frameColor=VBase4(0, 0, 0, 0), ) # creat the list items idx = 0 self.listBGEven = base.loader.loadModel("models/list_item_even") self.listBGOdd = base.loader.loadModel("models/list_item_odd") self.actionLabels = {} for action in self.mapping.actions: mapped = self.mapping.formatMapping(action) item = self.__makeListItem(action, mapped, idx) item.reparentTo(self.lstActionMap.getCanvas()) idx += 1 # recalculate the canvas size to set scrollbars if necesary self.lstActionMap["canvasSize"] = (base.a2dLeft + 0.05, base.a2dRight - 0.05, -(len(self.mapping.actions) * 0.1), 0.09) self.lstActionMap.setCanvasSize()
def __init__(self, services: Services, mouse1_press_callbacks: List[Callable[[], None]]): self.__services = services self.__services.ev_manager.register_listener(self) self.__base = self.__services.graphics.window self.__window = Window(self.__base, "view_editor", mouse1_press_callbacks, borderWidth=(0.0, 0.0), frameColor=WINDOW_BG_COLOUR, pos=(1.1, 0.5, 0.5), frameSize=(-1.1, 1.1, -5.79, 1.56)) self.__colour_picker = AdvancedColourPicker( self.__base, self.__window.frame, self.__colour_picker_callback, mouse1_press_callbacks) # spacers DirectFrame(parent=self.__window.frame, borderWidth=(.0, .0), frameColor=WIDGET_BG_COLOUR, frameSize=(-1., 1., -0.01, 0.01), pos=(0.0, 0.0, -1.75)) DirectFrame(parent=self.__window.frame, borderWidth=(.0, .0), frameColor=WIDGET_BG_COLOUR, frameSize=(-1., 1., -0.01, 0.01), pos=(0.0, 0.0, 1.1)) DirectFrame(parent=self.__window.frame, borderWidth=(.0, .0), frameColor=WIDGET_BG_COLOUR, frameSize=(-1., 1., -0.01, 0.01), pos=(0.0, 0.0, -4.1)) # ViewElements listing self.__elems_frame = DirectScrolledFrame(parent=self.__window.frame, frameColor=WINDOW_BG_COLOUR, frameSize=(-1, 1, -1.125, 1.1), pos=(0, 0, -2.9), autoHideScrollBars=True) # selected colour view frame self.__selected_cv_outline = DirectFrame( parent=self.__elems_frame.getCanvas(), relief=DGG.SUNKEN, frameColor=WHITE, borderWidth=(0.15, 0.15), frameSize=(-0.62, 0.62, -0.54, 0.54), scale=(0.18, 1.0, 0.18)) # selected view frame self.__selected_view_outline = DirectFrame(parent=self.__window.frame, relief=DGG.SUNKEN, frameColor=WHITE, borderWidth=(0.15, 0.15), frameSize=(-0.62, 0.62, -0.54, 0.54), scale=(0.3, 2.0, 0.35)) self.heading = DirectLabel(parent=self.__window.frame, text="View Editor", text_fg=WHITE, text_bg=WINDOW_BG_COLOUR, frameColor=WINDOW_BG_COLOUR, borderWidth=(.0, .0), pos=(-0.42, 0.0, 1.27), scale=(0.2, 3, 0.2)) self.__save_outline = DirectFrame(parent=self.__window.frame, frameColor=WHITE, pos=(-0.57, 0, -5.45), borderWidth=(0.25, 0.15), frameSize=(-0.62, 0.62, -0.54, 0.54), scale=(0.50, 2.1, 0.25)) self.__restore_outline = DirectFrame(parent=self.__window.frame, frameColor=WHITE, pos=(0.50, 0, -5.45), borderWidth=(0.25, 0.15), frameSize=(-0.62, 0.62, -0.54, 0.54), scale=(0.65, 2.1, 0.25)) # save and restore self.btn_s = DirectButton(text="Save", text_fg=(0.3, 0.3, 0.3, 1.0), pressEffect=1, command=self.__save, pos=(-0.575, 0, -5.5), parent=self.__window.frame, scale=(0.20, 2.1, 0.15), frameColor=TRANSPARENT) self.btn_r = DirectButton(text="Restore", text_fg=(0.3, 0.3, 0.3, 1.0), pressEffect=1, command=self.__reset, pos=(0.50, 0, -5.5), parent=self.__window.frame, scale=(0.20, 2.1, 0.15), frameColor=TRANSPARENT) # zoom window in / out self.btn_zoom_out = DirectButton(text="-", text_fg=WHITE, pressEffect=1, command=self.__window.zoom_out, pos=(0.5, 0., 1.25), parent=self.__window.frame, scale=(0.38, 4.25, 0.45), frameColor=TRANSPARENT) self.btn_zoom_in = DirectButton(text="+", text_fg=WHITE, pressEffect=1, command=self.__window.zoom_in, pos=(0.71, 0., 1.28), parent=self.__window.frame, scale=(0.35, 4.19, 0.38), frameColor=TRANSPARENT) # Quit button self.btn = DirectButton(text='x', text_fg=WHITE, command=self.__window.toggle_visible, pos=(0.91, 0.4, 1.3), parent=self.__window.frame, scale=(0.3, 2.9, 0.2), pressEffect=1, frameColor=TRANSPARENT) # Creating view selectors self.__view_selectors = [] for i in range(0, PersistentStateViews.MAX_VIEWS): num = os.path.join(GUI_DATA_PATH, str(i + 1) + ".png") self.__view_selectors.append( DirectButton(image=num, pos=(-0.7 + (i % 3) * 0.7, 0.4, -4.4 - 0.5 * (i // 3)), parent=self.__window.frame, scale=0.16, frameColor=TRANSPARENT, command=lambda v: setattr(self, "view_idx", v), extraArgs=[i])) self.__elems = [] self.__reset()
class ViewEditor(): __services: Services __base: ShowBase __window: Window __colour_picker: AdvancedColourPicker __elems: List[ViewElement] def __init__(self, services: Services, mouse1_press_callbacks: List[Callable[[], None]]): self.__services = services self.__services.ev_manager.register_listener(self) self.__base = self.__services.graphics.window self.__window = Window(self.__base, "view_editor", mouse1_press_callbacks, borderWidth=(0.0, 0.0), frameColor=WINDOW_BG_COLOUR, pos=(1.1, 0.5, 0.5), frameSize=(-1.1, 1.1, -5.79, 1.56)) self.__colour_picker = AdvancedColourPicker( self.__base, self.__window.frame, self.__colour_picker_callback, mouse1_press_callbacks) # spacers DirectFrame(parent=self.__window.frame, borderWidth=(.0, .0), frameColor=WIDGET_BG_COLOUR, frameSize=(-1., 1., -0.01, 0.01), pos=(0.0, 0.0, -1.75)) DirectFrame(parent=self.__window.frame, borderWidth=(.0, .0), frameColor=WIDGET_BG_COLOUR, frameSize=(-1., 1., -0.01, 0.01), pos=(0.0, 0.0, 1.1)) DirectFrame(parent=self.__window.frame, borderWidth=(.0, .0), frameColor=WIDGET_BG_COLOUR, frameSize=(-1., 1., -0.01, 0.01), pos=(0.0, 0.0, -4.1)) # ViewElements listing self.__elems_frame = DirectScrolledFrame(parent=self.__window.frame, frameColor=WINDOW_BG_COLOUR, frameSize=(-1, 1, -1.125, 1.1), pos=(0, 0, -2.9), autoHideScrollBars=True) # selected colour view frame self.__selected_cv_outline = DirectFrame( parent=self.__elems_frame.getCanvas(), relief=DGG.SUNKEN, frameColor=WHITE, borderWidth=(0.15, 0.15), frameSize=(-0.62, 0.62, -0.54, 0.54), scale=(0.18, 1.0, 0.18)) # selected view frame self.__selected_view_outline = DirectFrame(parent=self.__window.frame, relief=DGG.SUNKEN, frameColor=WHITE, borderWidth=(0.15, 0.15), frameSize=(-0.62, 0.62, -0.54, 0.54), scale=(0.3, 2.0, 0.35)) self.heading = DirectLabel(parent=self.__window.frame, text="View Editor", text_fg=WHITE, text_bg=WINDOW_BG_COLOUR, frameColor=WINDOW_BG_COLOUR, borderWidth=(.0, .0), pos=(-0.42, 0.0, 1.27), scale=(0.2, 3, 0.2)) self.__save_outline = DirectFrame(parent=self.__window.frame, frameColor=WHITE, pos=(-0.57, 0, -5.45), borderWidth=(0.25, 0.15), frameSize=(-0.62, 0.62, -0.54, 0.54), scale=(0.50, 2.1, 0.25)) self.__restore_outline = DirectFrame(parent=self.__window.frame, frameColor=WHITE, pos=(0.50, 0, -5.45), borderWidth=(0.25, 0.15), frameSize=(-0.62, 0.62, -0.54, 0.54), scale=(0.65, 2.1, 0.25)) # save and restore self.btn_s = DirectButton(text="Save", text_fg=(0.3, 0.3, 0.3, 1.0), pressEffect=1, command=self.__save, pos=(-0.575, 0, -5.5), parent=self.__window.frame, scale=(0.20, 2.1, 0.15), frameColor=TRANSPARENT) self.btn_r = DirectButton(text="Restore", text_fg=(0.3, 0.3, 0.3, 1.0), pressEffect=1, command=self.__reset, pos=(0.50, 0, -5.5), parent=self.__window.frame, scale=(0.20, 2.1, 0.15), frameColor=TRANSPARENT) # zoom window in / out self.btn_zoom_out = DirectButton(text="-", text_fg=WHITE, pressEffect=1, command=self.__window.zoom_out, pos=(0.5, 0., 1.25), parent=self.__window.frame, scale=(0.38, 4.25, 0.45), frameColor=TRANSPARENT) self.btn_zoom_in = DirectButton(text="+", text_fg=WHITE, pressEffect=1, command=self.__window.zoom_in, pos=(0.71, 0., 1.28), parent=self.__window.frame, scale=(0.35, 4.19, 0.38), frameColor=TRANSPARENT) # Quit button self.btn = DirectButton(text='x', text_fg=WHITE, command=self.__window.toggle_visible, pos=(0.91, 0.4, 1.3), parent=self.__window.frame, scale=(0.3, 2.9, 0.2), pressEffect=1, frameColor=TRANSPARENT) # Creating view selectors self.__view_selectors = [] for i in range(0, PersistentStateViews.MAX_VIEWS): num = os.path.join(GUI_DATA_PATH, str(i + 1) + ".png") self.__view_selectors.append( DirectButton(image=num, pos=(-0.7 + (i % 3) * 0.7, 0.4, -4.4 - 0.5 * (i // 3)), parent=self.__window.frame, scale=0.16, frameColor=TRANSPARENT, command=lambda v: setattr(self, "view_idx", v), extraArgs=[i])) self.__elems = [] self.__reset() def __reset(self) -> None: self.__services.state.views.restore_effective_view() ps_colours = self.__services.state.views.effective_view.colours for e in self.__elems: e.destroy() self.__elems.clear() for name, dc in ps_colours.items(): self.__elems.append( ViewElement(name, self.__update_visibility, self.__update_colour, self.__select_cv, self.__elems_frame.getCanvas(), dc.visible, dc.colour)) for i in range(len(self.__elems)): self.__elems[i].frame.set_pos((0.15, 0.0, -0.2 * i)) self.__elems_frame["canvasSize"] = (-0.95, 0.95, -0.2 * len(self.__elems) + 0.1, 0.1) self.__cur_view_idx = self.view_idx self.__selected_view_outline.set_pos( (-0.7 + (self.view_idx % 3) * 0.7, 0.4, -4.4 - 0.5 * (self.view_idx // 3))) self.__select_cv(self.__elems[0] if self.__elems else None) def __save(self) -> None: self.__services.state.views.apply_effective_view() def __update_visibility(self, name: str, visible: bool) -> None: self.__services.state.views.effective_view.colours[ name].visible = visible def __update_colour(self, name: str, colour: Colour) -> None: self.__services.state.views.effective_view.colours[ name].colour = colour def __colour_picker_callback(self, colour: Colour) -> None: self.__window.focus() if self.__selected_cv_elem is not None: self.__selected_cv_elem.colour = colour # calls self.__update_colour() def __select_cv(self, e: ViewElement): self.__window.focus() self.__selected_cv_elem = e if e is None: self.__selected_cv_outline.hide() self.__colour_picker.enabled = False else: self.__colour_picker.enabled = True self.__selected_cv_outline.show() self.__selected_cv_outline.set_pos( (-0.495, 1.0, -0.2 * self.__elems.index(e))) self.__colour_picker.colour = e.colour def notify(self, event: Event) -> None: if isinstance( event, NewColourEvent ) or self.__services.state.views.view_idx != self.__cur_view_idx: self.__reset() elif isinstance(event, ToggleViewEvent): self.__window.toggle_visible() @property def view_idx(self) -> str: return 'view_idx' @view_idx.setter def view_idx(self, idx: int) -> None: self.__services.state.views.view_idx = idx self.__reset() @view_idx.getter def view_idx(self) -> int: return self.__services.state.views.view_idx
class MappingGUIDemo(ShowBase): def __init__(self): ShowBase.__init__(self) self.setBackgroundColor(0, 0, 0) # make the font look nice at a big scale DGG.getDefaultFont().setPixelsPerUnit(100) # Store our mapping, with some sensible defaults. In a real game, you # will want to load these from a configuration file. self.mapping = InputMapping() self.mapping.mapAxis("Move forward", InputDevice.Axis.left_y) self.mapping.mapAxis("Move backward", InputDevice.Axis.left_y) self.mapping.mapAxis("Move left", InputDevice.Axis.left_x) self.mapping.mapAxis("Move right", InputDevice.Axis.left_x) self.mapping.mapButton("Jump", GamepadButton.face_a()) self.mapping.mapButton("Use", GamepadButton.face_b()) self.mapping.mapButton("Break", GamepadButton.face_x()) self.mapping.mapButton("Fix", GamepadButton.face_y()) # The geometry for our basic buttons maps = loader.loadModel("models/button_map") self.buttonGeom = ( maps.find("**/ready"), maps.find("**/click"), maps.find("**/hover"), maps.find("**/disabled")) # Change the default dialog skin. DGG.setDefaultDialogGeom("models/dialog.png") # create a sample title self.textscale = 0.1 self.title = DirectLabel( scale=self.textscale, pos=(base.a2dLeft + 0.05, 0.0, base.a2dTop - (self.textscale + 0.05)), frameColor=VBase4(0, 0, 0, 0), text="Button Mapping", text_align=TextNode.ALeft, text_fg=VBase4(1, 1, 1, 1), text_shadow=VBase4(0, 0, 0, 0.75), text_shadowOffset=Vec2(0.05, 0.05)) self.title.setTransparency(1) # Set up the list of actions that we can map keys to # create a frame that will create the scrollbars for us # Load the models for the scrollbar elements thumbMaps = loader.loadModel("models/thumb_map") thumbGeom = ( thumbMaps.find("**/thumb_ready"), thumbMaps.find("**/thumb_click"), thumbMaps.find("**/thumb_hover"), thumbMaps.find("**/thumb_disabled")) incMaps = loader.loadModel("models/inc_map") incGeom = ( incMaps.find("**/inc_ready"), incMaps.find("**/inc_click"), incMaps.find("**/inc_hover"), incMaps.find("**/inc_disabled")) decMaps = loader.loadModel("models/dec_map") decGeom = ( decMaps.find("**/dec_ready"), decMaps.find("**/dec_click"), decMaps.find("**/dec_hover"), decMaps.find("**/dec_disabled")) # create the scrolled frame that will hold our list self.lstActionMap = DirectScrolledFrame( # make the frame occupy the whole window frameSize=VBase4(base.a2dLeft, base.a2dRight, 0.0, 1.55), # make the canvas as big as the frame canvasSize=VBase4(base.a2dLeft, base.a2dRight, 0.0, 0.0), # set the frames color to white frameColor=VBase4(0, 0, 0.25, 0.75), pos=(0, 0, -0.8), verticalScroll_scrollSize=0.2, verticalScroll_frameColor=VBase4(0.02, 0.02, 0.02, 1), verticalScroll_thumb_relief=1, verticalScroll_thumb_geom=thumbGeom, verticalScroll_thumb_pressEffect=False, verticalScroll_thumb_frameColor=VBase4(0, 0, 0, 0), verticalScroll_incButton_relief=1, verticalScroll_incButton_geom=incGeom, verticalScroll_incButton_pressEffect=False, verticalScroll_incButton_frameColor=VBase4(0, 0, 0, 0), verticalScroll_decButton_relief=1, verticalScroll_decButton_geom=decGeom, verticalScroll_decButton_pressEffect=False, verticalScroll_decButton_frameColor=VBase4(0, 0, 0, 0),) # creat the list items idx = 0 self.listBGEven = base.loader.loadModel("models/list_item_even") self.listBGOdd = base.loader.loadModel("models/list_item_odd") self.actionLabels = {} for action in self.mapping.actions: mapped = self.mapping.formatMapping(action) item = self.__makeListItem(action, mapped, idx) item.reparentTo(self.lstActionMap.getCanvas()) idx += 1 # recalculate the canvas size to set scrollbars if necesary self.lstActionMap["canvasSize"] = ( base.a2dLeft+0.05, base.a2dRight-0.05, -(len(self.mapping.actions)*0.1), 0.09) self.lstActionMap.setCanvasSize() def closeDialog(self, action, newInputType, newInput): """Called in callback when the dialog is closed. newInputType will be "button" or "axis", or None if the remapping was cancelled.""" self.dlgInput = None if newInputType is not None: # map the event to the given action if newInputType == "axis": self.mapping.mapAxis(action, newInput) else: self.mapping.mapButton(action, newInput) # actualize the label in the list that shows the current # event for the action self.actionLabels[action]["text"] = self.mapping.formatMapping(action) # cleanup for bt in base.buttonThrowers: bt.node().setSpecificFlag(True) bt.node().setButtonDownEvent("") for bt in base.deviceButtonThrowers: bt.node().setSpecificFlag(True) bt.node().setButtonDownEvent("") taskMgr.remove("checkControls") # Now detach all the input devices. for device in self.attachedDevices: base.detachInputDevice(device) self.attachedDevices.clear() def changeMapping(self, action): # Create the dialog window self.dlgInput = ChangeActionDialog(action, button_geom=self.buttonGeom, command=self.closeDialog) # Attach all input devices. devices = base.devices.getDevices() for device in devices: base.attachInputDevice(device) self.attachedDevices = devices # Disable regular button events on all button event throwers, and # instead broadcast a generic event. for bt in base.buttonThrowers: bt.node().setSpecificFlag(False) bt.node().setButtonDownEvent("keyListenEvent") for bt in base.deviceButtonThrowers: bt.node().setSpecificFlag(False) bt.node().setButtonDownEvent("deviceListenEvent") self.accept("keyListenEvent", self.dlgInput.buttonPressed) self.accept("deviceListenEvent", self.dlgInput.buttonPressed) # As there are no events thrown for control changes, we set up a task # to check if the controls were moved # This list will help us for checking which controls were moved self.axisStates = {None: {}} # fill it with all available controls for device in devices: for axis in device.axes: if device not in self.axisStates.keys(): self.axisStates.update({device: {axis.axis: axis.value}}) else: self.axisStates[device].update({axis.axis: axis.value}) # start the task taskMgr.add(self.watchControls, "checkControls") def watchControls(self, task): # move through all devices and all it's controls for device in self.attachedDevices: if device.device_class == InputDevice.DeviceClass.mouse: # Ignore mouse axis movement, or the user can't even navigate # to the OK/Cancel buttons! continue for axis in device.axes: # if a control got changed more than the given dead zone if self.axisStates[device][axis.axis] + DEAD_ZONE < axis.value or \ self.axisStates[device][axis.axis] - DEAD_ZONE > axis.value: # set the current state in the dict self.axisStates[device][axis.axis] = axis.value # Format the axis for being displayed. if axis.axis != InputDevice.Axis.none: #label = axis.axis.name.replace('_', ' ').title() self.dlgInput.axisMoved(axis.axis) return task.cont def __makeListItem(self, action, event, index): def dummy(): pass if index % 2 == 0: bg = self.listBGEven else: bg = self.listBGOdd item = DirectFrame( text=action, geom=bg, geom_scale=(base.a2dRight-0.05, 1, 0.1), frameSize=VBase4(base.a2dLeft+0.05, base.a2dRight-0.05, -0.05, 0.05), frameColor=VBase4(1,0,0,0), text_align=TextNode.ALeft, text_scale=0.05, text_fg=VBase4(1,1,1,1), text_pos=(base.a2dLeft + 0.3, -0.015), text_shadow=VBase4(0, 0, 0, 0.35), text_shadowOffset=Vec2(-0.05, -0.05), pos=(0.05, 0, -(0.10 * index))) item.setTransparency(True) lbl = DirectLabel( text=event, text_fg=VBase4(1, 1, 1, 1), text_scale=0.05, text_pos=Vec2(0, -0.015), frameColor=VBase4(0, 0, 0, 0), ) lbl.reparentTo(item) lbl.setTransparency(True) self.actionLabels[action] = lbl buttonScale = 0.15 btn = DirectButton( text="Change", geom=self.buttonGeom, scale=buttonScale, text_scale=0.25, text_align=TextNode.ALeft, text_fg=VBase4(0.898, 0.839, 0.730, 1.0), text_pos=Vec2(-0.9, -0.085), relief=1, pad=Vec2(0.01, 0.01), frameColor=VBase4(0, 0, 0, 0), frameSize=VBase4(-1.0, 1.0, -0.25, 0.25), pos=(base.a2dRight-(0.898*buttonScale+0.3), 0, 0), pressEffect=False, command=self.changeMapping, extraArgs=[action]) btn.setTransparency(True) btn.reparentTo(item) return item
class DirectTree(DirectObject): def __init__( self, pos=(0, 0, 0), parent=None, frameSize=(1, 1), treeStructure=DirectTreeItem(), ): if parent is None: parent = aspect2d self.treeStructure = treeStructure self.treeStructureNodes = dict() self.highlightedNodes = list() self.frameWidth = frameSize[0] #0.8 self.frameHeight = frameSize[1] #1.5 self.itemIndent = 0.05 self.itemScale = 0.03 self.itemTextScale = 1.2 self.verticalSpacing = 0.0375 self.__createTreeLines() self.childrenFrame = DirectScrolledFrame( parent=parent, pos=pos, relief=DGG.GROOVE, state=DGG.NORMAL, # to create a mouse watcher region manageScrollBars=0, enableEdit=0, #suppressMouse=1, sortOrder=1000, frameColor=(0, 0, 0, .7), borderWidth=(0.005, 0.005), frameSize=(0, self.frameWidth, 0, self.frameHeight), canvasSize=(0, self.frameWidth - self.itemScale * 2, 0, self.frameHeight), verticalScroll_frameSize=[0, self.itemScale, 0, 1], horizontalScroll_frameSize=[0, 1, 0, self.itemScale], ) self.childrenCanvas = self.childrenFrame.getCanvas().attachNewNode( 'myCanvas') self.childrenCanvas.setX(0.05) self.childrenCanvas.setZ(self.frameHeight - 1) # some fix to have the list in the window self.accept(EVENT_DIRECTTREE_REFRESH, self.update) def destroy(self): self.treeStructure = DirectTreeItem() self.render() self.childrenFrame.destroy() #del self.treeStructureNodes def __createLine(self, length=1, color=(1, 1, 1, 1), endColor=None): LS = LineSegs() LS.setColor(*color) LS.moveTo(0, 0, 0) LS.drawTo(length * 1, 0, 0) node = LS.create() if endColor: LS.setVertexColor(1, *endColor) return node def __createTreeLines(self): # create horisontal tree line color = (1, 0, 0, .9) self.horizontalTreeLine = NodePath( self.__createLine(self.itemIndent + self.itemScale * .5, color, endColor=(1, 1, 1, .1))) self.horizontalTreeLine.setTwoSided(0, 100) self.horizontalTreeLine.setTransparency(1) # create vertical tree line self.verticalTreeLine = NodePath( self.__createLine(self.verticalSpacing, color)) self.verticalTreeLine.setR(90) self.verticalTreeLine.setTwoSided(0, 100) self.verticalTreeLine.setTransparency(1) def render(self): ''' traverse the tree and update the visuals according to it ''' for treeItem in self.treeStructure.getRec(): # create nodes that have no visual elements if not treeItem in self.treeStructureNodes: treeNode = self.childrenCanvas.attachNewNode('') hor = self.horizontalTreeLine.instanceUnderNode(treeNode, '') vert = self.verticalTreeLine.instanceUnderNode(treeNode, '') vert.setZ(0.007) hor.setPos(-1.5 * self.itemIndent, 0, self.itemScale * .25) vert.setX(-.5 * self.itemIndent) nodeButton = DirectButton( parent=treeNode, scale=self.itemScale, relief=DGG.FLAT, text_scale=self.itemTextScale, text_align=TextNode.ALeft, text=treeItem.name, rolloverSound=None, #clickSound=None, ) nodeButton.bind(DGG.B1PRESS, treeItem.button1press) nodeButton.bind(DGG.B2PRESS, treeItem.button2press) nodeButton.bind(DGG.B3PRESS, treeItem.button3press) #treeButton = None #if len(treeItem.childrens) > 0: treeButton = DirectButton( parent=nodeButton, frameColor=(1, 1, 1, 1), frameSize=(-.4, .4, -.4, .4), pos=(-.5 * self.itemIndent / self.itemScale, 0, .25), text='', text_pos=(-.1, -.22), text_scale=(1.6, 1), text_fg=(0, 0, 0, 1), enableEdit=0, command=treeItem.setOpen, sortOrder=1000, rolloverSound=None, #clickSound=None, ) self.treeStructureNodes[treeItem] = [ treeNode, nodeButton, treeButton, hor, vert ] # destroy nodes no more used for treeItem in self.treeStructureNodes.keys()[:]: #treeItem = self.treeStructureNodes[treeName] if treeItem not in self.treeStructure.getRec(): treeNode, nodeButton, treeButton, hor, vert = self.treeStructureNodes[ treeItem] #nodeButton['text']='' nodeButton.unbind(DGG.B1PRESS) nodeButton.unbind(DGG.B2PRESS) nodeButton.unbind(DGG.B3PRESS) #nodeButton.detachNode() #nodeButton.removeNode() nodeButton.destroy() if treeButton: #treeButton['text']='' #treeButton['command']=None treeButton.detachNode() treeButton.removeNode() hor.detachNode() hor.removeNode() vert.detachNode() vert.removeNode() treeItem.destroy() #treeNode.detachNode() treeNode.removeNode() #treeNode.destroy() del self.treeStructureNodes[treeItem] frameHeight = len(self.treeStructureNodes) * self.verticalSpacing self.childrenFrame['canvasSize'] = (0, self.frameWidth - self.itemScale * 2, 0, frameHeight) self.childrenCanvas.setZ(frameHeight - 1) def highlight(self, selectedTreeNodes): for treeNode in self.highlightedNodes: treeNode.highlighted = False self.highlightedNodes = selectedTreeNodes for treeNode in self.highlightedNodes: treeNode.highlighted = True self.update() def update(self): ''' update the tree, updating the positions and hidden status of childrens ''' idx = 0 for treeItem in self.treeStructure.getRec(): # show or hide the items treeNode, nodeButton, treeButton, hor, vert = self.treeStructureNodes[ treeItem] if treeItem.getShow(): treeNode.show() vert.show() if treeItem.parent: # dont show the horizontal line on the parent hor.show() else: hor.hide() idx += 1 else: treeNode.hide() hor.hide() vert.hide() if len(treeItem.childrens) > 0: treeButton.show() else: treeButton.hide() if treeItem.highlighted: nodeButton['text_fg'] = (1, 0, 0, 1) else: nodeButton['text_fg'] = (0, 0, 0, 1) # update the vertical position of the node treeNode.setPos(treeItem.getDepth() * self.itemIndent, 0, 1 - idx * self.verticalSpacing) # if the tree element has a treebutton (if it has childrens), update the +/- if treeButton: # update the text for the open/close button tag = ['+', '-'][treeItem.open] treeButton['text'] = tag # calculate length to the last children with the same depth as this treeitem # this gives the length of the vertical line c = -1 i = 0 treeItemDepth = treeItem.getDepth() for recItem in treeItem.getRec(): if recItem.getShow(): c += 1 if recItem.getDepth() == treeItemDepth + 1: i = c vert.setSz(i)
class HostMenu(DirectObject): def __init__(self): self.defaultBtnMap = base.loader.loadModel("gui/button_map") self.buttonGeom = ( self.defaultBtnMap.find("**/button_ready"), self.defaultBtnMap.find("**/button_click"), self.defaultBtnMap.find("**/button_rollover"), self.defaultBtnMap.find("**/button_disabled")) defaultFont = loader.loadFont('gui/eufm10.ttf') self.logFrame = DirectScrolledFrame( canvasSize = (0, base.a2dRight * 2, -5, 0), frameSize = (0, base.a2dRight * 2, (base.a2dBottom+.2) * 2, 0), frameColor = (0.1, 0.1, 0.1, 1)) self.logFrame.reparentTo(base.a2dTopLeft) # create the info and server debug output self.textscale = 0.1 self.txtinfo = OnscreenText( scale = self.textscale, pos = (0.1, -0.1), text = "", align = TextNode.ALeft, fg = (0.1,1.0,0.15,1), bg = (0, 0, 0, 0), shadow = (0, 0, 0, 1), shadowOffset = (-0.02, -0.02)) self.txtinfo.setTransparency(1) self.txtinfo.reparentTo(self.logFrame.getCanvas()) # create a close Server button self.btnBackPos = Vec3(0.4, 0, 0.2) self.btnBackScale = 0.25 self.btnBack = DirectButton( # Scale and position scale = self.btnBackScale, pos = self.btnBackPos, # Text text = "Quit Server", text_scale = 0.45, text_pos = (0, -0.1), text_fg = (0.82,0.85,0.87,1), text_shadow = (0, 0, 0, 1), text_shadowOffset = (-0.02, -0.02), text_font = defaultFont, # Frame geom = self.buttonGeom, frameColor = (0, 0, 0, 0), relief = 0, pressEffect = False, # Functionality command = self.back, rolloverSound = None, clickSound = None) self.btnBack.setTransparency(1) self.btnBack.reparentTo(base.a2dBottomLeft) # catch window resizes and recalculate the aspectration self.accept("window-event", self.recalcAspectRatio) self.accept("addLog", self.addLog) def show(self): self.logFrame.show() self.btnBack.show() def hide(self): self.logFrame.hide() self.btnBack.hide() def back(self): self.hide() base.messenger.send("stop_server") self.addLog("Quit Server!") def addLog(self, text): self.txtinfo.appendText(text + "\n") textbounds = self.txtinfo.getTightBounds() self.logFrame["canvasSize"] = (0, textbounds[1].getX(), textbounds[0].getZ(), 0) def recalcAspectRatio(self, window): """get the new aspect ratio to resize the mainframe""" # set the mainframe size to the window borders again self.logFrame["frameSize"] = ( 0, base.a2dRight * 2, (base.a2dBottom+.2) * 2, 0)
class DirectWindow( DirectFrame ): def __init__( self, pos = ( -.5, .5), title = 'Title', curSize = ( 1, 1), maxSize = ( 1, 1 ), minSize = ( .5, .5 ), backgroundColor = ( 1, 1, 1, 1 ), borderColor = ( 1, 1, 1, 1 ), titleColor = ( 1, 1, 1, 1 ), borderSize = 0.04, titleSize = 0.06, closeButton = False, windowParent = aspect2d, preserve = True, preserveWhole = True, ): self.preserve = preserve self.preserveWhole = preserveWhole self.windowParent = windowParent self.windowPos = pos DirectFrame.__init__( self, parent = windowParent, pos = ( self.windowPos[0], 0, self.windowPos[1] ), frameColor = ( 0, 0, 0, 0 ), frameTexture = loader.loadTexture( DIRECTORY+'transparent.png' ) ) self.setTransparency(True) # the title part of the window, drag around to move the window self.headerHeight = titleSize h = -self.headerHeight self.windowHeaderLeft = DirectButton( parent = self, frameTexture = DEFAULT_TITLE_GEOM_LEFT, frameSize = ( -.5, .5, -.5, .5 ), borderWidth = ( 0, 0 ), relief = DGG.FLAT, frameColor = titleColor, ) self.windowHeaderCenter = DirectButton( parent = self, frameTexture = DEFAULT_TITLE_GEOM_CENTER, frameSize = ( -.5, .5, -.5, .5 ), borderWidth = ( 0, 0 ), relief = DGG.FLAT, frameColor = titleColor, ) if closeButton: rightTitleGeom = DEFAULT_TITLE_GEOM_RIGHT_CLOSE command = self.destroy else: rightTitleGeom = DEFAULT_TITLE_GEOM_RIGHT command = None self.windowHeaderRight = DirectButton( parent = self, frameTexture = rightTitleGeom, frameSize = ( -.5, .5, -.5, .5 ), borderWidth = ( 0, 0 ), relief = DGG.FLAT, frameColor = titleColor, command = command ) self.windowHeaderLeft.setTransparency(True) self.windowHeaderCenter.setTransparency(True) self.windowHeaderRight.setTransparency(True) self.windowHeaderLeft.bind( DGG.B1PRESS, self.startWindowDrag ) self.windowHeaderCenter.bind( DGG.B1PRESS, self.startWindowDrag ) self.windowHeaderRight.bind( DGG.B1PRESS, self.startWindowDrag ) # this is not handled correctly, if a window is dragged which has been # created before another it will not be released # check the bugfixed startWindowDrag function #self.windowHeader.bind(DGG.B1RELEASE,self.stopWindowDrag) text = TextNode('WindowTitleTextNode') text.setText(title) text.setAlign(TextNode.ACenter) text.setTextColor( 0, 0, 0, 1 ) text.setShadow(0.05, 0.05) text.setShadowColor( 1, 1, 1, 1 ) self.textNodePath = self.attachNewNode(text) self.textNodePath.setScale(self.headerHeight*0.8) # the content part of the window, put stuff beneath # contentWindow.getCanvas() to put it into it self.maxVirtualSize = maxSize self.minVirtualSize = minSize self.resizeSize = borderSize self.contentWindow = DirectScrolledFrame( parent = self, pos = ( 0, 0, -self.headerHeight ), canvasSize = ( 0, self.maxVirtualSize[0], 0, self.maxVirtualSize[1] ), frameColor = ( 0, 0, 0, 0), # defines the background color of the resize-button relief = DGG.FLAT, borderWidth = (0, 0), verticalScroll_frameSize = [0, self.resizeSize, 0, 1], horizontalScroll_frameSize = [0, 1, 0, self.resizeSize], # resize the scrollbar according to window size verticalScroll_resizeThumb = False, horizontalScroll_resizeThumb = False, # define the textures for the scrollbars verticalScroll_frameTexture = VERTICALSCROLL_FRAMETEXTURE, verticalScroll_incButton_frameTexture = VERTICALSCROLL_INCBUTTON_FRAMETEXTURE, verticalScroll_decButton_frameTexture = VERTICALSCROLL_DECBUTTON_FRAMETEXTURE, verticalScroll_thumb_frameTexture = VERTICALSCROLL_TUMB_FRAMETEXTURE, horizontalScroll_frameTexture = HORIZONTALSCROLL_FRAMETEXTURE, horizontalScroll_incButton_frameTexture = HORIZONTALSCROLL_INCBUTTON_FRAMETEXTURE, horizontalScroll_decButton_frameTexture = HORIZONTALSCROLL_DECBUTTON_FRAMETEXTURE, horizontalScroll_thumb_frameTexture = HORIZONTALSCROLL_TUMB_FRAMETEXTURE, # make all flat, so the texture is as we want it verticalScroll_relief = DGG.FLAT, verticalScroll_thumb_relief = DGG.FLAT, verticalScroll_decButton_relief = DGG.FLAT, verticalScroll_incButton_relief = DGG.FLAT, horizontalScroll_relief = DGG.FLAT, horizontalScroll_thumb_relief = DGG.FLAT, horizontalScroll_decButton_relief = DGG.FLAT, horizontalScroll_incButton_relief = DGG.FLAT, # colors verticalScroll_frameColor = borderColor, verticalScroll_incButton_frameColor = borderColor, verticalScroll_decButton_frameColor = borderColor, verticalScroll_thumb_frameColor = borderColor, horizontalScroll_frameColor = borderColor, horizontalScroll_incButton_frameColor = borderColor, horizontalScroll_decButton_frameColor = borderColor, horizontalScroll_thumb_frameColor = borderColor, ) self.contentWindow.setTransparency(True) # background color self.backgroundColor = DirectFrame( parent = self.contentWindow.getCanvas(), frameSize = ( 0, self.maxVirtualSize[0], 0, self.maxVirtualSize[1] ), frameColor = backgroundColor, relief = DGG.FLAT, borderWidth = ( .01, .01), ) self.backgroundColor.setTransparency(True) # Add a box self.box = boxes.VBox(parent = self.getCanvas()) # is needed for some nicer visuals of the resize button (background) self.windowResizeBackground = DirectButton( parent = self, frameSize = ( -.5, .5, -.5, .5 ), borderWidth = ( 0, 0 ), scale = ( self.resizeSize, 1, self.resizeSize ), relief = DGG.FLAT, frameColor = backgroundColor, ) # the resize button of the window self.windowResize = DirectButton( parent = self, frameSize = ( -.5, .5, -.5, .5 ), borderWidth = ( 0, 0 ), scale = ( self.resizeSize, 1, self.resizeSize ), relief = DGG.FLAT, frameTexture = DEFAULT_RESIZE_GEOM, frameColor = borderColor, ) self.windowResize.setTransparency(True) self.windowResize.bind(DGG.B1PRESS,self.startResizeDrag) self.windowResize.bind(DGG.B1RELEASE,self.stopResizeDrag) # offset then clicking on the resize button from the mouse to the resizebutton # position, required to calculate the position / scaling self.offset = None self.taskName = "resizeTask-%s" % str(hash(self)) # do sizing of the window (minimum) #self.resize( Vec3(0,0,0), Vec3(0,0,0) ) # maximum #self.resize( Vec3(100,0,-100), Vec3(0,0,0) ) self.resize( Vec3(curSize[0], 0, -curSize[1]), Vec3(0,0,0)) def getCanvas(self): return self.contentWindow.getCanvas() # dragging functions def startWindowDrag( self, param ): self.wrtReparentTo( aspect2dMouseNode ) self.ignoreAll() self.accept( 'mouse1-up', self.stopWindowDrag ) def stopWindowDrag( self, param=None ): # this is called 2 times (bug), so make sure it's not already parented to aspect2d if self.getParent() != self.windowParent: self.wrtReparentTo( self.windowParent ) if self.preserve: if self.preserveWhole: if self.getZ() > 1: self.setZ(1) elif self.getZ() < -1 - self.getHeight(): self.setZ(-1 - self.getHeight()) if self.getX() > base.a2dRight - self.getWidth(): self.setX(base.a2dRight - self.getWidth()) elif self.getX() < base.a2dLeft: self.setX(base.a2dLeft) else: if self.getZ() > 1: self.setZ(1) elif self.getZ() < -1 + self.headerHeight: self.setZ(-1 + self.headerHeight) if self.getX() > base.a2dRight - self.headerHeight: self.setX(base.a2dRight - self.headerHeight) elif self.getX() < base.a2dLeft + self.headerHeight - self.getWidth(): self.setX(base.a2dLeft + self.headerHeight - self.getWidth()) #else: #Window moved beyond reach. Destroy window? # resize functions def resize( self, mPos, offset ): mXPos = max( min( mPos.getX(), self.maxVirtualSize[0] ), self.minVirtualSize[0]) mZPos = max( min( mPos.getZ(), -self.minVirtualSize[1] ), -self.maxVirtualSize[1]-self.headerHeight) self.windowResize.setPos( mXPos-self.resizeSize/2., 0, mZPos+self.resizeSize/2. ) self.windowResizeBackground.setPos( mXPos-self.resizeSize/2., 0, mZPos+self.resizeSize/2. ) self['frameSize'] = (0, mXPos, 0, mZPos) self.windowHeaderLeft.setPos( self.headerHeight/2., 0, -self.headerHeight/2. ) self.windowHeaderLeft.setScale( self.headerHeight, 1, self.headerHeight ) self.windowHeaderCenter.setPos( mXPos/2., 0, -self.headerHeight/2. ) self.windowHeaderCenter.setScale( mXPos - self.headerHeight*2., 1, self.headerHeight ) self.windowHeaderRight.setPos( mXPos-self.headerHeight/2., 0, -self.headerHeight/2. ) self.windowHeaderRight.setScale( self.headerHeight, 1, self.headerHeight ) self.contentWindow['frameSize'] = ( 0, mXPos, mZPos+self.headerHeight, 0) self.textNodePath.setPos( mXPos/2., 0, -self.headerHeight/3.*2. ) # show and hide that small background for the window sizer if mXPos == self.maxVirtualSize[0] and \ mZPos == -self.maxVirtualSize[1]-self.headerHeight: self.windowResizeBackground.hide() else: self.windowResizeBackground.show() def resizeTask( self, task=None ): mPos = aspect2dMouseNode.getPos( self )+self.offset self.resize( mPos, self.offset ) return task.cont def startResizeDrag( self, param ): self.offset = self.windowResize.getPos( aspect2dMouseNode ) taskMgr.remove( self.taskName ) taskMgr.add( self.resizeTask, self.taskName ) def stopResizeDrag( self, param ): taskMgr.remove( self.taskName ) # get the window to the front self.wrtReparentTo( self.windowParent ) def addHorizontal(self, widgets): """ Accepts a list of directgui objects which are added to a horizontal box, which is then added to the vertical stack. """ hbox = boxes.HBox() for widget in widgets: hbox.pack(widget) self.box.pack(hbox) self.updateMaxSize() def addVertical(self, widgets): """ Accepts a list of directgui objects which are added to a vertical box, which is then added to the vertical stack. May cause funky layout results. """ #vbox = boxes.VBox() for widget in widgets: self.box.pack(widget) self.updateMaxSize() def add(self, widgets): """Shortcut function for addVertical""" self.addVertical(widgets) def updateMaxSize(self): """Updates the max canvas size to include all items packed. Window is resized to show all contents.""" bottomLeft, topRight = self.box.getTightBounds() self.maxVirtualSize = (topRight[0], -bottomLeft[2]) self.contentWindow['canvasSize'] = ( 0, self.maxVirtualSize[0], -self.maxVirtualSize[1], 0) self.backgroundColor['frameSize'] = ( 0, self.maxVirtualSize[0], -self.maxVirtualSize[1], 0 ) #perhaps this should be optional -- automatically resize for new elements self.reset() def reset(self): """Poorly named function that resizes window to fit all contents""" self.resize( Vec3(self.maxVirtualSize[0], 0, -self.maxVirtualSize[1]-self.headerHeight), Vec3(0,0,0))
def __init__( self , pos = ( -.5, .5) , title = 'Title' , bgColor = (.5,.5,.5,1) , buttonColor = (1,1,1,1) #( .6, .6, .6, 1 ) #, minSize = ( .5, .5 ) #, maxSize = ( 1, 1 ) , minWindowSize = (0,0) , maxWindowSize = (10000,10000) , virtualSize = (1,1) , windowBorderTextureFiles = [ DEFAULT_TITLE_TEXTURE_LEFT , DEFAULT_TITLE_TEXTURE_CENTER , DEFAULT_TITLE_TEXTURE_RIGHT , DEFAULT_RESIZE_GEOM ] , windowBorderGeomFiles = [ DEFAULT_TITLE_GEOM_RIGHT ] , windowColors = [ ( 1, 1, 1, 1 ) , ( 1, 1, 1, 1 ) , ( 1, 1, 1, 1 ) , ( 1, 1, 1, 1 ) ] , borderSize = 0.01 , dragbarSize = 0.05 , parent=None): self.windowPos = pos self.minWindowSize = minWindowSize self.maxWindowSize = maxWindowSize self.virtualSize = virtualSize self.borderSize = borderSize self.dragbarSize = dragbarSize if parent is None: parent=aspect2d self.parent=parent self.previousSize = (10,10) self.collapsed = False # maybe we should check if aspect2d doesnt already contain the aspect2dMouseNode self.mouseNode = self.parent.attachNewNode( 'aspect2dMouseNode', sort = 999999 ) taskMgr.add( self.mouseNodeTask, 'mouseNodeTask' ) windowBorderTextures = list() for windowBorder in windowBorderTextureFiles: if windowBorder is not None: mdlFile = loader.loadTexture(windowBorder) windowBorderTextures.append(mdlFile) else: windowBorderTextures.append(None) windowBorderGeoms = list() for windowGeom in windowBorderGeomFiles: if windowGeom is not None: mdlFile = loader.loadModel(windowGeom) mdls = ( mdlFile.find('**/**-default'), mdlFile.find('**/**-click'), mdlFile.find('**/**-rollover'), mdlFile.find('**/**-disabled') ) windowBorderGeoms.append(mdls) else: windowBorderGeoms.append((None,None,None,None,),) # the main window we want to move around self.parentWindow = DirectFrame( parent=self.parent, pos=(self.windowPos[0], 0, self.windowPos[1]), #frameSize=# is defined in resize scale=(1, 1, -1), frameColor=bgColor, borderWidth=(0, 0), relief=DGG.FLAT, sortOrder=1, ) # header of the window (drag&drop with it) # the title part of the window, drag around to move the window self.headerParent = DirectButton( parent=self.parentWindow, pos=(0, 0, 0), #frameSize=# is defined in resize scale=(1, 1, self.dragbarSize), frameColor=(1, 1, 1, 1), borderWidth=(0, 0), relief=DGG.FLAT, ) self.headerParent.bind(DGG.B1PRESS,self.startWindowDrag) # images in the headerParent self.headerCenter = DirectFrame( parent=self.headerParent, pos=(0, 0, 1), #frameSize=# is defined in resize scale=(1,1,-1), frameColor=windowColors[1], frameTexture=windowBorderTextures[1], borderWidth=(0, 0), relief=DGG.FLAT, ) self.headerLeft = DirectFrame( parent=self.headerParent, pos=(0, 0, 1), frameSize=(0, self.dragbarSize, 0, 1), scale=(1,1,-1), frameColor=windowColors[0], frameTexture=windowBorderTextures[0], borderWidth=(0, 0), relief=DGG.FLAT, ) # collapse button self.headerRight = DirectButton( parent=self.headerParent, #pos=# is defined in resize frameSize=(0, self.dragbarSize, 0, 1), scale=(1,1,-1), frameColor=windowColors[2], #frameTexture=windowBorderTextures[2], borderWidth=(0, 0), relief=DGG.FLAT, command=self.toggleCollapsed, geom=windowBorderGeoms[0], geom_scale=(self.dragbarSize,1,1) ) # the resize button of the window self.resizeButton = DirectButton( parent=self.parentWindow, pos=(1-self.dragbarSize, 0, 1), frameSize=(0, 1, 0, 1), scale=(self.dragbarSize,1,-self.dragbarSize), frameColor=windowColors[3], frameTexture=windowBorderTextures[3], borderWidth=(0, 0), relief=DGG.FLAT, sortOrder=1, ) self.resizeButton.bind(DGG.B1PRESS,self.startResizeDrag) # text in the center of the window text = TextNode('WindowTitleTextNode') text.setText(title) text.setAlign(TextNode.ACenter) text.setTextColor( 0, 0, 0, 1 ) text.setShadow(0.05, 0.05) text.setShadowColor( 1, 1, 1, 1 ) self.textNodePath = self.headerCenter.attachNewNode(text) self.textNodePath.setPos(.5,0,.3) self.textNodePath.setScale(0.8*self.dragbarSize,1,0.8) if Y_INVERTED: scale = (1,1,-1) else: scale = (1,1,1) # the content part of the window, put stuff beneath # contentWindow.getCanvas() to put it into it self.contentWindow = DirectScrolledFrame( parent = self.parentWindow, #pos = # is defined in resize scale = scale, canvasSize = (0,self.virtualSize[0],0,self.virtualSize[1]), frameColor = buttonColor, relief = DGG.RAISED, borderWidth = (0,0), verticalScroll_frameSize = [0,self.dragbarSize,0,1], verticalScroll_frameTexture = loader.loadTexture( 'rightBorder.png' ), verticalScroll_incButton_frameTexture = loader.loadTexture( 'scrollDown.png' ), verticalScroll_decButton_frameTexture = loader.loadTexture( 'scrollDown.png' ), verticalScroll_thumb_frameTexture = loader.loadTexture( 'scrollBar.png' ), horizontalScroll_frameSize = [0,1,0,self.dragbarSize], horizontalScroll_frameTexture = loader.loadTexture( 'bottomBorder.png' ), horizontalScroll_incButton_frameTexture = loader.loadTexture( 'scrollDown.png' ), horizontalScroll_decButton_frameTexture = loader.loadTexture( 'scrollDown.png' ), horizontalScroll_thumb_frameTexture = loader.loadTexture( 'scrollBar.png' ), ) # child we attach should be inside the window DirectFrame.__init__( self, parent = self.contentWindow.getCanvas(), pos = (0,0,self.virtualSize[1]), scale = (1,1,1), frameSize = ( 0, self.virtualSize[0]+2*self.borderSize, 0, self.virtualSize[1] ), #frameColor = (0,0,0,1), relief = DGG.RIDGE, borderWidth = (0,0), ) self.initialiseoptions(DirectWindow) # offset then clicking on the resize button from the mouse to the resizebutton # position, required to calculate the position / scaling self.offset = None self.resizeButtonTaskName = "resizeTask-%s" % str(hash(self)) # do sizing of the window to virtualSize #self.resize( self.virtualSize[0]+2*self.borderSize # , self.virtualSize[1]+self.dragbarSize+2*self.borderSize ) self.resize(10,10)
class Journal: """Captain's journal GUI object. Args: winned (bool): Flag, saying if the player already won the game. """ def __init__(self, winned=False): self._is_shown = False self._read_coordinates = False self._winned = winned self._opened_num = None self._main_fr = DirectFrame( parent=base.a2dTopLeft, # noqa: F821 frameSize=(-0.37, 0.38, -0.6, 0.6), state=DGG.NORMAL, pos=(0.37, 0, -1), frameTexture="gui/tex/paper1.png", ) self._main_fr.setTransparency(TransparencyAttrib.MAlpha) self._main_fr.hide() self._fr = DirectScrolledFrame( parent=self._main_fr, frameSize=(-0.35, 0.3, -0.46, 0.5), frameColor=(0, 0, 0, 0), canvasSize=(-0.31, 0.3, -3, 1.5), state=DGG.NORMAL, pos=(0, 0, -0.1), verticalScroll_frameSize=(-0.003, 0.003, -0.5, 0.5), verticalScroll_frameColor=(0.46, 0.41, 0.37, 1), verticalScroll_thumb_frameColor=(0.31, 0.26, 0.22, 1), verticalScroll_incButton_relief=None, verticalScroll_decButton_relief=None, horizontalScroll_relief=None, horizontalScroll_thumb_relief=None, horizontalScroll_incButton_relief=None, horizontalScroll_decButton_relief=None, ) DirectLabel( # Journal parent=self._main_fr, text=base.labels.JOURNAL[0], # noqa: F821 text_font=base.cursive_font, # noqa: F821 text_scale=0.053, text_bg=(0, 0, 0, 0), text_fg=(0, 0, 0.25, 1), frameSize=(0.1, 0.1, 0.1, 0.1), pos=(-0.34, 0, 0.52), text_align=TextNode.ALeft, ) DirectButton( parent=self._main_fr, text="<", text_scale=0.06, text_bg=(0, 0, 0, 0), text_fg=(0, 0, 0.25, 1), pos=(-0.15, 0, 0.45), frameSize=(-0.2, 0.2, -0.2, 0.2), relief=None, command=self._open_page, extraArgs=[-1], ) DirectButton( parent=self._main_fr, text=">", text_scale=0.06, text_bg=(0, 0, 0, 0), text_fg=(0, 0, 0.25, 1), pos=(0.15, 0, 0.45), frameSize=(-0.2, 0.2, -0.2, 0.2), relief=None, command=self._open_page, extraArgs=[1], ) self._page_title = DirectLabel( parent=self._main_fr, text="", text_scale=0.043, text_font=base.cursive_font, # noqa: F821 text_fg=(0, 0, 0.25, 1), frameSize=(-0.02, 0.02, -3.5, 0.5), frameColor=(0, 0, 0, 0), pos=(0, 0, 0.45), ) self._page_text = DirectLabel( parent=self._fr.getCanvas(), text="", text_scale=0.045, text_font=base.cursive_font, # noqa: F821 text_align=TextNode.ALeft, text_fg=(0, 0, 0.25, 1), frameSize=(-0.02, 0.02, -3.5, 0.5), frameColor=(0, 0, 0, 0), pos=(-0.27, 0, 1.45), ) self._pages = [] self._open_snd = loader.loadSfx("sounds/GUI/journal.ogg") # noqa: F821 self._page_snd = loader.loadSfx("sounds/GUI/journal_page.ogg") # noqa: F821 self._close_snd = loader.loadSfx("sounds/GUI/journal_close.ogg") # noqa: F821 @property def winned(self): """The flag indicating if the player already won. Returns: bool: True if the player already won, False otherwise. """ return self._winned def _open_page(self, shift): """Open the given page of the journal. Args: shift (int): Page number shift. """ if self._opened_num is None: return if ( self._opened_num + shift > len(self._pages) - 1 or self._opened_num + shift < 0 ): return self._opened_num += shift self._page_text["text"] = self._pages[self._opened_num]["page"] self._page_title["text"] = self._pages[self._opened_num]["title"] self._page_snd.play() if self._opened_num == 7: self._read_coordinates = True def add_page(self, num): """Add a page into the journal. Args: num (int): The page number. """ type_, title, page_text = base.labels.JOURNAL_PAGES[num] # noqa: F821 page_rec = {"page": page_text, "type": type_, "title": title} self._pages.append(page_rec) if self._opened_num is None: self._opened_num = 0 self._page_text["text"] = self._pages[self._opened_num]["page"] self._page_title["text"] = self._pages[self._opened_num]["title"] def show(self): """Show/hide the journal GUI.""" if self._is_shown: self._main_fr.hide() self._close_snd.play() if not self._winned and self._read_coordinates: self._winned = True page = DirectFrame( frameSize=(-0.73, 0.73, -0.9, 0.9), frameTexture="gui/tex/paper1.png", state=DGG.NORMAL, ) page.setDepthTest(False) page.setTransparency(TransparencyAttrib.MAlpha) page.show() DirectLabel( parent=page, text=base.labels.UNTERRIFF_DISCOVERED_TITLE, # noqa: F821 text_font=base.main_font, # noqa: F821 frameSize=(0.6, 0.6, 0.6, 0.6), text_scale=0.043, pos=(0, 0, 0.65), ) DirectLabel( parent=page, text=base.labels.UNTERRIFF_DISCOVERED, # noqa: F821 text_font=base.main_font, # noqa: F821 frameSize=(0.6, 0.6, 0.6, 0.6), text_scale=0.037, pos=(0, 0, 0.55), ) DirectButton( # Done parent=page, pos=(0, 0, -0.77), text=base.labels.DISTINGUISHED[6], # noqa: F821 text_font=base.main_font, # noqa: F821 text_fg=RUST_COL, text_shadow=(0, 0, 0, 1), frameColor=(0, 0, 0, 0), command=page.destroy, extraArgs=[], scale=(0.05, 0, 0.05), clickSound=base.main_menu.click_snd, # noqa: F821 ) self._read_coordinates = False else: self._main_fr.show() self._open_snd.play() self._is_shown = not self._is_shown
class DeviceConnectivityMonitor(DirectObject): def __init__(self): super().__init__() self.mgr = InputDeviceManager.get_global_ptr() self.create_device_menu() self.devices = {} for device in self.mgr.get_devices(): self.connect_device(device) self.accept("connect-device", self.connect_device) self.accept("disconnect-device", self.disconnect_device) def create_device_menu(self): self.current_panel = None self.buttons = {} self.devices_frame = DirectScrolledFrame( frameSize=VBase4( 0, base.a2dLeft*-0.75, base.a2dBottom - base.a2dTop, 0, ), frameColor=VBase4(0, 0, 0.25, 1.0), canvasSize=VBase4( 0, base.a2dLeft*-0.75, 0, 0, ), scrollBarWidth=0.08, manageScrollBars=True, autoHideScrollBars=True, pos=(base.a2dLeft, 0, base.a2dTop), parent=base.aspect2d, ) self.devices_frame.setCanvasSize() def create_menu_button(self, device): button = DirectButton( command=self.switch_to_panel, extraArgs=[device], text=device.name, text_scale=0.05, text_align=TextNode.ALeft, text_fg=VBase4(0.0, 0.0, 0.0, 1.0), text_pos=Vec2(0.01, base.a2dBottom / 10.0), relief=1, pad=Vec2(0.01, 0.01), frameColor=VBase4(0.8, 0.8, 0.8, 1.0), frameSize=VBase4( 0.0, base.a2dLeft*-0.75 - 0.081, # 0.08=Scrollbar, 0.001=inaccuracy base.a2dBottom / 5.0, 0.0, ), parent=self.devices_frame.getCanvas(), ) self.buttons[device] = button def destroy_menu_button(self, device): self.buttons[device].detach_node() del self.buttons[device] def refresh_device_menu(self): self.devices_frame['canvasSize'] = VBase4( 0, base.a2dLeft*-0.75, base.a2dBottom / 5.0 * len(self.buttons), 0, ) self.devices_frame.setCanvasSize() sorted_buttons = sorted(self.buttons.items(), key=lambda i: i[0].name) for idx, (dev, button) in enumerate(sorted_buttons): button.set_pos( 0, 0, (base.a2dBottom / 5.0) * idx, ) def switch_to_panel(self, device): if self.current_panel is not None: self.devices[self.current_panel].hide() self.current_panel = device self.devices[self.current_panel].show() def connect_device(self, device): self.devices[device] = DeviceMonitor(device) self.switch_to_panel(device) self.create_menu_button(device) self.refresh_device_menu() def disconnect_device(self, device): self.devices[device].deactivate() del self.devices[device] if self.current_panel == device: self.current_panel = None if len(self.devices) > 0: active_device = sorted( self.devices.keys(), key=lambda d: d.name, )[0] self.switch_to_panel(active_device) self.destroy_menu_button(device) self.refresh_device_menu()
class CraftInventory(DirectObject): def __init__(self): self.itemFrame = DirectScrolledFrame( text="Inventory", text_scale=0.25, text_pos=(0, 0.75, 0), text_bg=(1, 1, 1, 1), # make the frame occupy the whole window frameSize=(-0.6, 0.6, -0.8, 0.8), pos=(-0.7, 0, 0), # make the canvas as big as the frame canvasSize=(-0.6, 0.6, -0.8, 0.8), # set the frames color to white frameColor=(1, 1, 1, 1), ) self.itemList = [] self.craftFrame = DirectFrame( text="Crafting", text_scale=0.25, text_pos=(0, 0.75, 0), text_bg=(1, 1, 1, 1), # make the frame occupy the whole window frameSize=(-0.6, 0.6, -0.8, 0.8), pos=(0.7, 0, 0), # set the frames color to white frameColor=(1, 1, 1, 1), ) self.craftDrop = DirectFrame( text="drop ore", text_scale=0.1, pos=(0, 0.4, 0), frameSize=(-0.25, 0.25, -0.25, 0.25), frameColor=(1, 0, 0, 1), ) self.craftDrop.reparentTo(self.craftFrame) def show(self): self.itemFrame.show() self.craftFrame.show() def hide(self): self.itemFrame.hide() self.craftFrame.hide() def __makeItem(self, item): obj = DirectLabel( text=str(item.giveLoot()) + "x " + item.giveType(), text_scale=0.5, text_pos=(0, -1, 0), image=("item.png", "item_hover.png", "item.png"), # normal, hover, disabled scale=0.16, numStates=2, state=DGG.NORMAL, relief=DGG.GROOVE, ) obj.setTransparency(True) obj["activeState"] = 0 obj.reparentTo(self.itemFrame.getCanvas()) obj.bind(DGG.B1PRESS, self.dragStart, [obj]) obj.bind(DGG.B1RELEASE, self.dragStop) obj.bind(DGG.ENTER, self.inObject, [obj]) obj.bind(DGG.EXIT, self.outObject, [obj]) return obj def updateList(self, items): for item in self.itemList: item.destroy() i = 1 j = 0 pad = 0.2 numItemsPerRow = 2 itemWidth = 0.32 itemHeight = 0.32 # left = -(itemWidth * (numItemsPerRow/2.0)) - 0.16 left = self.itemFrame.getX() # + (itemWidth + 0.16) xStep = itemWidth + 0.13 yStep = -(itemHeight + 0.13) top = 0.8 - (0.16 + pad) for item in items: self.itemList.append(self.__makeItem(item)) x = left + i * xStep y = top + j * yStep self.itemList[-1].setPos(x, 0.0, y) if i == numItemsPerRow: i = 0 j += 1 i += 1 if i == 1: j -= 1 height = ((j) * -yStep) - 0.16 # resize the canvas. This will make the scrollbars dis-/appear, # dependent on if the canvas is bigger than the frame size. self.itemFrame["canvasSize"] = (-0.6, 0.6, -height, 0.8) def inObject(self, element, event): # Can be used to highlight objects element["activeState"] = 1 element.setActiveState() # print "over object" def outObject(self, element, event): # Can be used to unhighlight objects # element["state"] = 0 element["activeState"] = 0 element.setActiveState() def dragStart(self, element, event): print "start drag" taskMgr.remove("dragDropTask") vWidget2render2d = element.getPos(render2d) vMouse2render2d = Point3(event.getMouse()[0], 0, event.getMouse()[1]) editVec = Vec3(vWidget2render2d - vMouse2render2d) t = taskMgr.add(self.dragTask, "dragDropTask") element.reparentTo(aspect2d) t.element = element t.editVec = editVec t.elementStartPos = element.getPos() def dragTask(self, state): mwn = base.mouseWatcherNode if mwn.hasMouse(): vMouse2render2d = Point3(mwn.getMouse()[0], 0, mwn.getMouse()[1]) newPos = vMouse2render2d + state.editVec state.element.setPos(render2d, newPos) return Task.cont def dragStop(self, event): print "stop drag with:", event isInArea = False t = taskMgr.getTasksNamed("dragDropTask")[0] # for dropArea in self.dropAreas: # if self.isInBounds(event.getMouse(), dropArea["frameSize"], dropArea.getPos(render)): # print "inside Area:", dropArea["text"], dropArea.getPos(render) # isInArea = True # t.element.setPos(dropArea.getPos(render)) # t.element.setX(t.element.getX() * self.ratio) # #t.element.setX(t.element.getX() - t.element.getWidth() / 2.0) # break if not isInArea: t.element.setPos(t.elementStartPos) t.element.reparentTo(self.itemFrame.getCanvas()) taskMgr.remove("dragDropTask") def isInBounds(self, location, bounds, posShift=None): x = 0 if posShift is None else posShift.getX() y = 0 if posShift is None else posShift.getZ() left = x + bounds[0] right = x + bounds[1] bottom = y + bounds[2] top = y + bounds[3] # are we outside of the bounding box from the left if location[0] < left: return False # are we outside of the bounding box from the right if location[0] > right: return False # are we outside of the bounding box from the bottom if location[1] < bottom: return False # are we outside of the bounding box from the top if location[1] > top: return False # the location is inside the bbox return True
class ScrolledButtonsList(DirectObject): """ A class to display a list of selectable buttons. It is displayed using scrollable window (DirectScrolledFrame). """ def __init__(self, parent=None, frameSize=(.8,1.2), buttonTextColor=(1,1,1,1), font=None, itemScale=.045, itemTextScale=0.85, itemTextZ=0, command=None, contextMenu=None, autoFocus=0, colorChange=1, colorChangeDuration=1, newItemColor=globals.colors['guiblue1'], rolloverColor=globals.colors['guiyellow'], suppressMouseWheel=1, modifier='control'): self.mode = None self.focusButton=None self.command=command self.contextMenu=contextMenu self.autoFocus=autoFocus self.colorChange=colorChange self.colorChangeDuration=colorChangeDuration*.5 self.newItemColor=newItemColor self.rolloverColor=rolloverColor self.rightClickTextColors=(Vec4(0,1,0,1),Vec4(0,35,100,1)) self.font=font if font: self.fontHeight=font.getLineHeight() else: self.fontHeight=TextNode.getDefaultFont().getLineHeight() self.fontHeight*=1.2 # let's enlarge font height a little self.xtraSideSpace=.2*self.fontHeight self.itemTextScale=itemTextScale self.itemTextZ=itemTextZ self.buttonTextColor=buttonTextColor self.suppressMouseWheel=suppressMouseWheel self.modifier=modifier self.buttonsList=[] self.numItems=0 self.__eventReceivers={} # DirectScrolledFrame to hold items self.itemScale=itemScale self.itemVertSpacing=self.fontHeight*self.itemScale self.frameWidth,self.frameHeight=frameSize # I set canvas' Z size smaller than the frame to avoid the auto-generated vertical slider bar self.childrenFrame = DirectScrolledFrame( parent=parent,pos=(-self.frameWidth*.5,0,.5*self.frameHeight), relief=DGG.GROOVE, state=DGG.NORMAL, # to create a mouse watcher region frameSize=(0, self.frameWidth, -self.frameHeight, 0), frameColor=(0,0,0,.7), canvasSize=(0, 0, -self.frameHeight*.5, 0), borderWidth=(0.01,0.01), manageScrollBars=0, enableEdit=0, suppressMouse=0, sortOrder=1000 ) # the real canvas is "self.childrenFrame.getCanvas()", # but if the frame is hidden since the beginning, # no matter how I set the canvas Z pos, the transform would be resistant, # so just create a new node under the canvas to be my canvas self.canvas=self.childrenFrame.getCanvas().attachNewNode('myCanvas') # slider background SliderBG=DirectFrame( parent=self.childrenFrame,frameSize=(-.025,.025,-self.frameHeight,0), frameColor=(0,0,0,.7), pos=(-.03,0,0),enableEdit=0, suppressMouse=0) # slider thumb track sliderTrack = DirectFrame( parent=SliderBG, relief=DGG.FLAT, #state=DGG.NORMAL, frameColor=(1,1,1,.2), frameSize=(-.015,.015,-self.frameHeight+.01,-.01), enableEdit=0, suppressMouse=0) # page up self.pageUpRegion=DirectFrame( parent=SliderBG, relief=DGG.FLAT, state=DGG.NORMAL, frameColor=(1,.8,.2,.1), frameSize=(-.015,.015,0,0), enableEdit=0, suppressMouse=0) self.pageUpRegion.setAlphaScale(0) self.pageUpRegion.bind(DGG.B1PRESS,self.__startScrollPage,[-1]) self.pageUpRegion.bind(DGG.WITHIN,self.__continueScrollUp) self.pageUpRegion.bind(DGG.WITHOUT,self.__suspendScrollUp) # page down self.pageDnRegion=DirectFrame( parent=SliderBG, relief=DGG.FLAT, state=DGG.NORMAL, frameColor=(1,.8,.2,.1), frameSize=(-.015,.015,0,0), enableEdit=0, suppressMouse=0) self.pageDnRegion.setAlphaScale(0) self.pageDnRegion.bind(DGG.B1PRESS,self.__startScrollPage,[1]) self.pageDnRegion.bind(DGG.WITHIN,self.__continueScrollDn) self.pageDnRegion.bind(DGG.WITHOUT,self.__suspendScrollDn) self.pageUpDnSuspended=[0,0] # slider thumb self.vertSliderThumb=DirectButton(parent=SliderBG, relief=DGG.FLAT, frameColor=(1,1,1,.6), frameSize=(-.015,.015,0,0), enableEdit=0, suppressMouse=0, rolloverSound=None, clickSound=None) self.vertSliderThumb.bind(DGG.B1PRESS,self.__startdragSliderThumb) self.vertSliderThumb.bind(DGG.WITHIN,self.__enteringThumb) self.vertSliderThumb.bind(DGG.WITHOUT,self.__exitingThumb) self.oldPrefix=base.buttonThrowers[0].node().getPrefix() self.sliderThumbDragPrefix='draggingSliderThumb-' # GOD & I DAMN IT !!! # These things below don't work well if the canvas has a lot of buttons. # So I end up checking the mouse region every frame by myself using a continuous task. # self.accept(DGG.WITHIN+self.childrenFrame.guiId,self.__enteringFrame) # self.accept(DGG.WITHOUT+self.childrenFrame.guiId,self.__exitingFrame) self.isMouseInRegion=False self.mouseOutInRegionCommand=(self.__exitingFrame,self.__enteringFrame) taskMgr.doMethodLater(.2,self.__getFrameRegion,'getFrameRegion') def __getFrameRegion(self,t): for g in range(base.mouseWatcherNode.getNumGroups()): region=base.mouseWatcherNode.getGroup(g).findRegion(self.childrenFrame.guiId) if region!=None: self.frameRegion=region taskMgr.add(self.__mouseInRegionCheck,'mouseInRegionCheck') break def __mouseInRegionCheck(self,t): """ check if the mouse is within or without the scrollable frame, and upon within or without, run the provided command """ if not base.mouseWatcherNode.hasMouse(): return Task.cont m=base.mouseWatcherNode.getMouse() bounds=self.frameRegion.getFrame() inRegion=bounds[0]<m[0]<bounds[1] and bounds[2]<m[1]<bounds[3] if self.isMouseInRegion==inRegion: return Task.cont self.isMouseInRegion=inRegion self.mouseOutInRegionCommand[inRegion]() return Task.cont def __startdragSliderThumb(self,m=None): if self.mode != None: if hasattr(self.mode, 'enableMouseCamControl') == 1: if self.mode.enableMouseCamControl == 1: self.mode.game.app.disableMouseCamControl() mpos=base.mouseWatcherNode.getMouse() parentZ=self.vertSliderThumb.getParent().getZ(render2d) sliderDragTask=taskMgr.add(self.__dragSliderThumb,'dragSliderThumb') sliderDragTask.ZposNoffset=mpos[1]-self.vertSliderThumb.getZ(render2d)+parentZ # sliderDragTask.mouseX=base.winList[0].getPointer(0).getX() self.oldPrefix=base.buttonThrowers[0].node().getPrefix() base.buttonThrowers[0].node().setPrefix(self.sliderThumbDragPrefix) self.acceptOnce(self.sliderThumbDragPrefix+'mouse1-up',self.__stopdragSliderThumb) def __dragSliderThumb(self,t): if not base.mouseWatcherNode.hasMouse(): return mpos=base.mouseWatcherNode.getMouse() # newY=base.winList[0].getPointer(0).getY() self.__updateCanvasZpos((t.ZposNoffset-mpos[1])/self.canvasRatio) # base.winList[0].movePointer(0, t.mouseX, newY) return Task.cont def __stopdragSliderThumb(self,m=None): if self.mode != None: if hasattr(self.mode, 'enableMouseCamControl') == 1: if self.mode.enableMouseCamControl == 1: self.mode.game.app.enableMouseCamControl() taskMgr.remove('dragSliderThumb') self.__stopScrollPage() base.buttonThrowers[0].node().setPrefix(self.oldPrefix) if self.isMouseInRegion: self.mouseOutInRegionCommand[self.isMouseInRegion]() def __startScrollPage(self,dir,m): self.oldPrefix=base.buttonThrowers[0].node().getPrefix() base.buttonThrowers[0].node().setPrefix(self.sliderThumbDragPrefix) self.acceptOnce(self.sliderThumbDragPrefix+'mouse1-up',self.__stopdragSliderThumb) t=taskMgr.add(self.__scrollPage,'scrollPage',extraArgs=[int((dir+1)*.5),dir*.01/self.canvasRatio]) self.pageUpDnSuspended=[0,0] def __scrollPage(self,dir,scroll): if not self.pageUpDnSuspended[dir]: self.__scrollCanvas(scroll) return Task.cont def __stopScrollPage(self,m=None): taskMgr.remove('scrollPage') def __suspendScrollUp(self,m=None): self.pageUpRegion.setAlphaScale(0) self.pageUpDnSuspended[0]=1 def __continueScrollUp(self,m=None): if taskMgr.hasTaskNamed('dragSliderThumb'): return self.pageUpRegion.setAlphaScale(1) self.pageUpDnSuspended[0]=0 def __suspendScrollDn(self,m=None): self.pageDnRegion.setAlphaScale(0) self.pageUpDnSuspended[1]=1 def __continueScrollDn(self,m=None): if taskMgr.hasTaskNamed('dragSliderThumb'): return self.pageDnRegion.setAlphaScale(1) self.pageUpDnSuspended[1]=0 def __suspendScrollPage(self,m=None): self.__suspendScrollUp() self.__suspendScrollDn() def __enteringThumb(self,m=None): self.vertSliderThumb['frameColor']=(1,1,1,1) self.__suspendScrollPage() def __exitingThumb(self,m=None): self.vertSliderThumb['frameColor']=(1,1,1,.6) def __scrollCanvas(self,scroll): if self.vertSliderThumb.isHidden() or self.buttonsList == []: return self.__updateCanvasZpos(self.canvas.getZ()+scroll) def __updateCanvasZpos(self,Zpos): newZ=clampScalar(Zpos, .0, self.canvasLen-self.frameHeight+.015) self.canvas.setZ(newZ) thumbZ=-newZ*self.canvasRatio self.vertSliderThumb.setZ(thumbZ) self.pageUpRegion['frameSize']=(-.015,.015,thumbZ-.01,-.01) self.pageDnRegion['frameSize']=(-.015,.015,-self.frameHeight+.01,thumbZ+self.vertSliderThumb['frameSize'][2]) def __adjustCanvasLength(self,numItem): self.canvasLen=float(numItem)*self.itemVertSpacing self.canvasRatio=(self.frameHeight-.015)/(self.canvasLen+.01) if self.canvasLen<=self.frameHeight-.015: canvasZ=.0 self.vertSliderThumb.hide() self.pageUpRegion.hide() self.pageDnRegion.hide() self.canvasLen=self.frameHeight-.015 else: canvasZ=self.canvas.getZ() self.vertSliderThumb.show() self.pageUpRegion.show() self.pageDnRegion.show() self.__updateCanvasZpos(canvasZ) self.vertSliderThumb['frameSize']=(-.015,.015,-self.frameHeight*self.canvasRatio,-.01) thumbZ=self.vertSliderThumb.getZ() self.pageUpRegion['frameSize']=(-.015,.015,thumbZ-.01,-.01) self.pageDnRegion['frameSize']=(-.015,.015,-self.frameHeight+.01,thumbZ+self.vertSliderThumb['frameSize'][2]) def __acceptAndIgnoreWorldEvent(self,event,command,extraArgs=[]): receivers=messenger.whoAccepts(event) if receivers is None: self.__eventReceivers[event]={} else: self.__eventReceivers[event]=receivers.copy() for r in self.__eventReceivers[event].keys(): if type(r) != types.TupleType: r.ignore(event) self.accept(event,command,extraArgs) def __ignoreAndReAcceptWorldEvent(self,events): for event in events: self.ignore(event) if self.__eventReceivers.has_key(event): for r, method_xtraArgs_persist in self.__eventReceivers[event].items(): if type(r) != types.TupleType: messenger.accept(event,r,*method_xtraArgs_persist) self.__eventReceivers[event]={} def __enteringFrame(self,m=None): # sometimes the WITHOUT event for page down region doesn't fired, # so directly suspend the page scrolling here self.__suspendScrollPage() BTprefix=base.buttonThrowers[0].node().getPrefix() if BTprefix==self.sliderThumbDragPrefix: return self.inOutBTprefix=BTprefix if self.suppressMouseWheel: self.__acceptAndIgnoreWorldEvent(self.inOutBTprefix+'wheel_up', command=self.__scrollCanvas, extraArgs=[-.07]) self.__acceptAndIgnoreWorldEvent(self.inOutBTprefix+'wheel_down', command=self.__scrollCanvas, extraArgs=[.07]) else: self.accept(self.inOutBTprefix+self.modifier+'-wheel_up',self.__scrollCanvas, [-.07]) self.accept(self.inOutBTprefix+self.modifier+'-wheel_down',self.__scrollCanvas, [.07]) def __exitingFrame(self,m=None): if not hasattr(self,'inOutBTprefix'): return if self.suppressMouseWheel: self.__ignoreAndReAcceptWorldEvent( ( self.inOutBTprefix+'wheel_up', self.inOutBTprefix+'wheel_down', ) ) else: self.ignore(self.inOutBTprefix+self.modifier+'-wheel_up') self.ignore(self.inOutBTprefix+self.modifier+'-wheel_down') def __setFocusButton(self,button,item): if self.focusButton: self.restoreNodeButton2Normal() self.focusButton=button self.highlightNodeButton() if callable(self.command) and button in self.buttonsList: # run user command and pass the selected item, it's index, and the button self.command(item,self.buttonsList.index(button),button) def __rightPressed(self,button,m): self.__isRightIn=True # text0 : normal # text1 : pressed # text2 : rollover # text3 : disabled button._DirectGuiBase__componentInfo['text2'][0].setColorScale(self.rightClickTextColors[self.focusButton==button]) button.bind(DGG.B3RELEASE,self.__rightReleased,[button]) button.bind(DGG.WITHIN,self.__rightIn,[button]) button.bind(DGG.WITHOUT,self.__rightOut,[button]) def __rightIn(self,button,m): self.__isRightIn=True button._DirectGuiBase__componentInfo['text2'][0].setColorScale(self.rightClickTextColors[self.focusButton==button]) def __rightOut(self,button,m): self.__isRightIn=False button._DirectGuiBase__componentInfo['text2'][0].setColorScale(Vec4(1,1,1,1)) def __rightReleased(self,button,m): button.unbind(DGG.B3RELEASE) button.unbind(DGG.WITHIN) button.unbind(DGG.WITHOUT) button._DirectGuiBase__componentInfo['text2'][0].setColorScale(self.rolloverColor) if not self.__isRightIn: return if callable(self.contextMenu): # run user command and pass the selected item, it's index, and the button self.contextMenu(button['extraArgs'][1],self.buttonsList.index(button),button) def scrollToBottom(self): ##for i in range(0,self.numItems): self.__scrollCanvas(1) def selectButton(self, button, item): self.__setFocusButton(button, item) def restoreNodeButton2Normal(self): """ stop highlighting item """ if self.focusButton != None: #self.focusButton['text_fg']=(1,1,1,1) self.focusButton['frameColor']=(0,0,0,0) def highlightNodeButton(self,idx=None): """ highlight the item """ if idx is not None: self.focusButton=self.buttonsList[idx] #self.focusButton['text_fg']=(.01,.01,.01,1) # nice dark blue. don't mess with the text fg color though! we want it custom self.focusButton['frameColor']=(0,.3,.8,1) def clear(self): """ clear the list """ for c in self.buttonsList: c.remove() self.buttonsList=[] self.focusButton=None self.numItems=0 def addItem(self,text,extraArgs=None,atIndex=None,textColorName=None): """ add item to the list text : text for the button extraArgs : the object which will be passed to user command(s) (both command and contextMenu) when the button get clicked atIndex : where to add the item <None> : put item at the end of list <integer> : put item at index <integer> <button> : put item at <button>'s index textColorName : the color name eg. 'yellow' """ textColor = self.buttonTextColor if textColorName != None: textColor = globals.colors[textColorName] button = DirectButton(parent=self.canvas, scale=self.itemScale, relief=DGG.FLAT, frameColor=(0,0,0,0),text_scale=self.itemTextScale, text=text, text_pos=(0,self.itemTextZ),text_fg=textColor, text_font=self.font, text_align=TextNode.ALeft, command=self.__setFocusButton, enableEdit=0, suppressMouse=0, rolloverSound=None,clickSound=None) #button.setMyMode(self.mode) l,r,b,t=button.getBounds() # top & bottom are blindly set without knowing where exactly the baseline is, # but this ratio fits most fonts baseline=-self.fontHeight*.25 #button['saved_color'] = textColor button['frameSize']=(l-self.xtraSideSpace,r+self.xtraSideSpace,baseline,baseline+self.fontHeight) # Zc=NodePath(button).getBounds().getCenter()[1]-self.fontHeight*.5+.25 # # Zc=button.getCenter()[1]-self.fontHeight*.5+.25 # button['frameSize']=(l-self.xtraSideSpace,r+self.xtraSideSpace,Zc,Zc+self.fontHeight) button['extraArgs']=[button,extraArgs] button._DirectGuiBase__componentInfo['text2'][0].setColorScale(self.rolloverColor) button.bind(DGG.B3PRESS,self.__rightPressed,[button]) if isinstance(atIndex,DirectButton): if atIndex.isEmpty(): atIndex=None else: index=self.buttonsList.index(atIndex) self.buttonsList.insert(index,button) if atIndex==None: self.buttonsList.append(button) index=self.numItems elif type(atIndex)==IntType: index=atIndex self.buttonsList.insert(index,button) Zpos=(-.7-index)*self.itemVertSpacing button.setPos(.02,0,Zpos) if index!=self.numItems: for i in range(index+1,self.numItems+1): self.buttonsList[i].setZ(self.buttonsList[i],-self.fontHeight) self.numItems+=1 self.__adjustCanvasLength(self.numItems) if self.autoFocus: self.focusViewOnItem(index) if self.colorChange: Sequence( button.colorScaleInterval(self.colorChangeDuration,self.newItemColor,globals.colors['guiblue3']), button.colorScaleInterval(self.colorChangeDuration,Vec4(1,1,1,1),self.newItemColor) ).start() def focusViewOnItem(self,idx): """ Scroll the window so the newly added item will be displayed in the middle of the window, if possible. """ Zpos=(idx+.7)*self.itemVertSpacing-self.frameHeight*.5 self.__updateCanvasZpos(Zpos) def setAutoFocus(self,b): """ set auto-view-focus state of newly added item """ self.autoFocus=b def index(self,button): """ get the index of button """ if not button in self.buttonsList: return None return self.buttonsList.index(button) def getNumItems(self): """ get the current number of items on the list """ return self.numItems def disableItem(self,i): if not 0<=i<self.numItems: print 'DISABLING : invalid index (%s)' %i return self.buttonsList[i]['state']=DGG.DISABLED self.buttonsList[i].setColorScale(.3,.3,.3,1) def enableItem(self,i): if not 0<=i<self.numItems: print 'ENABLING : invalid index (%s)' %i return self.buttonsList[i]['state']=DGG.NORMAL self.buttonsList[i].setColorScale(1,1,1,1) def removeItem(self,index): if not 0<=index<self.numItems: print 'REMOVAL : invalid index (%s)' %index return if self.numItems==0: return if self.focusButton==self.buttonsList[index]: self.focusButton=None self.buttonsList[index].removeNode() del self.buttonsList[index] self.numItems-=1 for i in range(index,self.numItems): self.buttonsList[i].setZ(self.buttonsList[i],self.fontHeight) self.__adjustCanvasLength(self.numItems) def destroy(self): self.clear() self.__exitingFrame() self.ignoreAll() self.childrenFrame.removeNode() taskMgr.remove('mouseInRegionCheck') def hide(self): self.childrenFrame.hide() self.isMouseInRegion=False self.__exitingFrame() taskMgr.remove('mouseInRegionCheck') def show(self): self.childrenFrame.show() if not hasattr(self,'frameRegion'): taskMgr.doMethodLater(.2,self.__getFrameRegion,'getFrameRegion') elif not taskMgr.hasTaskNamed('mouseInRegionCheck'): taskMgr.add(self.__mouseInRegionCheck,'mouseInRegionCheck') def toggleVisibility(self): if self.childrenFrame.isHidden(): self.show() else: self.hide() def setMyMode(self, myMode): self.mode = myMode
class DirectWindow(DirectFrame): def __init__( self, pos=(-.5, .5), title='Title', curSize=(1, 1), maxSize=(1, 1), minSize=(.5, .5), backgroundColor=(1, 1, 1, 1), borderColor=(1, 1, 1, 1), titleColor=(1, 1, 1, 1), borderSize=0.04, titleSize=0.06, closeButton=False, windowParent=aspect2d, preserve=True, preserveWhole=True, ): self.preserve = preserve self.preserveWhole = preserveWhole self.windowParent = windowParent self.windowPos = pos DirectFrame.__init__( self, parent=windowParent, pos=(self.windowPos[0], 0, self.windowPos[1]), frameColor=(0, 0, 0, 0), frameTexture=loader.loadTexture(DIRECTORY + 'transparent.png')) self.setTransparency(True) # the title part of the window, drag around to move the window self.headerHeight = titleSize h = -self.headerHeight self.windowHeaderLeft = DirectButton( parent=self, frameTexture=DEFAULT_TITLE_GEOM_LEFT, frameSize=(-.5, .5, -.5, .5), borderWidth=(0, 0), relief=DGG.FLAT, frameColor=titleColor, ) self.windowHeaderCenter = DirectButton( parent=self, frameTexture=DEFAULT_TITLE_GEOM_CENTER, frameSize=(-.5, .5, -.5, .5), borderWidth=(0, 0), relief=DGG.FLAT, frameColor=titleColor, ) if closeButton: rightTitleGeom = DEFAULT_TITLE_GEOM_RIGHT_CLOSE command = self.destroy else: rightTitleGeom = DEFAULT_TITLE_GEOM_RIGHT command = None self.windowHeaderRight = DirectButton(parent=self, frameTexture=rightTitleGeom, frameSize=(-.5, .5, -.5, .5), borderWidth=(0, 0), relief=DGG.FLAT, frameColor=titleColor, command=command) self.windowHeaderLeft.setTransparency(True) self.windowHeaderCenter.setTransparency(True) self.windowHeaderRight.setTransparency(True) self.windowHeaderLeft.bind(DGG.B1PRESS, self.startWindowDrag) self.windowHeaderCenter.bind(DGG.B1PRESS, self.startWindowDrag) self.windowHeaderRight.bind(DGG.B1PRESS, self.startWindowDrag) # this is not handled correctly, if a window is dragged which has been # created before another it will not be released # check the bugfixed startWindowDrag function #self.windowHeader.bind(DGG.B1RELEASE,self.stopWindowDrag) text = TextNode('WindowTitleTextNode') text.setText(title) text.setAlign(TextNode.ACenter) text.setTextColor(0, 0, 0, 1) text.setShadow(0.05, 0.05) text.setShadowColor(1, 1, 1, 1) self.textNodePath = self.attachNewNode(text) self.textNodePath.setScale(self.headerHeight * 0.8) # the content part of the window, put stuff beneath # contentWindow.getCanvas() to put it into it self.maxVirtualSize = maxSize self.minVirtualSize = minSize self.resizeSize = borderSize self.contentWindow = DirectScrolledFrame( parent=self, pos=(0, 0, -self.headerHeight), canvasSize=(0, self.maxVirtualSize[0], 0, self.maxVirtualSize[1]), frameColor=( 0, 0, 0, 0), # defines the background color of the resize-button relief=DGG.FLAT, borderWidth=(0, 0), verticalScroll_frameSize=[0, self.resizeSize, 0, 1], horizontalScroll_frameSize=[0, 1, 0, self.resizeSize], # resize the scrollbar according to window size verticalScroll_resizeThumb=False, horizontalScroll_resizeThumb=False, # define the textures for the scrollbars verticalScroll_frameTexture=VERTICALSCROLL_FRAMETEXTURE, verticalScroll_incButton_frameTexture= VERTICALSCROLL_INCBUTTON_FRAMETEXTURE, verticalScroll_decButton_frameTexture= VERTICALSCROLL_DECBUTTON_FRAMETEXTURE, verticalScroll_thumb_frameTexture=VERTICALSCROLL_TUMB_FRAMETEXTURE, horizontalScroll_frameTexture=HORIZONTALSCROLL_FRAMETEXTURE, horizontalScroll_incButton_frameTexture= HORIZONTALSCROLL_INCBUTTON_FRAMETEXTURE, horizontalScroll_decButton_frameTexture= HORIZONTALSCROLL_DECBUTTON_FRAMETEXTURE, horizontalScroll_thumb_frameTexture= HORIZONTALSCROLL_TUMB_FRAMETEXTURE, # make all flat, so the texture is as we want it verticalScroll_relief=DGG.FLAT, verticalScroll_thumb_relief=DGG.FLAT, verticalScroll_decButton_relief=DGG.FLAT, verticalScroll_incButton_relief=DGG.FLAT, horizontalScroll_relief=DGG.FLAT, horizontalScroll_thumb_relief=DGG.FLAT, horizontalScroll_decButton_relief=DGG.FLAT, horizontalScroll_incButton_relief=DGG.FLAT, # colors verticalScroll_frameColor=borderColor, verticalScroll_incButton_frameColor=borderColor, verticalScroll_decButton_frameColor=borderColor, verticalScroll_thumb_frameColor=borderColor, horizontalScroll_frameColor=borderColor, horizontalScroll_incButton_frameColor=borderColor, horizontalScroll_decButton_frameColor=borderColor, horizontalScroll_thumb_frameColor=borderColor, ) self.contentWindow.setTransparency(True) # background color self.backgroundColor = DirectFrame( parent=self.contentWindow.getCanvas(), frameSize=(0, self.maxVirtualSize[0], 0, self.maxVirtualSize[1]), frameColor=backgroundColor, relief=DGG.FLAT, borderWidth=(.01, .01), ) self.backgroundColor.setTransparency(True) # Add a box self.box = boxes.VBox(parent=self.getCanvas()) # is needed for some nicer visuals of the resize button (background) self.windowResizeBackground = DirectButton( parent=self, frameSize=(-.5, .5, -.5, .5), borderWidth=(0, 0), scale=(self.resizeSize, 1, self.resizeSize), relief=DGG.FLAT, frameColor=backgroundColor, ) # the resize button of the window self.windowResize = DirectButton( parent=self, frameSize=(-.5, .5, -.5, .5), borderWidth=(0, 0), scale=(self.resizeSize, 1, self.resizeSize), relief=DGG.FLAT, frameTexture=DEFAULT_RESIZE_GEOM, frameColor=borderColor, ) self.windowResize.setTransparency(True) self.windowResize.bind(DGG.B1PRESS, self.startResizeDrag) self.windowResize.bind(DGG.B1RELEASE, self.stopResizeDrag) # offset then clicking on the resize button from the mouse to the resizebutton # position, required to calculate the position / scaling self.offset = None self.taskName = "resizeTask-%s" % str(hash(self)) # do sizing of the window (minimum) #self.resize( Vec3(0,0,0), Vec3(0,0,0) ) # maximum #self.resize( Vec3(100,0,-100), Vec3(0,0,0) ) self.resize(Vec3(curSize[0], 0, -curSize[1]), Vec3(0, 0, 0)) def getCanvas(self): return self.contentWindow.getCanvas() # dragging functions def startWindowDrag(self, param): self.wrtReparentTo(aspect2dMouseNode) self.ignoreAll() self.accept('mouse1-up', self.stopWindowDrag) def stopWindowDrag(self, param=None): # this is called 2 times (bug), so make sure it's not already parented to aspect2d if self.getParent() != self.windowParent: self.wrtReparentTo(self.windowParent) if self.preserve: if self.preserveWhole: if self.getZ() > 1: self.setZ(1) elif self.getZ() < -1 - self.getHeight(): self.setZ(-1 - self.getHeight()) if self.getX() > base.a2dRight - self.getWidth(): self.setX(base.a2dRight - self.getWidth()) elif self.getX() < base.a2dLeft: self.setX(base.a2dLeft) else: if self.getZ() > 1: self.setZ(1) elif self.getZ() < -1 + self.headerHeight: self.setZ(-1 + self.headerHeight) if self.getX() > base.a2dRight - self.headerHeight: self.setX(base.a2dRight - self.headerHeight) elif self.getX( ) < base.a2dLeft + self.headerHeight - self.getWidth(): self.setX(base.a2dLeft + self.headerHeight - self.getWidth()) #else: #Window moved beyond reach. Destroy window? # resize functions def resize(self, mPos, offset): mXPos = max(min(mPos.getX(), self.maxVirtualSize[0]), self.minVirtualSize[0]) mZPos = max(min(mPos.getZ(), -self.minVirtualSize[1]), -self.maxVirtualSize[1] - self.headerHeight) self.windowResize.setPos(mXPos - self.resizeSize / 2., 0, mZPos + self.resizeSize / 2.) self.windowResizeBackground.setPos(mXPos - self.resizeSize / 2., 0, mZPos + self.resizeSize / 2.) self['frameSize'] = (0, mXPos, 0, mZPos) self.windowHeaderLeft.setPos(self.headerHeight / 2., 0, -self.headerHeight / 2.) self.windowHeaderLeft.setScale(self.headerHeight, 1, self.headerHeight) self.windowHeaderCenter.setPos(mXPos / 2., 0, -self.headerHeight / 2.) self.windowHeaderCenter.setScale(mXPos - self.headerHeight * 2., 1, self.headerHeight) self.windowHeaderRight.setPos(mXPos - self.headerHeight / 2., 0, -self.headerHeight / 2.) self.windowHeaderRight.setScale(self.headerHeight, 1, self.headerHeight) self.contentWindow['frameSize'] = (0, mXPos, mZPos + self.headerHeight, 0) self.textNodePath.setPos(mXPos / 2., 0, -self.headerHeight / 3. * 2.) # show and hide that small background for the window sizer if mXPos == self.maxVirtualSize[0] and \ mZPos == -self.maxVirtualSize[1]-self.headerHeight: self.windowResizeBackground.hide() else: self.windowResizeBackground.show() def resizeTask(self, task=None): mPos = aspect2dMouseNode.getPos(self) + self.offset self.resize(mPos, self.offset) return task.cont def startResizeDrag(self, param): self.offset = self.windowResize.getPos(aspect2dMouseNode) taskMgr.remove(self.taskName) taskMgr.add(self.resizeTask, self.taskName) def stopResizeDrag(self, param): taskMgr.remove(self.taskName) # get the window to the front self.wrtReparentTo(self.windowParent) def addHorizontal(self, widgets): """ Accepts a list of directgui objects which are added to a horizontal box, which is then added to the vertical stack. """ hbox = boxes.HBox() for widget in widgets: hbox.pack(widget) self.box.pack(hbox) self.updateMaxSize() def addVertical(self, widgets): """ Accepts a list of directgui objects which are added to a vertical box, which is then added to the vertical stack. May cause funky layout results. """ #vbox = boxes.VBox() for widget in widgets: self.box.pack(widget) self.updateMaxSize() def add(self, widgets): """Shortcut function for addVertical""" self.addVertical(widgets) def updateMaxSize(self): """Updates the max canvas size to include all items packed. Window is resized to show all contents.""" bottomLeft, topRight = self.box.getTightBounds() self.maxVirtualSize = (topRight[0], -bottomLeft[2]) self.contentWindow['canvasSize'] = (0, self.maxVirtualSize[0], -self.maxVirtualSize[1], 0) self.backgroundColor['frameSize'] = (0, self.maxVirtualSize[0], -self.maxVirtualSize[1], 0) #perhaps this should be optional -- automatically resize for new elements self.reset() def reset(self): """Poorly named function that resizes window to fit all contents""" self.resize( Vec3(self.maxVirtualSize[0], 0, -self.maxVirtualSize[1] - self.headerHeight), Vec3(0, 0, 0))
def create_leaderboard(self,level): # Direct frame to hold all contents of the leaderboard self.leaderboard_frame = DirectFrame(parent=self.main_frame,frameColor = (.8,.8,.8,.9),frameSize=(-2,2,-1,1), pos=(0,0,0)) # Create a scroll_frame to hold contents of leaderboard file scroll_frame = DirectScrolledFrame(parent = self.leaderboard_frame, canvasSize=(-1,1,-4,4), frameColor = (1,1,1,.9), frameSize=(-1,1,-.5,.5), pos=(0,0,0), manageScrollBars=True, scrollBarWidth = .04, autoHideScrollBars = True) # Frame title title = OnscreenText(parent=self.leaderboard_frame, text = 'LEADERBOARD', pos = (0, .6), scale = 0.15, fg=(0,.2,.2,1),shadow=(.5,.5,.5,1)) # Open .leaderboard.txt file as read only leaderboard_file = open('files/.leaderboard.txt','r') start_read = False # Boolean that will used to notify loop when to start generating text on the scroll canvas start = leaderboard_file.read(1) # Reads only the first byte of the file, equivalent to a character # Guide for leaderboard name = OnscreenText(parent=scroll_frame.getCanvas(), text = 'NAME', pos = (-.1, 3.9), scale = 0.075,fg=(0,.2,.2,1)) score = OnscreenText(parent=scroll_frame.getCanvas(), text = 'SCORE', pos = (.5, 3.9), scale = 0.075,fg=(0,.2,.2,1)) index = 1 v_pos = 3.8 # Loop will iterate through the contents of the file while len(start) != 0: if start == '#': leaderboard_file.readline() # Comments in text file start with an octothorpe and are ignored elif start == '@'and start_read is False: # Line with @ signify the beginning of a set of level info if leaderboard_file.readline().split()[0] == level: # This checks if the info that follows is the information we need start_read = True elif start == '@'and start_read is True: # If this condition is true then we read through all the information we need break elif start_read is True: coord = leaderboard_file.readline().split(',') if len(coord) == 1: name = 'Unknown' score = coord[0] else: name = start + coord[0] score = coord[1] entry_text = str(index) + ".\t " + name + '\t\t' + score # Create onscreen text for each entry entry = OnscreenText(parent=scroll_frame.getCanvas(), text = entry_text, pos = (0,v_pos), scale = 0.07,fg=(0,0,0,1)) # Increase index and decrease vertical position index += 1 v_pos -= .1 # Read the first byte of the next line start = leaderboard_file.read(1) leaderboard_file.close() # Create button to go back to the leaderboard selection frame self.create_menu_button(self.leaderboard_frame,'Back',LVecBase3f(0,0,-.7),self.show_lb_selection) # Hide frame self.leaderboard_frame.hide()
class TabbedFrame(DirectFrame): def __init__(self, parent=None, **kwargs): optiondefs = ( ('frameSize', (-0.5, 0.5, -0.5, 0.5), None), ('tabClickOffsetColor', Vec4(0.1, 0.1, 0.1, 0), None), ('tabRolloverOffsetColor', Vec4(0.1, 0.1, 0.1, 0), None), ('tabInactiveColor', Vec4(0.2, 0.2, 0.2, 1), None), ('tabUnselectedColor', Vec4(0.7, 0.7, 0.7, 1), None), ('tabSelectedColor', Vec4(0.4, 0.7, 1.0, 1), None), ('tab_scale', 0.05, None), ('tab_frameSize', (0, 5, 0, 2), None), ('tab_geom_scale', 1, None), ('tabHighlightFrameTexture', None, None), ('tabFrameTexture', None, None), ('tabHighlightGeom', None, None), ('tabGeom', None, None), ) # Button colours: Selected, unselected, rollover-offset, clicked-offset, inactive if "scrollFrameConstructor" in kwargs: self.scrollFrameConstructor = kwargs["scrollFrameConstructor"] del kwargs["scrollFrameConstructor"] else: self.scrollFrameConstructor = None #type(DirectScrolledFrame) if "pageChangeCallback" in kwargs: self.pageChangeCallback = kwargs["pageChangeCallback"] del kwargs["pageChangeCallback"] else: self.pageChangeCallback = None #type(DirectScrolledFrame) viewingArgs = {} for key, arg in list(kwargs.items()): if key.startswith("scroll_"): key = key[7:] viewingArgs[key] = arg for key in viewingArgs: del kwargs["scroll_" + key] if not "canvasSize" in viewingArgs: viewingArgs["canvasSize"] = (0, 0, 0, 0) self.defineoptions(kwargs, optiondefs) DirectFrame.__init__(self, parent) if self.scrollFrameConstructor is not None: self.viewingArea = self.scrollFrameConstructor(parent=self, **viewingArgs) else: self.viewingArea = DirectScrolledFrame(parent=self, **viewingArgs) self.pages = [] self.pageButtons = [] self.currentPageIndex = -1 self.tabArgs = {} for key, arg in self._constructorKeywords.items(): if key.startswith("tab_") and \ not key.endswith("highlightGeom") and \ not key.endswith("unselectedColor") and \ not key.endswith("selectedColor") and \ not key.endswith("highlightFrameTexture") and \ not key.endswith("highlightGeom"): self.tabArgs[key[4:]] = arg[0] self.addPage(DirectFrame(), "<stand-in>") self.initialiseoptions(TabbedFrame) def __setitem__(self, key, value): DirectFrame.__setitem__(self, key, value) if key.startswith("tab_"): self.tabArgs[key[4:]] = value def addPage(self, page, pageName, selectedCallback=None, deselectedCallback=None, callbackArg=None): if len(self.pages) > 0 and self.pageButtons[0]["text"] == "<stand-in>": self.pageButtons[0].destroy() self.pageButtons = [] self.pages[0][0].destroy() self.pages = [] btn = self.makeButton(pageName, len(self.pages)) self.pageButtons.append(btn) self.dehighlightButton(-1) self.pages.append( (page, selectedCallback, deselectedCallback, callbackArg)) page.hide() page.detachNode() self.layoutButtons() if len(self.pages) == 1: self.currentPageIndex = -1 self.setPage(0) def makeButton(self, pageName, pageIndex): btn = self.createcomponent("tab%d" % len(self.pageButtons), (), "tab", DirectButton, (self, ), command=self.setPage, text=pageName, extraArgs=[pageIndex], **self.tabArgs) return btn def highlightButton(self, index): if index >= -len(self.pageButtons) and index < len(self.pageButtons): btn = self.pageButtons[index] if self["tabHighlightGeom"] is not None: btn["geom"] = self["tabHighlightGeom"] if self["tabHighlightFrameTexture"] is not None: btn["frameTexture"] = self["tabHighlightFrameTexture"] btn["frameColor"] = (self["tabSelectedColor"], self["tabSelectedColor"], self["tabSelectedColor"], self["tabInactiveColor"]) def dehighlightButton(self, index): if index >= -len(self.pageButtons) and index < len(self.pageButtons): btn = self.pageButtons[index] if self["tabGeom"] is not None: btn["geom"] = self["tabGeom"] if self["tabFrameTexture"] is not None: btn["frameTexture"] = self["tabFrameTexture"] btn["frameColor"] = (self["tabUnselectedColor"], self["tabUnselectedColor"] + self["tabClickOffsetColor"], self["tabUnselectedColor"] + self["tabRolloverOffsetColor"], self["tabInactiveColor"]) def setPage(self, index): if index == self.currentPageIndex: return if self.currentPageIndex >= 0: page, selectedCallback, deselectedCallback, callbackArg = self.pages[ self.currentPageIndex] page.hide() page.detachNode() self.dehighlightButton(self.currentPageIndex) if deselectedCallback is not None: deselectedCallback(callbackArg) if index >= 0 and index < len(self.pages): newPage, selectedCallback, deselectedCallback, callbackArg = self.pages[ index] newPage.show() newPage.reparentTo(self.viewingArea.getCanvas()) if selectedCallback is not None: selectedCallback(callbackArg) self.layoutPage(newPage) self.highlightButton(index) self.currentPageIndex = index if self.pageChangeCallback is not None: self.pageChangeCallback(self) def nextPage(self): if self.currentPageIndex < len(self.pages) - 1: self.setPage(self.currentPageIndex + 1) def previousPage(self): if self.currentPageIndex > 0: self.setPage(self.currentPageIndex - 1) def layoutPage(self, page): pageBounds = page["frameSize"] if pageBounds is None: pageBounds = tuple(self.viewingArea["frameSize"]) mainBounds = self.viewingArea["frameSize"] tall = False if pageBounds[2] < mainBounds[2]: tall = True b = pageBounds[2] - 0.15 else: b = mainBounds[2] if pageBounds[3] > mainBounds[3]: tall = True t = pageBounds[3] else: t = mainBounds[3] if pageBounds[0] < mainBounds[0]: l = pageBounds[0] else: l = mainBounds[0] if tall or pageBounds[1] > mainBounds[1]: r = pageBounds[1] else: r = mainBounds[1] self.viewingArea["canvasSize"] = (l, r, b, t) def layoutButtons(self): width = self["tab_frameSize"][1] - self["tab_frameSize"][0] buttonScale = self["tab_scale"] if isinstance(buttonScale, tuple) or isinstance(buttonScale, list) or \ isinstance(buttonScale, VBase3) or hasattr(buttonScale, "__getitem__"): buttonScale = buttonScale[0] for pageIndex, button in enumerate(self.pageButtons): bounds = self["frameSize"] pos = (bounds[0] + pageIndex * width * buttonScale, 0, bounds[3]) button.setPos(*pos) def setFrameSize(self, fClearFrame=0): self.layoutButtons() DirectFrame.setFrameSize(self, fClearFrame) self.viewingArea["frameSize"] = self["frameSize"] self.layoutPage(self.pages[self.currentPageIndex][0]) def clearPages(self): for btn in self.pageButtons: btn.destroy() for page, callback1, callback2, arg in self.pages: page.destroy() self.currentdeselectedCallback = None self.pageButtons = [] self.pages = [] self.currentPageIndex = -1 def destroy(self): self.clearPages() DirectFrame.destroy(self)
class TextScrolledFrame(object): def __init__(self, parent=None, scale=0.05, limitText=1, frameSize=(0, 1.3, 0.2, 0.697), pos=(0, 0, 0.1)): self.__scale = scale self.__frameSize = frameSize self.__canvasSize = (frameSize[0], frameSize[2] - 0.01, frameSize[2], frameSize[3]) self.__limitText = limitText self.__countLine = [] self.dsf = DirectScrolledFrame( parent=parent, canvasSize=self.__canvasSize, frameSize=self.__frameSize, pos=pos, frameColor=COR_OPACITY_03_PRETO, autoHideScrollBars=1, scrollBarWidth=0.05, borderWidth=(0, 0), verticalScroll_value=1, verticalScroll_decButton_frameColor=(1, 1, 1, 0.3), verticalScroll_decButton_rolloverSound=None, verticalScroll_decButton_clickSound=None, verticalScroll_incButton_frameColor=(1, 1, 1, 0.3), verticalScroll_incButton_rolloverSound=None, verticalScroll_incButton_clickSound=None, verticalScroll_thumb_frameColor=(1, 1, 1, 0.3), verticalScroll_thumb_rolloverSound=None, verticalScroll_thumb_clickSound=None, ) self.__textoHeight = scale self.__canvasHeight = self.dsf.getHeight() self.__canvas = self.dsf.getCanvas() def __command_clear_msg(self): self.etyMsg.set("") def __reposicionaTexto(self, obj_text): height = obj_text.getScale() * obj_text.textNode.getNumRows() for text in self.__countLine: lastPos = text.textNodePath.getPos() text.setPos((lastPos[0], 0, lastPos[2] + height)) def __resizeCanvasSize(self, text): self.__textoHeight += text.getScale() * text.textNode.getNumRows() if self.__textoHeight > self.__canvasHeight: self.__canvasHeight += self.__textoHeight - self.__canvasHeight self.dsf["canvasSize"] = ( self.dsf["canvasSize"][0], self.dsf["canvasSize"][1], self.dsf["canvasSize"][2], self.dsf["canvasSize"][2] + self.__canvasHeight, ) self.dsf.setCanvasSize() def show(self, texto, cor=(1, 1, 1, 1)): dfs_pos = self.dsf.getPos() pos = (dfs_pos[0] + 0.01, 0, dfs_pos[1] + 0.16) text = Text(parent=self.__canvas, scale=self.__scale, text=texto, wordwrap=25, pos=pos, cor=cor) numText = len(self.__countLine) if numText > 0: self.__reposicionaTexto(text) self.__countLine.append(text) if numText > self.__limitText: self.__countLine[0].remove() self.__countLine.pop(0) else: self.__resizeCanvasSize(text) self.dsf["verticalScroll_value"] = 1
class ScrolledItemSelector(DirectObject): '''Touch optimised list that holds a set of items. By clicking on one you select it and return its Value with get_selected(). To add an item simply use add_item(). You can also pass a function with the 'command' field that gets called on a selection switch''' def __init__(self, frame_size=(1, 1.5), frame_color=(0.2, 0.2, 0.2, 0.8), pos=(0, 0, 0), item_v_padding=0.02, item_h_padding=0.04, item_scale=1, item_side_ratio=0.2, item_background=(0.3, 0.3, 0.3, 1), item_background_active=(0.6, 0.6, 0.6, 1), command=lambda: None): self.f_x, self.f_y = frame_size self.c_x = self.f_x self.c_y = self.f_y self.item_v_padding = item_v_padding self.item_h_padding = item_h_padding self.item_scale = item_scale self.item_background = item_background self.item_background_active = item_background_active self.frame = DirectScrolledFrame( frameSize=(-self.f_x / 2, self.f_x / 2, -self.f_y / 2, self.f_y / 2), canvasSize=(-self.c_x / 2, self.c_x / 2, -self.c_y / 2, self.c_y / 2), frameColor=frame_color, pos=pos, scrollBarWidth=(0), manageScrollBars=False, state=DGG.NORMAL) self.frame.verticalScroll.destroy() self.frame.horizontalScroll.destroy() self.frame.bind(DGG.WITHIN, self._start_listening) self.frame.bind(DGG.WITHOUT, self._stop_listening) self.canvas = self.frame.getCanvas() self.i_x = self.f_x * (1 - item_h_padding) self.i_y = self.f_y * item_side_ratio self.i_size = (-self.i_x / 2, self.i_x / 2, -self.i_y / 2, self.i_y / 2) self.i_start = self.c_y / 2 + self.i_y / 2 self.active_item = None self.item_list = [] self.value_list = [] self.start_mY = None self.old_mY = None self.m_diff = 0 self.is_scrolling = False self.command = command # messenger.toggleVerbose() def _start_listening(self, watcher): print('start listening') self.accept("mouse1", self._start_scroll) self.accept("mouse1-up", self._stop_scroll) def _stop_listening(self, watcher): print('stop listening') self.ignore("mouse1") self.ignore("mouse1-up") self._stop_scroll() def _switch_active_item(self, item, watcher): if not self.is_scrolling: print('switched') if self.active_item is not None: self.active_item['frameColor'] = self.item_background item['frameColor'] = self.item_background_active self.active_item = item self.command() def _start_scroll(self): n = len(self.item_list) content_length = ( (n * (self.i_y + self.item_v_padding)) + # Size of all elements with padding self.item_v_padding) # Add one padding for the bottom if content_length > self.c_y: taskMgr.doMethodLater(0.01, self._scroll_task, 'scroll_task') self.start_mY = base.mouseWatcherNode.getMouse().getY() self.old_mY = self.start_mY def _stop_scroll(self): taskMgr.remove('scroll_task') taskMgr.doMethodLater(0.01, self._scroll_fade_task, 'scrollfadetask') self.is_scrolling = False def _scroll_task(self, task): mY = base.mouseWatcherNode.getMouse().getY() old_c = self.canvas.getZ() self.m_diff = self.old_mY - mY n = len(self.item_list) if self.m_diff != 0: self.is_scrolling = True self.c_scroll_start = 0 self.c_scroll_stop = ( (n * (self.i_y + self.item_v_padding)) + # Size of all elements with padding self.item_v_padding - # Add one padding for the bottom self.f_y) # Substract the length of the canvas self.c_new_pos = (old_c - self.m_diff) hits_not_upper_bound = self.c_new_pos >= self.c_scroll_start hits_not_lower_bound = self.c_new_pos <= self.c_scroll_stop # print('canvas : ' + str(self.canvas.getZ())) if hits_not_upper_bound and hits_not_lower_bound: self.canvas.setZ(self.c_new_pos) elif not hits_not_upper_bound: self.canvas.setZ(self.c_scroll_start) elif not hits_not_lower_bound: self.canvas.setZ(self.c_scroll_stop) self.old_mY = mY return task.again def _scroll_fade_task(self, task): if self.m_diff is None or abs(self.m_diff) < 0.005: self.m_diff = 0 return task.done old_c = self.canvas.getZ() n = len(self.item_list) self.c_scroll_start = 0 self.c_scroll_stop = ( (n * (self.i_y + self.item_v_padding)) + # Size of all elements with padding self.item_v_padding - # Add one padding for the bottom self.c_y) # Substract the length of the canvas hits_not_upper_bound = (old_c - self.m_diff) >= self.c_scroll_start hits_not_lower_bound = (old_c - self.m_diff) <= self.c_scroll_stop if hits_not_upper_bound and hits_not_lower_bound: self.canvas.setZ(old_c - self.m_diff) self.m_diff *= 0.85 return task.again elif not hits_not_upper_bound: self.canvas.setZ(self.c_scroll_start) self.m_diff = 0 return task.done elif not hits_not_lower_bound: self.canvas.setZ(self.c_scroll_stop) self.m_diff = 0 return task.done def add_item(self, image=None, image_scale=0.15, image_pos=(0, 0, 0), title=None, title_pos=(0, 0, 0), text=None, text_pos=(0, 0, 0), value=None): '''Appends an item to the end of the list. It can hold an image, title and text. Image: Panda3d path eg. 'models/picture.jpg'. Value: The item has function 'get/set_value()' to work with individual values of an activated element. Value gets set to the item on adding it.''' item_nr = len(self.item_list) + 1 item_pos = self.i_start - (self.i_y + self.item_v_padding) * item_nr item = DirectFrame( parent=self.canvas, text=str(item_nr), # Abused as an ID tag text_fg=(0, 0, 0, 0), frameSize=self.i_size, frameColor=self.item_background, borderWidth=(0.01, 0.01), pos=(0, 0, item_pos), relief=DGG.FLAT, state=DGG.NORMAL, enableEdit=0, suppressMouse=0) item.bind(DGG.B1RELEASE, self._switch_active_item, [item]) if image is not None: OnscreenImage( # Add an Image image=image, pos=image_pos, scale=(1 * image_scale, 1, 1 * image_scale), parent=(item)) DirectLabel( parent=item, # Add a Title text=title, text_scale=self.i_y / 4, text_fg=(1, 1, 1, 1), text_align=TextNode.ALeft, frameColor=(0, 0, 0, 0), pos=title_pos) DirectLabel( parent=item, # Add a Text text=text, text_scale=self.i_y / 5, text_fg=(1, 1, 1, 1), text_align=TextNode.ALeft, frameColor=(0, 0, 0, 0), pos=text_pos) self.item_list.append(item) self.value_list.append(value) def get_active_item(self): return self.active_item def set_active_item(self, pos): self._switch_active_item(self.item_list[pos], None) def get_active_id(self): return int(self.active_item['text']) def get_active_value(self): return self.value_list[int(self.active_item['text']) - 1] def hide(self): '''Triggers the DirectFrame.hide() of the main frame''' self.frame.hide() def show(self): '''Triggers the DirectFrame.show() of the main frame''' self.frame.show() def clear(self): '''Destroys every item that was added to the list''' for item in self.item_list: item.destroy() self.item_list = [] self.active_item = None self.value_list = [] self.canvas.setZ(0) def destroy(self): '''Destroys the whole list and every item in it''' self.canvas.destroy() self.frame.destroy()
class TextScrolledFrame(object): def __init__(self, parent=None, scale=.05, limitText=1, frameSize=(0, 1.3, .2, .697), pos=(0, 0, .1)): self.__scale = scale self.__frameSize = frameSize self.__canvasSize = (frameSize[0], frameSize[2] - .01, frameSize[2], frameSize[3]) self.__limitText = limitText self.__countLine = [] self.dsf = DirectScrolledFrame( parent=parent, canvasSize=self.__canvasSize, frameSize=self.__frameSize, pos=pos, frameColor=COR_OPACITY_03_PRETO, autoHideScrollBars=1, scrollBarWidth=0.05, borderWidth=(0, 0), verticalScroll_value=1, verticalScroll_decButton_frameColor=(1, 1, 1, 0.3), verticalScroll_decButton_rolloverSound=None, verticalScroll_decButton_clickSound=None, verticalScroll_incButton_frameColor=(1, 1, 1, 0.3), verticalScroll_incButton_rolloverSound=None, verticalScroll_incButton_clickSound=None, verticalScroll_thumb_frameColor=(1, 1, 1, 0.3), verticalScroll_thumb_rolloverSound=None, verticalScroll_thumb_clickSound=None) self.__textoHeight = scale self.__canvasHeight = self.dsf.getHeight() self.__canvas = self.dsf.getCanvas() def __command_clear_msg(self): self.etyMsg.set("") def __reposicionaTexto(self, obj_text): height = obj_text.getScale() * obj_text.textNode.getNumRows() for text in self.__countLine: lastPos = text.textNodePath.getPos() text.setPos((lastPos[0], 0, lastPos[2] + height)) def __resizeCanvasSize(self, text): self.__textoHeight += text.getScale() * text.textNode.getNumRows() if self.__textoHeight > self.__canvasHeight: self.__canvasHeight += self.__textoHeight - self.__canvasHeight self.dsf['canvasSize'] = (self.dsf['canvasSize'][0], self.dsf['canvasSize'][1], self.dsf['canvasSize'][2], self.dsf['canvasSize'][2] + self.__canvasHeight) self.dsf.setCanvasSize() def show(self, texto, cor=(1, 1, 1, 1)): dfs_pos = self.dsf.getPos() pos = (dfs_pos[0] + .01, 0, dfs_pos[1] + 0.16) text = Text(parent=self.__canvas, scale=self.__scale, text=texto, wordwrap=25, pos=pos, cor=cor) numText = len(self.__countLine) if numText > 0: self.__reposicionaTexto(text) self.__countLine.append(text) if numText > self.__limitText: self.__countLine[0].remove() self.__countLine.pop(0) else: self.__resizeCanvasSize(text) self.dsf['verticalScroll_value'] = 1
class DeviceMonitor(DirectObject): def __init__(self, device): super().__init__() self.device = device self.create_panel() self.activate() self.hide() def activate(self): print("Device connected") print(" Name : {}".format(self.device.name)) print(" Type : {}".format(self.device.device_class.name)) print(" Manufacturer: {}".format(self.device.manufacturer)) print(" ID : {:04x}:{:04x}".format(self.device.vendor_id, self.device.product_id)) axis_names = [axis.axis.name for axis in self.device.axes] print(" Axes : {} ({})".format(len(self.device.axes), ', '.join(axis_names))) button_names = [button.handle.name for button in self.device.buttons] print(" Buttons : {} ({})".format(len(self.device.buttons), ', '.join(button_names))) base.attachInputDevice(self.device) self.task = base.taskMgr.add( self.update, "Monitor for {}".format(self.device.name), sort=10, ) def deactivate(self): print("\"{}\" disconnected".format(self.device.name)) base.taskMgr.remove(self.task) self.panel.detach_node() def create_panel(self): panel_width = base.a2dLeft * -0.25 + base.a2dRight scroll_bar_width = 0.08 # NOTE: -0.001 because thanks to inaccuracy the vertical bar appears... canvas_width = panel_width - scroll_bar_width - 0.001 canvas_height = base.a2dBottom - base.a2dTop self.panel = DirectScrolledFrame( frameSize=VBase4( 0, panel_width, canvas_height, 0, ), frameColor=VBase4(0.8, 0.8, 0.8, 1), canvasSize=VBase4( 0, canvas_width, canvas_height, 0, ), scrollBarWidth=scroll_bar_width, manageScrollBars=True, autoHideScrollBars=True, pos=(base.a2dLeft * 0.25, 0, base.a2dTop), parent=base.aspect2d, ) panel_canvas = self.panel.getCanvas() offset = -0.0 # Style sheets half_width_entry = dict( frameSize=VBase4( 0, canvas_width / 2, -0.1, 0, ), parent=panel_canvas, frameColor=VBase4(0.8, 0.8, 0.8, 1), ) left_aligned_small_text = dict( text_align=TextNode.ALeft, text_scale=0.05, text_fg=VBase4(0,0,0,1), text_pos=(0.05, -0.06), ) half_width_text_frame = dict( **half_width_entry, **left_aligned_small_text, ) header = dict( frameSize=VBase4( 0, canvas_width, -0.1, 0, ), parent=panel_canvas, frameColor=VBase4(0.6, 0.6, 0.6, 1), text_align=TextNode.ALeft, text_scale=0.1, text_fg=VBase4(0,0,0,1), text_pos=(0.05, -0.075), ) # Basic device data (name, device class, manufacturer, USB ID) self.device_header = DirectLabel( text="Device data", pos=(0, 0, offset), **header, ) offset -= 0.1 def add_data_entry(offset, label, text): self.name = DirectLabel( text=label, pos=(0, 0, offset), **half_width_text_frame, ) self.name = DirectLabel( text=text, pos=(canvas_width / 2, 0, offset), **half_width_text_frame, ) metadata = [ ('Name', self.device.name), ('Device class', self.device.device_class.name), ('Manufacturer', self.device.manufacturer), ('USB ID', "{:04x}:{:04x}".format( self.device.vendor_id, self.device.product_id, ), ), ] for label, text in metadata: add_data_entry(offset, label, text) offset -= 0.1 # Axes self.axis_sliders = [] if len(self.device.axes) > 0: offset -= 0.1 self.axes_header = DirectLabel( text="Axes", pos=(0, 0, offset), **header, ) offset -= 0.1 def add_axis(offset, axis_name): slider_width = canvas_width / 2 label = DirectLabel( text=axis_name, **left_aligned_small_text, pos=(0.05, 0, offset), parent=panel_canvas, ) slider = DirectSlider( value=0.0, range=(-1.0, 1.0), state=DGG.DISABLED, frameSize=VBase4( 0, slider_width, -0.1, 0, ), thumb_frameSize=VBase4( 0.0, 0.04, -0.04, 0.04), frameColor=VBase4(0.3, 0.3, 0.3, 1), pos=(canvas_width - slider_width, 0, offset), parent=panel_canvas, ) return slider for axis in self.device.axes: axis_slider = add_axis(offset, axis.axis.name) self.axis_sliders.append(axis_slider) offset -= 0.1 # Buttons self.button_buttons = [] if len(self.device.buttons) > 0: offset -= 0.1 self.buttons_header = DirectLabel( text="Buttons", pos=(0, 0, offset), **header, ) offset -= 0.1 def add_button(offset, button_name): button_width = canvas_width / 2 label = DirectLabel( text=button_name, **left_aligned_small_text, pos=(0.05, 0, offset), parent=panel_canvas, ) button = DirectFrame( frameSize=VBase4( 0, button_width, -0.1, 0, ), text="", text_align=TextNode.ACenter, text_scale=0.05, text_fg=VBase4(0,0,0,1), text_pos=(button_width / 2, -0.06), frameColor=VBase4(0.3, 0.3, 0.3, 1), pos=(canvas_width - button_width, 0, offset), parent=panel_canvas, ) return button for i in range(len(self.device.buttons)): button_name = self.device.buttons[i].handle.name button_button = add_button(offset, button_name) self.button_buttons.append(button_button) offset -= 0.1 # Vibration self.vibration = [] if self.device.has_feature(InputDevice.Feature.vibration): offset -= 0.1 self.vibration_header = DirectLabel( text="Vibration", pos=(0, 0, offset), **header, ) offset -= 0.1 def add_vibration(offset, axis_name, index): slider_width = canvas_width / 2 label = DirectLabel( text=axis_name, **left_aligned_small_text, pos=(0.05, 0, offset), parent=panel_canvas, ) slider = DirectSlider( value=0.0, range=(0.0, 1.0), command=self.update_vibration, frameSize=VBase4( 0, slider_width, -0.1, 0, ), thumb_frameSize=VBase4( 0.0, 0.04, -0.04, 0.04), frameColor=VBase4(0.3, 0.3, 0.3, 1), pos=(canvas_width - slider_width, 0, offset), parent=panel_canvas, ) return slider for index, name in enumerate(["low frequency", "high frequency"]): self.vibration.append(add_vibration(offset, name, index)) offset -= 0.1 # Resize the panel's canvas to the widgets actually in it. if -offset > -canvas_height: self.panel['canvasSize'] = VBase4( 0, canvas_width, offset, 0, ) self.panel.setCanvasSize() def show(self): # FIXME: Activate update task here, and deactivate it in hide()? self.panel.show() def hide(self): self.panel.hide() def update_vibration(self): low = self.vibration[0]['value'] high = self.vibration[1]['value'] self.device.set_vibration(low, high) def update(self, task): # FIXME: There needs to be a demo of events here, too. for idx, slider in enumerate(self.axis_sliders): slider["value"] = self.device.axes[idx].value for idx, button in enumerate(self.button_buttons): if self.device.buttons[idx].known: if self.device.buttons[idx].pressed: button['frameColor'] = VBase4(0.0, 0.8, 0.0, 1) button['text'] = "down" else: button['frameColor'] = VBase4(0.3, 0.3, 0.3, 1) button['text'] = "up" else: # State is InputDevice.S_unknown. This happens if the device # manager hasn't polled yet, and in some cases before a button # has been pressed after the program's start. button['frameColor'] = VBase4(0.8, 0.8, 0.0, 1) button['text'] = "unknown" return task.cont
def create_panel(self): panel_width = base.a2dLeft * -0.25 + base.a2dRight scroll_bar_width = 0.08 # NOTE: -0.001 because thanks to inaccuracy the vertical bar appears... canvas_width = panel_width - scroll_bar_width - 0.001 canvas_height = base.a2dBottom - base.a2dTop self.panel = DirectScrolledFrame( frameSize=VBase4( 0, panel_width, canvas_height, 0, ), frameColor=VBase4(0.8, 0.8, 0.8, 1), canvasSize=VBase4( 0, canvas_width, canvas_height, 0, ), scrollBarWidth=scroll_bar_width, manageScrollBars=True, autoHideScrollBars=True, pos=(base.a2dLeft * 0.25, 0, base.a2dTop), parent=base.aspect2d, ) panel_canvas = self.panel.getCanvas() offset = -0.0 # Style sheets half_width_entry = dict( frameSize=VBase4( 0, canvas_width / 2, -0.1, 0, ), parent=panel_canvas, frameColor=VBase4(0.8, 0.8, 0.8, 1), ) left_aligned_small_text = dict( text_align=TextNode.ALeft, text_scale=0.05, text_fg=VBase4(0,0,0,1), text_pos=(0.05, -0.06), ) half_width_text_frame = dict( **half_width_entry, **left_aligned_small_text, ) header = dict( frameSize=VBase4( 0, canvas_width, -0.1, 0, ), parent=panel_canvas, frameColor=VBase4(0.6, 0.6, 0.6, 1), text_align=TextNode.ALeft, text_scale=0.1, text_fg=VBase4(0,0,0,1), text_pos=(0.05, -0.075), ) # Basic device data (name, device class, manufacturer, USB ID) self.device_header = DirectLabel( text="Device data", pos=(0, 0, offset), **header, ) offset -= 0.1 def add_data_entry(offset, label, text): self.name = DirectLabel( text=label, pos=(0, 0, offset), **half_width_text_frame, ) self.name = DirectLabel( text=text, pos=(canvas_width / 2, 0, offset), **half_width_text_frame, ) metadata = [ ('Name', self.device.name), ('Device class', self.device.device_class.name), ('Manufacturer', self.device.manufacturer), ('USB ID', "{:04x}:{:04x}".format( self.device.vendor_id, self.device.product_id, ), ), ] for label, text in metadata: add_data_entry(offset, label, text) offset -= 0.1 # Axes self.axis_sliders = [] if len(self.device.axes) > 0: offset -= 0.1 self.axes_header = DirectLabel( text="Axes", pos=(0, 0, offset), **header, ) offset -= 0.1 def add_axis(offset, axis_name): slider_width = canvas_width / 2 label = DirectLabel( text=axis_name, **left_aligned_small_text, pos=(0.05, 0, offset), parent=panel_canvas, ) slider = DirectSlider( value=0.0, range=(-1.0, 1.0), state=DGG.DISABLED, frameSize=VBase4( 0, slider_width, -0.1, 0, ), thumb_frameSize=VBase4( 0.0, 0.04, -0.04, 0.04), frameColor=VBase4(0.3, 0.3, 0.3, 1), pos=(canvas_width - slider_width, 0, offset), parent=panel_canvas, ) return slider for axis in self.device.axes: axis_slider = add_axis(offset, axis.axis.name) self.axis_sliders.append(axis_slider) offset -= 0.1 # Buttons self.button_buttons = [] if len(self.device.buttons) > 0: offset -= 0.1 self.buttons_header = DirectLabel( text="Buttons", pos=(0, 0, offset), **header, ) offset -= 0.1 def add_button(offset, button_name): button_width = canvas_width / 2 label = DirectLabel( text=button_name, **left_aligned_small_text, pos=(0.05, 0, offset), parent=panel_canvas, ) button = DirectFrame( frameSize=VBase4( 0, button_width, -0.1, 0, ), text="", text_align=TextNode.ACenter, text_scale=0.05, text_fg=VBase4(0,0,0,1), text_pos=(button_width / 2, -0.06), frameColor=VBase4(0.3, 0.3, 0.3, 1), pos=(canvas_width - button_width, 0, offset), parent=panel_canvas, ) return button for i in range(len(self.device.buttons)): button_name = self.device.buttons[i].handle.name button_button = add_button(offset, button_name) self.button_buttons.append(button_button) offset -= 0.1 # Vibration self.vibration = [] if self.device.has_feature(InputDevice.Feature.vibration): offset -= 0.1 self.vibration_header = DirectLabel( text="Vibration", pos=(0, 0, offset), **header, ) offset -= 0.1 def add_vibration(offset, axis_name, index): slider_width = canvas_width / 2 label = DirectLabel( text=axis_name, **left_aligned_small_text, pos=(0.05, 0, offset), parent=panel_canvas, ) slider = DirectSlider( value=0.0, range=(0.0, 1.0), command=self.update_vibration, frameSize=VBase4( 0, slider_width, -0.1, 0, ), thumb_frameSize=VBase4( 0.0, 0.04, -0.04, 0.04), frameColor=VBase4(0.3, 0.3, 0.3, 1), pos=(canvas_width - slider_width, 0, offset), parent=panel_canvas, ) return slider for index, name in enumerate(["low frequency", "high frequency"]): self.vibration.append(add_vibration(offset, name, index)) offset -= 0.1 # Resize the panel's canvas to the widgets actually in it. if -offset > -canvas_height: self.panel['canvasSize'] = VBase4( 0, canvas_width, offset, 0, ) self.panel.setCanvasSize()
def __init__(self): self.defaultBtnMap = base.loader.loadModel("gui/button_map") self.buttonGeom = ( self.defaultBtnMap.find("**/button_ready"), self.defaultBtnMap.find("**/button_click"), self.defaultBtnMap.find("**/button_rollover"), self.defaultBtnMap.find("**/button_disabled")) defaultFont = loader.loadFont('gui/eufm10.ttf') self.logFrame = DirectScrolledFrame( canvasSize = (0, base.a2dRight * 2, -5, 0), frameSize = (0, base.a2dRight * 2, (base.a2dBottom+.2) * 2, 0), frameColor = (0.1, 0.1, 0.1, 1)) self.logFrame.reparentTo(base.a2dTopLeft) # create the info and server debug output self.textscale = 0.1 self.txtinfo = OnscreenText( scale = self.textscale, pos = (0.1, -0.1), text = "", align = TextNode.ALeft, fg = (0.1,1.0,0.15,1), bg = (0, 0, 0, 0), shadow = (0, 0, 0, 1), shadowOffset = (-0.02, -0.02)) self.txtinfo.setTransparency(1) self.txtinfo.reparentTo(self.logFrame.getCanvas()) # create a close Server button self.btnBackPos = Vec3(0.4, 0, 0.2) self.btnBackScale = 0.25 self.btnBack = DirectButton( # Scale and position scale = self.btnBackScale, pos = self.btnBackPos, # Text text = "Quit Server", text_scale = 0.45, text_pos = (0, -0.1), text_fg = (0.82,0.85,0.87,1), text_shadow = (0, 0, 0, 1), text_shadowOffset = (-0.02, -0.02), text_font = defaultFont, # Frame geom = self.buttonGeom, frameColor = (0, 0, 0, 0), relief = 0, pressEffect = False, # Functionality command = self.back, rolloverSound = None, clickSound = None) self.btnBack.setTransparency(1) self.btnBack.reparentTo(base.a2dBottomLeft) # catch window resizes and recalculate the aspectration self.accept("window-event", self.recalcAspectRatio) self.accept("addLog", self.addLog)
class DirectWindow( DirectFrame ): def __init__( self , pos = ( -.5, .5) , title = 'Title' , bgColor = (.5,.5,.5,1) , buttonColor = (1,1,1,1) #( .6, .6, .6, 1 ) #, minSize = ( .5, .5 ) #, maxSize = ( 1, 1 ) , minWindowSize = (0,0) , maxWindowSize = (10000,10000) , virtualSize = (1,1) , windowBorderTextureFiles = [ DEFAULT_TITLE_TEXTURE_LEFT , DEFAULT_TITLE_TEXTURE_CENTER , DEFAULT_TITLE_TEXTURE_RIGHT , DEFAULT_RESIZE_GEOM ] , windowBorderGeomFiles = [ DEFAULT_TITLE_GEOM_RIGHT ] , windowColors = [ ( 1, 1, 1, 1 ) , ( 1, 1, 1, 1 ) , ( 1, 1, 1, 1 ) , ( 1, 1, 1, 1 ) ] , borderSize = 0.01 , dragbarSize = 0.05 , parent=None): self.windowPos = pos self.minWindowSize = minWindowSize self.maxWindowSize = maxWindowSize self.virtualSize = virtualSize self.borderSize = borderSize self.dragbarSize = dragbarSize if parent is None: parent=aspect2d self.parent=parent self.previousSize = (10,10) self.collapsed = False # maybe we should check if aspect2d doesnt already contain the aspect2dMouseNode self.mouseNode = self.parent.attachNewNode( 'aspect2dMouseNode', sort = 999999 ) taskMgr.add( self.mouseNodeTask, 'mouseNodeTask' ) windowBorderTextures = list() for windowBorder in windowBorderTextureFiles: if windowBorder is not None: mdlFile = loader.loadTexture(windowBorder) windowBorderTextures.append(mdlFile) else: windowBorderTextures.append(None) windowBorderGeoms = list() for windowGeom in windowBorderGeomFiles: if windowGeom is not None: mdlFile = loader.loadModel(windowGeom) mdls = ( mdlFile.find('**/**-default'), mdlFile.find('**/**-click'), mdlFile.find('**/**-rollover'), mdlFile.find('**/**-disabled') ) windowBorderGeoms.append(mdls) else: windowBorderGeoms.append((None,None,None,None,),) # the main window we want to move around self.parentWindow = DirectFrame( parent=self.parent, pos=(self.windowPos[0], 0, self.windowPos[1]), #frameSize=# is defined in resize scale=(1, 1, -1), frameColor=bgColor, borderWidth=(0, 0), relief=DGG.FLAT, sortOrder=1, ) # header of the window (drag&drop with it) # the title part of the window, drag around to move the window self.headerParent = DirectButton( parent=self.parentWindow, pos=(0, 0, 0), #frameSize=# is defined in resize scale=(1, 1, self.dragbarSize), frameColor=(1, 1, 1, 1), borderWidth=(0, 0), relief=DGG.FLAT, ) self.headerParent.bind(DGG.B1PRESS,self.startWindowDrag) # images in the headerParent self.headerCenter = DirectFrame( parent=self.headerParent, pos=(0, 0, 1), #frameSize=# is defined in resize scale=(1,1,-1), frameColor=windowColors[1], frameTexture=windowBorderTextures[1], borderWidth=(0, 0), relief=DGG.FLAT, ) self.headerLeft = DirectFrame( parent=self.headerParent, pos=(0, 0, 1), frameSize=(0, self.dragbarSize, 0, 1), scale=(1,1,-1), frameColor=windowColors[0], frameTexture=windowBorderTextures[0], borderWidth=(0, 0), relief=DGG.FLAT, ) # collapse button self.headerRight = DirectButton( parent=self.headerParent, #pos=# is defined in resize frameSize=(0, self.dragbarSize, 0, 1), scale=(1,1,-1), frameColor=windowColors[2], #frameTexture=windowBorderTextures[2], borderWidth=(0, 0), relief=DGG.FLAT, command=self.toggleCollapsed, geom=windowBorderGeoms[0], geom_scale=(self.dragbarSize,1,1) ) # the resize button of the window self.resizeButton = DirectButton( parent=self.parentWindow, pos=(1-self.dragbarSize, 0, 1), frameSize=(0, 1, 0, 1), scale=(self.dragbarSize,1,-self.dragbarSize), frameColor=windowColors[3], frameTexture=windowBorderTextures[3], borderWidth=(0, 0), relief=DGG.FLAT, sortOrder=1, ) self.resizeButton.bind(DGG.B1PRESS,self.startResizeDrag) # text in the center of the window text = TextNode('WindowTitleTextNode') text.setText(title) text.setAlign(TextNode.ACenter) text.setTextColor( 0, 0, 0, 1 ) text.setShadow(0.05, 0.05) text.setShadowColor( 1, 1, 1, 1 ) self.textNodePath = self.headerCenter.attachNewNode(text) self.textNodePath.setPos(.5,0,.3) self.textNodePath.setScale(0.8*self.dragbarSize,1,0.8) if Y_INVERTED: scale = (1,1,-1) else: scale = (1,1,1) # the content part of the window, put stuff beneath # contentWindow.getCanvas() to put it into it self.contentWindow = DirectScrolledFrame( parent = self.parentWindow, #pos = # is defined in resize scale = scale, canvasSize = (0,self.virtualSize[0],0,self.virtualSize[1]), frameColor = buttonColor, relief = DGG.RAISED, borderWidth = (0,0), verticalScroll_frameSize = [0,self.dragbarSize,0,1], verticalScroll_frameTexture = loader.loadTexture( 'rightBorder.png' ), verticalScroll_incButton_frameTexture = loader.loadTexture( 'scrollDown.png' ), verticalScroll_decButton_frameTexture = loader.loadTexture( 'scrollDown.png' ), verticalScroll_thumb_frameTexture = loader.loadTexture( 'scrollBar.png' ), horizontalScroll_frameSize = [0,1,0,self.dragbarSize], horizontalScroll_frameTexture = loader.loadTexture( 'bottomBorder.png' ), horizontalScroll_incButton_frameTexture = loader.loadTexture( 'scrollDown.png' ), horizontalScroll_decButton_frameTexture = loader.loadTexture( 'scrollDown.png' ), horizontalScroll_thumb_frameTexture = loader.loadTexture( 'scrollBar.png' ), ) # child we attach should be inside the window DirectFrame.__init__( self, parent = self.contentWindow.getCanvas(), pos = (0,0,self.virtualSize[1]), scale = (1,1,1), frameSize = ( 0, self.virtualSize[0]+2*self.borderSize, 0, self.virtualSize[1] ), #frameColor = (0,0,0,1), relief = DGG.RIDGE, borderWidth = (0,0), ) self.initialiseoptions(DirectWindow) # offset then clicking on the resize button from the mouse to the resizebutton # position, required to calculate the position / scaling self.offset = None self.resizeButtonTaskName = "resizeTask-%s" % str(hash(self)) # do sizing of the window to virtualSize #self.resize( self.virtualSize[0]+2*self.borderSize # , self.virtualSize[1]+self.dragbarSize+2*self.borderSize ) self.resize(10,10) # a task that keeps a node at the position of the mouse-cursor def mouseNodeTask(self, task): if WindowManager.hasMouse(): x=WindowManager.getMouseX() y=WindowManager.getMouseY() # the mouse position is read relative to render2d, so set it accordingly self.mouseNode.setPos( render2d, x, 0, y ) return task.cont # dragging functions def startWindowDrag( self, param ): self.parentWindow.wrtReparentTo( self.mouseNode ) self.ignoreAll() self.accept( 'mouse1-up', self.stopWindowDrag ) def stopWindowDrag( self, param=None ): # this could be called even after the window has been destroyed #if self: # this is called 2 times (bug), so make sure it's not already parented to aspect2d if self.parentWindow.getParent() != self.parent: self.parentWindow.wrtReparentTo(self.parent) self.ignoreAll() # resize functions def startResizeDrag(self, param): self.offset = self.resizeButton.getPos(aspect2d) - self.mouseNode.getPos(aspect2d) taskMgr.remove( self.resizeButtonTaskName ) taskMgr.add( self.resizeButtonTask, self.resizeButtonTaskName ) self.accept( 'mouse1-up', self.stopResizeDrag,['x'] ) def resize(self,windowX,windowY): # limit max/min size of the window maxX = min(self.maxWindowSize[0], self.virtualSize[0]+2*self.borderSize) minX = max( self.dragbarSize*3, self.minWindowSize[0]) windowWidth = min( maxX, max( minX, windowX ) ) maxY = min( self.maxWindowSize[1], self.virtualSize[1]+self.dragbarSize+2*self.borderSize ) minY = max( self.dragbarSize*4, self.minWindowSize[1]) windowHeight = min( maxY, max( minY, windowY ) ) if self.collapsed: windowHeight = 2*self.dragbarSize+2*self.borderSize windowWidth = windowWidth self.contentWindow.hide() # store changed window width only self.previousSize = windowWidth, self.previousSize[1] else: self.contentWindow.show() self.previousSize = windowWidth, windowHeight # set the window size self.headerParent['frameSize'] = (0, windowWidth, 0, 1) self.headerCenter['frameSize'] = (0, windowWidth, 0, 1) self.parentWindow['frameSize'] = (0, windowWidth, 0, windowHeight) self.contentWindow['frameSize'] = (0, windowWidth-self.borderSize*2, 0, windowHeight-self.dragbarSize-2*self.borderSize) self.contentWindow.setPos(self.borderSize,0,windowHeight-self.borderSize) self.headerRight.setPos(windowWidth-self.dragbarSize, 0, 1) self.textNodePath.setPos(windowWidth/2.,0,.3) self.resizeButton.setPos(windowWidth-self.dragbarSize, 0, windowHeight) def resizeButtonTask(self, task=None): mPos = self.mouseNode.getPos(self.parentWindow) # max height, the smaller of (given maxWindowSize and real size of content and borders windowX = mPos.getX() + self.offset.getX() + self.dragbarSize windowY = mPos.getZ() - self.offset.getZ() self.resize(windowX,windowY) return task.cont def stopResizeDrag(self, param): taskMgr.remove( self.resizeButtonTaskName ) self.ignoreAll() # a bugfix for a wrong implementation def detachNode( self ): self.parentWindow.detachNode() #self. = None #DirectFrame.detachNode( self ) def removeNode( self ): self.parentWindow.removeNode() #DirectFrame.removeNode( self ) def toggleCollapsed(self,state=None): if state is None: state=not self.collapsed if state: self.collapse() else: self.uncollapse() def collapse(self): self.collapsed = True self.resize(*self.previousSize) def uncollapse(self): self.collapsed = False self.resize(*self.previousSize)