def __createFile(self, filename, xPos, zPos): name = filename if len(filename) > 10: name = "" for i in range(min(math.ceil(len(filename)/10), 4)): name += filename[i*10:i*10+10]+"\n" name = name[:-1] if math.ceil(len(filename)/10) > 4: name += "..." btn = DirectButton( parent=self.container.getCanvas(), image="icons/File.png", image_scale=35, relief=1, frameColor = ( (0.9, 0.9, 0.9, 0), # Normal (0.95, 0.95, 1, 1), # Click (0.9, 0.9, 1, 1), # Hover (0.5, 0.5, 0.5, 1)), # Disabled frameSize=(-40, 40, -40, 40), pos=LPoint3f(xPos, 0, zPos), text = name, text_scale=12, text_pos=(0,-40), command=self.txtFileName.set, extraArgs=[filename] ) btn.bind(DGG.MWDOWN, self.scroll, [0.01]) btn.bind(DGG.MWUP, self.scroll, [-0.01]) btn.setTransparency(TransparencyAttrib.M_multisample)
class BetterButton(DebugObject): """ This is a wrapper around DirectButton, providing a simpler interface and better visuals """ def __init__(self, parent, x, y, text, width=50, callback=None, callbackArgs=None): DebugObject.__init__(self, "BetterButton") if callbackArgs is None: callbackArgs = [] self._node = DirectButton(text=text, parent=parent, pressEffect=1, command=callback, extraArgs=callbackArgs, scale=1, pos=(x + width, 1, -y - 15), frameSize=(-width, width, -15, 15), text_fg=(1, 1, 1, 1), frameColor=(0.1, 0.1, 0.1, 1.0), text_font=Globals.font, text_pos=(0, -4), text_scale=14) # Add a hover effect self._node.bind(DGG.ENTER, self._onMouseOver) self._node.bind(DGG.EXIT, self._onMouseOut) def _onMouseOver(self, coords): self._node["frameColor"] = (0.0, 0.0, 0.0, 1.0) def _onMouseOut(self, coords): self._node["frameColor"] = (0.1, 0.1, 0.1, 1.0)
def __createFolder(self, entry, xPos, zPos): name = entry.name if len(entry.name) > 10: name = "" for i in range(max(math.ceil(len(entry.name) / 10), 4)): name += entry.name[i * 10:i * 10 + 10] + "\n" name = name[:-1] if math.ceil(len(entry.name) / 10) > 4: name += "..." btn = DirectButton(parent=self.container.getCanvas(), image=loader.load_texture(f"{self.iconDir}/Folder.png", loaderOptions=self.imageOpts), image_scale=35, relief=1, frameColor=self.theme.folder_background, frameSize=(-40, 40, -40, 40), pos=LPoint3f(xPos, 0, zPos), text=name, text_scale=12, text_pos=(0, -40), text_fg=self.theme.default_text_color, command=self.folderMoveIn, extraArgs=[entry.path]) btn.bind(DGG.MWDOWN, self.scroll, [0.01]) btn.bind(DGG.MWUP, self.scroll, [-0.01]) btn.setTransparency(TransparencyAttrib.M_multisample)
def __createFolder(self, entry, xPos, zPos): name = entry.name btn = DirectButton( parent=self.container.getCanvas(), image=loader.load_texture(f"{self.iconDir}/Folder.png", loaderOptions=self.imageOpts), image_scale=16, image_pos=(16,0,0), relief=1, frameColor = self.theme.folder_background, frameSize=(0, self.screenWidthPxHalf*2, -16, 16), pos=LPoint3f(xPos, 0, zPos), text = name, text_scale=12, text_align=TextNode.ALeft, text_pos=(32,-4), text_fg=self.theme.default_text_color, command=self.folderMoveIn, extraArgs=[entry.path] ) lblInfo = __createMIMEInfo(self, btn, entry, True) #lblSize = __createSizeInfo(self, btn, entry) btn.bind(DGG.MWDOWN, self.scroll, [0.01]) btn.bind(DGG.MWUP, self.scroll, [-0.01]) btn.setTransparency(TransparencyAttrib.M_multisample)
class MPBtn(GameObject): tooltip_align = TextNode.A_right tooltip_offset = (.01, 0, -.08) def __init__(self, parent, owner, menu_args, img_path, msg_btn_x, cb, usr_name, tooltip): GameObject.__init__(self) self.owner = owner lab_args = menu_args.label_args lab_args['scale'] = .046 #lab_args['text_fg'] = menu_args.text_normal self.btn = ImgBtn(parent=parent, scale=.024, pos=(msg_btn_x, 1, .01), frameColor=(1, 1, 1, 1), frameTexture=img_path, command=cb, extraArgs=[usr_name], **menu_args.imgbtn_args) self.btn.bind(ENTER, self.on_enter) self.btn.bind(EXIT, self.on_exit) self.tooltip_btn = DirectButton(parent=parent, scale=.024, pos=(msg_btn_x, 1, .01), frameColor=(1, 1, 1, 0), frameSize=(-1, 1, -1, 1), command=None, **menu_args.imgbtn_args) self.tooltip_btn.bind(ENTER, self.on_enter) self.tooltip_btn.bind(EXIT, self.on_exit) self.on_create() self.tooltip = DirectLabel(text=tooltip, pos=self.btn.get_pos() + self.tooltip_offset, parent=parent, text_wordwrap=10, text_bg=(.2, .2, .2, .8), text_align=self.tooltip_align, **lab_args) self.tooltip.set_bin('gui-popup', 10) self.tooltip.hide() def on_create(self): self.btn.hide() self.tooltip_btn.hide() def is_hidden(self): return self.btn.is_hidden() def show(self): if self.btn['state'] == DISABLED: self.tooltip_btn.show() else: self.tooltip_btn.hide() return self.btn.show() def hide(self): self.tooltip_btn.hide() return self.btn.hide() def enable(self): self.tooltip_btn.hide() return self.btn.enable() def disable(self): self.tooltip_btn.show() return self.btn.disable() def on_enter(self, pos): self.owner.on_enter(pos) self.tooltip.show() def on_exit(self, pos): self.owner.on_exit(pos) self.tooltip.hide()
class DirectFolderBrowser(DirectObject): def __init__(self, command, fileBrowser=False, defaultPath="~", defaultFilename="unnamed.txt", fileExtensions=[], tooltip=None): """ A simple file and folder browser command: The command that will be called on closing the browser fileBrowser: If set to True the browser will show files, otherwise it will only show folders defaultPath: The initial path the browser will be set to show defaultFilename: The filename that will be set by default, only usefull if fileBrowser is True fileExtensions: A list of extensions. Only files with those extensions will be shown. Only usefull if fileBrowser is True tooltip: An instance of the Tooltip class to display tooltips for certain parts of the editor """ self.tt = tooltip self.command = command self.showFiles = fileBrowser self.fileExtensions = fileExtensions self.showHidden = False self.currentPath = os.path.expanduser(defaultPath) if not os.path.exists(self.currentPath): self.currentPath = os.path.expanduser("~") self.previousPath = self.currentPath self.screenWidthPx = base.getSize()[0] self.screenWidthPxHalf = self.screenWidthPx * 0.5 self.screenHeightPx = base.getSize()[1] self.screenHeightPxHalf = self.screenHeightPx * 0.5 self.mainFrame = DirectFrame( relief=1, frameSize=(-self.screenWidthPxHalf,self.screenWidthPxHalf,-self.screenHeightPxHalf,self.screenHeightPxHalf), frameColor=(1, 1, 1, 1), pos=LPoint3f(base.getSize()[0]/2, 0, -base.getSize()[1]/2), parent=base.pixel2d, state=DGG.NORMAL, ) self.pathRightMargin = 153 self.pathEntryWidth = self.screenWidthPx - self.pathRightMargin self.pathEntry = DirectEntry( parent=self.mainFrame, relief=DGG.SUNKEN, frameColor=(1, 1, 1, 1), pad=(0.2, 0.2), pos=LPoint3f(-self.screenWidthPxHalf + 15, 0, self.screenHeightPxHalf - 25), scale=12, width=self.pathEntryWidth/12, overflow=True, command=self.entryAccept, initialText=self.currentPath, focusInCommand=base.messenger.send, focusInExtraArgs=["unregisterKeyboardEvents"], focusOutCommand=base.messenger.send, focusOutExtraArgs=["reregisterKeyboardEvents"], ) x = self.pathEntryWidth/2-28 self.btnReload = DirectButton( parent=self.mainFrame, relief=1, frameColor = ( (0.8, 0.8, 0.8, 1), # Normal (0.9, 0.9, 1, 1), # Click (0.8, 0.8, 1, 1), # Hover (0.5, 0.5, 0.5, 1)), # Disabled frameSize=(-14, 14, -10, 18), pos=LPoint3f(x, 0, self.screenHeightPxHalf - 25), command=self.folderReload, image="icons/Reload.png", image_scale=14, image_pos=(0,0,4), ) self.btnReload.setTransparency(TransparencyAttrib.M_multisample) if self.tt is not None: self.btnReload.bind(DGG.ENTER, self.tt.show, ["Reload Folder"]) self.btnReload.bind(DGG.EXIT, self.tt.hide) x += 28 self.btnFolderUp = DirectButton( parent=self.mainFrame, relief=1, frameColor = ( (0.8, 0.8, 0.8, 1), # Normal (0.9, 0.9, 1, 1), # Click (0.8, 0.8, 1, 1), # Hover (0.5, 0.5, 0.5, 1)), # Disabled frameSize=(-14, 14, -10, 18), pos=LPoint3f(x, 0, self.screenHeightPxHalf - 25), command=self.folderUp, image="icons/FolderUp.png", image_scale=14, image_pos=(0,0,4), ) self.btnFolderUp.setTransparency(TransparencyAttrib.M_multisample) if self.tt is not None: self.btnFolderUp.bind(DGG.ENTER, self.tt.show, ["Move up one level"]) self.btnFolderUp.bind(DGG.EXIT, self.tt.hide) x += 28 self.btnFolderNew = DirectButton( parent=self.mainFrame, relief=1, frameColor = ( (0.8, 0.8, 0.8, 1), # Normal (0.9, 0.9, 1, 1), # Click (0.8, 0.8, 1, 1), # Hover (0.5, 0.5, 0.5, 1)), # Disabled frameSize=(-14, 14, -10, 18), pos=LPoint3f(x, 0, self.screenHeightPxHalf - 25), command=self.folderNew, image="icons/FolderNew.png", image_scale=14, image_pos=(0,0,4), ) self.btnFolderNew.setTransparency(TransparencyAttrib.M_multisample) if self.tt is not None: self.btnFolderNew.bind(DGG.ENTER, self.tt.show, ["Create new folder"]) self.btnFolderNew.bind(DGG.EXIT, self.tt.hide) x += 28 self.btnFolderShowHidden = DirectButton( parent=self.mainFrame, relief=1, frameColor = ( (0.8, 0.8, 0.8, 1), # Normal (0.9, 0.9, 1, 1), # Click (0.8, 0.8, 1, 1), # Hover (0.5, 0.5, 0.5, 1)), # Disabled frameSize=(-14, 14, -10, 18), pos=LPoint3f(x, 0, self.screenHeightPxHalf - 25), command=self.folderShowHidden, image="icons/FolderShowHidden.png", image_scale=14, image_pos=(0,0,4), ) self.btnFolderShowHidden.setTransparency(TransparencyAttrib.M_multisample) if self.tt is not None: self.btnFolderShowHidden.bind(DGG.ENTER, self.tt.show, ["Show/Hide hidden files and folders"]) self.btnFolderShowHidden.bind(DGG.EXIT, self.tt.hide) color = ( (0.8, 0.8, 0.8, 1), # Normal (0.9, 0.9, 1, 1), # Click (0.8, 0.8, 1, 1), # Hover (0.5, 0.5, 0.5, 1)) # Disabled self.container = DirectScrolledFrame( relief=DGG.RIDGE, borderWidth=(2, 2), frameColor=(1, 1, 1, 1), frameSize=(-self.screenWidthPxHalf+10, self.screenWidthPxHalf-10, -self.screenHeightPxHalf+50, self.screenHeightPxHalf-50), canvasSize=(-self.screenWidthPxHalf+31, self.screenWidthPxHalf-10, -self.screenHeightPxHalf+50, self.screenHeightPxHalf-50), pos=LPoint3f(0, 0, 0), parent=self.mainFrame, scrollBarWidth=20, verticalScroll_scrollSize=20, verticalScroll_thumb_relief=DGG.FLAT, verticalScroll_incButton_relief=DGG.FLAT, verticalScroll_decButton_relief=DGG.FLAT, verticalScroll_thumb_frameColor=color, verticalScroll_incButton_frameColor=color, verticalScroll_decButton_frameColor=color, horizontalScroll_thumb_relief=DGG.FLAT, horizontalScroll_incButton_relief=DGG.FLAT, horizontalScroll_decButton_relief=DGG.FLAT, horizontalScroll_thumb_frameColor=color, horizontalScroll_incButton_frameColor=color, horizontalScroll_decButton_frameColor=color, state=DGG.NORMAL, ) self.container.bind(DGG.MWDOWN, self.scroll, [0.01]) self.container.bind(DGG.MWUP, self.scroll, [-0.01]) self.btnOk = DirectButton( parent=self.mainFrame, relief=1, frameColor = ( (0.8, 0.8, 0.8, 1), # Normal (0.9, 0.9, 1, 1), # Click (0.8, 0.8, 1, 1), # Hover (0.5, 0.5, 0.5, 1)), # Disabled frameSize=(-45, 45, -6, 14), pos=LPoint3f(self.screenWidthPxHalf-160, 0, -self.screenHeightPxHalf+25), text = "ok", text_scale=12, command=command, extraArgs=[1], ) self.btnCancel = DirectButton( parent=self.mainFrame, relief=1, frameColor = ( (0.8, 0.8, 0.8, 1), # Normal (0.9, 0.9, 1, 1), # Click (0.8, 0.8, 1, 1), # Hover (0.5, 0.5, 0.5, 1)), # Disabled frameSize=(-45, 45, -6, 14), pos=LPoint3f(self.screenWidthPxHalf-55, 0, -self.screenHeightPxHalf+25), text = "Cancel", text_scale=12, command=command, extraArgs=[0] ) if self.showFiles: self.txtFileName = DirectEntry( parent=self.mainFrame, relief=DGG.SUNKEN, frameColor=(1, 1, 1, 1), pad=(0.2, 0.2), pos=LPoint3f(-self.screenWidthPxHalf+25, 0, -self.screenHeightPxHalf+25), scale=12, width=200/12, overflow=True, command=self.filenameAccept, initialText=defaultFilename, focusInCommand=base.messenger.send, focusInExtraArgs=["unregisterKeyboardEvents"], focusOutCommand=base.messenger.send, focusOutExtraArgs=["reregisterKeyboardEvents"], ) self.newFolderFrame = DirectFrame( parent=self.mainFrame, relief=1, frameSize=(-self.screenWidthPxHalf+10,self.screenWidthPxHalf-10,-20,20), pos=LPoint3f(0, 0, self.screenHeightPxHalf-55), frameColor=(0.5,0.5,0.5,1), ) self.txtNewFolderName = DirectLabel( parent=self.newFolderFrame, text="New Folder Name", text_scale=12, frameColor=(0,0,0,0), text_align=TextNode.ALeft, pos=(-self.screenWidthPxHalf+15, 0, -3), ) self.folderName = DirectEntry( parent=self.newFolderFrame, relief=DGG.SUNKEN, frameColor=(1, 1, 1, 1), pad=(0.2, 0.2), pos=LPoint3f(-self.screenWidthPxHalf+25 + self.txtNewFolderName.getWidth(), 0, -4), scale=12, width=((self.screenWidthPxHalf-25)*2-self.txtNewFolderName.getWidth() - 100)/12, overflow=True, command=self.entryAccept, initialText="New Folder", focusInCommand=base.messenger.send, focusInExtraArgs=["unregisterKeyboardEvents"], focusOutCommand=base.messenger.send, focusOutExtraArgs=["reregisterKeyboardEvents"], ) self.btnCreate = DirectButton( parent=self.newFolderFrame, relief=1, frameColor = ( (0.8, 0.8, 0.8, 1), # Normal (0.9, 0.9, 1, 1), # Click (0.8, 0.8, 1, 1), # Hover (0.5, 0.5, 0.5, 1)), # Disabled frameSize=(-45, 45, -6, 14), pos=LPoint3f(self.screenWidthPxHalf-65, 0, -4), text = "Create", text_scale=12, command=self.folderCreate, extraArgs=[0] ) self.newFolderFrame.hide() self.folderReload() # handle window resizing self.prevScreenSize = base.getSize() self.accept("window-event", self.windowEventHandler) def show(self): self.mainFrame.show() self.accept("window-event", self.windowEventHandler) def hide(self): self.ignore("window-event") self.mainFrame.hide() def destroy(self): self.ignore("window-event") self.mainFrame.destroy() def scroll(self, scrollStep, event): self.container.verticalScroll.scrollStep(scrollStep) def get(self): if self.showFiles: return os.path.join(self.currentPath, self.txtFileName.get(True)) return self.currentPath def filenameAccept(self, filename): self.command(1) def entryAccept(self, path): self.folderReload() def folderReload(self): for element in self.container.getCanvas().getChildren(): element.removeNode() path = self.pathEntry.get(True) path = os.path.expanduser(path) path = os.path.expandvars(path) if not os.path.exists(path): return self.currentPath = path try: content = os.scandir(path) except PermissionError: base.messenger.send("showWarning", ["Access denied!"]) self.pathEntry.set(self.previousPath) self.currentPath = self.previousPath self.folderReload() return # start position for the folders and files xPos = -self.screenWidthPxHalf + 20 + 50 - 110 zPos = self.screenHeightPxHalf-60-40 dirList = [] fileList = [] unkList = [] for entry in content: if entry.name.startswith(".") and not self.showHidden: continue if entry.is_dir(): dirList.append(entry) elif entry.is_file() and self.showFiles: if len(self.fileExtensions) > 0: if os.path.splitext(entry.name)[1] in self.fileExtensions: fileList.append(entry) else: fileList.append(entry) elif self.showFiles: unkList.append(entry) def moveNext(entry): nonlocal xPos nonlocal zPos if entry.is_dir() or self.showFiles: if xPos + 110 > self.screenWidthPxHalf - 45: # move to the next line if we hit the right border (incl. scrollbar size) xPos = -self.screenWidthPxHalf + 20 + 50 zPos -= 110 else: # move right the next position xPos += 110 def getKey(item): return item.name.lower() for entry in sorted(dirList, key=getKey): moveNext(entry) self.__createFolder(entry, xPos, zPos) for entry in sorted(fileList, key=getKey): moveNext(entry) self.__createFile(entry.name, xPos, zPos) for entry in sorted(unkList, key=getKey): moveNext(entry) self.__createUnknown(entry.name, xPos, zPos) # recalculate the canvas size self.container["canvasSize"] = (-self.screenWidthPxHalf+31, self.screenWidthPxHalf-15, zPos-90, self.screenHeightPxHalf-50) self.container.setCanvasSize() def folderUp(self): self.previousPath = self.currentPath self.currentPath = os.path.normpath(os.path.join(self.currentPath, "..")) self.pathEntry.set(self.currentPath) self.folderReload() def folderMoveIn(self, path): path = os.path.expanduser(path) path = os.path.expandvars(path) self.previousPath = self.currentPath self.currentPath = path self.pathEntry.set(path) self.folderReload() self.container.verticalScroll["value"] = 0 def folderNew(self): if self.newFolderFrame.isHidden(): self.newFolderFrame.show() else: self.newFolderFrame.hide() def folderShowHidden(self): self.showHidden = not self.showHidden self.folderReload() def folderCreate(self, path=""): try: os.makedirs(os.path.join(self.currentPath, self.folderName.get(True))) except: base.messenger.send("showWarning", ["Can't create folder"]) self.newFolderFrame.hide() self.folderReload() def __createFolder(self, entry, xPos, zPos): name = entry.name if len(entry.name) > 10: name = "" for i in range(max(math.ceil(len(entry.name)/10), 4)): name += entry.name[i*10:i*10+10]+"\n" name = name[:-1] if math.ceil(len(entry.name)/10) > 4: name += "..." btn = DirectButton( parent=self.container.getCanvas(), image="icons/Folder.png", image_scale=35, relief=1, frameColor = ( (0.9, 0.9, 0.9, 0), # Normal (0.95, 0.95, 1, 1), # Click (0.9, 0.9, 1, 1), # Hover (0.5, 0.5, 0.5, 1)), # Disabled frameSize=(-40, 40, -40, 40), pos=LPoint3f(xPos, 0, zPos), text = name, text_scale=12, text_pos=(0,-40), command=self.folderMoveIn, extraArgs=[entry.path] ) btn.bind(DGG.MWDOWN, self.scroll, [0.01]) btn.bind(DGG.MWUP, self.scroll, [-0.01]) btn.setTransparency(TransparencyAttrib.M_multisample) def __createFile(self, filename, xPos, zPos): name = filename if len(filename) > 10: name = "" for i in range(min(math.ceil(len(filename)/10), 4)): name += filename[i*10:i*10+10]+"\n" name = name[:-1] if math.ceil(len(filename)/10) > 4: name += "..." btn = DirectButton( parent=self.container.getCanvas(), image="icons/File.png", image_scale=35, relief=1, frameColor = ( (0.9, 0.9, 0.9, 0), # Normal (0.95, 0.95, 1, 1), # Click (0.9, 0.9, 1, 1), # Hover (0.5, 0.5, 0.5, 1)), # Disabled frameSize=(-40, 40, -40, 40), pos=LPoint3f(xPos, 0, zPos), text = name, text_scale=12, text_pos=(0,-40), command=self.txtFileName.set, extraArgs=[filename] ) btn.bind(DGG.MWDOWN, self.scroll, [0.01]) btn.bind(DGG.MWUP, self.scroll, [-0.01]) btn.setTransparency(TransparencyAttrib.M_multisample) def __createUnknown(self, filename, xPos, zPos): name = filename if len(filename) > 10: name = "" for i in range(math.ceil(len(filename)/10)): name += filename[i*10:i*10+10]+"\n" name = name[:-1] lbl = DirectLabel( parent=self.container.getCanvas(), image="icons/File.png", image_scale=35, image_color=(0.9,0.5,0.5,1), relief=1, frameColor = (0.7, 0.7, 0.7, 0), frameSize=(-40, 40, -40, 40), pos=LPoint3f(xPos, 0, zPos), text = name, text_scale=12, text_pos=(0,-40), ) lbl.bind(DGG.MWDOWN, self.scroll, [0.01]) lbl.bind(DGG.MWUP, self.scroll, [-0.01]) lbl.setTransparency(TransparencyAttrib.M_multisample) def windowEventHandler(self, window=None): if window != base.win: # This event isn't about our window. return if window is not None: # window is none if panda3d is not started if self.prevScreenSize == base.getSize(): return self.prevScreenSize = base.getSize() self.screenWidthPx = base.getSize()[0] self.screenWidthPxHalf = self.screenWidthPx * 0.5 self.screenHeightPx = base.getSize()[1] self.screenHeightPxHalf = self.screenHeightPx * 0.5 # reposition and resize all gui elements self.mainFrame.setPos(self.screenWidthPx/2, 0, -self.screenHeightPx/2) self.mainFrame["frameSize"] = (-self.screenWidthPxHalf,self.screenWidthPxHalf,-self.screenHeightPxHalf,self.screenHeightPxHalf) self.pathEntryWidth = self.screenWidthPx - self.pathRightMargin self.pathEntry.setPos(LPoint3f(-self.screenWidthPxHalf + 15, 0, self.screenHeightPxHalf - 25)) self.pathEntry["width"] = self.pathEntryWidth/12 self.pathEntry.resetFrameSize() # reposition top right icons x = self.pathEntryWidth/2-28 self.btnReload.setPos(LPoint3f(x, 0, self.screenHeightPxHalf - 25)) x += 28 self.btnFolderUp.setPos(pos=LPoint3f(x, 0, self.screenHeightPxHalf - 25)) x += 28 self.btnFolderNew.setPos(pos=LPoint3f(x, 0, self.screenHeightPxHalf - 25)) x += 28 self.btnFolderShowHidden.setPos(pos=LPoint3f(x, 0, self.screenHeightPxHalf - 25)) # resize the browsing area self.container["frameSize"] = (-self.screenWidthPxHalf+10, self.screenWidthPxHalf-10, -self.screenHeightPxHalf+50, self.screenHeightPxHalf-50) # Note: canvas size of the container will be reset in the # folder Reload call at the end of this function self.btnOk.setPos(LPoint3f(self.screenWidthPxHalf-160, 0, -self.screenHeightPxHalf+25)) self.btnCancel.setPos(LPoint3f(self.screenWidthPxHalf-55, 0, -self.screenHeightPxHalf+25)) if self.showFiles: self.txtFileName.setPos(LPoint3f(-self.screenWidthPxHalf+25, 0, -self.screenHeightPxHalf+25)) self.newFolderFrame.setPos(LPoint3f(0, 0, self.screenHeightPxHalf-55)) self.newFolderFrame["frameSize"] = (-self.screenWidthPxHalf+10,self.screenWidthPxHalf-10,-20,20) self.txtNewFolderName.setPos(-self.screenWidthPxHalf+15, 0, -3) self.folderName.setPos(LPoint3f(-self.screenWidthPxHalf+25 + self.txtNewFolderName.getWidth(), 0, -4)) self.folderName["width"]=((self.screenWidthPxHalf-25)*2-self.txtNewFolderName.getWidth() - 100)/12 self.btnCreate.setPos(LPoint3f(self.screenWidthPxHalf-65, 0, -4)) self.folderReload()
class InventoryGui(DirectObject): directNotify = DirectNotify().newCategory('InventoryGui') HiddenPos = (0.2, 0, 0) VisiblePos = (-0.1725, 0, 0) SwitchTime = 0.3 AutoShowTime = 1.5 DELETED = False def __init__(self): DirectObject.__init__(self) self.backpack = base.localAvatar.backpack if not self.backpack: return self.backpack.loadoutGUI = self self.oneSlotPos = [(0, 0, 0)] self.twoSlotsPos = [(0, 0, 0.3), (0, 0, -0.2)] self.threeSlotsPos = [(0, 0, 0.5), (0, 0, 0), (0, 0, -0.5)] self.fourSlotPos = [(0, 0, 0.5), (0, 0, 0.15), (0, 0, -0.2), (0, 0, -0.55)] self.availableSlot = 0 self.slots = [] self.activeSlot = None self.defaultSlots = 3 self.prevSlot = None self.ammoLabel = None self.inventoryFrame = DirectFrame(parent=base.a2dRightCenter, pos=(-0.1725, 0, 0)) self.visibilityBtn = DirectButton(text='', relief=None, text_bg=(1, 1, 1, 0), parent=base.a2dRightCenter, pos=(-0.1725, 0, 0), frameSize=(-0.2, 0.2, -0.725, 0.7), clickSound=None, rolloverSound=None) self.visibilityBtn.bind(DGG.WITHIN, self.__handleVisEnter) self.visibilityBtn.bind(DGG.WITHOUT, self.__handleVisExit) self.visibilityBtn.setBin('background', 10) self.visibilityBtn = None self.visibilityBtnStatus = 0 self.switchSound = True self.switchSoundSfx = base.loadSfx( 'phase_3/audio/sfx/GUI_balloon_popup.ogg') self.visibilityFSM = ClassicFSM('InventoryGui-VisibilityFSM', [ State('off', self.enterOff, self.exitOff), State('hidden', self.enterHidden, self.exitHidden), State('hidden2visible', self.enterHidden2Visible, self.exitHidden2Visible), State('visible', self.enterVisible, self.exitVisible), State('visible2hidden', self.enterVisible2Hidden, self.exitVisible2Hidden) ], 'off', 'off') self.visibilityFSM.enterInitialState() self.visibilityFSM.request('hidden') return def enterOff(self): pass def exitOff(self): pass def enterHidden(self): self.inventoryFrame.setPos(InventoryGui.HiddenPos) self.inventoryFrame.hide() def exitHidden(self): pass def enterVisible(self, autoShow=False): self.inventoryFrame.setPos(InventoryGui.VisiblePos) self.inventoryFrame.show() if self.visibilityBtnStatus == 0: if autoShow is False: self.visibilityFSM.request('visible2hidden') def exitVisible(self): pass def enterHidden2Visible(self, autoShow=False): self.inventoryFrame.show() self.moveIval = LerpPosInterval(self.inventoryFrame, duration=InventoryGui.SwitchTime, pos=InventoryGui.VisiblePos, startPos=InventoryGui.HiddenPos) self.moveIval.setDoneEvent('hidden2visible') self.acceptOnce('hidden2visible', self.visibilityFSM.request, ['visible', [autoShow]]) self.moveIval.start() def exitHidden2Visible(self): self.ignore('hidden2visible') self.moveIval.finish() del self.moveIval def enterVisible2Hidden(self): self.moveIval = LerpPosInterval(self.inventoryFrame, duration=InventoryGui.SwitchTime, pos=InventoryGui.HiddenPos, startPos=InventoryGui.VisiblePos) self.moveIval.setDoneEvent('visible2hidden') self.acceptOnce('visible2hidden', self.visibilityFSM.request, ['hidden']) self.moveIval.start() def exitVisible2Hidden(self): self.ignore('visible2hidden') self.moveIval.finish() del self.moveIval def click_setWeapon(self, slot, cmd): self.setWeapon(slot, playSound=False) def setWeapon(self, slot, playSound=True, showUpIfHidden=False): if isinstance(slot, str): for iSlot in self.slots: if iSlot.getGag(): if iSlot.getGag().getID() == slot: slot = iSlot if self.activeSlot and slot != self.activeSlot: self.activeSlot.setOutlineImage('idle') self.prevSlot = self.activeSlot if slot.getGag() and self.backpack.getSupply(slot.getGag().getID( )) > 0 and not slot.getGag().getState() == GagState.RECHARGING: if self.activeSlot != slot: gagId = slot.getGag().getID() base.localAvatar.needsToSwitchToGag = gagId if base.localAvatar.gagsTimedOut == False: base.localAvatar.b_equip(gagId) base.localAvatar.enableGagKeys() slot.setOutlineImage('selected') self.activeSlot = slot else: if self.activeSlot == slot and slot.getGag().getState() in [ GagState.LOADED, GagState.RECHARGING ]: base.localAvatar.needsToSwitchToGag = 'unequip' if base.localAvatar.gagsTimedOut == False: base.localAvatar.b_unEquip() base.localAvatar.enableGagKeys() self.activeSlot = None self.update() if self.switchSound and playSound: base.playSfx(self.switchSoundSfx) if showUpIfHidden: base.taskMgr.remove('showUpIfHidden') self.__autoVisEnter() base.taskMgr.doMethodLater(InventoryGui.AutoShowTime, self.__autoVisExitTask, 'showUpIfHidden') return def __autoVisExitTask(self, task): if self.visibilityBtnStatus == 0: self.__handleVisExit(None, updateBtnStatus=False) return task.done def __autoVisEnter(self): self.__handleVisEnter(None, True, False) return def __handleVisEnter(self, foo, autoShow=False, updateBtnStatus=True): if updateBtnStatus: self.visibilityBtnStatus = 1 if self.visibilityFSM.getCurrentState().getName() == 'hidden': self.visibilityFSM.request('hidden2visible', [autoShow]) else: if self.visibilityFSM.getCurrentState().getName( ) == 'visible2hidden': self.visibilityFSM.request('visible') def __handleVisExit(self, foo, updateBtnStatus=True): if updateBtnStatus: self.visibilityBtnStatus = 0 base.taskMgr.remove('showUpIfHidden') if self.visibilityFSM.getCurrentState().getName() == 'visible': self.visibilityFSM.request('visible2hidden') def createGui(self): self.deleteGui() posGroup = self.threeSlotsPos if self.defaultSlots == 4: posGroup = self.fourSlotPos for slot in range(len(posGroup) + 1): if slot == 3: posGroup = self.fourSlotPos slotObj = Slot(self, slot + 1, posGroup[slot], self.inventoryFrame) self.slots.append(slotObj) if slot == 3: slotObj.hide() self.ammoLabel = DirectLabel(text='Ammo: 0', text_fg=(1, 1, 1, 1), relief=None, text_shadow=(0, 0, 0, 1), text_scale=0.08, pos=(0.2, 0, 0.35), parent=base.a2dBottomLeft) self.ammoLabel.hide() self.enableWeaponSwitch() self.resetScroll() self.update() return def deleteGui(self): self.disableWeaponSwitch() for slot in self.slots: slot.destroy() self.slots = [] if self.ammoLabel: self.ammoLabel.destroy() self.ammoLabel = None self.DELETED = True return def resetScroll(self): nextGag = 0 prevGag = -1 curGag = -1 if self.prevSlot: prevGag = self.slots.index(self.prevSlot) if self.activeSlot: curGag = self.slots.index(self.activeSlot) if curGag == len(self.slots) - 1: nextGag = 0 prevGag = curGag - 1 else: if curGag == 0: nextGag = 1 prevGag = len(self.slots) - 1 else: if curGag == -1: prevGag = len(self.slots) - 1 else: nextGag = curGag + 1 prevGag = curGag - 1 self.accept('wheel_down', self.setWeapon, extraArgs=[self.slots[nextGag], True, True]) self.accept('wheel_up', self.setWeapon, extraArgs=[self.slots[prevGag], True, True]) def update(self): if not self.backpack: return for element in [self.ammoLabel, self.inventoryFrame]: if not element: return updateSlots = list(self.slots) for slot in self.slots: gag = slot.getGag() if not gag: updateSlots.remove(slot) slot.hide() continue supply = self.backpack.getSupply(gag.getID()) index = self.slots.index(slot) if not gag and len(self.backpack.getGags()) - 1 >= index: gag = self.backpack.getGagByIndex(index) slot.setGag(gag) if self.backpack.getSupply(gag.getID( )) > 0 and not gag.getState() == GagState.RECHARGING: slot.setOutlineImage('idle') else: slot.setOutlineImage('no_ammo') elif slot == self.activeSlot: self.ammoLabel['text_fg'] = (1, 1, 1, 1) if supply > 0 and not gag.getState() == GagState.RECHARGING: slot.setOutlineImage('selected') else: if supply <= 0: self.ammoLabel['text_fg'] = (0.9, 0, 0, 1) slot.setOutlineImage('no_ammo') self.activeSlot = None self.ammoLabel.show() self.ammoLabel['text'] = 'Ammo: %s' % self.backpack.getSupply( slot.getGag().getID()) elif self.backpack.getSupply(slot.getGag().getID( )) > 0 and not gag.getState() == GagState.RECHARGING: slot.setOutlineImage('idle') else: slot.setOutlineImage('no_ammo') numSlots = len(updateSlots) posGroup = { 1: self.oneSlotPos, 2: self.twoSlotsPos, 3: self.threeSlotsPos, 4: self.fourSlotPos }.get(numSlots) for i in xrange(len(updateSlots)): updateSlots[i].setPos(posGroup[i]) updateSlots[i].show() if self.activeSlot == None: self.ammoLabel.hide() self.ammoLabel['text'] = 'Ammo: 0' self.resetScroll() return def setBackpack(self, backpack): self.backpack = backpack def updateLoadout(self): if self.backpack: loadout = self.backpack.getLoadout() if len(loadout) <= 3: self.reseatSlots() else: if len(loadout) == 4: self.reseatSlots(slots=4) for i in range(len(self.slots)): slot = self.slots[i] if i < len(loadout): slot.setGag(loadout[i]) else: slot.setGag(None) self.update() return def reseatSlots(self, slots=3): for slot in range(len(self.slots) - 1): if slots == 4: self.slots[slot].setPos(self.fourSlotPos[slot]) else: self.slots[slot].setPos(self.threeSlotsPos[slot]) def enableWeaponSwitch(self): for index in range(len(self.slots)): self.accept(str(index + 1), self.setWeapon, extraArgs=[self.slots[index], True, True]) def disableWeaponSwitch(self): for key in ['1', '2', '3', '4', 'wheel_down', 'wheel_up']: self.ignore(key) def getSlots(self): return self.slots def getActiveSlot(self): return self.activeSlot def isDeleted(self): return self.DELETED
class Slot(DirectFrame): def __init__(self, baseGui, index, pos, parent): DirectFrame.__init__( self, pos=pos, parent=parent, image=loader.loadTexture('phase_3.5/maps/slot_%s_%s.png' % (str(index), 'idle')), scale=0.15, frameSize=(-1, 1, -1, 1), frameColor=(0, 0, 0, 0), sortOrder=0) self.initialiseoptions(Slot) self.gui = baseGui self.index = index self.hoverObj = None self.gagImage = None self.gag = None self.mouseRlvrSfx = base.loadSfx('phase_3/audio/sfx/GUI_rollover.ogg') self.soundRecharged = base.loadSfx( 'phase_3.5/audio/sfx/tt_s_gui_sbk_cdrSuccess.ogg') self.infoText = OnscreenText(text='No\nAmmo', fg=(1, 0, 0, 1), parent=self, scale=0.5, shadow=(0, 0, 0, 1), align=TextNode.ACenter, pos=(0, 0.1)) self.infoText.setBin('unsorted', 100) self.infoText.hide() self.rechargeBar = DirectWaitBar(value=0, range=100, frameColor=(1, 1, 1, 1), barColor=(0.286, 0.901, 1, 1), relief=DGG.RAISED, borderWidth=(0.04, 0.04), pos=(-1.25, 0, 0), hpr=(0, 0, -90), parent=self, frameSize=(-0.85, 0.85, -0.12, 0.12)) self.rechargeBar.setBin('fixed', 60) self.rechargeBar.hide() self.gagLabel = OnscreenText(text='Birthday Cake', fg=(1, 1, 1, 1), parent=self, scale=0.25, shadow=(0, 0, 0, 1), align=TextNode.ACenter, pos=(0, -0.9), mayChange=1) self.gagLabel.setBin('fixed', 50) self.gagLabel.hide() battleGui = loader.loadModel('phase_3.5/models/gui/battle_gui.bam') arrow = battleGui.find('**/PckMn_BackBtn') arrowRlvr = battleGui.find('**/PckMn_BackBtn_Rlvr') arrowDn = battleGui.find('**/PckMn_BackBtn_Dn') self.leftArrow = DirectButton(geom=(arrow, arrowDn, arrowRlvr, arrow), parent=self, pos=(-0.925, -2.0, -1.02), relief=None, scale=2, command=self.updateLoadout, extraArgs=[0], geom3_color=(0.5, 0.5, 0.5, 1.0)) self.leftArrow.setBin('fixed', 60) self.rightArrow = DirectButton(geom=(arrow, arrowDn, arrowRlvr, arrow), parent=self, pos=(0.925, -2.0, -1.02), hpr=(180, 0, 0), relief=None, scale=2, command=self.updateLoadout, extraArgs=[1], geom3_color=(0.5, 0.5, 0.5, 1.0)) self.rightArrow.setBin('fixed', 60) self.hoverObj = DirectButton(relief=None, parent=self, frameSize=self['frameSize']) self.setBin('transparent', 30) self.setOutlineImage('idle') self.hoverObj.guiItem.setActive(True) self.hoverObj.bind(DGG.WITHIN, self.mouseEntered) self.hoverObj.bind(DGG.WITHOUT, self.mouseExited) self.hoverObj.bind(DGG.B1CLICK, self.gui.click_setWeapon, [self]) return def toggleArrows(self, left, right): if left: self.leftArrow['state'] = DGG.NORMAL else: self.leftArrow['state'] = DGG.DISABLED if right: self.rightArrow['state'] = DGG.NORMAL else: self.rightArrow['state'] = DGG.DISABLED def updateArrows(self): if not self.gag: self.toggleArrows(False, False) else: track = GagGlobals.TrackGagNamesByTrackName.get( GagGlobals.getTrackOfGag(self.gag.getID())) index = None useTrack = [] for name in track: gag = self.gui.backpack.getGagByID( GagGlobals.getIDByName(name)) if gag == self.gag or gag not in self.gui.backpack.getLoadout( ): useTrack.append(name) index = useTrack.index(self.gag.getName()) if index == 0: self.toggleArrows(False, True) else: if index > 0 and index < len(useTrack) - 1: gagId = GagGlobals.getIDByName(useTrack[index + 1]) if not self.gui.backpack.hasGag(gagId): self.toggleArrows(True, False) else: if index == len(useTrack) - 1: self.toggleArrows(True, False) else: self.toggleArrows(True, True) return def updateLoadout(self, forward): if self.gag and self.gag.getState() in [ GagState.RECHARGING, GagState.LOADED ]: track = GagGlobals.TrackGagNamesByTrackName.get( GagGlobals.getTrackOfGag(self.gag.getID())) index = None useTrack = [] for name in track: gag = self.gui.backpack.getGagByID( GagGlobals.getIDByName(name)) if gag == self.gag or gag not in self.gui.backpack.getLoadout( ): useTrack.append(name) index = useTrack.index(self.gag.getName()) if forward == 1: nextGagIndex = index + 1 else: nextGagIndex = index - 1 if nextGagIndex < 0 or nextGagIndex >= len(useTrack): return gagId = GagGlobals.getIDByName(useTrack[nextGagIndex]) loadout = self.gui.backpack.getLoadout() if self.gui.backpack.hasGag(gagId) and self.gag in loadout: self.hideInfoText() if self.gag not in loadout: return loadout[loadout.index( self.gag)] = self.gui.backpack.getGagByID(gagId) self.gui.backpack.setLoadout(loadout) return def showNoAmmo(self): self.infoText['text'] = 'No\nAmmo' self.infoText['scale'] = 0.5 self.infoText['fg'] = (1, 0, 0, 1) self.infoText['pos'] = (0, 0.1) self.infoText.show() if self.gag and self.gag.getState() == GagState.RECHARGING: self.rechargeBar.show() def showRecharging(self): self.infoText['text'] = 'Recharging...' self.infoText['scale'] = 0.315 self.infoText['fg'] = (0.286, 0.901, 1, 1) self.infoText['pos'] = (0, 0) self.infoText.show() self.rechargeBar.show() def __tickRecharge(self): if not self.gag: self.ignoreAll() else: elapsedTime = float(self.gag.getRechargeElapsedTime()) totalTime = float(self.gag.getRechargeTime()) barValue = int( float(elapsedTime / totalTime) * self.rechargeBar['range']) self.rechargeBar['value'] = barValue if barValue == 0: self.gui.setWeapon(self, playSound=False) self.setOutlineImage('no_ammo') self.showRecharging() else: if barValue >= 100: base.playSfx(self.soundRecharged) slotImage = 'idle' if base.localAvatar.getBackpack().getSupply( self.gag.getID()) <= 0: slotImage = 'no_ammo' else: if self.gui.getActiveSlot() == self: slotImage = 'selected' Sequence(Wait(0.5), Func(self.setOutlineImage, slotImage)).start() def hideInfoText(self): self.infoText.hide() self.rechargeBar.hide() def setSlotImage(self, gagImage): if self.gagImage: self.gagImage.destroy() self.gagImage = None self.gagImage = OnscreenImage(image=gagImage, parent=self) self.gagImage.setTransparency(TransparencyAttrib.MAlpha) return def setOutline(self): self.setTransparency(TransparencyAttrib.MAlpha) def setOutlineImage(self, image): phase = 'phase_3.5/maps/' if hasattr(self, '_optionInfo'): self['image'] = loader.loadTexture(phase + 'slot_%s_%s.png' % (str(self.index), image)) self.setOutline() if image != 'no_ammo': if self.gag and base.localAvatar.getBackpack().getSupply( self.gag.getID( )) == 0 or self.gag and self.gag.getState( ) == GagState.RECHARGING: image = 'no_ammo' if image == 'no_ammo': if self.gag and self.gag.getState() == GagState.RECHARGING: self.showRecharging() else: self.showNoAmmo() self.rechargeBar.hide() self.setBin('fixed', 40) if self.gagImage: self.gagImage.setBin('transparent', 30) else: self.hideInfoText() if self.gagImage: self.gagImage.setBin('fixed', 40) self.setBin('transparent', 30) def getOutline(self): return self.outline def mouseEntered(self, cmd): if self.gag: self.gagLabel.show() self.mouseRlvrSfx.play() def mouseExited(self, cmd): self.gagLabel.hide() def setGag(self, gag): if type(gag) == types.IntType: gag = self.gui.backpack.getGagByID(gag) self.ignoreAll() self.gag = gag if gag: self.show() self.setSlotImage(self.gag.getImage()) self.gagLabel['text'] = self.gag.getName() self.accept('%s-Recharge-Tick' % str(self.gag.getID()), self.__tickRecharge) else: self.hide() self.gagLabel['text'] = '' self.updateArrows() def getGag(self): return self.gag
class DraggableWindow(RPObject): """ This is a simple draggable but not resizeable window """ def __init__(self, width=800, height=500, title="Window", parent=None): """ Constructs a new window with the given dimensions and title """ RPObject.__init__(self, "Window-" + title) self._width = width self._height = height self._title = title self._visible = True self._parent = parent if parent else Globals.base.pixel2d self._dragging = False self._drag_offset = Vec2(0) self._pos = Vec2(0) def center_on_screen(self): """ Centers the window on screen """ self._context_scale = 1.0 / self._parent.get_sx() self._context_width = Globals.native_resolution.x * self._context_scale self._context_height = Globals.native_resolution.y * self._context_scale self._set_pos( Vec2((self._context_width - self._width) / 2, (self._context_height - self._height) / 2)) def set_title(self, title): """ Sets the window title """ self._title = title self._window_title.set_text(title) def show(self): """ Shows the window """ self._visible = True self.center_on_screen() self._node.show() def hide(self): """ Hides the window """ self._visible = False self._stop_drag() self._node.hide() def remove(self): """ Removes the window from the scene graph. You should still delete the instance """ self._stop_drag() self._node.remove_node() def _create_components(self): """ Creates the window components """ self._node = self._parent.attach_new_node("Window") self._node.set_pos(self._pos.x, 1, -self._pos.y) border_px = 1 border_frame_size = (-border_px, self._width + border_px, border_px, -self._height - border_px) self._border_frame = DirectFrame(pos=(0, 1, 0), frameSize=border_frame_size, frameColor=(24 / 255.0, 131 / 255.0, 215 / 255.0, 1), parent=self._node, state=DGG.NORMAL) self._background = DirectFrame(pos=(0, 1, 0), frameSize=(0, self._width, 0, -self._height), frameColor=(0.1, 0.1, 0.1, 1.0), parent=self._node) self._title_bar = DirectFrame( pos=(0, 1, 0), frameSize=(0, self._width, 0, -25), # frameColor=(0.058, 0.058, 0.058, 1), frameColor=(1, 1, 1, 1), parent=self._node, state=DGG.NORMAL) self._window_title = Text(parent=self._node, x=8, y=17, text=self._title, size=13, color=Vec3(0.15), may_change=True) self._btn_close = DirectButton(relief=DGG.FLAT, pressEffect=1, pos=(self._width - 22, 1, -12), frameColor=(1.0, 0.2, 0.2, 0.5), parent=self._node, scale=(45 / 2, 1, 24 / 2), image="/$$rp/data/gui/close_window.png") # Init bindings self._btn_close.set_transparency(TransparencyAttrib.M_alpha) self._btn_close.bind(DGG.B1CLICK, self._request_close) self._btn_close.bind(DGG.WITHIN, self._on_close_btn_hover) self._btn_close.bind(DGG.WITHOUT, self._on_close_btn_out) self._title_bar.bind(DGG.B1PRESS, self._start_drag) self._title_bar.bind(DGG.B1RELEASE, self._stop_drag) def _start_drag(self, evt=None): # pylint: disable=unused-argument """ Gets called when the user starts dragging the window """ self._dragging = True self._node.detach_node() self._node.reparent_to(self._parent) Globals.base.taskMgr.add(self._on_tick, "UIWindowDrag", uponDeath=self._stop_drag) self._drag_offset = self._pos - self._get_mouse_pos() def _on_close_btn_hover(self, evt=None): # pylint: disable=unused-argument """ Internal method when the close button got hovered """ self._btn_close["image"] = "/$$rp/data/gui/close_window_hover.png" def _on_close_btn_out(self, evt=None): # pylint: disable=unused-argument """ Internal method when the close button is no longer hovered """ self._btn_close["image"] = "/$$rp/data/gui/close_window.png" def _request_close(self, evt=None): # pylint: disable=unused-argument """ This method gets called when the close button gets clicked """ self.hide() def _stop_drag(self, evt=None): # pylint: disable=unused-argument """ Gets called when the user stops dragging the window """ Globals.base.taskMgr.remove("UIWindowDrag") self._dragging = False def _get_mouse_pos(self): """ Internal helper function to get the mouse position, scaled by the context scale """ mouse_x, mouse_y = (Globals.base.win.get_pointer(0).x, Globals.base.win.get_pointer(0).y) return Vec2(mouse_x, mouse_y) * self._context_scale def _set_pos(self, pos): """ Moves the window to the specified position """ self._pos = pos self._pos.x = max(self._pos.x, -self._width + 100) self._pos.y = max(self._pos.y, 25) self._pos.x = min(self._pos.x, self._context_width - 100) self._pos.y = min(self._pos.y, self._context_height - 50) self._node.set_pos(self._pos.x, 1, -self._pos.y) def _on_tick(self, task): """ Task which updates the window while being dragged """ self._set_pos(self._get_mouse_pos() + self._drag_offset) return task.cont
class DraggableWindow(DebugObject): """ This is a simple draggable but not resizeable window """ def __init__(self, width=800, height=500, title="Window", parent=None): DebugObject.__init__(self, "Window-" + title) self._width = width self._height = height self._title = title self._visible = True self._parent = parent if parent else Globals.base.pixel2d self._context_scale = 1.0 / parent.get_sx() self._context_width = Globals.base.win.get_x_size() * self._context_scale self._context_height = Globals.base.win.get_y_size() * self._context_scale self._pos = Vec2((self._context_width - self._width) / 2, (self._context_height - self._height) / 2) self._dragging = False self._drag_offset = Vec2(0) def set_title(self, title): """ Sets the window title """ self._title = title self._window_title.set_text(title) def show(self): """ Shows the window """ self._visible = True self._node.show() def hide(self): """ Hides the window """ self._visible = False self._stop_drag() self._node.hide() def remove(self): """ Removes the window from the scene graph. You should still delete the instance """ self._stop_drag() self._node.remove_node() def _create_components(self): """ Creates the window components """ self._node = self._parent.attach_new_node("Window") self._node.set_pos(self._pos.x, 1, -self._pos.y) border_px = 1 self._border_frame = DirectFrame( pos=(0, 1, 0), frameSize=(-border_px, self._width + border_px, border_px, -self._height - border_px), frameColor=(0.0, 0.0, 0.0, 1), parent=self._node, state=DGG.NORMAL, ) # self._border_frame.hide() self._background = DirectFrame( pos=(0, 1, 0), frameSize=(0, self._width, 0, -self._height), frameColor=(0.098, 0.098, 0.098, 1), parent=self._node, ) self._title_bar = DirectFrame( pos=(0, 1, 0), frameSize=(0, self._width, 0, -45), frameColor=(0.058, 0.058, 0.058, 1), parent=self._node, state=DGG.NORMAL, ) self._window_title = BetterOnscreenText( parent=self._node, x=12, y=29, text=self._title, size=19, color=Vec3(0.7), may_change=True ) self._btn_close = DirectButton( relief=DGG.FLAT, pressEffect=1, pos=(self._width - 22, 1, -22), frameColor=(0, 0, 0, 0), scale=(20, 1, 20), parent=self._node, image="Data/GUI/CloseWindow.png", ) # Init bindings self._btn_close.set_transparency(TransparencyAttrib.M_alpha) self._btn_close.bind(DGG.B1CLICK, self._request_close) self._btn_close.bind(DGG.WITHIN, self._on_close_btn_hover) self._btn_close.bind(DGG.WITHOUT, self._on_close_btn_out) self._title_bar.bind(DGG.B1PRESS, self._start_drag) self._title_bar.bind(DGG.B1RELEASE, self._stop_drag) def _start_drag(self, evt=None): """ Gets called when the user starts dragging the window """ self._dragging = True self._node.detach_node() self._node.reparent_to(self._parent) Globals.base.taskMgr.add(self._on_tick, "UIWindowDrag", uponDeath=self._stop_drag) self._drag_offset = self._pos - self._get_mouse_pos() def _on_close_btn_hover(self, evt=None): """ Internal method when the close button got hovered """ self._btn_close["frameColor"] = (1.0, 0.2, 0.2, 1.0) def _on_close_btn_out(self, evt=None): """ Internal method when the close button is no longer hovered """ self._btn_close["frameColor"] = (0, 0, 0, 0) def _request_close(self, evt=None): """ This method gets called when the close button gets clicked """ self.hide() def _stop_drag(self, evt=None): """ Gets called when the user stops dragging the window """ Globals.base.taskMgr.remove("UIWindowDrag") self._dragging = False def _get_mouse_pos(self): """ Internal helper function to get the mouse position, scaled by the context scale """ mouse_x, mouse_y = (Globals.base.win.get_pointer(0).x, Globals.base.win.get_pointer(0).y) return Vec2(mouse_x, mouse_y) * self._context_scale def _set_pos(self, pos): """ Moves the window to the specified position """ self._pos = pos self._pos.x = max(self._pos.x, -self._width + 100) self._pos.y = max(self._pos.y, 25) self._pos.x = min(self._pos.x, self._context_width - 100) self._pos.y = min(self._pos.y, self._context_height - 50) self._node.set_pos(self._pos.x, 1, -self._pos.y) def _on_tick(self, task): """ Task which updates the window while being dragged """ self._set_pos(self._get_mouse_pos() + self._drag_offset) return task.cont
class CustomizeScreen(DirectFrame): notify = directNotify.newCategory('CustomizeScreen') def __init__(self, callback, **kw): self._callback = callback geom = loader.loadModel('phase_6/models/gui/ui_frame') optiondefs = (('relief', None, None), ('geom', geom, None), ('geom_scale', 1.5, 1.5), ('text', base.localAvatar.getName(), None), ('text_align', TextNode.ACenter, None), ('text_font', FONT, None), ('text_scale', 0.075, None), ('text_pos', (0, 0.65), None), ('pos', (-0.7, 0, 0.16), None)) self.defineoptions(kw, optiondefs) DirectFrame.__init__(self, aspect2d) self.initialiseoptions(CustomizeScreen) self.genderOptions = None self.genderLabel = None self.speciesOptions = None self.speciesLabel = None self.legOptions = None self.legLabel = None self.torsoOptions = None self.torsoLabel = None self.headOptions = None self.headLabel = None self.muzzleOptions = None self.muzzleLabel = None self.gloveOptions = None self.gloveLabel = None self.headColorOptions = None self.headColorLabel = None self.armColorOptions = None self.armColorLabel = None self.legColorOptions = None self.legColorLabel = None self.shirtColorOptions = None self.shirtColorLabel = None self.bottomsColorOptions = None self.bottomsColorLabel = None self.shirtLabel = None self.shirtEntry = None self.shortsLabel = None self.shortsEntry = None self.doneButton = None geom.removeNode() rotateGeoms = loader.loadModel('phase_6/models/gui/ui_arrow_buttons') leftGeom = (rotateGeoms.find('**/*ArrowLeft*Up'), rotateGeoms.find('**/*ArrowLeft*Down'), rotateGeoms.find('**/*ArrowLeft*Rollover')) rightGeom = (rotateGeoms.find('**/*ArrowRight*Up'), rotateGeoms.find('**/*ArrowRight*Down'), rotateGeoms.find('**/*ArrowRight*Rollover')) self.leftButton = DirectButton(parent=self, relief=None, image=leftGeom, pos=(-0.11, 0, -0.07)) self.rightButton = DirectButton(parent=self, relief=None, image=rightGeom, pos=(0.11, 0, -0.07)) self.leftButton.bind(DGG.B1PRESS, self.__rotateToon, [-3]) self.leftButton.bind(DGG.B1RELEASE, self.__stopRotation) self.rightButton.bind(DGG.B1PRESS, self.__rotateToon, [3]) self.rightButton.bind(DGG.B1RELEASE, self.__stopRotation) rotateGeoms.removeNode() self.toon = None self.dna = None self.pitch = self.attachNewNode('pitch') self.rotate = self.pitch.attachNewNode('rotate') self.scale = self.rotate.attachNewNode('scale') self.pitch.setP(0) self.makeToon() def makeToon(self, dna=None): if self.toon: self.toon.cleanup() self.toon.delete() self.toon.removeNode() self.toon = None self.dna = None if not dna: dna = base.localAvatar.getDNAString() self.toon = Toon.Toon() self.dna = ToonDNA.ToonDNA() self.dna.makeFromNetString(dna) self.toon.setDNA(self.dna) self.toon.getGeomNode().setDepthWrite(1) self.toon.getGeomNode().setDepthTest(1) self.toon.setHpr(180, 0, 0) self.toon.setZ(-0.45) scaleFactor = 0.2 if self.dna.legs == 'l': scaleFactor = 0.19 self.toon.setScale(scaleFactor) self.toon.reparentTo(self.scale) def __rotateToon(self, *args): taskMgr.add(self.__rotateTask, 'toonRotateTask', extraArgs=[args[0]], appendTask=True) def __rotateTask(self, direction, task): if hasattr(self, 'pitch'): self.pitch.setH((self.pitch.getH() % 360) + 0.4 * direction) return task.cont else: return task.done def __stopRotation(self, *args): taskMgr.remove('toonRotateTask') def __selectHead(self, *args): species = name2code.get(args[0].lower()) newDNA = ToonDNA.ToonDNA() newDNA.makeFromNetString(self.dna.makeNetString()) newDNA.updateToonProperties(head=species + self.dna.head[1:]) self.makeToon(newDNA.makeNetString()) def __selectLegs(self, *args): legs = args[0].lower() if legs == 'long': legs = 'l' elif legs == 'medium': legs = 'm' else: legs = 's' newDNA = ToonDNA.ToonDNA() newDNA.makeFromNetString(self.dna.makeNetString()) newDNA.updateToonProperties(legs=legs) self.makeToon(newDNA.makeNetString()) def __selectGloves(self, *args): color = args[0] if color == 'White': index = len(ToonDNA.NumToColor) + 1 else: index = ToonDNA.NumToColor.index(color) newDNA = ToonDNA.ToonDNA() newDNA.makeFromNetString(self.dna.makeNetString()) newDNA.updateToonProperties(gloveColor=index) self.makeToon(newDNA.makeNetString()) def __selectTorso(self, *args): torso = args[0][0].lower() if self.dna.gender == 'f': torso += 'd' else: torso += 's' newDNA = ToonDNA.ToonDNA() newDNA.makeFromNetString(self.dna.makeNetString()) newDNA.updateToonProperties(torso=torso) self.makeToon(newDNA.makeNetString()) def __selectHeadSize(self, *args): size = args[0][0].lower() head = self.dna.head newDNA = ToonDNA.ToonDNA() newDNA.makeFromNetString(self.dna.makeNetString()) newDNA.updateToonProperties(head=head[0] + size + head[2]) self.makeToon(newDNA.makeNetString()) def __selectMuzzleSize(self, *args): size = args[0][0].lower() head = self.dna.head newDNA = ToonDNA.ToonDNA() newDNA.makeFromNetString(self.dna.makeNetString()) newDNA.updateToonProperties(head=head[0] + head[1] + size) if newDNA.head in ToonDNA.toonHeadTypes: self.makeToon(newDNA.makeNetString()) def __selectGender(self, *args): gender = args[0].lower() if gender == 'boy': gender = 'm' else: gender = 'f' newDNA = ToonDNA.ToonDNA() newDNA.makeFromNetString(self.dna.makeNetString()) #newDNA.updateToonProperties(gender=gender) newDNA.updateToonProperties(gender=gender, bottomTexture=0) self.makeToon(newDNA.makeNetString()) def __choseHeadColor(self, *args): color = args[0] if color == 'White': index = len(ToonDNA.NumToColor) + 1 else: index = ToonDNA.NumToColor.index(color) newDNA = ToonDNA.ToonDNA() newDNA.makeFromNetString(self.dna.makeNetString()) newDNA.updateToonProperties(headColor=index) self.makeToon(newDNA.makeNetString()) def __choseArmColor(self, *args): color = args[0] if color == 'White': index = len(ToonDNA.NumToColor) + 1 else: index = ToonDNA.NumToColor.index(color) newDNA = ToonDNA.ToonDNA() newDNA.makeFromNetString(self.dna.makeNetString()) newDNA.updateToonProperties(armColor=index) self.makeToon(newDNA.makeNetString()) def __choseLegColor(self, *args): color = args[0] if color == 'White': index = len(ToonDNA.NumToColor) + 1 else: index = ToonDNA.NumToColor.index(color) newDNA = ToonDNA.ToonDNA() newDNA.makeFromNetString(self.dna.makeNetString()) newDNA.updateToonProperties(legColor=index) self.makeToon(newDNA.makeNetString()) def __choseShirtColor(self, *args): color = args[0] index = ToonDNA.ClothesColorNames.index(color) newDNA = ToonDNA.ToonDNA() newDNA.makeFromNetString(self.dna.makeNetString()) newDNA.updateToonProperties(topTextureColor=index, sleeveTextureColor=index) self.makeToon(newDNA.makeNetString()) def __choseShortsColor(self, *args): color = args[0] index = ToonDNA.ClothesColorNames.index(color) newDNA = ToonDNA.ToonDNA() newDNA.makeFromNetString(self.dna.makeNetString()) newDNA.updateToonProperties(bottomTextureColor=index) self.makeToon(newDNA.makeNetString()) def __changeShirt(self, *args): index = int(args[0]) if index not in range(0, len(ToonDNA.Shirts)): return newDNA = ToonDNA.ToonDNA() newDNA.makeFromNetString(self.dna.makeNetString()) newDNA.updateToonProperties(topTexture=index) self.makeToon(newDNA.makeNetString()) def __changeShorts(self, *args): index = int(args[0]) bottoms = ToonDNA.BoyShorts if self.dna.gender == 'm' else ToonDNA.GirlBottoms if index not in range(0, len(bottoms)): return newDNA = ToonDNA.ToonDNA() newDNA.makeFromNetString(self.dna.makeNetString()) newDNA.updateToonProperties(bottomTexture=index) self.makeToon(newDNA.makeNetString()) def load(self): genders = ['Boy', 'Girl'] gMap = {'m': genders[0], 'f': genders[1]} gIndex = gMap.get(self.dna.gender) self.genderOptions = CustomizeOption(parent=self, command=self.__selectGender, initialitem=gIndex, items=genders, pos=(1.15, 0, 0.7)) self.genderLabel = DirectLabel(parent=self.genderOptions, relief=None, text_font=FONT, text='Gender:', text_scale=0.85, pos=(-2.59, 0, 0)) species = [ 'Bear', 'Cat', 'Dog', 'Duck', 'Horse', 'Monkey', 'Mouse', 'Pig', 'Rabbit' ] sIndex = species.index(code2name.get(self.dna.head[0]).capitalize()) self.speciesOptions = CustomizeOption(parent=self, command=self.__selectHead, initialitem=sIndex, items=species, pos=(1.15, 0, 0.55)) self.speciesLabel = DirectLabel(parent=self.speciesOptions, relief=None, text_font=FONT, text='Species:', text_scale=0.85, pos=(-2.7, 0, 0)) headOptions = ['Short', 'Long'] types = {'s': headOptions[0], 'l': headOptions[1]} hIndex = headOptions.index(types.get(self.dna.head[1])) self.headOptions = CustomizeOption(parent=self, command=self.__selectHeadSize, initialitem=hIndex, items=headOptions, pos=(1.15, 0, 0.4)) self.headLabel = DirectLabel(parent=self.headOptions, relief=None, text_font=FONT, text='Head Size:', text_scale=0.85, pos=(-3.07, 0, 0)) mIndex = headOptions.index(types.get(self.dna.head[2])) self.muzzleOptions = CustomizeOption(parent=self, command=self.__selectMuzzleSize, initialitem=mIndex, items=headOptions, pos=(1.15, 0, 0.25)) self.muzzleLabel = DirectLabel(parent=self.muzzleOptions, relief=None, text_font=FONT, text='Muzzle Size:', text_scale=0.85, pos=(-3.4, 0, 0)) legs = ['Small', 'Medium', 'Long'] legType = {'s': 'Small', 'm': 'Medium', 'l': 'Long'} lIndex = legs.index(legType.get(self.dna.legs)) self.legOptions = CustomizeOption(parent=self, command=self.__selectLegs, initialitem=lIndex, items=legs, pos=(1.15, 0, 0.1)) self.legLabel = DirectLabel(parent=self.legOptions, relief=None, text_font=FONT, text='Leg Length:', text_scale=0.85, pos=(-3.21, 0, 0)) tIndex = legs.index(legType.get(self.dna.torso[0])) self.torsoOptions = CustomizeOption(parent=self, command=self.__selectTorso, initialitem=tIndex, items=legs, pos=(1.15, 0, -0.05)) self.torsoLabel = DirectLabel(parent=self.torsoOptions, relief=None, text_font=FONT, text='Torso Length:', text_scale=0.85, pos=(-3.57, 0, 0)) gloveColor = self.dna.gloveColor length = len(ToonDNA.NumToColor) if gloveColor > length: gloveColor = 0 headColor = self.dna.headColor if headColor > length: headColor = 0 armColor = self.dna.armColor if armColor > length: armColor = 0 legColor = self.dna.legColor if legColor > length: legColor = 0 self.gloveOptions = CustomizeOption(parent=self, command=self.__selectGloves, initialitem=gloveColor, items=ToonDNA.NumToColor, pos=(1.15, 0, -0.2), image_pos=(1.55, 0, 0.15), text_pos=(-0.13, -.1)) self.gloveLabel = DirectLabel(parent=self.gloveOptions, relief=None, text_font=FONT, text='Glove Color:', text_scale=0.85, pos=(-3.35, 0, 0)) self.headColorOptions = CustomizeOption(parent=self, command=self.__choseHeadColor, initialitem=headColor, items=ToonDNA.NumToColor, pos=(1.15, 0, -0.35), image_pos=(1.55, 0, 0.15), text_pos=(-0.13, -.1)) self.headColorLabel = DirectLabel(parent=self.headColorOptions, relief=None, text_font=FONT, text='Head Color:', text_scale=0.85, pos=(-3.27, 0, 0)) self.armColorOptions = CustomizeOption(parent=self, command=self.__choseArmColor, initialitem=armColor, items=ToonDNA.NumToColor, pos=(1.15, 0, -0.5), image_pos=(1.55, 0, 0.15), text_pos=(-0.13, -.1)) self.armColorLabel = DirectLabel(parent=self.armColorOptions, relief=None, text_font=FONT, text='Arm Color:', text_scale=0.85, pos=(-3.074, 0, 0)) self.legColorOptions = CustomizeOption(parent=self, command=self.__choseLegColor, initialitem=legColor, items=ToonDNA.NumToColor, pos=(1.15, 0, -0.65), image_pos=(1.55, 0, 0.15), text_pos=(-0.13, -.1)) self.legColorLabel = DirectLabel(parent=self.legColorOptions, relief=None, text_font=FONT, text='Leg Color:', text_scale=0.85, pos=(-3, 0, 0)) self.shirtColorOptions = CustomizeOption( parent=self, command=self.__choseShirtColor, initialitem=self.dna.topTexColor - 1, items=ToonDNA.ClothesColorNames[1:], pos=(1.15, 0, -0.8), image_pos=(1.55, 0, 0.15), text_pos=(-0.13, -.1)) self.shirtColorLabel = DirectLabel(parent=self.shirtColorOptions, relief=None, text_font=FONT, text='Shirt Color:', text_scale=0.85, pos=(-3, 0, 0)) self.bottomsColorOptions = CustomizeOption( parent=self, command=self.__choseShortsColor, initialitem=self.dna.botTexColor - 1, items=ToonDNA.ClothesColorNames[1:], pos=(1.15, 0, -0.95), image_pos=(1.55, 0, 0.15), text_pos=(-0.13, -.1)) self.bottomsColorLabel = DirectLabel(parent=self.bottomsColorOptions, relief=None, text_font=FONT, text='Shorts Color:', text_scale=0.85, pos=(-3, 0, 0)) self.shirtEntry = DirectEntry(parent=self, relief=DGG.GROOVE, scale=0.08, pos=(1.6, 0, 0.3), borderWidth=(0.05, 0.05), state=DGG.NORMAL, text_font=FONT, frameColor=((1, 1, 1, 1), (1, 1, 1, 1), (0.5, 0.5, 0.5, 0.5)), text_align=TextNode.ALeft, text_scale=0.8, width=3.5, numLines=1, focus=1, backgroundFocus=0, cursorKeys=1, text_fg=(0, 0, 0, 1), suppressMouse=1, autoCapitalize=0, command=self.__changeShirt) self.shirtEntry.enterText(str(self.dna.topTex)) self.shirtLabel = DirectLabel(parent=self.shirtEntry, relief=None, text_font=FONT, text='Shirt:', text_scale=0.85, pos=(1.25, 0, 1.25)) self.shortsEntry = DirectEntry(parent=self, relief=DGG.GROOVE, scale=0.08, pos=(1.6, 0, 0.0), borderWidth=(0.05, 0.05), state=DGG.NORMAL, text_font=FONT, frameColor=((1, 1, 1, 1), (1, 1, 1, 1), (0.5, 0.5, 0.5, 0.5)), text_align=TextNode.ALeft, text_scale=0.8, width=3.5, numLines=1, focus=1, backgroundFocus=0, cursorKeys=1, text_fg=(0, 0, 0, 1), suppressMouse=1, autoCapitalize=0, command=self.__changeShorts) self.shortsEntry.enterText(str(self.dna.botTex)) self.shortsLabel = DirectLabel(parent=self.shortsEntry, relief=None, text_font=FONT, text='Shorts:', text_scale=0.85, pos=(1.25, 0, 1.25)) buttonModels = loader.loadModel('phase_3.5/models/gui/inventory_gui') upButton = buttonModels.find('**//InventoryButtonUp') downButton = buttonModels.find('**/InventoryButtonDown') rolloverButton = buttonModels.find('**/InventoryButtonRollover') self.doneButton = DirectButton(parent=self, text_font=FONT, text='Done', command=self.__handleDone, scale=0.2, image=(upButton, downButton, rolloverButton), relief=None, text_fg=(1, 1, 0.65, 1), pos=(0, 0, -0.94), text_pos=(0, -.23), image_color=(1, 0, 0, 1), image_scale=(20, 1, 15), sortOrder=DGG.GEOM_SORT_INDEX) buttonModels.removeNode() def __handleDone(self): base.localAvatar.b_setDNAString(self.dna.makeNetString()) self.unload() def unload(self): if self.genderLabel: self.genderLabel.destroy() self.genderLabel = None if self.genderOptions: self.genderOptions.destroy() self.genderOptions = None if self.speciesLabel: self.speciesLabel.destroy() self.speciesLabel = None if self.speciesOptions: self.speciesOptions.destroy() self.speciesOptions = None if self.headLabel: self.headLabel.destroy() self.headLabel = None if self.headOptions: self.headOptions.destroy() self.headOptions = None if self.muzzleLabel: self.muzzleLabel.destroy() self.muzzleLabel = None if self.muzzleOptions: self.muzzleOptions.destroy() self.muzzleOptions = None if self.torsoLabel: self.torsoLabel.destroy() self.torsoLabel = None if self.torsoOptions: self.torsoOptions.destroy() self.torsoOptions = None if self.legLabel: self.legLabel.destroy() self.legLabel = None if self.legOptions: self.legOptions.destroy() self.legOptions = None if self.gloveLabel: self.gloveLabel.destroy() self.gloveLabel = None if self.gloveOptions: self.gloveOptions.destroy() self.gloveOptions = None if self.headColorOptions: self.headColorOptions.destroy() self.headColorOptions = None if self.headColorLabel: self.headColorLabel.destroy() self.headColorLabel = None if self.armColorOptions: self.armColorOptions.destroy() self.armColorOptions = None if self.armColorLabel: self.armColorLabel.destroy() self.armColorLabel = None if self.legColorOptions: self.legColorOptions.destroy() self.legColorOptions = None if self.legColorLabel: self.legColorLabel.destroy() self.legColorLabel = None if self.shirtColorLabel: self.shirtColorLabel.destroy() self.shirtColorLabel = None if self.shirtColorOptions: self.shirtColorOptions.destroy() self.shirtColorOptions = None if self.bottomsColorLabel: self.bottomsColorLabel.destroy() self.bottomsColorLabel = None if self.bottomsColorOptions: self.bottomsColorOptions.destroy() self.bottomsColorOptions = None if self.shirtLabel: self.shirtLabel.destroy() self.shirtLabel = None if self.shirtEntry: self.shirtEntry.destroy() self.shirtEntry = None if self.shortsLabel: self.shortsLabel.destroy() self.shortsLabel = None if self.shortsEntry: self.shortsEntry.destroy() self.shortsEntry = None if self.doneButton: self.doneButton.destroy() self.doneButton = None if self.toon: self.toon.cleanup() self.toon.delete() self.toon.removeNode() self.toon = None self.dna = None self._callback(self) self.destroy()
class Menu: def __init__(self, otherProperties, baseClass): self.text_pointers = [] self.keyboard = Controller() self.IsFullScreen = False self.others = otherProperties self.baseClass = baseClass def __del__(self): print('Destructor called') def start(self): self.fullScreenShape = loader.loadModel("models/fullscreen_shape.bam") self.fullScreenShape.reparentTo(render) self.fullScreenShape.setScale(0.25, 0.25, 0.25) self.fullScreenShape.setPos(-1.5, 6, -1) self.fondo = loader.loadModel("models/fondo_menu.bam") self.fondo.reparentTo(render) self.fondo.setScale(0.27, 0.01, 0.32) self.fondo.setPos(0, 7, 0) font = loader.loadFont('./fonts/comic/comic.ttf') self.TextInsertName = OnscreenText(font=font, text='Ingrese su nombre:', pos=(-0.5, 0.02), scale=0.07, fg=(143 / 255, 250 / 255, 2 / 255, 1)) self.TextFullScreen = OnscreenText(font=font, text='Fulscreen:', pos=(-0.99, -0.67), scale=0.04, fg=(143 / 255, 250 / 255, 2 / 255, 1)) self.TextInsertNameInput = DirectEntry(text="", scale=.05, numLines=1, focus=1) self.ButtonInsertName = DirectButton(text=("Insertar nombre"), scale=.05, pos=(0.25, 0, -0.10), command=self.make_player) self.InvisibleButton = DirectButton(text=("*"), scale=.05, pos=(-1, 5, -0.73), command=self.setFullScreen) self.InvisibleButton.bind(WITHIN, command=self.mouseOver) self.fullScreenShape.reparentTo(render) self.fondo.reparentTo(render) self.TextInsertNameInput.show() self.fullScreenShape.show() self.fondo.show() self.TextInsertName.show() self.TextFullScreen.show() self.ButtonInsertName.show() self.InvisibleButton.show() def stop(self): self.fullScreenShape.hide() self.fondo.remove_node() self.TextInsertName.hide() self.TextFullScreen.hide() self.ButtonInsertName.hide() self.InvisibleButton.hide() self.TextInsertNameInput.hide() self.keyboard.press('3') self.keyboard.release('3') self.__del__() def mouseOver(self, argumento): rotation_interval = self.fullScreenShape.hprInterval( 10, Vec3(360, 0, 0)) rotation_interval.start() def setFullScreen(self): props = self.others if (self.IsFullScreen == True): props.fullscreen = False self.IsFullScreen = False else: props.fullscreen = True self.IsFullScreen = True self.baseClass.win.requestProperties(props) def make_player(self): self.player = player.Player(self.TextInsertNameInput.get()) self.player.savefile() self.stop()
def __makeStructureFrameTreeItem(self, elementNP, elementInfo, parentsLevel, z): if elementInfo is None: lbl = DirectLabel(text=elementNP.getName(), text_align=TextNode.ALeft, frameColor=(0, 0, 0, 0), relief=DGG.FLAT, pos=(self.structureFrame["frameSize"][0] + 20 * parentsLevel, 0, z), scale=16, parent=self.structureFrame.getCanvas()) self.maxWidth = max( self.maxWidth, lbl.getX() + lbl.getWidth() * lbl.getScale()[0]) else: margin = 5 shift = 6 if hasattr(elementNP, "getChildren"): if len(elementNP.getChildren()) > 0: # Collapse Button btnC = DirectCheckBox( relief=DGG.FLAT, pos=(self.structureFrame["frameSize"][0] + 20 * parentsLevel - 16 + margin, 0, z + shift), frameSize=(-8, 8, -8, 8), frameColor=(0, 0, 0, 0), command=self.__collapseElement, extraArgs=[elementInfo], image="icons/Collapsed.png" if elementInfo in self.collapsedElements else "icons/Collapse.png", uncheckedImage="icons/Collapse.png", checkedImage="icons/Collapsed.png", image_scale=8, isChecked=elementInfo in self.collapsedElements, parent=self.structureFrame.getCanvas()) btnC.setTransparency(TransparencyAttrib.M_alpha) btnC.bind(DGG.MWDOWN, self.scroll, [0.01]) btnC.bind(DGG.MWUP, self.scroll, [-0.01]) # Element Name btn = DirectButton( frameColor=( VBase4(1, 1, 1, 1), #normal VBase4(0.9, 0.9, 0.9, 1), #click VBase4(0.8, 0.8, 0.8, 1), #hover VBase4(0.5, 0.5, 0.5, 1)), #disabled text=elementInfo.name, text_align=TextNode.ALeft, relief=DGG.FLAT, pos=(self.structureFrame["frameSize"][0] + 20 * parentsLevel, 0, z), scale=16, command=self.__selectElement, extraArgs=[elementInfo], parent=self.structureFrame.getCanvas()) btn.bind(DGG.MWDOWN, self.scroll, [0.01]) btn.bind(DGG.MWUP, self.scroll, [-0.01]) if self.selectedElement is not None and self.selectedElement == elementInfo: btn.setColorScale(1, 1, 0, 1) # Delete Button btnX = DirectButton( relief=DGG.FLAT, pos=(self.structureFrame["frameSize"][0] + 8 + margin + 20 * parentsLevel + btn.getWidth() * btn.getScale()[0], 0, z + shift), frameSize=(-8, 8, -8, 8), frameColor=(0, 0, 0, 0), command=self.__removeElement, extraArgs=[elementInfo], image="icons/DeleteSmall.png", image_scale=8, parent=self.structureFrame.getCanvas()) btnX.setTransparency(TransparencyAttrib.M_multisample) btnX.bind(DGG.MWDOWN, self.scroll, [0.01]) btnX.bind(DGG.MWUP, self.scroll, [-0.01]) # Visibility Button btnV = DirectCheckBox( relief=DGG.FLAT, pos=(self.structureFrame["frameSize"][0] + 8 + margin * 2 + 20 * parentsLevel + btn.getWidth() * btn.getScale()[0] + btnX.getWidth(), 0, z + shift), frameSize=(-8, 8, -8, 8), frameColor=(0, 0, 0, 0), command=self.__toggleElementVisibility, extraArgs=[elementInfo], image="icons/VisibilityOffSmall.png" if elementInfo.element.isHidden() else "icons/VisibilityOnSmall.png", uncheckedImage="icons/VisibilityOffSmall.png", checkedImage="icons/VisibilityOnSmall.png", image_scale=8, isChecked=not elementInfo.element.isHidden(), parent=self.structureFrame.getCanvas()) btnV.setTransparency(TransparencyAttrib.M_multisample) btnV.bind(DGG.MWDOWN, self.scroll, [0.01]) btnV.bind(DGG.MWUP, self.scroll, [-0.01]) self.maxWidth = max(self.maxWidth, btnV.getX() + 8)
class Button: def __init__(self, parent, text="", pos=(0, 0), size=(0.4, 0.2), command=None, extraArgs=[], icon=None, icon_style='solid', disabled=False, anchor=None): parent_path = parent.path if anchor is None else parent.anchors[anchor] #frame = (-size[0] * 0.5, size[0] * 0.5, -size[1] * 0.5, size[1] * 0.5) frame = (-0.15, 0.25 if icon else 0.15, -0.03, 0.08) self.path = DirectButton(parent=parent_path, text_fg=UI_COLOR, relief=None, frameSize=frame, text=text, text_scale=0.09, pos=(pos[0], 0, pos[1]), command=command, extraArgs=extraArgs) #generate_border(self.path, frame) if disabled: self.path['state'] = DGG.DISABLED if icon is not None: self.icon_pivot = self.path.attach_new_node('pivot') self.icon_pivot.set_pos(-0.1, 0, 0.025) font = base.icon_fonts[icon_style] text = OnscreenText(parent=self.icon_pivot, text=icon, fg=(1, 1, 1, 1), font=font, align=core.TextNode.A_center, scale=0.07, pos=(-0.002, -0.025)) else: self.icon_pivot = None self.path.bind('enter-', self.on_focus) self.path.bind('exit-', self.on_blur) self.path.bind('fin-', self.on_focus) self.path.bind('fout-', self.on_blur) self.path.set_shader_off(1) self.path.set_color_scale((1, 1, 1, 0.6)) parent._child_item_added(self.path) def set_text(self, text): self.path['text'] = text def focus(self): self.path.guiItem.set_focus(True) def enable(self): self.path['state'] = DGG.NORMAL def disable(self): self.path['state'] = DGG.DISABLED def on_focus(self, param=None): if self.icon_pivot is not None: self.icon_pivot.hprInterval(0.2, (0, 0, 360), blendType='easeInOut').start() self.path.colorScaleInterval(0.2, (1, 1, 1, 1), blendType='easeInOut').start() self.path.guiItem.set_state(2) def on_blur(self, param=None): if self.icon_pivot is not None: self.icon_pivot.hprInterval(0.2, (0, 0, 0), blendType='easeInOut').start() self.path.colorScaleInterval(0.2, (1, 1, 1, 0.6), blendType='easeInOut').start() self.path.guiItem.set_state(0)
def __init__(self, tooltip, grid): self.tt = tooltip self.grid = grid screenWidthPx = base.getSize()[0] left = screenWidthPx * 0.25 barWidth = screenWidthPx * 0.75 color = ( (0.25, 0.25, 0.25, 1), # Normal (0.35, 0.35, 1, 1), # Click (0.25, 0.25, 1, 1), # Hover (0.1, 0.1, 0.1, 1)) # Disabled # # Toolbar # self.toolBar = DirectBoxSizer(frameColor=(0.25, 0.25, 0.25, 1), frameSize=(0, barWidth, -24, 24), autoUpdateFrameSize=False, pos=(0, 0, 0), parent=base.pixel2d) buttonColor = ( (0.8, 0.8, 0.8, 1), # Normal (0.9, 0.9, 1, 1), # Click (0.8, 0.8, 1, 1), # Hover (0.5, 0.5, 0.5, 1)) # Disabled btn = DirectButton(frameSize=(-24, 24, -24, 24), frameColor=buttonColor, relief=DGG.FLAT, command=base.messenger.send, extraArgs=["newProject"], image="icons/New.png", image_scale=24) btn.setTransparency(TransparencyAttrib.M_multisample) btn.bind(DGG.ENTER, self.tt.show, ["Create New GUI (Ctrl-N)"]) btn.bind(DGG.EXIT, self.tt.hide) self.toolBar.addItem(btn) btn = DirectButton(frameSize=(-24, 24, -24, 24), frameColor=buttonColor, relief=DGG.FLAT, command=base.messenger.send, extraArgs=["saveProject"], image="icons/Save.png", image_scale=24) btn.setTransparency(TransparencyAttrib.M_multisample) btn.bind(DGG.ENTER, self.tt.show, ["Save GUI as gui Project (Ctrl-S)"]) btn.bind(DGG.EXIT, self.tt.hide) self.toolBar.addItem(btn) btn = DirectButton(frameSize=(-24, 24, -24, 24), frameColor=buttonColor, text_scale=0.33, relief=DGG.FLAT, command=base.messenger.send, extraArgs=["exportProject"], image="icons/Export.png", image_scale=24) btn.setTransparency(TransparencyAttrib.M_multisample) btn.bind(DGG.ENTER, self.tt.show, ["Export GUI as python script (Ctrl-E)"]) btn.bind(DGG.EXIT, self.tt.hide) self.toolBar.addItem(btn) btn = DirectButton(frameSize=(-24, 24, -24, 24), frameColor=buttonColor, relief=DGG.FLAT, text_scale=0.33, command=base.messenger.send, extraArgs=["loadProject"], image="icons/Load.png", image_scale=24) btn.setTransparency(TransparencyAttrib.M_multisample) btn.bind(DGG.ENTER, self.tt.show, ["Load GUI project (Ctrl-O)"]) btn.bind(DGG.EXIT, self.tt.hide) self.toolBar.addItem(btn) placeholder = DirectFrame(text="|", frameSize=(-1, 1, -24, 24), pad=(4, 0), frameColor=(0, 0, 0, 1)) self.toolBar.addItem(placeholder) btn = DirectButton(frameSize=(-24, 24, -24, 24), frameColor=buttonColor, relief=DGG.FLAT, text_scale=0.33, command=base.messenger.send, extraArgs=["undo"], image="icons/Undo.png", image_scale=24) btn.setTransparency(TransparencyAttrib.M_multisample) btn.bind(DGG.ENTER, self.tt.show, ["Undo last action (Ctrl-Z)"]) btn.bind(DGG.EXIT, self.tt.hide) self.toolBar.addItem(btn) btn = DirectButton(frameSize=(-24, 24, -24, 24), frameColor=buttonColor, relief=DGG.FLAT, text_scale=0.33, command=base.messenger.send, extraArgs=["redo"], image="icons/Redo.png", image_scale=24) btn.setTransparency(TransparencyAttrib.M_multisample) btn.bind(DGG.ENTER, self.tt.show, ["Redo last action (Ctrl-Y)"]) btn.bind(DGG.EXIT, self.tt.hide) self.toolBar.addItem(btn) btn = DirectButton(frameSize=(-24, 24, -24, 24), frameColor=buttonColor, relief=DGG.FLAT, text_scale=0.33, command=base.messenger.send, extraArgs=["cycleRedo"], image="icons/CycleRedo.png", image_scale=24) btn.setTransparency(TransparencyAttrib.M_multisample) btn.bind(DGG.ENTER, self.tt.show, ["Cycle through redo branches (Ctrl-Shift-Y)"]) btn.bind(DGG.EXIT, self.tt.hide) self.toolBar.addItem(btn) placeholder = DirectFrame(text="|", frameSize=(-1, 1, -24, 24), pad=(4, 0), frameColor=(0, 0, 0, 1)) self.toolBar.addItem(placeholder) btn = DirectButton(frameSize=(-24, 24, -24, 24), frameColor=buttonColor, relief=DGG.FLAT, text_scale=0.33, command=base.messenger.send, extraArgs=["removeElement"], image="icons/Delete.png", image_scale=24) btn.setTransparency(TransparencyAttrib.M_multisample) btn.bind(DGG.ENTER, self.tt.show, ["Delete selected element (Del)"]) btn.bind(DGG.EXIT, self.tt.hide) self.toolBar.addItem(btn) placeholder = DirectFrame(text="|", frameSize=(-1, 1, -24, 24), pad=(4, 0), frameColor=(0, 0, 0, 1)) self.toolBar.addItem(placeholder) self.cb_grid = DirectCheckBox( frameSize=(-24, 24, -24, 24), frameColor=buttonColor, relief=DGG.FLAT, text_scale=12, image="icons/GridOff.png" if self.grid.isHidden() else "icons/GridOn.png", uncheckedImage="icons/GridOff.png", checkedImage="icons/GridOn.png", image_scale=24, isChecked=not self.grid.isHidden(), command=self.toggleGrid) self.cb_grid.setTransparency(TransparencyAttrib.M_multisample) self.cb_grid.bind(DGG.ENTER, self.tt.show, ["Toggle Grid (Ctrl-G)"]) self.cb_grid.bind(DGG.EXIT, self.tt.hide) self.toolBar.addItem(self.cb_grid) self.cb_scale = DirectCheckBox(frameSize=(-24, 24, -24, 24), frameColor=buttonColor, relief=DGG.FLAT, text_scale=12, image="icons/Scale1.png", uncheckedImage="icons/Scale2.png", checkedImage="icons/Scale1.png", image_scale=24, isChecked=True, command=self.toggleVisualEditorParent) self.cb_scale.setTransparency(TransparencyAttrib.M_alpha) self.cb_scale.bind(DGG.ENTER, self.tt.show, ["Toggle editor scale (Aspect/Pixel)"]) self.cb_scale.bind(DGG.EXIT, self.tt.hide) self.toolBar.addItem(self.cb_scale) placeholder = DirectFrame(text="|", frameSize=(-1, 1, -24, 24), pad=(4, 0), frameColor=(0, 0, 0, 1)) self.toolBar.addItem(placeholder) zoomHolder = DirectFrame( frameSize=(-48, 48, -24, 24), #pad=(4, 0), frameColor=(0, 0, 0, 0)) self.toolBar.addItem(zoomHolder) self.zoomSlider = DirectSlider(zoomHolder, scale=(48, 1, 96), pos=(0, 0, 0), range=(0.1, 1.5), command=self.zoomSliderChanged) self.zoomSlider.bind(DGG.ENTER, self.tt.show, ["Zoom"]) self.zoomSlider.bind(DGG.EXIT, self.tt.hide) #self.toolBar.addItem(self.zoomSlider) placeholder = DirectFrame(text="|", frameSize=(-1, 1, -24, 24), pad=(4, 0), frameColor=(0, 0, 0, 1)) self.toolBar.addItem(placeholder) btn = DirectButton(frameSize=(-24, 24, -24, 24), frameColor=buttonColor, relief=DGG.FLAT, text_scale=0.33, command=base.messenger.send, extraArgs=["quitApp"], image="icons/Quit.png", image_scale=24) btn.setTransparency(TransparencyAttrib.M_alpha) btn.bind(DGG.ENTER, self.tt.show, ["Quit Direct GUI Designer (Ctrl-Q)"]) btn.bind(DGG.EXIT, self.tt.hide) self.toolBar.addItem(btn) placeholder = DirectFrame(text="|", frameSize=(-1, 1, -24, 24), pad=(4, 0), frameColor=(0, 0, 0, 1)) self.toolBar.addItem(placeholder) btn = DirectButton(frameSize=(-24, 24, -24, 24), frameColor=buttonColor, relief=DGG.FLAT, text_scale=0.33, command=base.messenger.send, extraArgs=["showHelp"], image="icons/Help.png", image_scale=24) btn.setTransparency(TransparencyAttrib.M_multisample) btn.bind(DGG.ENTER, self.tt.show, ["Show a help Dialog (F1)"]) btn.bind(DGG.EXIT, self.tt.hide) self.toolBar.addItem(btn) btn = DirectButton(frameSize=(-24, 24, -24, 24), frameColor=buttonColor, relief=DGG.FLAT, text_scale=0.33, command=base.messenger.send, extraArgs=["showSettings"], image="icons/Settings.png", image_scale=24) btn.setTransparency(TransparencyAttrib.M_multisample) btn.bind(DGG.ENTER, self.tt.show, ["Show Designer Settings"]) btn.bind(DGG.EXIT, self.tt.hide) self.toolBar.addItem(btn) if not ConfigVariableBool("show-toolbar", True).getValue(): self.toolBar.hide() self.accept("setVisualEditorParent", self.setVisualEditorParent) self.accept("toggleGrid", self.setGrid)
class SaveLoadLabel(NodePath): ''' A data label of save/load scene ''' def __init__(self, command = None, always_enable = False, fileName = None, head = '',extraArgs = None,style = color_themes.ilia_button): self.__exists = False self.__command = command self.__always_enable = always_enable self.__fileName = fileName self.__head = head if not extraArgs: self.__extraArgs = [] else: self.__extraArgs = extraArgs NodePath.__init__(self,'SaveLoadLabel') self.__button = DirectButton(parent = self, command = command, extraArgs = self.__extraArgs, frameSize = (0,1.2,-0.33,0), **style) #In case of interfering with mouse wheel input self.__button.bind(WHEELUP, self.__rethrowEvent, ['wheel_up']) self.__button.bind(WHEELDOWN, self.__rethrowEvent, ['wheel_down']) self.__button.bind(WHEELLEFT, self.__rethrowEvent, ['wheel_left']) self.__button.bind(WHEELRIGHT, self.__rethrowEvent, ['wheel_right']) self.__button.bind(DGG.B2PRESS, self.__rethrowEvent, ['mouse2']) self.__button.bind(DGG.B3PRESS, self.__rethrowEvent, ['mouse3']) self.__text = OnscreenText(parent = self, pos = (0.05, -0.10), align = TextNode.ALeft, **color_themes.system_text) # @UndefinedVariable self.reload() def reload(self): if self.__always_enable: self.__button['state'] = DGG.NORMAL else: self.__button['state'] = DGG.DISABLED datafile = game_settings['save_folder']+ self.__fileName + game_settings['save_type'] infofile = game_settings['save_folder']+ self.__fileName + game_settings['save_infotype'] if exists(datafile) and exists(infofile): infostream = open(game_settings['save_folder']+ self.__fileName + game_settings['save_infotype'],'rb') info = pickle.load(infostream) infostream.close() temp = info.text.splitlines() if temp: text = temp[0] else: text = '' if len(text)>15: text = text[0:13] + '...' self.__text.setText(self.__head+'\n'+info.time.strftime('%Y-%m-%d %H:%M')+'\n'+' '+text) self.__button['state'] = DGG.NORMAL self.__exists = True else: self.__text.setText(self.__head + '\n NO DATA') self.__exists = False def getExists(self): return self.__exists def getFileName(self): return self.__fileName def __rethrowEvent(self,sevent,event): messenger.send(sevent)
class SaveLoadLabel(NodePath): ''' A data label of save/load scene ''' def __init__(self, command=None, always_enable=False, fileName=None, head='', extraArgs=None, style=color_themes.ilia_button): self.__exists = False self.__command = command self.__always_enable = always_enable self.__fileName = fileName self.__head = head if not extraArgs: self.__extraArgs = [] else: self.__extraArgs = extraArgs NodePath.__init__(self, 'SaveLoadLabel') self.__button = DirectButton(parent=self, command=command, extraArgs=self.__extraArgs, frameSize=(0, 1.2, -0.33, 0), **style) #In case of interfering with mouse wheel input self.__button.bind(WHEELUP, self.__rethrowEvent, ['wheel_up']) self.__button.bind(WHEELDOWN, self.__rethrowEvent, ['wheel_down']) self.__button.bind(WHEELLEFT, self.__rethrowEvent, ['wheel_left']) self.__button.bind(WHEELRIGHT, self.__rethrowEvent, ['wheel_right']) self.__button.bind(DGG.B2PRESS, self.__rethrowEvent, ['mouse2']) self.__button.bind(DGG.B3PRESS, self.__rethrowEvent, ['mouse3']) self.__text = OnscreenText( parent=self, pos=(0.05, -0.10), align=TextNode.ALeft, **color_themes.system_text) # @UndefinedVariable self.reload() def reload(self): if self.__always_enable: self.__button['state'] = DGG.NORMAL else: self.__button['state'] = DGG.DISABLED datafile = game_settings[ 'save_folder'] + self.__fileName + game_settings['save_type'] infofile = game_settings[ 'save_folder'] + self.__fileName + game_settings['save_infotype'] if exists(datafile) and exists(infofile): infostream = open( game_settings['save_folder'] + self.__fileName + game_settings['save_infotype'], 'rb') info = pickle.load(infostream) infostream.close() temp = info.text.splitlines() if temp: text = temp[0] else: text = '' if len(text) > 15: text = text[0:13] + '...' self.__text.setText(self.__head + '\n' + info.time.strftime('%Y-%m-%d %H:%M') + '\n' + ' ' + text) self.__button['state'] = DGG.NORMAL self.__exists = True else: self.__text.setText(self.__head + '\n NO DATA') self.__exists = False def getExists(self): return self.__exists def getFileName(self): return self.__fileName def __rethrowEvent(self, sevent, event): messenger.send(sevent)
class DirectFolderBrowser(DirectObject): def __init__(self, command, fileBrowser=False, defaultPath="~", defaultFilename="unnamed.txt", fileExtensions=[], tooltip=None, iconDir=None, parent=None, theme=None): """ A simple file and folder browser command: The command that will be called on closing the browser fileBrowser: If set to True the browser will show files, otherwise it will only show folders defaultPath: The initial path the browser will be set to show defaultFilename: The filename that will be set by default, only usefull if fileBrowser is True fileExtensions: A list of extensions. Only files with those extensions will be shown. Only usefull if fileBrowser is True tooltip: An instance of the Tooltip class to display tooltips for certain parts of the editor iconDir: A directory path that contains replacement images. It must contain all required images which are: File.png Folder.png FolderNew.png FolderShowHidden.png FolderUp.png Reload.png parent: Another DirectGUI element which has pixel2d as root parent. The browser frame is placed centered so a frame for example should have equal sizes in horizontal and vertical directions e.g. frameSize=(-250,250,-200,200) """ self.theme = theme if theme is not None else LightTheme() self.tt = tooltip self.command = command self.showFiles = fileBrowser self.fileExtensions = fileExtensions self.showHidden = False self.parent = parent self.imageOpts = LoaderOptions() self.imageOpts.set_auto_texture_scale(ATS_none) if self.theme.icon_dir is not None: self.iconDir = self.theme.icon_dir elif iconDir is None: fn = Filename.fromOsSpecific(os.path.dirname(__file__)) fn.makeTrueCase() self.iconDir = str(fn) + "/icons" else: self.iconDir = iconDir self.selectedViewType = "Symbol" self.currentPath = os.path.expanduser(defaultPath) if not os.path.exists(self.currentPath): self.currentPath = os.path.expanduser("~") self.previousPath = self.currentPath if self.parent is None: self.parent = base.pixel2d self.screenWidthPx = base.getSize()[0] self.screenHeightPx = base.getSize()[1] self.position = LPoint3f(base.getSize()[0] / 2, 0, -base.getSize()[1] / 2) else: self.screenWidthPx = self.parent.getWidth() self.screenHeightPx = self.parent.getHeight() self.position = LPoint3f(0) self.screenWidthPxHalf = self.screenWidthPx * 0.5 self.screenHeightPxHalf = self.screenHeightPx * 0.5 self.mainFrame = DirectFrame( relief=1, frameSize=(-self.screenWidthPxHalf, self.screenWidthPxHalf, -self.screenHeightPxHalf, self.screenHeightPxHalf), frameColor=self.theme.main_background, pos=self.position, parent=self.parent, state=DGG.NORMAL, ) self.pathRightMargin = 155 # NOTE: Add 28 for each button to the right + 15px margin self.pathEntryWidth = self.screenWidthPx - self.pathRightMargin - 28 # The path entry on top of the window self.pathEntry = DirectEntry( text_fg=self.theme.default_text_color, parent=self.mainFrame, relief=DGG.SUNKEN, frameColor=self.theme.entry_background, pad=(0.2, 0.2), pos=LPoint3f(-self.screenWidthPxHalf + 15, 0, self.screenHeightPxHalf - 25), scale=12, width=self.pathEntryWidth / 12, overflow=True, command=self.entryAccept, initialText=self.currentPath, focusInCommand=base.messenger.send, focusInExtraArgs=["unregisterKeyboardEvents"], focusOutCommand=base.messenger.send, focusOutExtraArgs=["reregisterKeyboardEvents"], ) # ---------------- # CONTROL BUTTONS # ---------------- x = self.screenWidthPxHalf - self.pathRightMargin + 18 # RELOAD self.btnReload = DirectButton( parent=self.mainFrame, relief=1, frameColor=self.theme.icon_button_background, frameSize=(-14, 14, -10, 18), pos=LPoint3f(x, 0, self.screenHeightPxHalf - 25), command=self.folderReload, image=loader.load_texture(f"{self.iconDir}/Reload.png", loaderOptions=self.imageOpts), image_scale=14, image_pos=(0, 0, 4), ) self.btnReload.setTransparency(TransparencyAttrib.M_multisample) if self.tt is not None: self.btnReload.bind(DGG.ENTER, self.tt.show, ["Reload Folder"]) self.btnReload.bind(DGG.EXIT, self.tt.hide) # MOVE UP ONE FOLDER x += 28 self.btnFolderUp = DirectButton( parent=self.mainFrame, relief=1, frameColor=self.theme.icon_button_background, frameSize=(-14, 14, -10, 18), pos=LPoint3f(x, 0, self.screenHeightPxHalf - 25), command=self.folderUp, image=loader.load_texture(f"{self.iconDir}/FolderUp.png", loaderOptions=self.imageOpts), image_scale=14, image_pos=(0, 0, 4), ) self.btnFolderUp.setTransparency(TransparencyAttrib.M_multisample) if self.tt is not None: self.btnFolderUp.bind(DGG.ENTER, self.tt.show, ["Move up one level"]) self.btnFolderUp.bind(DGG.EXIT, self.tt.hide) # CREATE NEW FOLDER x += 28 self.btnFolderNew = DirectButton( parent=self.mainFrame, relief=1, frameColor=self.theme.icon_button_background, frameSize=(-14, 14, -10, 18), pos=LPoint3f(x, 0, self.screenHeightPxHalf - 25), command=self.folderNew, image=loader.load_texture(f"{self.iconDir}/FolderNew.png", loaderOptions=self.imageOpts), image_scale=14, image_pos=(0, 0, 4), ) self.btnFolderNew.setTransparency(TransparencyAttrib.M_multisample) if self.tt is not None: self.btnFolderNew.bind(DGG.ENTER, self.tt.show, ["Create new folder"]) self.btnFolderNew.bind(DGG.EXIT, self.tt.hide) # SHOW HIDDEN FOLDERS x += 28 self.btnFolderShowHidden = DirectButton( parent=self.mainFrame, relief=1, frameColor=self.theme.icon_button_background, frameSize=(-14, 14, -10, 18), pos=LPoint3f(x, 0, self.screenHeightPxHalf - 25), command=self.folderShowHidden, image=loader.load_texture(f"{self.iconDir}/FolderShowHidden.png", loaderOptions=self.imageOpts), image_scale=14, image_pos=(0, 0, 4), ) self.btnFolderShowHidden.setTransparency( TransparencyAttrib.M_multisample) if self.tt is not None: self.btnFolderShowHidden.bind( DGG.ENTER, self.tt.show, ["Show/Hide hidden files and folders"]) self.btnFolderShowHidden.bind(DGG.EXIT, self.tt.hide) # TOGGLE VIEW TYPE x += 28 self.btnViewType = DirectButton( parent=self.mainFrame, relief=1, frameColor=self.theme.icon_button_background, frameSize=(-14, 14, -10, 18), pos=LPoint3f(x, 0, self.screenHeightPxHalf - 25), command=self.toggleViewType, image=loader.load_texture(f"{self.iconDir}/ViewTypeSymbol.png", loaderOptions=self.imageOpts), image_scale=14, image_pos=(0, 0, 4), ) self.btnViewType.setTransparency(TransparencyAttrib.M_multisample) if self.tt is not None: self.btnViewType.bind( DGG.ENTER, self.tt.show, ["Toggle view between Symbols and Detail list"]) self.btnViewType.bind(DGG.EXIT, self.tt.hide) # -------------- # CONTENT FRAME # -------------- color = self.theme.scrollbar_controlls_color self.container = DirectScrolledFrame( relief=DGG.RIDGE, borderWidth=(2, 2), frameColor=self.theme.main_background, frameSize=(-self.screenWidthPxHalf + 10, self.screenWidthPxHalf - 10, -self.screenHeightPxHalf + 50, self.screenHeightPxHalf - 50), canvasSize=(-self.screenWidthPxHalf + 31, self.screenWidthPxHalf - 10, -self.screenHeightPxHalf + 50, self.screenHeightPxHalf - 50), pos=LPoint3f(0, 0, 0), parent=self.mainFrame, scrollBarWidth=20, verticalScroll_scrollSize=20, verticalScroll_thumb_relief=DGG.FLAT, verticalScroll_incButton_relief=DGG.FLAT, verticalScroll_decButton_relief=DGG.FLAT, verticalScroll_thumb_frameColor=color, verticalScroll_incButton_frameColor=color, verticalScroll_decButton_frameColor=color, verticalScroll_frameColor=self.theme.scroll_background, horizontalScroll_thumb_relief=DGG.FLAT, horizontalScroll_incButton_relief=DGG.FLAT, horizontalScroll_decButton_relief=DGG.FLAT, horizontalScroll_thumb_frameColor=color, horizontalScroll_incButton_frameColor=color, horizontalScroll_decButton_frameColor=color, horizontalScroll_frameColor=self.theme.scroll_background, state=DGG.NORMAL, ) self.container.bind(DGG.MWDOWN, self.scroll, [0.01]) self.container.bind(DGG.MWUP, self.scroll, [-0.01]) # ACCEPT BUTTON self.btnOk = DirectButton( parent=self.mainFrame, relief=1, frameColor=self.theme.text_button_background, frameSize=(-45, 45, -6, 14), pos=LPoint3f(self.screenWidthPxHalf - 160, 0, -self.screenHeightPxHalf + 25), text="ok", text_scale=12, text_fg=self.theme.default_text_color, command=command, extraArgs=[1], ) # CANCEL BUTTON self.btnCancel = DirectButton( parent=self.mainFrame, relief=1, frameColor=self.theme.text_button_background, frameSize=(-45, 45, -6, 14), pos=LPoint3f(self.screenWidthPxHalf - 55, 0, -self.screenHeightPxHalf + 25), text="Cancel", text_scale=12, text_fg=self.theme.default_text_color, command=command, extraArgs=[0]) # SELECTED FILE ENTRY FIELD if self.showFiles: self.txtFileName = DirectEntry( text_fg=self.theme.default_text_color, parent=self.mainFrame, relief=DGG.SUNKEN, frameColor=self.theme.entry_background, pad=(0.2, 0.2), pos=LPoint3f(-self.screenWidthPxHalf + 25, 0, -self.screenHeightPxHalf + 25), scale=12, width=200 / 12, overflow=True, command=self.filenameAccept, initialText=defaultFilename, focusInCommand=base.messenger.send, focusInExtraArgs=["unregisterKeyboardEvents"], focusOutCommand=base.messenger.send, focusOutExtraArgs=["reregisterKeyboardEvents"], ) # ------------------ # CREATE NEW FOLDER # ------------------ # FRAME FOR CREATING NEW FOLDER self.newFolderFrame = DirectFrame( parent=self.mainFrame, relief=1, frameSize=(-self.screenWidthPxHalf + 10, self.screenWidthPxHalf - 10, -20, 20), pos=LPoint3f(0, 0, self.screenHeightPxHalf - 55), frameColor=self.theme.popup_frame_background, ) # LABEL FOR NEW FOLDER NAME ENTRY self.txtNewFolderName = DirectLabel( parent=self.newFolderFrame, text="New Folder Name", text_scale=12, text_fg=self.theme.default_text_color, frameColor=(0, 0, 0, 0), text_align=TextNode.ALeft, pos=(-self.screenWidthPxHalf + 15, 0, -3), ) # ENTRY FOR THE NEW FOLDER NAME self.folderName = DirectEntry( text_fg=self.theme.default_text_color, parent=self.newFolderFrame, relief=DGG.SUNKEN, frameColor=self.theme.entry_background, pad=(0.2, 0.2), pos=LPoint3f( -self.screenWidthPxHalf + 25 + self.txtNewFolderName.getWidth(), 0, -4), scale=12, width=((self.screenWidthPxHalf - 25) * 2 - self.txtNewFolderName.getWidth() - 100) / 12, overflow=True, command=self.entryAccept, initialText="New Folder", focusInCommand=base.messenger.send, focusInExtraArgs=["unregisterKeyboardEvents"], focusOutCommand=base.messenger.send, focusOutExtraArgs=["reregisterKeyboardEvents"], ) # ACCEPT BUTTON FOR THE CREATE NEW FOLDER self.btnCreate = DirectButton( parent=self.newFolderFrame, relief=1, frameColor=self.theme.text_button_background, frameSize=(-45, 45, -6, 14), pos=LPoint3f(self.screenWidthPxHalf - 65, 0, -4), text="Create", text_scale=12, text_fg=self.theme.default_text_color, command=self.folderCreate, extraArgs=[0]) # Hide the create new folder frame by default self.newFolderFrame.hide() # --------------- # UPDATE CONTENT # --------------- # Initial loading of the files and folders of the current path self.folderReload() # handle window resizing self.prevScreenSize = base.getSize() if self.parent is base.pixel2d: self.accept("window-event", self.windowEventHandler) def show(self): self.mainFrame.show() if self.parent is None: self.accept("window-event", self.windowEventHandler) def hide(self): self.ignore("window-event") self.mainFrame.hide() def destroy(self): self.ignore("window-event") self.mainFrame.destroy() def scroll(self, scrollStep, event): self.container.verticalScroll.scrollStep(scrollStep) def get(self): if self.showFiles: return os.path.join(self.currentPath, self.txtFileName.get(True)) return self.currentPath def filenameAccept(self, filename): self.command(1) def entryAccept(self, path): self.folderReload() def folderReload(self): for element in self.container.getCanvas().getChildren(): element.removeNode() path = self.pathEntry.get(True) path = os.path.expanduser(path) path = os.path.expandvars(path) if not os.path.exists(path): return self.currentPath = path try: content = os.scandir(path) except PermissionError: base.messenger.send("showWarning", ["Access denied!"]) self.pathEntry.set(self.previousPath) self.currentPath = self.previousPath self.folderReload() return # start position for the folders and files VIEWTYPE[self.selectedViewType](self, content) def folderUp(self): self.previousPath = self.currentPath self.currentPath = os.path.normpath( os.path.join(self.currentPath, "..")) self.pathEntry.set(self.currentPath) self.folderReload() def folderMoveIn(self, path): path = os.path.expanduser(path) path = os.path.expandvars(path) self.previousPath = self.currentPath self.currentPath = path self.pathEntry.set(path) self.folderReload() self.container.verticalScroll["value"] = 0 def folderNew(self): if self.newFolderFrame.isHidden(): self.newFolderFrame.show() else: self.newFolderFrame.hide() def folderShowHidden(self): self.showHidden = not self.showHidden self.folderReload() def toggleViewType(self): if self.selectedViewType == "Symbol": self.selectedViewType = "Detail" self.btnViewType["image"] = loader.load_texture( f"{self.iconDir}/ViewTypeDetail.png", loaderOptions=self.imageOpts) else: self.selectedViewType = "Symbol" self.btnViewType["image"] = loader.load_texture( f"{self.iconDir}/ViewTypeSymbol.png", loaderOptions=self.imageOpts) self.folderReload() def folderCreate(self, path=""): try: os.makedirs( os.path.join(self.currentPath, self.folderName.get(True))) except: base.messenger.send("showWarning", ["Can't create folder"]) self.newFolderFrame.hide() self.folderReload() def windowEventHandler(self, window=None): if window != base.win: # This event isn't about our window. return if window is not None: # window is none if panda3d is not started if self.prevScreenSize == base.getSize(): return self.prevScreenSize = base.getSize() self.screenWidthPx = base.getSize()[0] self.screenWidthPxHalf = self.screenWidthPx * 0.5 self.screenHeightPx = base.getSize()[1] self.screenHeightPxHalf = self.screenHeightPx * 0.5 # reposition and resize all gui elements self.mainFrame.setPos(self.screenWidthPx / 2, 0, -self.screenHeightPx / 2) self.mainFrame["frameSize"] = (-self.screenWidthPxHalf, self.screenWidthPxHalf, -self.screenHeightPxHalf, self.screenHeightPxHalf) self.pathEntryWidth = self.screenWidthPx - self.pathRightMargin - 28 self.pathEntry.setPos( LPoint3f(-self.screenWidthPxHalf + 15, 0, self.screenHeightPxHalf - 25)) self.pathEntry["width"] = self.pathEntryWidth / 12 self.pathEntry.resetFrameSize() # reposition top right icons x = self.screenWidthPxHalf - self.pathRightMargin + 14 self.btnReload.setPos(LPoint3f(x, 0, self.screenHeightPxHalf - 25)) x += 28 self.btnFolderUp.setPos( pos=LPoint3f(x, 0, self.screenHeightPxHalf - 25)) x += 28 self.btnFolderNew.setPos( pos=LPoint3f(x, 0, self.screenHeightPxHalf - 25)) x += 28 self.btnFolderShowHidden.setPos( pos=LPoint3f(x, 0, self.screenHeightPxHalf - 25)) x += 28 self.btnViewType.setPos( pos=LPoint3f(x, 0, self.screenHeightPxHalf - 25)) # resize the browsing area self.container["frameSize"] = (-self.screenWidthPxHalf + 10, self.screenWidthPxHalf - 10, -self.screenHeightPxHalf + 50, self.screenHeightPxHalf - 50) # Note: canvas size of the container will be reset in the # folder Reload call at the end of this function self.btnOk.setPos( LPoint3f(self.screenWidthPxHalf - 160, 0, -self.screenHeightPxHalf + 25)) self.btnCancel.setPos( LPoint3f(self.screenWidthPxHalf - 55, 0, -self.screenHeightPxHalf + 25)) if self.showFiles: self.txtFileName.setPos( LPoint3f(-self.screenWidthPxHalf + 25, 0, -self.screenHeightPxHalf + 25)) self.newFolderFrame.setPos( LPoint3f(0, 0, self.screenHeightPxHalf - 55)) self.newFolderFrame["frameSize"] = (-self.screenWidthPxHalf + 10, self.screenWidthPxHalf - 10, -20, 20) self.txtNewFolderName.setPos(-self.screenWidthPxHalf + 15, 0, -3) self.folderName.setPos( LPoint3f( -self.screenWidthPxHalf + 25 + self.txtNewFolderName.getWidth(), 0, -4)) self.folderName["width"] = ( (self.screenWidthPxHalf - 25) * 2 - self.txtNewFolderName.getWidth() - 100) / 12 self.btnCreate.setPos(LPoint3f(self.screenWidthPxHalf - 65, 0, -4)) self.folderReload()