class connectGUI(): def __init__(self, _client): # Ref self.client = _client # create a host button self.btnConnect = DirectButton( # Scale and position scale=0.25, pos=(0, 0, 0), # Text text="Connect", # Frame # Functionality command=self.connect) # create the IP input field self.txtIP = DirectEntry( # scale and position pos=(0, 0, -.35), scale=0.25, width=9, # Text text="", text_align=TextNode.ACenter, initialText="127.0.0.1", numLines=1, # Functionality command=self.connect, focusInCommand=self.clearText) self.hide() def show(self): self.btnConnect.show() self.txtIP.show() def hide(self): self.btnConnect.hide() self.txtIP.hide() def clearText(self): """Function to clear the text that was previously entered in the IP input field""" self.txtIP.enterText("") #TODO: Do something with the ip def connect(self, ip=None): """Function which will be called by pressing the connect button or hit enter while the focus is on the inut field""" if ip == None: ip = self.txtIP.get(True) if ip != "": if self.client.connectionMgr.connectToServer(ip, 5001): gui = lobbyGUI(self.client) self.client.gui.hide() gui.show() else: return
class ClientPageGui(ThanksPageGui): def __init__(self, mdt, menu): self.ent = None ThanksPageGui.__init__(self, mdt, menu) def build_page(self): menu_gui = self.menu.gui menu_args = self.menu.gui.menu_args txt = OnscreenText(text=_('Client'), pos=(0, .4), **menu_gui.text_args) widgets = [txt] self.ent = DirectEntry(scale=.12, pos=(-.68, 1, .2), entryFont=menu_args.font, width=12, frameColor=menu_args.btn_color, initialText=_('insert the server address')) self.ent.onscreenText['fg'] = menu_args.text_fg btn = DirectButton(text=_('Connect'), pos=(0, 1, -.2), command=self.connect, **menu_gui.btn_args) widgets += [self.ent, btn] map(self.add_widget, widgets) ThanksPageGui.build_page(self) def connect(self): menu_gui = self.menu.gui try: eng.log(self.ent.get()) Client().start(self.mdt.event.process_msg, self.ent.get()) menu_args = self.menu.gui.menu_args self.add_widget( OnscreenText(text=_('Waiting for the server'), scale=.12, pos=(0, -.5), font=menu_gui.font, fg=menu_args.text_fg)) except ClientError: txt = OnscreenText(_('Error'), pos=(0, -.05), fg=(1, 0, 0, 1), scale=.16, font=menu_gui.menu_args.font) eng.do_later(5, txt.destroy)
class Entry(DirectObject): def __init__(self, placeholder, pos, on_enter, focus=False, sort_order=0): """ Object of a simple entry field @param placeholder: text to appear in textbox automatically @type placeholder: string @param pos: where to place the textbox @type pos: (float, float, float) @param on_enter: function to call upon them submitting a response @type on_enter: function @param focus: Should the entry auto-focus? @type focus: bool @param sort_order: Where should Entry display? (Alert is at 1000) @type sort_order: int """ DirectObject.__init__(self) self.accept('mouse1', self.click_out) self.placeholder = placeholder self.on_enter = on_enter self.entry = DirectEntry(initialText=self.placeholder, scale=0.05, focus=focus, focusOutCommand=self.focus_out, focusInCommand=self.focus_in, pos=pos, sortOrder=sort_order) def focus_out(self): if self.entry.get() == "": self.entry.enterText(self.placeholder) else: # they typed Something. # TODO validate self.on_enter(self.entry.get()) def focus_in(self): self.entry.set("") def click_out(self): self.entry.setFocus() def destroy(self): self.entry.destroy() self.ignoreAll()
class NamePicker: def __init__(self): self.instructions = OnscreenText(text='Type your name', scale=0.1, fg=(1, 1, 1, 1), pos=(0, 0.8, 0.8), shadow=(0, 0, 0, 1)) self.nameEntry = DirectEntry(focus=1, initialText='Toon', width=10, scale=0.1, pos=(-0.5, 0.3, 0.3), command=self.confirmNameAndContinue) self.confirmBtn = DirectButton(text='Confirm', scale=0.1, pos=(0, 0.1, 0.1), command=self.confirmNameAndContinue, extraArgs=[self.nameEntry.get()]) def confirmNameAndContinue(self, textEntered): try: self.badName_lbl.remove() del self.badName_lbl except: pass if self.nameEntry.get().isspace() or len(self.nameEntry.get()) <= 0: self.badName_lbl = OnscreenText(text=CIGlobals.InvalidName, scale=0.09, fg=(1, 0, 0, 1), pos=(0, -0.1, -0.1), shadow=(0, 0, 0, 1)) return self.instructions.remove() self.nameEntry.remove() self.confirmBtn.remove() try: self.badName_lbl.remove() except: pass messenger.send('nameConfirmed', [self.nameEntry.get()])
class PlacerToolSpinner(DirectFrame): def __init__(self, parent=render2d, pos=(0.0, 0.0, 0.0), scale=1.0, value=0, callback=None, increment=0.01): DirectFrame.__init__(self, parent, pos=pos, scale=1.0) self.increment = increment self.value = Decimal(value) self.callback = callback self.display = DirectEntry(parent=self, relief=None, initialText="%.2f" % value, scale=1, text_scale=0.055, text_align=TextNode.ACenter, pos=(0.0, 0.0, 0.0), frameColor=(0.8, 0.8, 0.5, 1), borderWidth=(0.1, 0.1), numLines=1, width=6, frameSize=(-0.1, 0.1, -0.1, 0.1), cursorKeys=1) self.display.bind(DGG.TYPE, self.typeCallback) # This allows the text box to handle mouse events self.display.guiItem.setActive(True) gui = loader.loadModel('phase_3/models/gui/tt_m_gui_mat_mainGui.bam') image = (gui.find('**/tt_t_gui_mat_shuffleArrowUp'), gui.find('**/tt_t_gui_mat_shuffleArrowDown'), gui.find('**/tt_t_gui_mat_shuffleArrowUp'), gui.find('**/tt_t_gui_mat_shuffleArrowDisabled')) self.upArrow = DirectButton(self, relief=None, image=image, image_scale=(0.6, 0.6, 0.6), image1_scale=(0.7, 0.7, 0.7), image2_scale=(0.7, 0.7, 0.7), pos=(0.0, 0.0, 0.08), command=self.__handleUpClicked) self.upArrow.setR(90) self.downArrow = DirectButton(self, relief=None, image=image, image_scale=(0.6, 0.6, 0.6), image1_scale=(0.7, 0.7, 0.7), image2_scale=(0.7, 0.7, 0.7), pos=(0.0, 0.0, -0.05), command=self.__handleDownClicked) self.downArrow.setR(-90) def typeCallback(self, e): if self.display is None: return value = self.display.get() value = re.sub("[^0-9\.-]", "", value) if value == '': value = '000.00' elif value == '-': return if '.' not in value: try: value = int(value) except: return else: try: value = '%.2f' % float(value) except: return self.setValue(value) def setValue(self, value): getcontext().prec = 2 self.value = Decimal(value) self.display.enterText('%.2f' % float(value)) if self.callback: self.callback(self.value) def __handleUpClicked(self): getcontext().prec = 2 self.setValue(float(self.value) + float(self.increment)) def __handleDownClicked(self): getcontext().prec = 2 self.setValue(float(self.value) - float(self.increment))
class DeveloperConsole(InteractiveInterpreter, DirectObject): """The name says it all.""" def __init__(self, manager, xml): sys.stdout = PseudoFile(self.writeOut) sys.stderr = PseudoFile(self.writeErr) tpErr = TextProperties() tpErr.setTextColor(1, 0.5, 0.5, 1) TextPropertiesManager.getGlobalPtr().setProperties("err", tpErr) self.manager = manager font = loader.loadFont("cmss12") self.frame = DirectFrame(parent=base.a2dTopCenter, text_align=TextNode.ALeft, text_pos=(-base.getAspectRatio() + TEXT_MARGIN[0], TEXT_MARGIN[1]), text_scale=0.05, text_fg=(1, 1, 1, 1), frameSize=(-2.0, 2.0, -0.5, 0.0), frameColor=(0, 0, 0, 0.5), text='', text_font=font) self.entry = DirectEntry(parent=base.a2dTopLeft, command=self.command, scale=0.05, width=1000.0, pos=(-0.02, 0, -0.48), relief=None, text_pos=(1.5, 0, 0), text_fg=(1, 1, 0.5, 1), rolloverSound=None, clickSound=None, text_font=font) self.otext = OnscreenText(parent=self.entry, scale=1, align=TextNode.ALeft, pos=(1, 0, 0), fg=(1, 1, 0.5, 1), text=':', font=font) self.lines = [''] * 9 self.commands = [] # All previously sent commands self.cscroll = None # Index of currently navigated command, None if current self.command = '' # Currently entered command self.block = '' # Temporarily stores a block of commands self.hide() self.initialized = False def prevCommand(self): if self.hidden: return if len(self.commands) == 0: return if self.cscroll == None: self.cscroll = len(self.commands) self.command = self.entry.get() elif self.cscroll <= 0: return else: self.commands[self.cscroll] = self.entry.get() self.cscroll -= 1 self.entry.set(self.commands[self.cscroll]) self.entry.setCursorPosition(len(self.commands[self.cscroll])) def nextCommand(self): if self.hidden: return if len(self.commands) == 0: return if self.cscroll == None: return self.commands[self.cscroll] = self.entry.get() self.cscroll += 1 if self.cscroll >= len(self.commands): self.cscroll = None self.entry.set(self.command) self.entry.setCursorPosition(len(self.command)) else: self.entry.set(self.commands[self.cscroll]) self.entry.setCursorPosition(len(self.commands[self.cscroll])) def writeOut(self, line, copy=True): if copy: sys.__stdout__.write(line) lines = line.split('\n') firstline = lines.pop(0) self.lines[-1] += firstline self.lines += lines self.frame['text'] = '\n'.join(self.lines[-9:]) def writeErr(self, line, copy=True): if copy: sys.__stderr__.write(line) line = '\1err\1%s\2' % line lines = line.split('\n') firstline = lines.pop(0) self.lines[-1] += firstline self.lines += lines self.frame['text'] = '\n'.join(self.lines[-9:]) def command(self, text): if not self.hidden: self.cscroll = None self.command = '' self.entry.set('') self.entry['focus'] = True self.writeOut(self.otext['text'] + ' ' + text + '\n', False) if text != '' and (len(self.commands) == 0 or self.commands[-1] != text): self.commands.append(text) # Insert plugins into the local namespace locals = __main__.__dict__ locals['manager'] = self.manager for plugin in self.manager.named.keys(): locals[plugin] = self.manager.named[plugin] locals['panda3d'] = panda3d # Run it and print the output. if not self.initialized: InteractiveInterpreter.__init__(self, locals=locals) self.initialized = True try: if self.runsource(self.block + '\n' + text) and text != '': self.otext['text'] = '.' self.block += '\n' + text else: self.otext['text'] = ':' self.block = '' except Exception: # Not just "except", it will also catch SystemExit # Whoops! Print out a traceback. self.writeErr(traceback.format_exc()) def toggle(self): if self.hidden: self.show() else: self.hide() def show(self): self.accept('arrow_up', self.prevCommand) self.accept('arrow_up-repeat', self.prevCommand) self.accept('arrow_down', self.nextCommand) self.accept('arrow_down-repeat', self.nextCommand) self.hidden = False self.entry['focus'] = True self.frame.show() self.entry.show() self.otext.show() def hide(self): self.ignoreAll() self.hidden = True self.entry['focus'] = False self.frame.hide() self.entry.hide() self.otext.hide() def destroy(self): sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ self.ignoreAll() self.frame.destroy() self.entry.destroy() self.otext.destroy()
class DeveloperConsole(InteractiveInterpreter, DirectObject): def __init__(self): sys.stdout = PseudoFile(self.write_out) sys.stderr = PseudoFile(self.write_err) tp_err = TextProperties() tp_err.setTextColor(1, 0.5, 0.5, 1) TextPropertiesManager.getGlobalPtr().setProperties('err', tp_err) font = loader.loadFont('cmss12') self.frame = DirectFrame(parent=base.a2dTopCenter, text_align=TextNode.ALeft, text_pos=(base.a2dLeft + TEXT_MARGIN[0], TEXT_MARGIN[1]), text_scale=0.05, text_fg=(1, 1, 1, 1), frameSize=(-2.0, 2.0, -1, 0.0), frameColor=(0, 0, 0, 0.5), text='', text_font=font, sortOrder=4) self.entry = DirectEntry(parent=base.a2dTopLeft, command=self.command, scale=0.05, width=1000.0, pos=(-0.02, 0, -0.98), relief=None, text_pos=(1.5, 0, 0), text_fg=(1, 1, 0.5, 1), rolloverSound=None, clickSound=None, text_font=font) self.otext = OnscreenText(parent=self.entry, scale=1, align=TextNode.ALeft, pos=(1, 0, 0), fg=(1, 1, 0.5, 1), text=':', font=font) self.lines = [''] * 19 self.commands = [] # All previously sent commands self.cscroll = None # Index of currently navigated command, None if current self.command = '' # Currently entered command self.block = '' # Temporarily stores a block of commands self.hide() self.initialized = False def prev_command(self): if self.hidden: return if len(self.commands) == 0: return if self.cscroll is None: self.cscroll = len(self.commands) self.command = self.entry.get() elif self.cscroll <= 0: return else: self.commands[self.cscroll] = self.entry.get() self.cscroll -= 1 self.entry.set(self.commands[self.cscroll]) self.entry.setCursorPosition(len(self.commands[self.cscroll])) def next_command(self): if self.hidden: return if len(self.commands) == 0: return if self.cscroll is None: return self.commands[self.cscroll] = self.entry.get() self.cscroll += 1 if self.cscroll >= len(self.commands): self.cscroll = None self.entry.set(self.command) self.entry.setCursorPosition(len(self.command)) else: self.entry.set(self.commands[self.cscroll]) self.entry.setCursorPosition(len(self.commands[self.cscroll])) def write_out(self, line, copy=True): if copy: sys.__stdout__.write(line) lines = line.split('\n') firstline = lines.pop(0) self.lines[-1] += firstline self.lines += lines self.frame['text'] = '\n'.join(self.lines[-19:]) def write_err(self, line, copy=True): if copy: sys.__stderr__.write(line) line = '\1err\1%s\2' % line lines = line.split('\n') firstline = lines.pop(0) self.lines[-1] += firstline self.lines += lines self.frame['text'] = '\n'.join(self.lines[-19:]) def command(self, text): if self.hidden: return self.cscroll = None self.command = '' self.entry.set('') self.entry['focus'] = True self.write_out(self.otext['text'] + ' ' + text + '\n', False) if text != '' and (len(self.commands) == 0 or self.commands[-1] != text): self.commands.append(text) if not self.initialized: InteractiveInterpreter.__init__(self) self.initialized = True try: if self.runsource(self.block + '\n' + text) and text != '': self.otext['text'] = '.' self.block += '\n' + text else: self.otext['text'] = ':' self.block = '' except Exception: self.write_err(traceback.format_exc()) def toggle(self): if self.hidden: self.show() else: self.hide() def show(self): self.accept('arrow_up', self.prev_command) self.accept('arrow_up-repeat', self.prev_command) self.accept('arrow_down', self.next_command) self.accept('arrow_down-repeat', self.next_command) self.hidden = False self.entry['focus'] = True self.frame.show() self.entry.show() self.otext.show() def hide(self): self.ignoreAll() self.hidden = True self.entry['focus'] = False self.entry.set(self.entry.get()[:-1]) self.frame.hide() self.entry.hide() self.otext.hide() def destroy(self): sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ self.ignoreAll() self.frame.destroy() self.entry.destroy() self.otext.destroy()
class Pregame(): def __init__(self, showbase): self.showbase = showbase self.ready = False self.background = DirectFrame( frameSize=(-1, 1, -1, 1), frameTexture='media/gui/mainmenu/menu.png', parent=self.showbase.render2d, ) self.title = OnscreenText(text='Lobby!', fg=(1, 1, 1, 1), parent=self.background, pos=(-0.6, 0.1), scale=0.06) self.buttons = [] controlButtons = Vec3(-0.60, 0, -0.79) # Toggle ready p = controlButtons + Vec3(-0.25, 0, 0) self.toggleReadyButton = DirectButton( text='Ready/Unready', pos=p, scale=0.048, relief=DGG.GROOVE, command=self.toggleReady, ) self.buttons.append(self.toggleReadyButton) # Disconnect p = controlButtons + Vec3(0.0, 0.0, 0.0) self.disconnectButton = DirectButton( text='Disconnect', pos=p, scale=0.048, relief=DGG.GROOVE, command=self.disconnect, ) self.buttons.append(self.disconnectButton) # Send message p = controlButtons + Vec3(0.25, 0.0, 0.0) self.sendMessageButton = DirectButton( text='Send Message', pos=p, scale=0.048, relief=DGG.GROOVE, command=self.sendMessage, extraArgs=[''], ) self.buttons.append(self.sendMessageButton) # Message input self.message = DirectEntry( command=self.sendMessage, focusInCommand=self.clearText, frameSize=(-3, 3, -.5, 1), initialText='', parent=self.buttons[2], pos=(0, -0.6, -1.5), text_align=TextNode.ACenter, ) self.showbase.gameData = GameData() self.showbase.users = [] self.hide() def clearText(self): self.message.set('') def reset(self): self.messages = [] self.showbase.users = [] def updateLobby(self, task): temp = self.showbase.client.getData() for package in temp: if len(package) == 2: print 'Received: ', str(package) if package[0] == 'chat': if len(package[1]) == 2: self.messages.append(package[1]) print self.messages elif package[0] == 'client': self.showbase.users.append(User(package[1])) for user in self.showbase.users: print user.name, user.ready print 'all users' elif package[0] == 'ready': for user in self.showbase.users: if user.name == package[1][0]: user.ready = package[1][1] for user in self.showbase.users: print user.name, user.ready print 'all users' elif package[0] == 'disconnect': for user in self.showbase.users: if user.name == package[1]: self.showbase.users.remove(user) for user in self.showbase.users: print user.name, user.ready print 'all users' elif package[0] == 'gamedata': self.showbase.gameData.unpackageData(package[1]) elif package[0] == 'state': print 'state: ', package[1] if package[1] == 'preround': self.showbase.startRound() return task.done return task.again def toggleReady(self): self.ready = not self.ready self.showbase.client.sendData(('ready', self.ready)) def disconnect(self): self.showbase.client.sendData(('disconnect', 'disconnect')) self.showbase.authCon = self.showbase.client self.showbase.returnToMenu() def sendMessage(self, message): if message == '': message = self.message.get() if message != '': self.showbase.client.sendData(('chat', message)) self.message.set('') def hide(self): self.background.hide() self.message.hide() for b in self.buttons: b.hide() self.showbase.taskMgr.remove('Update Lobby') def show(self): self.background.show() self.message.show() for b in self.buttons: b.show() # Add the game loop procedure to the task manager. self.showbase.taskMgr.add(self.updateLobby, 'Update Lobby')
class Pregame(): def __init__(self, showbase): self.showbase = showbase self.ready = False self.background = DirectFrame( frameSize = (-1, 1, -1, 1), frameTexture = 'media/gui/mainmenu/menu.png', parent = self.showbase.render2d, ) self.title = OnscreenText( text = 'Lobby!', fg = (1, 1, 1, 1), parent = self.background, pos = (-0.6, 0.1), scale = 0.06 ) self.buttons = [] controlButtons = Vec3(-0.60, 0, -0.79) # Toggle ready p = controlButtons + Vec3(-0.25, 0, 0) self.toggleReadyButton = DirectButton( text = 'Ready/Unready', pos = p, scale = 0.048, relief = DGG.GROOVE, command = self.toggleReady, ) self.buttons.append(self.toggleReadyButton) # Disconnect p = controlButtons + Vec3(0.0, 0.0, 0.0) self.disconnectButton = DirectButton( text = 'Disconnect', pos = p, scale = 0.048, relief = DGG.GROOVE, command = self.disconnect, ) self.buttons.append(self.disconnectButton) # Send message p = controlButtons + Vec3(0.25, 0.0, 0.0) self.sendMessageButton = DirectButton( text = 'Send Message', pos = p, scale = 0.048, relief = DGG.GROOVE, command = self.sendMessage, extraArgs = [''], ) self.buttons.append(self.sendMessageButton) # Message input self.message = DirectEntry( command = self.sendMessage, focusInCommand = self.clearText, frameSize = (-3, 3, -.5, 1), initialText = '', parent = self.buttons[2], pos = (0, -0.6, -1.5), text_align = TextNode.ACenter, ) self.showbase.gameData = GameData() self.showbase.users = [] self.hide() def clearText(self): self.message.set('') def reset(self): self.messages = [] self.showbase.users = [] def updateLobby(self, task): temp = self.showbase.client.getData() for package in temp: if len(package) == 2: print 'Received: ', str(package) if package[0] == 'chat': if len(package[1]) == 2: self.messages.append(package[1]) print self.messages elif package[0] == 'client': self.showbase.users.append(User(package[1])) for user in self.showbase.users: print user.name, user.ready print 'all users' elif package[0] == 'ready': for user in self.showbase.users: if user.name == package[1][0]: user.ready = package[1][1] for user in self.showbase.users: print user.name, user.ready print 'all users' elif package[0] == 'disconnect': for user in self.showbase.users: if user.name == package[1]: self.showbase.users.remove(user) for user in self.showbase.users: print user.name, user.ready print 'all users' elif package[0] == 'gamedata': self.showbase.gameData.unpackageData(package[1]) elif package[0] == 'state': print 'state: ', package[1] if package[1] == 'preround': self.showbase.startRound() return task.done return task.again def toggleReady(self): self.ready = not self.ready self.showbase.client.sendData(('ready', self.ready)) def disconnect(self): self.showbase.client.sendData(('disconnect', 'disconnect')) self.showbase.authCon = self.showbase.client self.showbase.returnToMenu() def sendMessage(self, message): if message == '': message = self.message.get() if message != '': self.showbase.client.sendData(('chat', message)) self.message.set('') def hide(self): self.background.hide() self.message.hide() for b in self.buttons: b.hide() self.showbase.taskMgr.remove('Update Lobby') def show(self): self.background.show() self.message.show() for b in self.buttons: b.show() # Add the game loop procedure to the task manager. self.showbase.taskMgr.add(self.updateLobby, 'Update Lobby')
class ConsoleWindow(DirectObject.DirectObject): console_output = None gui_key = PANDA3D_CONSOLE_TOGGLE_KEY autocomplete_key = PANDA3D_CONSOLE_AUTOCOMPLETE_KEY autohelp_key = PANDA3D_CONSOLE_AUTOHELP_KEY # change size of text and number of characters on one line # scale of frame (must be small (0.0x) scale = PANDA3D_CONSOLE_SCALE # to define a special font, if loading fails the default font is used # (without warning) font = PANDA3D_CONSOLE_FONT fontWidth = PANDA3D_CONSOLE_FONT_WIDTH # frame position and size (vertical & horizontal) h_pos = PANDA3D_CONSOLE_HORIZONTAL_POS h_size = PANDA3D_CONSOLE_HORIZONTAL_SIZE # v_size + v_pos should not exceed 2.0, else parts of the interface # will not be visible # space above the frame (must be below 2.0, best between 0.0 and 1.0) v_pos = PANDA3D_CONSOLE_VERTICAL_POS # vertical size of the frame (must be at max 2.0, best between 0.5 and 2.0) v_size = PANDA3D_CONSOLE_VERTICAL_SIZE linelength = int((h_size / scale - 5) / fontWidth) textBuffer = list() MAX_BUFFER_LINES = 5000 commandPos = 0 _iconsole = None _commandBuffer = '' logger.debug("max number of characters on a length:", linelength) numlines = int(v_size / scale - 5) defaultTextColor = (0.0, 0.0, 0.0, 1.0) autoCompleteColor = (0.9, 0.9, 0.9, 1.0) consoleFrame = None commandList = [] maxCommandHistory = 10000 textBufferPos = -1 clipboardTextLines = None clipboardTextRaw = None def __init__(self, parent): global base if not logger.isEnabledFor(logging.DEBUG): global CONSOLE_MESSAGE CONSOLE_MESSAGE = ''' ----------------- Ship's Interface version 3.0.9_749 ------------------- Direct Ship Interface Enabled. Please use caution. Irresponsible use of this console may result in the ship's AI refusing access to this interface. type 'help' for basic commands. -------------------------------------------------------------------------''' # change up from parent/IC self.parent = parent localenv = globals() localenv['gameroot'] = self.parent self._iconsole = customConsoleClass(localsEnv=localenv) # line wrapper self.linewrap = textwrap.TextWrapper() self.linewrap.width = self.linelength # calculate window size # left = (self.h_pos) / self.scale # right = (self.h_pos + self.h_size) / self.scale # bottom = (self.v_pos) / self.scale # top = (self.v_pos + self.v_size) /self.scale # panda3d interface self.consoleFrame = DirectFrame(relief=DGG.GROOVE, frameColor=(200, 200, 200, 0.5), scale=self.scale, frameSize=(0, self.h_size / self.scale, 0, self.v_size / self.scale)) self.windowEvent(base.win) fixedWidthFont = None try: # try to load the defined font fixedWidthFont = parent.loader.loadFont(self.font) except Exception: traceback.print_exc() # if font is not valid use default font logger.warn('could not load the defined font %s" % str(self.font') fixedWidthFont = DGG.getDefaultFont() # text lines self._visibleLines = list( OnscreenText(parent=self.consoleFrame, text="", pos=(1, -i + 3 + self.numlines), align=TextNode.ALeft, mayChange=1, scale=1.0, fg=self.defaultTextColor) for i in range(self.numlines)) map(lambda x: x.setFont(fixedWidthFont), self._visibleLines) # text entry line self.consoleEntry = DirectEntry(self.consoleFrame, text="", command=self.submitTrigger, width=self.h_size / self.scale - 2, pos=(1, 0, 1.5), initialText="", numLines=1, focus=1, entryFont=fixedWidthFont) # self.console_output = ConsoleOutput(testme=True) self.echo(CONSOLE_MESSAGE) self.clipboard = pyperclip def windowEvent(self, window): """ This is a special callback. It is called when the panda window is modified. """ wp = window.getProperties() width = wp.getXSize() / float(wp.getYSize()) height = wp.getYSize() / float(wp.getXSize()) if width > height: height = 1.0 else: width = 1.0 # aligned to center consolePos = Vec3(-self.h_size / 2, 0, -self.v_size / 2) # aligned to left bottom # consolePos = Vec3(-width+self.h_pos, 0, -height+self.v_pos) # aligned to right top # consolePos = Vec3(width-self.h_size, 0, height-self.v_size) # set position self.consoleFrame.setPos(consolePos) def submitTrigger(self, cmdtext): # set to last message # clear line self.consoleEntry.enterText('') self.focus() # add text entered to user command list & remove oldest entry self.commandList.append(cmdtext) self.commandPos += 1 self._commandBuffer = '' logger.debug('CP {}'.format(self.commandPos)) # push to interp for text, pre, color in self._iconsole.push(cmdtext): self.echo(text, pre, color) # set up console controls def mapControls(self): hidden = self.consoleFrame.isHidden() self.consoleEntry['focus'] != hidden if hidden: self.ignoreAll() else: self.accept('page_up', self.scroll, [-5]) self.accept('page_up-repeat', self.scroll, [-5]) self.accept('page_down', self.scroll, [5]) self.accept('page_down-repeat', self.scroll, [5]) self.accept('window-event', self.windowEvent) self.accept('arrow_up', self.scrollCmd, [-1]) self.accept('arrow_down', self.scrollCmd, [1]) self.accept(self.gui_key, self.toggleConsole) self.accept('escape', self.toggleConsole) self.accept(self.autocomplete_key, self.autocomplete) self.accept(self.autohelp_key, self.autohelp) # accept v, c and x, where c & x copy's the whole console text # messenger.toggleVerbose() # for osx use ('meta') if sys.platform == 'darwin': self.accept('meta', self.unfocus) self.accept('meta-up', self.focus) self.accept('meta-c', self.copy) self.accept('meta-x', self.cut) self.accept('meta-v', self.paste) # for windows use ('control') if sys.platform == 'win32' or sys.platform == 'linux2': self.accept('control', self.unfocus) self.accept('control-up', self.focus) self.accept('control-c', self.copy) self.accept('control-x', self.cut) self.accept('control-v', self.paste) # toggle the gui console def toggleConsole(self, hide=False): if hide: self.consoleFrame.hide() self.ignoreAll() # express hide, don't call setControls() return if self.consoleFrame.is_hidden(): self.consoleFrame.show() self.parent.setControls(self) else: self.consoleFrame.hide() self.ignoreAll() self.parent.setControls() def scroll(self, step): newpos = self.textBufferPos + step if newpos < 0 or newpos >= len(self.textBuffer): # no... no... I no think so return self.textBufferPos = newpos self.redrawConsole() def redrawConsole(self): windowstart = max(self.textBufferPos - len(self._visibleLines) + 1, 0) windowend = min( len(self._visibleLines) + windowstart, len(self.textBuffer)) logger.debug('windowS: {} WindowE: {}'.format(windowstart, windowend)) for lineNumber, (lineText, color) in \ enumerate(self.textBuffer[ windowstart: windowend]): logger.debug("LN {}, LEN {}".format(lineNumber, len(self.textBuffer))) self._visibleLines[lineNumber].setText(lineText) self._visibleLines[lineNumber]['fg'] = color def scrollCmd(self, step): if not self.commandList: # 0 or null - nothing to scroll return # should we update a temp buffer? if self.commandPos == len(self.commandList): if step > 0: self.consoleEntry.set(self._commandBuffer) return else: tmp = self.consoleEntry.get() if self.commandList[-1] != tmp: self._commandBuffer = tmp self.commandPos += step if self.commandPos >= len(self.commandList): self.commandPos = len(self.commandList) - 1 self.consoleEntry.set(self._commandBuffer) self.consoleEntry.setCursorPosition( len(self.commandList[self.commandPos])) elif self.commandPos < 0: self.commandPos = -1 # No need to change anything, can't go past the beginning return # finally, just set it self.consoleEntry.set(self.commandList[self.commandPos]) self.consoleEntry.setCursorPosition( len(self.commandList[self.commandPos])) def autocomplete(self): currentText = self.consoleEntry.get() currentPos = self.consoleEntry.guiItem.getCursorPosition() newText = self._iconsole.autocomplete(currentText, currentPos) if newText[-1] and newText[-1] != currentText: self.consoleEntry.set(newText[-1]) self.consoleEntry.setCursorPosition(len(newText)) def autohelp(self): currentText = self.consoleEntry.get() currentPos = self.consoleEntry.guiItem.getCursorPosition() self.parent.autohelp(currentText, currentPos) def unfocus(self): self.consoleEntry['focus'] = 0 def focus(self): self.consoleEntry['focus'] = 1 def copy(self): copy = self.consoleEntry.get() pyperclip.copy(copy) def paste(self): oldCursorPos = self.consoleEntry.guiItem.getCursorPosition() self.clipboardTextRaw = pyperclip.paste() # compose new text line oldText = self.consoleEntry.get() newText = oldText[0:oldCursorPos] + self.clipboardTextRaw + oldText[ oldCursorPos:] self.clipboardTextLines = newText.split(os.linesep) for i in range(len(self.clipboardTextLines) - 1): currentLine = self.clipboardTextLines[i] # we only want printable characters currentLine = re.sub( r'[^' + re.escape(string.printable[:95]) + ']', "", currentLine) # set new text and position self.consoleEntry.set(currentLine) self.submitTrigger(currentLine) currentLine = self.clipboardTextLines[-1] currentLine = re.sub(r'[^' + re.escape(string.printable[:95]) + ']', "", currentLine) self.consoleEntry.set(currentLine) self.consoleEntry.setCursorPosition(len(self.consoleEntry.get())) self.focus() def cut(self): pyperclip.copy(self.consoleEntry.get()) self.consoleEntry.enterText('') self.focus() def echo(self, output, pre='*', color=defaultTextColor): if logger.isEnabledFor(logging.DEBUG): logger.debug('output: {}'.format(pprint.pformat(output))) for line in output.split('\n'): fmtline = "{}{}".format(pre, line) logger.debug(fmtline) if len(line) > 0: self.write_to_panel(fmtline, color) def write_to_panel(self, output, color=defaultTextColor): # remove not printable characters (which can be input by console input) output = re.sub(r'[^%s]' % re.escape(string.printable[:95]), "", output) logger.debug('write_to_panel: output="{}"'.format(output)) splitLines = self.linewrap.wrap(output) logger.debug('write_to_panel: splitLines="{}"'.format(splitLines)) for line in splitLines: self.textBuffer.append([line, color]) if len(self.textBuffer) > self.MAX_BUFFER_LINES: self.textBuffer.pop(0) else: self.textBufferPos += 1 self.redrawConsole()
class ColourChannel(DirectObject): __slider_edit_callback: Callable[['ColourChannel', float], None] __entry_edit_callback: Callable[['ColourChannel', float], None] __frame: DirectFrame __label: DirectLabel __slider: DirectSlider __entry: DirectEntry __disable_frame_overlay: DirectButton __enabled: bool def __init__(self, parent: DirectFrame, text: str, value: float, slider_edit_callback: Callable[['ColourChannel', float], None], entry_edit_callback: Callable[['ColourChannel', float], None], mouse1_press_callbacks: List[Callable[[], None]]): self.__frame = DirectFrame(parent=parent) self.__slider_edit_callback = slider_edit_callback self.__entry_edit_callback = entry_edit_callback self.__label = DirectLabel(parent=self.__frame, text=text, text_fg=WHITE, text_bg=WINDOW_BG_COLOUR, pos=(-0.5, 0.0, 0.0), scale=(0.1, 1.0, 0.1)) self.__slider = DirectSlider(parent=self.__frame, orientation=DGG.HORIZONTAL, borderWidth=(0.0, 0.0), frameColor=WIDGET_BG_COLOUR, frameSize=(-1.0, 1.0, -0.4, 0.4), thumb_frameSize=(-0.075, 0.075, -0.2, 0.2), value=value, pos=(0.05, 0.0, 0.0255), scale=(0.45, 1.0, 0.5)) self.__entry_hovered = False mouse1_press_callbacks.append(self.__entry_mouse_click_callback) self.__entry = DirectEntry(parent=self.__frame, frameColor=WIDGET_BG_COLOUR, text_fg=WHITE, initialText=str(value), scale=0.1, width=3, suppressKeys=True, pos=(0.55, 0.0, -0.01105)) self.__entry.bind(DGG.EXIT, self.__entry_exit_callback) self.__entry.bind(DGG.ENTER, self.__entry_enter_callback) self.__entry.bind(DGG.B1PRESS, self.__entry_mouse_click_callback) self.accept("mouse1", self.__entry_mouse_click_callback) self.__disable_frame_overlay = DirectButton(parent=self.__frame, frameColor=TRANSPARENT, borderWidth=(0.0, 0.0), frameSize=(-0.6, 0.9, -0.2, 0.2), suppressMouse=True) self.__disable_frame_overlay.hide() self.__enabled = True self.__set_callbacks() def __entry_exit_callback(self, *discard) -> None: self.__entry_hovered = False def __entry_enter_callback(self, *discard) -> None: self.__entry_hovered = True def __entry_mouse_click_callback(self, *discard) -> None: if self.__entry_hovered: s = self.__entry.get() try: f = float(s) except: return self.__entry_edit_callback(self, f) else: self.__entry['focus'] = False def __unset_callbacks(self): self.__slider['command'] = None self.__entry['command'] = None def __set_callbacks(self): def slider_callback() -> None: self.__slider_edit_callback(self, self.__slider['value']) def entry_callback(s) -> None: try: f = float(s) except: return self.__entry_edit_callback(self, f) self.__slider['command'] = slider_callback self.__entry['command'] = entry_callback @property def frame(self) -> DirectFrame: return self.__frame def update_slider(self, value: float): if not self.__enabled: return self.__unset_callbacks() self.__slider['value'] = value self.__set_callbacks() def update_entry(self, value: float): if not self.__enabled: return self.__unset_callbacks() self.__entry.enterText(f'{value:.3f}') self.__set_callbacks() def update(self, value: float): self.update_slider(value) self.update_entry(value) @property def value(self) -> float: return self.__slider['value'] @property def enabled(self) -> str: return 'enabled' @enabled.setter def enabled(self, enabled: bool) -> None: if self.__enabled == enabled: return self.__enabled = enabled if enabled: self.__disable_frame_overlay.hide() else: self.__disable_frame_overlay.show() @enabled.getter def enabled(self) -> bool: return self.__enabled
class MyApp(ShowBase): def __init__(self): """ Initialize the MyApp class, including defining the GUI objects and layout. Inherits from ShowBase. """ # Because MyApp inherits from ShowBase, ShowBase needs to be initialized also (?) ShowBase.__init__(self) # doesn't disable the mouse, only disables the default setting of the mouse controlling the camera # can't import base and showbase at the same time. showbase is moreimportant right now. #base.disableMouse() # prints the coords of direct gui objects (DGO) when 'P' key is pressed or LMB is clicked self.accept("p", self.getDGOcoords) self.accept("mouse1", self.getDGOcoords) # only catches mouse when clicked on not gui elements >:| # add frmChatBox self.frmChatBox = DirectFrame(frameColor=(0, 255, 0, 1), frameSize=(-0.5, 0.5, -0.25, 0.25), pos=(0, 0, 0)) ### Add some gui objects and parent them to 'frmChatBox'. They move relative to 'frmChatBox', but are positioned relative to aspect2d. WHY?? ### Solution might be to create the frame at 0,0,0 and the DGOs relative to it (currently at 0,0,0) THEN move the frame. ### TODO: get mouse coords on screen to help with sizing DGOs? # add button btnClear = DirectButton(pos=(-0.15,0,-0.95),text = ("Clear", "CLEAR", "Clear", "disabled"), scale=.05, command=self.clearText, parent=self.frmChatBox) # add text entry box self.txtEntry = DirectEntry(text = "",pos=(-0.99,0,-0.95),scale=.05,command=self.setTextBox,initialText="Type Something", numLines = 2, focus=1, parent=self.frmChatBox) # add button btnCommit = DirectButton(pos=(-0.35,0,-0.95),text = ("Commit", "COMMIT", "Commit", "disabled"), scale=.05, command=self.changeText, parent=self.frmChatBox) # define some text to be used in bk_text = "This is my Demo" # add text label, not parented to 'frmChatBox' self.lblLabel = DirectLabel(text = bk_text, pos = (0.95, 0, -0.95), scale = 0.07, text_fg=(1,0.5,0.5,1), text_bg=(0,0,0,1), textMayChange=1) def changeText(self): """ Gets the text from input box "txtEntry" and sets it as the text of label "lblLabel" """ bk_text = self.txtEntry.get() self.lblLabel['text'] = bk_text def setTextBox(self, textEntered): """ Sets the text of label "textObject" to the value passed """ self.textObject['text'] = textEntered def clearText(self): """ Clears the text entry box """ self.txtEntry.enterText('') def getDGOcoords(self): """ Prints the coordinates of DirectGUI objects """ for child in self.frmChatBox.getChildren(): if "Direct" in str(child): print child, " position = ", child.getPos() print child, " scale = ", child.getScale() print "-" * 10
class panda3dIOClass(DirectObject.DirectObject): # set gui key to None if you want to call toggleConsole from outside this class gui_key = PANDA3D_CONSOLE_TOGGLE_KEY autocomplete_key = PANDA3D_CONSOLE_AUTOCOMPLETE_KEY autohelp_key = PANDA3d_CONSOLE_AUTOHELP_KEY # change size of text and number of characters on one line # scale of frame ( must be small (0.0x) scale = PANDA3D_CONSOLE_SCALE # to define a special font, if loading fails the default font is used (without warning) font = PANDA3D_CONSOLE_FONT fontWidth = PANDA3D_CONSOLE_FONT_WIDTH # frame position and size (vertical & horizontal) h_pos = PANDA3D_CONSOLE_HORIZONTAL_POS h_size = PANDA3D_CONSOLE_HORIZONTAL_SIZE # v_size + v_pos should not exceed 2.0, else parts of the interface will not be visible # space above the frame ( must be below 2.0, best between 0.0 and 1.0 ) v_pos = PANDA3D_CONSOLE_VERTICAL_POS # vertical size of the frame ( must be at max 2.0, best between 0.5 and 2.0 ) v_size = PANDA3D_CONSOLE_VERTICAL_SIZE linelength = int((h_size / scale - 5) / fontWidth) print "max number of characters on a length:", linelength numlines = int(v_size / scale - 5) defaultTextColor = (0.0, 0.0, 0.0, 1.0) autoCompleteColor = (0.9, 0.9, 0.9, 1.0) def __init__(self, parent): self.parent = parent # line wrapper self.linewrap = textwrap.TextWrapper() self.linewrap.width = self.linelength # calculate window size left = (self.h_pos) / self.scale right = (self.h_pos + self.h_size) / self.scale bottom = (self.v_pos) / self.scale top = (self.v_pos + self.v_size) / self.scale # panda3d interface self.consoleFrame = DirectFrame( relief=DGG.GROOVE, frameColor=(200, 200, 200, 0.5), scale=self.scale, frameSize=(0, self.h_size / self.scale, 0, self.v_size / self.scale), ) self.windowEvent(base.win) # try to load the defined font fixedWidthFont = loader.loadFont(self.font) # if font is not valid use default font if not fixedWidthFont.isValid(): if self.font is None: print "pandaInteractiveConsole.py :: could not load the defined font %s" % str(self.font) fixedWidthFont = DGG.getDefaultFont() # text entry line self.consoleEntry = DirectEntry( self.consoleFrame, text="", command=self.onEnterPress, width=self.h_size / self.scale - 2, pos=(1, 0, 1.5), initialText="", numLines=1, focus=1, entryFont=fixedWidthFont, ) # output lines self.consoleOutputList = list() for i in xrange(self.numlines): label = OnscreenText( parent=self.consoleFrame, text="", pos=(1, -i + 3 + self.numlines), align=TextNode.ALeft, mayChange=1, scale=1.0, fg=self.defaultTextColor, ) label.setFont(fixedWidthFont) self.consoleOutputList.append(label) # list of the last commands of the user self.userCommandList = list() self.userCommandListLength = 100 for i in xrange(self.userCommandListLength): self.userCommandList.append("") self.userCommandPos = 0 # buffer for data self.textBuffer = list() self.textBufferLength = 1000 for i in xrange(self.textBufferLength): self.textBuffer.append(["", DEFAULT_COLOR]) self.textBufferPos = self.textBufferLength - self.numlines # toggle the window at least once to activate the events self.toggleConsole() self.toggleConsole() self.help() def help(self): # output some info text about this module infoTxt = """ ------ Panda3dConsole ------ - press F10 to toggle it on/off - use the usual copy, cut & paste keys - page_up : scrolls up - page_down : scrolls down - arrow_up : previous command - arrow_down : next command - BUGS : if you paste a to long text, the entry blocks FIX : use cut to remove the whole line""" # for line in infoTxt.split('\n'): # self.write( line, color=DEFAULT_COLOR ) return infoTxt # write a string to the panda3d console def write(self, printString, color=defaultTextColor): # remove not printable characters (which can be input by console input) printString = re.sub(r"[^%s]" % re.escape(string.printable[:95]), "", printString) splitLines = self.linewrap.wrap(printString) for line in splitLines: self.textBuffer.append([line, color]) self.textBuffer.pop(0) self.updateOutput() def updateOutput(self): for lineNumber in xrange(self.numlines): lineText, color = self.textBuffer[lineNumber + self.textBufferPos] self.consoleOutputList[lineNumber].setText(lineText) self.consoleOutputList[lineNumber]["fg"] = color # toggle the gui console def toggleConsole(self): self.consoleFrame.toggleVis() hidden = self.consoleFrame.isHidden() self.consoleEntry["focus"] != hidden if hidden: self.ignoreAll() self.accept(self.gui_key, self.toggleConsole) else: self.ignoreAll() self.accept("page_up", self.scroll, [-5]) self.accept("page_up-repeat", self.scroll, [-5]) self.accept("page_down", self.scroll, [5]) self.accept("page_down-repeat", self.scroll, [5]) self.accept("window-event", self.windowEvent) self.accept("arrow_up", self.scrollCmd, [1]) self.accept("arrow_down", self.scrollCmd, [-1]) self.accept(self.gui_key, self.toggleConsole) self.accept(self.autocomplete_key, self.autocomplete) self.accept(self.autohelp_key, self.autohelp) # accept v, c and x, where c & x copy's the whole console text # messenger.toggleVerbose() # for osx use ('meta') if sys.platform == "darwin": self.accept("meta", self.unfocus) self.accept("meta-up", self.focus) self.accept("meta-c", self.copy) self.accept("meta-x", self.cut) self.accept("meta-v", self.paste) # for windows use ('control') if sys.platform == "win32" or sys.platform == "linux2": self.accept("control", self.unfocus) self.accept("control-up", self.focus) self.accept("control-c", self.copy) self.accept("control-x", self.cut) self.accept("control-v", self.paste) def autocomplete(self): currentText = self.consoleEntry.get() currentPos = self.consoleEntry.guiItem.getCursorPosition() newText = self.parent.autocomplete(currentText, currentPos) if newText != currentText: self.consoleEntry.set(newText) self.consoleEntry.setCursorPosition(len(newText)) def autohelp(self): currentText = self.consoleEntry.get() currentPos = self.consoleEntry.guiItem.getCursorPosition() self.parent.autohelp(currentText, currentPos) def focus(self): self.consoleEntry["focus"] = 1 def unfocus(self): self.consoleEntry["focus"] = 0 def copy(self): copy = self.consoleEntry.get() clipboard.setText(copy) def paste(self): oldCursorPos = self.consoleEntry.guiItem.getCursorPosition() clipboardText = clipboard.getText() # compose new text line oldText = self.consoleEntry.get() newText = oldText[0:oldCursorPos] + clipboardText + oldText[oldCursorPos:] clipboardTextLines = newText.split(os.linesep) for i in xrange(len(clipboardTextLines) - 1): currentLine = clipboardTextLines[i] # we only want printable characters currentLine = re.sub(r"[^" + re.escape(string.printable[:95]) + "]", "", currentLine) # set new text and position self.consoleEntry.set(currentLine) self.onEnterPress(currentLine) currentLine = clipboardTextLines[-1] currentLine = re.sub(r"[^" + re.escape(string.printable[:95]) + "]", "", currentLine) self.consoleEntry.set(currentLine) self.consoleEntry.setCursorPosition(len(self.consoleEntry.get())) self.focus() def cut(self): clipboard.setText(self.consoleEntry.get()) self.consoleEntry.enterText("") self.focus() def scroll(self, step): self.textBufferPos += step self.textBufferPos = min(self.textBufferLength - self.numlines, max(0, self.textBufferPos)) self.updateOutput() def scrollCmd(self, step): oldCmdPos = self.userCommandPos self.userCommandPos += step self.userCommandPos = min(self.userCommandListLength - 1, max(0, self.userCommandPos)) self.userCommandList[oldCmdPos] = self.consoleEntry.get() newCmd = self.userCommandList[self.userCommandPos] self.consoleEntry.set(newCmd) self.consoleEntry.setCursorPosition(len(newCmd)) def onEnterPress(self, textEntered): # set to last message self.textBufferPos = self.textBufferLength - self.numlines # clear line self.consoleEntry.enterText("") self.focus() # add text entered to user command list & remove oldest entry self.userCommandList.insert(1, textEntered) self.userCommandList[0] = "" self.userCommandList.pop(-1) self.userCommandPos = 0 # call our parent self.parent.push(textEntered) def windowEvent(self, window): """ This is a special callback. It is called when the panda window is modified. """ wp = window.getProperties() width = wp.getXSize() / float(wp.getYSize()) height = wp.getYSize() / float(wp.getXSize()) if width > height: height = 1.0 else: width = 1.0 # aligned to center consolePos = Vec3(-self.h_size / 2, 0, -self.v_size / 2) # aligned to left bottom # consolePos = Vec3(-width+self.h_pos, 0, -height+self.v_pos) # aligned to right top # consolePos = Vec3(width-self.h_size, 0, height-self.v_size) # set position self.consoleFrame.setPos(consolePos)
class Login(): def __init__(self, showbase): self.showbase = showbase self.background = DirectFrame( frameSize = (-1, 1, -1, 1), frameTexture = 'media/gui/login/bg.png', parent = self.showbase.render2d, ) ### CONFIG LOADER ### config = ConfigParser.RawConfigParser() config.read('master.cfg') self.LOGIN_IP = config.get('MASTER SERVER CONNECTION', 'masterIp') self.LOGIN_PORT = config.getint('MASTER SERVER CONNECTION', 'masterPort') config = ConfigParser.RawConfigParser() config.read('client.cfg') self.storeUsername = config.getint('USERDATA', 'storeUsername') if self.storeUsername == 1: self.username = config.get('USERDATA', 'username') else: self.username = '' self.storePassword = config.getint('USERDATA', 'storePassword') if self.storePassword == 1: self.password = config.get('USERDATA', 'password') else: self.password = '' ### CONFIG END ### self.loginScreen("Press 'Enter' to login") # draws the login screen self.usernameBox['focus'] = 1 # sets the cursor to the username field by default self.showbase.accept('tab', self.cycleLoginBox) self.showbase.accept('shift-tab', self.cycleLoginBox) # enables the user to cycle through the text fields with the tab key # this is a standard feature on most login forms self.showbase.accept('enter', self.attemptLogin) # submits the login form, or you can just click the Login button # checking variable to stop multiple presses of the button spawn multiple tasks self.requestAttempt = False self.showbase.authCon = Client(self.showbase, self.LOGIN_IP, self.LOGIN_PORT, compress = True) if not self.showbase.authCon.getConnected(): self.updateStatus("Could not connect to the Login server\nOFFLINE MODE") self.showbase.online = False def updateConfig(self): config = ConfigParser.RawConfigParser() config.read('client.cfg') config.set('USERDATA', 'storeUsername', self.usernameStoreBox["indicatorValue"]) config.set('USERDATA', 'storePassword', self.passwordStoreBox["indicatorValue"]) if self.usernameStoreBox["indicatorValue"] == 1: config.set('USERDATA', 'username', self.usernameBox.get()) if self.passwordStoreBox["indicatorValue"] == 1: config.set('USERDATA', 'password', self.passwordBox.get()) with open('client.cfg', 'wb') as configfile: config.write(configfile) def loginScreen(self, statusText): # creates a basic login screen that asks for a username/password boxloc = Vec3(0.0, 0.0, 0.0) # all items in the login form will have a position relative to this # this makes it easier to shift the entire form around once we have # some graphics to display with it without having to change the # positioning of every form element # p is the position of the form element relative to the boxloc # coordinates set above it is changed for every form element p = boxloc + Vec3(-0.22, 0.09, 0.0) self.usernameText = OnscreenText(text = "Username:"******"Username: "******"", pos = p, scale=.04, initialText = self.username, numLines = 1) # Username textbox where you type in your username p = boxloc + Vec3(0.4, 0.0, 0.09) self.usernameStoreBox = DirectCheckButton(text = "Save Username?", pos = p, scale = .04, indicatorValue = self.storeUsername) # Toggle to save/not save your username p = boxloc + Vec3(-0.22, 0.0, 0.0) self.passwordText = OnscreenText(text = "Password:"******"Password: "******"", pos = p, scale = .04, initialText = self.password, numLines = 1, obscured = 1) # Password textbox where you type in your password # Note - obscured = 1 denotes that all text entered will be replaced # with a * like a standard password box p = boxloc + Vec3(0.4, 0.0, 0.0) self.passwordStoreBox = DirectCheckButton(text = "Save Password?", pos = p, scale = .04, indicatorValue = self.storePassword) # Toggle to save/not save your username p = boxloc + Vec3(0, 0, -0.090) self.loginButton = DirectButton(text = "Login", pos = p, scale = 0.048, relief = DGG.GROOVE, command = self.attemptLogin) # The 'Quit' button that will trigger the Quit function # when clicked p = boxloc + Vec3(0.95, 0, -0.9) self.createAccButton = DirectButton(text = "Create Account", scale = 0.050, pos = p, relief = DGG.GROOVE, command = self.attemptCreateAccount) # Made a quick button for adding accounts. Its fugly p = boxloc + Vec3(1.20, 0, -0.9) self.quitButton = DirectButton(text = "Quit", pos = p, scale = 0.048, relief = DGG.GROOVE, command = self.showbase.quit) # The 'Quit' button that will trigger the Quit function # when clicked p = boxloc + Vec3(0, -0.4, 0) self.statusText = OnscreenText(text = statusText, pos = p, scale = 0.043, fg = (1, 0.5, 0, 1), align = TextNode.ACenter) # A simple text object that you can display an error/status messages # to the user def updateStatus(self, statusText): self.statusText.setText(statusText) # all this does is change the status text. def checkBoxes(self): # checks to make sure the user inputed a username and password: # if they didn't it will spit out an error message self.updateStatus("") if self.usernameBox.get() == "": if self.passwordBox.get() == "": self.updateStatus("You must enter a username and password before logging in.") else: self.updateStatus("You must specify a username") self.passwordBox['focus'] = 0 self.usernameBox['focus'] = 1 return False elif self.passwordBox.get() == "": self.updateStatus("You must enter a password") self.usernameBox['focus'] = 0 self.passwordBox['focus'] = 1 return False # if both boxes are filled then return True return True def attemptLogin(self): if self.checkBoxes(): self.showbase.username = self.usernameBox.get() self.updateStatus("Attempting to login...") self.request(self.usernameBox.get(), self.passwordBox.get(), 'client') def attemptCreateAccount(self): if self.checkBoxes(): self.updateStatus("Attempting to create account and login...") self.request(self.usernameBox.get(), self.passwordBox.get(), 'create') def request(self, username, password, request): if not self.requestAttempt: # attempt to connect again if it failed on startup if self.showbase.authCon.getConnected(): self.requestAttempt = True self.loginButton["state"] = DGG.DISABLED self.createAccButton["state"] = DGG.DISABLED self.showbase.authCon.sendData((request, (username, password))) self.showbase.username = username self.showbase.online = True self.showbase.taskMgr.doMethodLater(0.2, self.responseReader, 'Update Login') else: # client not connected to login/auth server so display message self.updateStatus("Offline Mode") self.showbase.username = username self.showbase.online = False self.updateConfig() self.showbase.startMainmenu() def responseReader(self, task): if task.time > 2.5: self.loginButton["state"] = DGG.NORMAL self.createAccButton["state"] = DGG.NORMAL self.updateStatus("Timeout from Login server") return task.done else: temp = self.showbase.authCon.getData() for package in temp: if len(package) == 2: print "Received: " + str(package) print "Connected to login server" if package[0] == 'loginFailed': print "Login failed: ", package[1] if package[1] == 'username': self.updateStatus("Username Doesnt Exist") self.passwordBox.set("") self.usernameBox.set("") self.passwordBox['focus'] = 0 self.usernameBox['focus'] = 1 elif package[1] == 'password': self.updateStatus("Password Incorrect") self.passwordBox.set("") self.usernameBox['focus'] = 0 self.passwordBox['focus'] = 1 elif package[1] == 'logged': self.updateStatus("Username already logged in") self.requestAttempt = False self.loginButton["state"] = DGG.NORMAL self.createAccButton["state"] = DGG.NORMAL return task.done elif package[0] == 'loginValid': print "Login valid: ", package[1] self.updateStatus(package[1]) self.updateConfig() self.showbase.startMainmenu() return task.done elif package[0] == 'createFailed': print "Create failed: ", package[1] if package[1] == 'exists': self.updateStatus("Username Already Exists") self.passwordBox.set("") self.usernameBox.set("") self.passwordBox['focus'] = 0 self.usernameBox['focus'] = 1 self.requestAttempt = False self.loginButton["state"] = DGG.NORMAL self.createAccButton["state"] = DGG.NORMAL return task.done elif package[0] == 'createSuccess': print "Create success", package[1] self.updateStatus("Account Created Successfully") self.requestAttempt = False self.attemptLogin() return task.done return task.cont def cycleLoginBox(self): # function is triggered by the tab key so you can cycle between # the two input fields like on most login screens if self.passwordBox['focus'] == 1: self.passwordBox['focus'] = 0 self.usernameBox['focus'] = 1 elif self.usernameBox['focus'] == 1: self.usernameBox['focus'] = 0 self.passwordBox['focus'] = 1 # IMPORTANT: When you change the focus to one of the text boxes, # you have to unset the focus on the other textbox. If you do not # do this Panda seems to get confused. def hide(self): self.background.destroy() self.usernameText.destroy() self.usernameBox.destroy() self.usernameStoreBox.destroy() self.passwordText.destroy() self.passwordBox.destroy() self.passwordStoreBox.destroy() self.loginButton.destroy() self.quitButton.destroy() self.createAccButton.destroy() self.statusText.destroy() self.showbase.ignore('tab') self.showbase.ignore('shift-tab') self.showbase.ignore('enter')
class FrameAutenticacao(object): ''' FrameAutenticacao ''' def __init__(self, parent = None, **kw): self.__qtd_conexao = 0 self.__frmAuth = DirectFrame( frameColor = (0,0,0,.3), frameSize = (-.5,.5,0,0.45), pos = (0,0,-.1), enableEdit = 1 ) self.__lblLogin = DirectLabel( text = "Login: "******"Senha: ", scale = 0.05, pos = (-0.3, 0, 0.2), frameColor = (0,0,0,0), text_fg = (1,1,1,1) ) self.__etySenha = DirectEntry( scale = 0.05, width = 12, pos = (-.2, 0, 0.2), cursorKeys = 1, obscured = 1, focusInCommand = self.__command_clear_senha) self.__btnEntrar = DirectButton( frameColor = (0,0,0,1), text = "Entrar", scale = 0.06, pos = (0.3, 0, 0.1), text_fg = (1,1,1,1), rolloverSound = None, clickSound = None, command = self.__command_entrar) self.__lblLogin.reparentTo(self.__frmAuth) self.__etyLogin.reparentTo(self.__frmAuth) self.__lblSenha.reparentTo(self.__frmAuth) self.__etySenha.reparentTo(self.__frmAuth) self.__btnEntrar.reparentTo(self.__frmAuth) self.__etyLogin.set("viner") self.__etySenha.set("viner") def __command_clear_senha(self): self.__etySenha.set("") def __command_entrar(self, txt = None): login = self.__etyLogin.get() senha = self.__etySenha.get() valido = True if login == "": addMensagem("O campo Login e obrigatorio !", COR_BRANCO) valido = False if senha == "": addMensagem("O campo Senha e obrigatorio !", COR_BRANCO) valido = False if valido: self.__btnEntrar["state"] = DGG.DISABLED taskMgr.add( self.__task_conectar_servidor, 'ConectarServidor', extraArgs=[login,senha], appendTask=True) #inicia_nova_thread(1, 0, "Conectar Servidor", self.__conectar_servidor, login, senha) def __task_conectar_servidor(self, login, senha, task): if self.__qtd_conexao < TENTATIVAS: if vinerOnline.flg_conectado == vinerOnline.ERROLOGIN: vinerOnline.flg_conectado = vinerOnline.DESCONECT self.__btnEntrar["state"] = DGG.NORMAL self.__qtd_conexao = 0 addMensagem('Login ou senha invalido', COR_VERMELHO) self.__etyLogin.setFocus() elif vinerOnline.flg_conectado == vinerOnline.CONECTADO: #addMensagem("Conectado 12 !!!") #self.destroy() pass else: vinerOnline.conectar_servidor(login, senha) self.__qtd_conexao += 1 taskMgr.doMethodLater( INTERVALO_TENTATIVAS, self.__task_conectar_servidor, 'ConectarServidorLater', extraArgs = [login,senha], appendTask = True) msg = "Tentativa %s/5 - Conectando..." % (self.__qtd_conexao) addMensagem(msg, COR_BRANCO) else: vinerOnline.flg_conectado = vinerOnline.DESCONECT self.__btnEntrar["state"] = DGG.NORMAL self.__qtd_conexao = 0 addMensagem("Servidor nao encontrado", COR_VERMELHO) return task.done def destroy(self): self.__frmAuth.destroy() del self.__lblLogin del self.__etyLogin del self.__lblSenha del self.__etySenha del self.__btnEntrar del self.__frmAuth
class EntyButtonFrame(object): def __init__(self, parent=None, scale=.05, limitText=100, frameSize=(0, 1.3, 0.11, .2), pos=(0, 0, .1)): self.__show = True self.frmMsg = DirectFrame(parent=parent, frameColor=(0, 0, 0, .5), frameSize=frameSize, pos=pos, enableEdit=1) self.etyMsg = DirectEntry(frameColor=(1, 1, 1, .5), scale=scale, width=22, numLines=1, pos=(.02, 0, .14), cursorKeys=1, focus=1, command=self.__command_enviar_msg, focusInCommand=self.__command_clear_msg) self.btnMsgr = DirectButton(frameColor=(0, 0, 0, 1), text="Enviar", scale=scale, pos=(1.21, 0, .14), text_fg=(1, 1, 1, 1), rolloverSound=None, clickSound=None, command=self.__command_enviar_msg) self.etyMsg.reparentTo(self.frmMsg) self.btnMsgr.reparentTo(self.frmMsg) self.hide() def hide(self): self.frmMsg.hide() self.__show = False def show(self): self.frmMsg.show() self.__show = True self.etyMsg.setFocus() def isShowing(self): return self.__show def __command_clear_msg(self): self.etyMsg.set("") def __command_enviar_msg(self, txt=None): msg = self.etyMsg.get() if msg != "": vinerOnline.envia_pacote_server(0, ACAO_SERVER_falar, [msg]) self.__command_clear_msg() self.etyMsg.setFocus() return False
class NamePicker(): """ A UI element that lets the players pick their name. Also has a confirmation element to the right of the entry box. """ def __init__(self, classSelectionMenu): self._classSelectionMenu = classSelectionMenu self._nameEntry = None self._confirmButton = None self._rootFrame = None self._font = loader.loadFont(PIERCEROMAN_FONT) self._draw() def _draw(self): winWidth = base.getAspectRatio() * 2 winHeight = 2 # Draw container: frameHeight = winHeight * NPKR_HEIGHT_PERCENTAGE frameWidth = winWidth * NPKR_WIDTH_PERCENTAGE cFCenterY = -winHeight / 2 + frameHeight / 2 self._rootFrame = DirectFrame( pos=(0, 0, cFCenterY), frameSize=(-frameWidth / 2, frameWidth / 2, -frameHeight / 2, frameHeight / 2), frameTexture=IMG_GRADIENT_1) self._rootFrame.setTransparency(TransparencyAttrib.MAlpha) # Draw Name Entry: entryWidth = self._rootFrame.getWidth() * NPKR_ENTRY_WIDTH_PERCENTAGE entryHeight = self._rootFrame.getHeight() entryCX = -(self._rootFrame.getWidth() - entryWidth) / 2 self._nameEntry = DirectEntry( parent=self._rootFrame, pos=(entryCX, 0, 0), frameSize=(-entryWidth / 2, entryWidth / 2, -entryHeight / 2, entryHeight / 2), frameColor=(0.25, 0.25, 0.25, 1), text_align=TextNode.ACenter, text_font=self._font, text_scale=NPKR_ENTRY_FONT_SIZE, text_pos=NPKR_ENTRY_FONT_OFFSET, initialText=NPKR_ENTRY_INITIAL_TEXT, numLines=1, focusOutCommand=self._syncName, focusInCommand=self._checkPlaceholderText, command=self._syncName, frameTexture=UI_WINDOW) # Draw Confirm Button: confirmWidth = self._rootFrame.getWidth()\ * (1-NPKR_ENTRY_WIDTH_PERCENTAGE) confirmHeight = self._rootFrame.getHeight() confirmCX = (self._rootFrame.getWidth() - confirmWidth) / 2 self._confirmButton = DirectButton( parent=self._rootFrame, pos=(confirmCX, 0, 0), frameSize=(-confirmWidth / 2, confirmWidth / 2, -confirmHeight / 2, confirmHeight / 2), command=self._onConfirmPressed, text_font=self._font, text_scale=NPKR_BUTTON_FONT_SIZE, text_pos=NPKR_BUTTON_FONT_OFFSET, text="Create Character", borderWidth=NPKR_BUTTON_BORDER_WIDTH) def getName(self): return str(self._nameEntry.get()) def _onConfirmPressed(self): """ Reroutes this input to the parent ClassSelectionMenu """ self._classSelectionMenu.createCharacter() def _checkPlaceholderText(self): """ Makes the nameEntry behave more like a real name entry by removing the placeholder text when the player begins to interact. """ # If the text entered is the placeholder text, simply remove it: if self._nameEntry.get() == NPKR_ENTRY_INITIAL_TEXT: self._nameEntry.set("") def _syncName(self, extraArgs=None): """ Syncs name with this game's host/client manager """ self._classSelectionMenu.syncInfo(cName=self.getName()) def close(self): self._rootFrame.destroy() # Destroy ui del self # Destroy this instance
class MainMenu(): def __init__(self, showbase): self.showbase = showbase self.status = OnscreenText(text="", pos=Vec3(0, -0.35, 0), scale=0.05, fg=(1, 0, 0, 1), align=TextNode.ACenter, mayChange=True) self.background = DirectFrame( frameSize=(-1, 1, -1, 1), frameTexture='media/gui/mainmenu/menu.png', parent=self.showbase.render2d, ) self.title = OnscreenText(text='Main Menu', fg=(1, 1, 1, 1), parent=self.background, pos=(-0.6, 0.1), scale=0.06) self.ip = '127.0.0.1' # Should make this write to file... so that the user can save ip's... # yep thats a good idea, there will be a few things i guess that need to be done like this # like settings and keys and whatnot # Buttons self.buttons = [] serverButtons = Vec3(-0.60, 0, -0.79) # Host self.params = ['3', '8'] p = serverButtons + Vec3(-0.25, 0, 0) self.hostButton = DirectButton(text='Host', pos=p, scale=0.048, relief=DGG.GROOVE, command=self.showbase.hostGame, extraArgs=[self.params]) self.buttons.append(self.hostButton) # Join p = serverButtons + Vec3(0.0, 0.0, 0.0) self.joinButton = DirectButton(text='Join', pos=p, scale=0.048, relief=DGG.GROOVE, command=self.joinServer) self.buttons.append(self.joinButton) # Refresh if self.showbase.online: p = serverButtons + Vec3(0.25, 0, 0) self.refreshButton = DirectButton(text="Refresh", pos=p, scale=0.048, relief=DGG.GROOVE, command=self.refreshStart) self.buttons.append(self.refreshButton) self.refreshStart() chatFrameCenter = (0.0, 0.325) chatFrameSize = (2.5, 1.2) self.chat = DirectFrame( frameColor=(0, 0, 0, 1), frameSize=(chatFrameSize[0] / 2, -chatFrameSize[0] / 2, chatFrameSize[1] / 2, -chatFrameSize[1] / 2), pos=(chatFrameCenter[0], 0, chatFrameCenter[1])) channelFrameSize = (chatFrameSize[0] / 4, chatFrameSize[1]) channelFrameCenter = (-chatFrameSize[0] / 2 + channelFrameSize[0] / 2, 0) numItemsVisible = 8 itemHeight = channelFrameSize[1] / (numItemsVisible + 1) self.channels = DirectScrolledList( parent=self.chat, pos=(channelFrameCenter[0], 0, channelFrameCenter[1]), frameSize=(-channelFrameSize[0] / 2, channelFrameSize[0] / 2, channelFrameSize[1] / 2, -channelFrameSize[1] / 2), frameColor=(1, 0, 0, 0.5), numItemsVisible=numItemsVisible, forceHeight=itemHeight, #itemFrame_frameSize = (-channelFrameSize[0] / 2.1, channelFrameSize[0] / 2.1, itemHeight, -channelFrameSize[1] + itemHeight), itemFrame_pos=(0, 0, channelFrameSize[1] / 2 - itemHeight), decButton_pos=(-0.2, 0, channelFrameCenter[1] - channelFrameSize[1] / 2 + itemHeight / 4), decButton_text='Prev', decButton_text_scale=0.05, decButton_borderWidth=(0.005, 0.005), incButton_pos=(0.2, 0, channelFrameCenter[1] - channelFrameSize[1] / 2 + itemHeight / 4), incButton_text='Next', incButton_text_scale=0.05, incButton_borderWidth=(0.005, 0.005), ) b1 = DirectButton(text=("Button1", "click!", "roll", "disabled"), text_scale=0.1, borderWidth=(0.01, 0.01), relief=2) b2 = DirectButton(text=("Button2", "click!", "roll", "disabled"), text_scale=0.1, borderWidth=(0.01, 0.01), relief=2) l1 = DirectLabel(text="Test1", text_scale=0.1) l2 = DirectLabel(text="Test2", text_scale=0.1) l3 = DirectLabel(text="Test3", text_scale=0.1) self.channels.addItem(b1) self.channels.addItem(b2) self.channels.addItem(l1) self.channels.addItem(l2) self.channels.addItem(l3) for fruit in [ 'apple', 'pear', 'banana', 'orange', 'cake', 'chocolate' ]: l = DirectLabel(text=fruit, text_scale=0.1) self.channels.addItem(l) # need to add the chat stuff # i guess have like a chat manager which will hold an array of 'chat_instances' # and the chat manager can sort out which is displayed and which channel the text is sent from/received to # a bit more thinking needs to be done i guess # can discuss sometime (not really that important now :P) # also i guess the layout and shit will need to be sorted (for whoever is doing the designing) # current games list (need to implement this) # it should send a query to the master server to get the current list (just ip's atmo i guess) # options shit aswell needs to be sorted # maybe just an overlay or something # functionality for the host button (popup an overlay that will be able to set options and then 'start_game' button # then should auto connect and go to lobby (will be same as for all clients, except have a couple of different buttons i guess) # close game instead of disconnect, start game instead of ready (greyed until all others are ready), kick button i suppose # once the options are set the 'server_inst' should be started on the local computer (which will broadcast to master server, once host can successfully connect) # then game client will move to pregame state (connect to the server, and wait for others and ready) else: self.entry = DirectEntry( focusInCommand=self.clearText, frameSize=(-3, 3, -.5, 1), initialText=self.ip, parent=self.buttons[0], pos=(0, -0.6, -1.5), text_align=TextNode.ACenter, ) self.hide() def refreshStart(self): self.refreshButton["state"] = DGG.DISABLED if self.showbase.authCon.getConnected(): self.servers = [] self.showbase.authCon.sendData('serverQuery') self.showbase.taskMgr.doMethodLater(0.25, self.queryServers, 'Server Query') def queryServers(self, task): finished = False temp = self.showbase.authCon.getData() for package in temp: if len(package) == 2: # Handle Server Query if package[0] == 'server': self.servers.append(package[1]) print package[1] elif package[0] == 'final': self.refreshButton["state"] = DGG.NORMAL finished = True else: self.showbase.authCon.passData(package) if finished: return task.done return task.cont def joinChat(self): pass # Let the client mini auth with the lobby server(lobby_loop) by "Logging into the chat" # Since everything will be in the main menu? like a main chat window.. something similar to HoN i guess? # When the player opens the Join game by button, a list will be send from the lobby server telling it what games are active. # Then the player picks one and it connects via the host name/ip or whatever. # While this is busy happening the client stays connected to the lobby server. def joinServer(self): if self.showbase.online: self.ip = '127.0.0.1' else: self.ip = self.entry.get() self.status.setText('Attempting to join server @ ' + self.ip + '...') # attempt to connect to the game server self.showbase.client = Client(self.showbase, self.ip, 9099, compress=True) if self.showbase.client.getConnected(): print 'Connected to server, Awaiting authentication...' self.showbase.client.sendData(('username', self.showbase.username)) self.showbase.taskMgr.add(self.authorizationListener, 'Authorization Listener') else: self.status.setText('Could not Connect...') def authorizationListener(self, task): temp = self.showbase.client.getData() auth = False if temp != []: for package in temp: if len(package) == 2: if package[0] == 'auth': print 'Authentication Successful' auth = True elif package[0] == 'fail': self.status.setText( 'Authentication failed on server...') return task.done else: self.showbase.client.passData(package) if auth: self.showbase.startPregame() return task.done return task.again def clearText(self): self.entry.enterText('') def hide(self): self.showbase.taskMgr.remove('Server Query Timeout') self.background.hide() for b in self.buttons: b.hide() self.status.hide() if self.showbase.online: self.chat.hide() self.channels.hide() else: self.entry.hide() def show(self): self.background.show() for b in self.buttons: b.show() self.status.show() if self.showbase.online: self.chat.show() self.channels.show() else: self.entry.show()
class MainMenu(DirectObject): """This class represents the main menu as seen directly after the application has been started""" def __init__(self): # loading music self.menuMusic = loader.loadMusic("music/01Menu.mp3") self.menuMusic.setLoop(True) # create a main frame as big as the window self.frameMain = DirectFrame( # set framesize the same size as the window frameSize = (base.a2dLeft, base.a2dRight, base.a2dTop, base.a2dBottom), # position center pos = (0, 0, 0), # set tramsparent background color frameColor = (0.15, 0.15, 0.15, 1)) #self.frameMain.reparentTo(render2d) self.menuBackground = OnscreenImage( image = 'gui/Background.png', scale = (1.66, 1, 1), pos = (0, 0, 0)) self.menuBackground.reparentTo(self.frameMain) self.defaultBtnMap = base.loader.loadModel("gui/button_map") self.buttonGeom = ( self.defaultBtnMap.find("**/button_ready"), self.defaultBtnMap.find("**/button_click"), self.defaultBtnMap.find("**/button_rollover"), self.defaultBtnMap.find("**/button_disabled")) self.defaultTxtMap = base.loader.loadModel("gui/textbox_map") self.textboxGeom = self.defaultTxtMap.find("**/textbox") monospace = loader.loadFont('gui/DejaVuSansMono.ttf') defaultFont = loader.loadFont('gui/eufm10.ttf') # create the title self.textscale = 0.25 self.title = DirectLabel( # scale and position scale = self.textscale, pos = (0.0, 0.0, base.a2dTop - self.textscale), # frame frameColor = (0, 0, 0, 0), # Text text = "Dungeon Crawler", text_align = TextNode.ACenter, text_fg = (0.82,0.85,0.87,1), text_shadow = (0, 0, 0, 1), text_shadowOffset = (-0.02, -0.02), text_font = defaultFont) self.title.setTransparency(1) self.title.reparentTo(self.frameMain) # create a host button self.btnHostPos = Vec3(0, 0, .45) self.btnHostScale = 0.25 self.btnHost = DirectButton( # Scale and position scale = self.btnHostScale, pos = self.btnHostPos, # Text text = "Host", text_scale = 0.8, text_pos = (0, -0.2), text_fg = (0.82,0.85,0.87,1), text_shadow = (0, 0, 0, 1), text_shadowOffset = (-0.02, -0.02), text_font = defaultFont, # Frame geom = self.buttonGeom, frameColor = (0, 0, 0, 0), relief = 0, pressEffect = False, # Functionality command = self.host, rolloverSound = None, clickSound = None) self.btnHost.setTransparency(1) self.btnHost.reparentTo(self.frameMain) # create a join button self.btnJoinPos = Vec3(0, 0, 0) self.btnJoinScale = 0.25 self.btnJoin = DirectButton( scale = self.btnJoinScale, pos = self.btnJoinPos, text = "Join", text_scale = 0.8, text_pos = (0, -0.2), text_fg = (0.82,0.85,0.87,1), text_shadow = (0, 0, 0, 1), text_shadowOffset = (-0.02, -0.02), text_font = defaultFont, geom = self.buttonGeom, frameColor = (0, 0, 0, 0), relief = 0, pressEffect = False, command = self.join, rolloverSound = None, clickSound = None) self.btnJoin.setTransparency(1) self.btnJoin.reparentTo(self.frameMain) # create the IP input field self.txtIPPos = Vec3(0, 0, -.30) self.txtIPScale = 0.25 self.txtIPWidth = 9 self.txtIP = DirectEntry( # scale and position pos = self.txtIPPos, scale = self.txtIPScale, width = self.txtIPWidth, # Text entryFont = monospace, text_align = TextNode.ACenter, text = "", text_scale = 0.5, text_pos = (0, -0.2), text_fg = (0.82,0.85,0.87,1), text_shadow = (0, 0, 0, 1), text_shadowOffset = (0.04, 0.04), initialText = "127.0.0.1", numLines = 1, # Frame geom = self.textboxGeom, frameColor = (0, 0, 0, 0), relief = 0, # Functionality command = self.join, focusInCommand = self.clearText) self.txtIP.reparentTo(self.frameMain) # create an exit button self.btnExitPos = Vec3(0, 0, -.75) self.btnExitScale = 0.25 self.btnExit = DirectButton( scale = self.btnExitScale, pos = self.btnExitPos, text = "Exit", text_scale = 0.8, text_pos = (0, -0.2), text_fg = (0.82,0.85,0.87,1), text_shadow = (0, 0, 0, 1), text_shadowOffset = (-0.02, -0.02), text_font = defaultFont, geom = self.buttonGeom, frameColor = (0, 0, 0, 0), relief = 0, pressEffect = False, command = lambda: base.messenger.send("escape"), rolloverSound = None, clickSound = None) self.btnExit.setTransparency(1) self.btnExit.reparentTo(self.frameMain) # create a mute checkbox self.cbVolumeMute = DirectCheckBox( # set size scale = (0.1, 0.1, 0.1), frameSize = (-1, 1, 1, -1), # functionality and visuals command = self.cbVolumeMute_CheckedChanged, isChecked = True, checkedImage = "gui/SoundSwitch_off.png", uncheckedImage = "gui/SoundSwitch_on.png", # mouse behaviour relief = 0, pressEffect = False, rolloverSound = None, clickSound = None ) self.cbVolumeMute.setTransparency(1) self.cbVolumeMute.reparentTo(self.frameMain) self.cbVolumeMute.commandFunc(None) # catch window resizes and recalculate the aspectration self.accept("window-event", self.recalcAspectRatio) self.accept("showerror", self.showError) # show the menu right away self.show() def host(self): """Function which will be called by pressing the host button""" self.hide() base.messenger.send("start_server") def join(self, ip=None): """Function which will be called by pressing the join button""" if ip == None: ip = self.txtIP.get(True) if ip == "": return self.hide() base.messenger.send("start_client", [ip]) def showError(self, msg): self.show() self.dialog = OkDialog( dialogName="ErrorDialog", text="Error: {}".format(msg), command=self.closeDialog) def closeDialog(self, args): self.dialog.hide() def show(self): """Show the GUI""" self.frameMain.show() self.menuMusic.play() def hide(self): """Hide the GUI""" self.frameMain.hide() self.menuMusic.stop() def clearText(self): """Function to clear the text that was previously entered in the IP input field""" self.txtIP.enterText("") def cbVolumeMute_CheckedChanged(self, checked): if bool(checked): base.disableAllAudio() else: base.enableAllAudio() def recalcAspectRatio(self, window): """get the new aspect ratio to resize the mainframe""" # set the mainframe size to the window borders again self.frameMain["frameSize"] = ( base.a2dLeft, base.a2dRight, base.a2dTop, base.a2dBottom) # calculate new aspec tratio wp = window.getProperties() aspX = 1.0 aspY = 1.0 wpXSize = wp.getXSize() wpYSize = wp.getYSize() if wpXSize > wpYSize: aspX = wpXSize / float(wpYSize) else: aspY = wpYSize / float(wpXSize) # calculate new position/size/whatever of the gui items self.title.setPos(0.0, 0.0, base.a2dTop - self.textscale) self.menuBackground.setScale(1.0 * aspX, 1.0, 1.0 * aspY) self.cbVolumeMute.setPos(base.a2dRight - 0.15, 0, base.a2dBottom + 0.15)
class MainScreen(): def __init__(self): self.txtPlayerName = DirectEntry( text="", scale=0.08, pos=(-0.15, 0, 0.6), initialText="Name", numLines = 1, width = 4, focus=False, focusInCommand=self.__clearText, focusOutCommand=self.__checkText) self.btnStart = DirectButton( text = "Start", # size of the button scale = (0.25, 0.25, 0.25), # set no relief relief = 1, frameColor = (0,0,0,0), # No sink in when press pressEffect = False, # position on the window pos = (0, 0, .3), # the event which is thrown on clickSound command = self.btnStart_Click, # sounds that should be played rolloverSound = None, clickSound = None) self.btnStart.setTransparency(1) self.btnHighscore = DirectButton( text = "Highscore", # size of the button scale = (0.25, 0.25, 0.25), # set no relief relief = 1, frameColor = (0,0,0,0), # No sink in when press pressEffect = False, # position on the window pos = (0, 0, 0), # the event which is thrown on clickSound command = self.btnHighscore_Click, # sounds that should be played rolloverSound = None, clickSound = None) self.btnHighscore.setTransparency(1) self.btnQuit = DirectButton( text = "Quit", # size of the button scale = (0.25, 0.25, 0.25), # set no relief relief = 1, frameColor = (0,0,0,0), # No sink in when press pressEffect = False, # position on the window pos = (0, 0, -.3), # the event which is thrown on clickSound command = self.btnQuit_Click, # sounds that should be played rolloverSound = None, clickSound = None) self.btnQuit.setTransparency(1) def show(self): self.txtPlayerName.show() self.btnStart.show() self.btnHighscore.show() self.btnQuit.show() def hide(self): self.txtPlayerName.hide() self.btnStart.hide() self.btnHighscore.hide() self.btnQuit.hide() def __clearText(self): if self.txtPlayerName.get() == "" or \ self.txtPlayerName.get() == "Name": self.txtPlayerName.enterText("") def __checkText(self): if self.txtPlayerName.get() == "": self.txtPlayerName.enterText("Name") def btnStart_Click(self): self.hide() base.messenger.send("MainMenu_start") def btnHighscore_Click(self): self.hide() base.messenger.send("Highscore_show") def btnQuit_Click(self): base.messenger.send("MainMenu_quit") def getPlayername(self): return self.txtPlayerName.get()
class JoinGameDialogue(): """ The options pop-up used when the player presses the MainMenu's "Join Party" button. The client can be configured in many ways, including: * Display Name * Host IP Address * Game Password """ def __init__(self, confirmHandler): # Draw this GUI on object creation. self._confirmHandler = confirmHandler # The callback handler to this GUI self._ipAddressEntry = None # Reference to the IP Address Text Entry self._userNameEntry = None # Reference to the User Name Text Entry self._font = loader.loadFont(PIERCEROMAN_FONT) self._elements = [] self._draw() def _draw(self): """ Draws this JoinGameDialogue """ winWidth = base.getAspectRatio() * 2 winHeight = 2 # Draw translucent background frame to block clicks: blockingFrame = DirectFrame(parent=base.a2dTopLeft, frameSize=(0, winWidth, -winHeight, 0), frameColor=(0, 0, 0, 0.5)) # Draw Main Dialogue Frame: dFOffsetY = 0.05 dFSizeX, dFSizeY = winWidth * (3 / 5), winHeight * (2 / 3) dialogueFrame = DirectFrame(pos=(-dFSizeX / 2, 0, dFSizeY / 2 + dFOffsetY), frameSize=(0, dFSizeX, -dFSizeY, 0), frameTexture=UI_WINDOW) dialogueFrame.setTransparency(TransparencyAttrib.MAlpha) # Draw Title Text: verticalMargin = 0.102 titleWidth = dFSizeX titleHeight = 0.15 titleFontSize = (0.15, 0.15) dialogueTitle = DirectLabel(parent=dialogueFrame, pos=(dFSizeX / 2, 0, -verticalMargin), frameSize=(-titleWidth / 2, titleWidth / 2, -titleHeight / 2, titleHeight / 2), frameTexture=IMG_GRADIENT_1, text_align=TextNode.ACenter, text_font=self._font, text_scale=titleFontSize, text_pos=PIERCEROMAN_OFFSET_MC, text="Join Party Configuration") self._drawControls(dialogueFrame) # Draw options for the pop-up frame. # Draw Back Button: buttonVerticalMargin = 0.203 buttonHeight = 0.2 buttonPosY = -1 - buttonVerticalMargin sidesMargin = 0.1 buttonWidth = dFSizeX / 2 - sidesMargin / 2 backButton = DirectButton(parent=dialogueFrame, pos=(dFSizeX / 2 - buttonWidth / 2, 0, -1 - buttonVerticalMargin), frameSize=(-buttonWidth / 2, buttonWidth / 2, -buttonHeight / 2, buttonHeight / 2), command=self.close, text="Back", text_font=self._font, text_scale=JOPTS_BUTON_FONT_SIZE, text_pos=JOPTS_BUTON_FONT_OFFSET, borderWidth=JOPTS_BUTTON_BORDER_WIDTH) # Draw Connect Button: connButton = DirectButton(parent=dialogueFrame, pos=(dFSizeX / 2 + buttonWidth / 2, 0, -1 - buttonVerticalMargin), frameSize=(-buttonWidth / 2, buttonWidth / 2, -buttonHeight / 2, buttonHeight / 2), command=self._onConnectButton, text_font=self._font, text="Connect", text_scale=JOPTS_BUTON_FONT_SIZE, text_pos=JOPTS_BUTON_FONT_OFFSET, borderWidth=JOPTS_BUTTON_BORDER_WIDTH) # Add parent elements to be deleted in self.close() self._elements.extend([blockingFrame, dialogueFrame]) def _drawControls(self, dialogueFrame): """ Draw Helper that draws client settings controls """ iTopMrgn = JOPTS_CONTROL_TOP_MARGIN spacing = JOPTS_CONTROL_SPACING height = JOPTS_CONTROL_HEIGHT width = dialogueFrame.getWidth() # Create containers for UI: ipFrame = DirectFrame(parent=dialogueFrame, pos=(width / 2, 0, -iTopMrgn - spacing), frameSize=(-width / 2, width / 2, -height / 2, height / 2), frameTexture=UI_WINDOW) #nameFrame = DirectFrame(parent=dialogueFrame, # pos=(width/2, 0, -iTopMrgn - spacing * 2), # frameSize=(-width/2, width/2, -height/2, # height/2)) # Create the UI: ctrlWidth = ipFrame.getWidth() * (1 / 3) ctrlFontSize = (0.15, 0.15) self._ipAddressEntry = DirectEntry(parent=ipFrame, pos=(ctrlWidth / 2 - ctrlWidth * 1, 0, 0), frameSize=(0, ctrlWidth * 2, -height / 2, height / 2), frameColor=(0, 0, 0, 0), text_font=self._font, text_scale=ctrlFontSize, text_pos=PIERCEROMAN_OFFSET_MC, initialText=DEFAULT_IP_ADDRESS, width=8, cursorKeys=1, numLines=1) ipLabel = DirectLabel(parent=ipFrame, pos=(ctrlWidth - ctrlWidth * 2, 0, 0), frameSize=(-ctrlWidth / 2, ctrlWidth / 2, -height / 2, height / 2), text="Host IP:", text_font=self._font, text_scale=ctrlFontSize, text_pos=PIERCEROMAN_OFFSET_MC, frameTexture=(IMG_GRADIENT_1)) """self._userNameEntry = DirectEntry(parent=nameFrame, pos=(ctrlWidth/2-ctrlWidth*1, 0, 0), frameSize=(0, ctrlWidth*2, -height/2, height/2), text_font=self._font, text_scale=ctrlFontSize, text_pos=PIERCEROMAN_OFFSET_MC, width=8, cursorKeys=1, numLines=1)""" """ nmLabel = DirectLabel(parent=nameFrame, pos=(ctrlWidth-ctrlWidth*2, 0, 0), frameSize=(-ctrlWidth/2, ctrlWidth/2, -height/2, height/2), text="User Name:", text_font=self._font, text_scale=(0.12, 0.12), text_pos=PIERCEROMAN_OFFSET_MC, frameColor=(0.25,0.5,0.5,1))""" #TODO Change above to a server-password system def _onConnectButton(self): """ Called when the connect button is pressed. Read the user's inputs and tell the gameManager to create a client. """ targetIP = str(self._ipAddressEntry.get()) #userName = self._userNameEntry.get() self._confirmHandler(targetIP) def close(self): """ Closes this window and deletes all elements inside. """ for element in self._elements: element.destroy() del self # Destroy this instance
class DroneManager(DirectObject.DirectObject): def __init__(self, base, droneList, delay): self.base = base # the actual dimensions of the bcs drone lab in meters # self.roomSize = Vec3(3.40, 4.56, 2.56) # confined dimensions because the room and drone coordinates dont match up yet. # Also, flying near the windows/close to walls/too high often makes the llighthouse positioning system loose track self.roomSize = Vec3(1.5, 2.5, 1.7) self.initDrones(droneList) self.initUI() self.currentFormation = 0 self.isRotating = False self.currentTimeslot = 0 self.timeslotLengthMilli = delay def initDrones(self, droneList): """Initializes the drones defined in droneList.""" self.isStarted = False self.isConnected = False self.drones = [] # this is the list of all drones self.currentDronePos = [ ] # this is the list of the most recent position that was sent by each drone if droneList == []: print("No drones to spawn") else: for i in range(0, len(droneList)): position = droneList[i][0] uri = droneList[i][1] self.drones.append(Drone(self, position, uri=uri)) self.base.taskMgr.add(self.updateDronesTask, "UpdateDrones") self.base.taskMgr.add(self.updateTimeslotTask, "UpdateTimeslot") def updateDronesTask(self, task): """Run the update methods of all drones.""" for drone in self.drones: drone.update() return task.cont def updateTimeslotTask(self, task): timeslotAmount = 2 task.delayTime = self.timeslotLengthMilli / 1000 self.currentTimeslot += 1 if self.currentTimeslot >= timeslotAmount: self.currentTimeslot = 0 for drone in self.drones: drone.updateSentPosition(self.currentTimeslot) return task.again def initUI(self): # initialize drone control panel buttonSize = (-4, 4, -.2, .8) buttonDistance = 0.15 entrySize = (0, 2, -.2, .8) # frame = DirectFrame(frameColor=(.2, .2, .2, 1), frameSize=(-.5, .5, -.7, .15), pos=(-.9, 0, -.6), scale=.5) frame = DirectFrame(frameColor=(.2, .2, .2, 1), frameSize=(-.5, .5, -.7, .15), pos=(-.9, 0, -.4), scale=.5) button = DirectButton(text="Start", scale=.1, frameSize=buttonSize, command=self.startLandAll) button["extraArgs"] = [button] button.reparentTo(frame) button = DirectButton(text="Random Target", scale=.1, frameSize=buttonSize, command=self.setRandomTargets) button.reparentTo(frame) button.setPos(Vec3(0, 0, -1 * buttonDistance)) button = DirectButton(text="Stop", scale=.1, frameSize=buttonSize, command=self.stopAll) button.reparentTo(frame) button.setPos(Vec3(0, 0, -2 * buttonDistance)) button = DirectButton(text="Return", scale=.1, frameSize=buttonSize, command=self.returnToWaitingPosition) button.reparentTo(frame) button.setPos(Vec3(0, 0, -3 * buttonDistance)) button = DirectButton(text="Connect", scale=.1, frameSize=buttonSize, command=self.toggleConnections) button["extraArgs"] = [button] button.reparentTo(frame) button.setPos(Vec3(0, 0, -4 * buttonDistance)) button = DirectButton(text="Rotate", scale=.1, frameSize=buttonSize, command=self.toggleRotation) button.reparentTo(frame) button.setPos(Vec3(0, 0, -5 * buttonDistance)) button = DirectButton(text="Move", scale=.1, frameSize=buttonSize, command=self.moveFormation) button.reparentTo(frame) button.setPos(Vec3(0, 0, -6 * buttonDistance)) self.moveX = DirectEntry(text="", initialText="0", scale=.1, frameSize=entrySize) self.moveX.reparentTo(frame) self.moveX.setPos(Vec3(0.5, 0, -6 * buttonDistance)) self.moveY = DirectEntry(text="", initialText="0", scale=.1, frameSize=entrySize) self.moveY.reparentTo(frame) self.moveY.setPos(Vec3(0.75, 0, -6 * buttonDistance)) self.moveZ = DirectEntry(text="", initialText="0", scale=.1, frameSize=entrySize) self.moveZ.reparentTo(frame) self.moveZ.setPos(Vec3(1, 0, -6 * buttonDistance)) self.rotSpeed = DirectEntry(text="", initialText="3", scale=.1, frameSize=entrySize) self.rotSpeed.reparentTo(frame) self.rotSpeed.setPos(Vec3(0.5, 0, -5 * buttonDistance)) # initialize an UI element with all available formations loadFormationSelectionFrame(self) def startLandAll(self, button): if not self.isStarted: self.isStarted = True button["text"] = "Land" print("starting all") for drone in self.drones: pos = drone.getPos() drone.setTarget(target=Vec3(pos[0], pos[1], 1)) else: self.isStarted = False button["text"] = "Start" print("landing all") for drone in self.drones: pos = drone.getPos() drone.setTarget(target=Vec3(pos[0], pos[1], 0)) def returnToWaitingPosition(self): """Makes all drones hover above their starting position. Useful to make the drones land just where they started.""" if not self.isStarted: print("can't return to waiting position, drones are not started") return print("returning to waiting positions") for drone in self.drones: drone.setTarget(drone.waitingPosition) def setRandomTargets(self): """Set random targets for all drones.""" if not self.isStarted: print("can't set random targets, drones are not started") return print("setting random targets") for drone in self.drones: drone.setRandomTarget() def stopAll(self): """Stops all drones and makes them hover where they are.""" if not self.isStarted: print("can't stop drones, drones are not started") return print("stopping drones") for drone in self.drones: drone.setTarget(target=drone.getPos()) def toggleConnections(self, button): """Connects/Disconnects the virtual drones to/from the real drones.""" # connect drones if not self.isConnected: self.isConnected = True button["text"] = "Disconnect" print("initializing drivers") cflib.crtp.init_drivers(enable_debug_driver=False) print("connecting drones") for drone in self.drones: drone.connect() # time.sleep(5) # wait a moment so that the position estimator reports a consisten position # disconnect drones else: self.isConnected = False button["text"] = "Connect" print("disconnecting drones") for drone in self.drones: if drone.isConnected: drone.disconnect() def applyFormation(self, formation): """Applies the supplied formation to the drones.""" if not self.isStarted: print("Can't apply formation, drones are not started") return # name = formation[0] dronePositions = formation[1] requiredDrones = len(dronePositions) availableDrones = self.drones.__len__() maxNumber = availableDrones if requiredDrones > availableDrones: print( "The formation contains {0} points but there are only {1} available drones" .format(requiredDrones, availableDrones)) if requiredDrones < availableDrones: print( "The formation contains {0} points but there are {1} available drones, some drones will remain stationary" .format(requiredDrones, availableDrones)) maxNumber = requiredDrones # print("applying {} formation".format(formation[0])) for i in range(0, maxNumber): self.drones[i].setNewRandVec() self.drones[i].setTarget( Vec3(dronePositions[i, 0], dronePositions[i, 1], dronePositions[i, 2])) self.currentFormation = formation def moveFormation(self): if (self.currentFormation == 0): return newFormation = self.currentFormation newFormation[1] += [ float(self.moveX.get()), float(self.moveY.get()), float(self.moveZ.get()) ] self.applyFormation(newFormation) def toggleRotation(self): if (self.currentFormation == 0): return if not self.isRotating: self.isRotating = True self.base.taskMgr.doMethodLater(0, self.rotateFormationTask, "RotateDrones") else: self.isRotating = False self.base.taskMgr.remove("RotateDrones") def rotateFormationTask(self, task): task.delayTime = 0.1 newFormation = self.currentFormation speed = 2 try: speed = float(self.rotSpeed.get()) except: speed = 2 r = R.from_euler('xyz', [0, 0, speed], degrees=True) newFormation[1] = r.apply(newFormation[1]) self.applyFormation(newFormation) return task.again def getRandomRoomCoordinate(self) -> Vec3: """Returns random 3D coordinates withing the confines of the room.""" newX = random.uniform(-self.roomSize.x / 2, self.roomSize.x / 2) newY = random.uniform(-self.roomSize.y / 2, self.roomSize.y / 2) newZ = random.uniform(0 + 0.3, self.roomSize.z) return Vec3(newX, newY, newZ) def getAllPositions(self): """Returns a list of the positions of all drones. Usefull when recording their paths for later.""" lst = [] for drone in self.drones: pos = drone.getPos() lst.append([pos.x, pos.y, pos.z]) return lst def getAllVelocities(self): """Returns a list of the velocities of all drones. Usefull when recording their paths for later.""" lst = [] for drone in self.drones: vel = drone.getVel() lst.append([vel.x, vel.y, vel.z]) return lst
class FrameAutenticacao(object): ''' FrameAutenticacao ''' def __init__(self, parent=None, **kw): self.__qtd_conexao = 0 self.__frmAuth = DirectFrame(frameColor=(0, 0, 0, .3), frameSize=(-.5, .5, 0, 0.45), pos=(0, 0, -.1), enableEdit=1) self.__lblLogin = DirectLabel(text="Login: "******"Senha: ", scale=0.05, pos=(-0.3, 0, 0.2), frameColor=(0, 0, 0, 0), text_fg=(1, 1, 1, 1)) self.__etySenha = DirectEntry( scale=0.05, width=12, pos=(-.2, 0, 0.2), cursorKeys=1, obscured=1, focusInCommand=self.__command_clear_senha) self.__btnEntrar = DirectButton(frameColor=(0, 0, 0, 1), text="Entrar", scale=0.06, pos=(0.3, 0, 0.1), text_fg=(1, 1, 1, 1), rolloverSound=None, clickSound=None, command=self.__command_entrar) self.__lblLogin.reparentTo(self.__frmAuth) self.__etyLogin.reparentTo(self.__frmAuth) self.__lblSenha.reparentTo(self.__frmAuth) self.__etySenha.reparentTo(self.__frmAuth) self.__btnEntrar.reparentTo(self.__frmAuth) self.__etyLogin.set("viner") self.__etySenha.set("viner") def __command_clear_senha(self): self.__etySenha.set("") def __command_entrar(self, txt=None): login = self.__etyLogin.get() senha = self.__etySenha.get() valido = True if login == "": addMensagem("O campo Login e obrigatorio !", COR_BRANCO) valido = False if senha == "": addMensagem("O campo Senha e obrigatorio !", COR_BRANCO) valido = False if valido: self.__btnEntrar["state"] = DGG.DISABLED taskMgr.add(self.__task_conectar_servidor, 'ConectarServidor', extraArgs=[login, senha], appendTask=True) #inicia_nova_thread(1, 0, "Conectar Servidor", self.__conectar_servidor, login, senha) def __task_conectar_servidor(self, login, senha, task): if self.__qtd_conexao < TENTATIVAS: if vinerOnline.flg_conectado == vinerOnline.ERROLOGIN: vinerOnline.flg_conectado = vinerOnline.DESCONECT self.__btnEntrar["state"] = DGG.NORMAL self.__qtd_conexao = 0 addMensagem('Login ou senha invalido', COR_VERMELHO) self.__etyLogin.setFocus() elif vinerOnline.flg_conectado == vinerOnline.CONECTADO: #addMensagem("Conectado 12 !!!") #self.destroy() pass else: vinerOnline.conectar_servidor(login, senha) self.__qtd_conexao += 1 taskMgr.doMethodLater(INTERVALO_TENTATIVAS, self.__task_conectar_servidor, 'ConectarServidorLater', extraArgs=[login, senha], appendTask=True) msg = "Tentativa %s/5 - Conectando..." % (self.__qtd_conexao) addMensagem(msg, COR_BRANCO) else: vinerOnline.flg_conectado = vinerOnline.DESCONECT self.__btnEntrar["state"] = DGG.NORMAL self.__qtd_conexao = 0 addMensagem("Servidor nao encontrado", COR_VERMELHO) return task.done def destroy(self): self.__frmAuth.destroy() del self.__lblLogin del self.__etyLogin del self.__lblSenha del self.__etySenha del self.__btnEntrar del self.__frmAuth
class MainMenu(): def __init__(self, showbase): self.showbase = showbase self.status = OnscreenText(text = "", pos = Vec3(0, -0.35, 0), scale = 0.05, fg = (1, 0, 0, 1), align = TextNode.ACenter, mayChange = True) self.background = DirectFrame( frameSize = (-1, 1, -1, 1), frameTexture = 'media/gui/mainmenu/menu.png', parent = self.showbase.render2d, ) self.title = OnscreenText( text = 'Main Menu', fg = (1, 1, 1, 1), parent = self.background, pos = (-0.6, 0.1), scale = 0.06 ) self.ip = '127.0.0.1' # Should make this write to file... so that the user can save ip's... # yep thats a good idea, there will be a few things i guess that need to be done like this # like settings and keys and whatnot # Buttons self.buttons = [] serverButtons = Vec3(-0.60, 0, -0.79) # Host self.params = ['3', '8'] p = serverButtons + Vec3(-0.25, 0, 0) self.hostButton = DirectButton(text = 'Host', pos = p, scale = 0.048, relief = DGG.GROOVE, command = self.showbase.hostGame, extraArgs = [self.params]) self.buttons.append(self.hostButton) # Join p = serverButtons + Vec3(0.0, 0.0, 0.0) self.joinButton = DirectButton(text = 'Join', pos = p, scale = 0.048, relief = DGG.GROOVE, command = self.joinServer) self.buttons.append(self.joinButton) # Refresh if self.showbase.online: p = serverButtons + Vec3(0.25, 0, 0) self.refreshButton = DirectButton(text = "Refresh", pos = p, scale = 0.048, relief = DGG.GROOVE, command = self.refreshStart) self.buttons.append(self.refreshButton) self.refreshStart() chatFrameCenter = (0.0, 0.325) chatFrameSize = (2.5, 1.2) self.chat = DirectFrame( frameColor = (0, 0, 0, 1), frameSize = (chatFrameSize[0] / 2, -chatFrameSize[0] / 2, chatFrameSize[1] / 2, -chatFrameSize[1] / 2), pos = (chatFrameCenter[0], 0, chatFrameCenter[1]) ) channelFrameSize = (chatFrameSize[0] / 4, chatFrameSize[1]) channelFrameCenter = (- chatFrameSize[0] / 2 + channelFrameSize[0] / 2, 0) numItemsVisible = 8 itemHeight = channelFrameSize[1] / (numItemsVisible + 1) self.channels = DirectScrolledList( parent = self.chat, pos = (channelFrameCenter[0], 0, channelFrameCenter[1]), frameSize = (-channelFrameSize[0] / 2, channelFrameSize[0] / 2, channelFrameSize[1] / 2, -channelFrameSize[1] / 2), frameColor = (1, 0, 0, 0.5), numItemsVisible = numItemsVisible, forceHeight = itemHeight, #itemFrame_frameSize = (-channelFrameSize[0] / 2.1, channelFrameSize[0] / 2.1, itemHeight, -channelFrameSize[1] + itemHeight), itemFrame_pos = (0, 0, channelFrameSize[1] / 2 - itemHeight), decButton_pos = (-0.2, 0, channelFrameCenter[1] - channelFrameSize[1] / 2 + itemHeight / 4), decButton_text = 'Prev', decButton_text_scale = 0.05, decButton_borderWidth = (0.005, 0.005), incButton_pos = (0.2, 0, channelFrameCenter[1] - channelFrameSize[1] / 2 + itemHeight / 4), incButton_text = 'Next', incButton_text_scale = 0.05, incButton_borderWidth = (0.005, 0.005), ) b1 = DirectButton(text = ("Button1", "click!", "roll", "disabled"), text_scale = 0.1, borderWidth = (0.01, 0.01), relief = 2) b2 = DirectButton(text = ("Button2", "click!", "roll", "disabled"), text_scale = 0.1, borderWidth = (0.01, 0.01), relief = 2) l1 = DirectLabel(text = "Test1", text_scale = 0.1) l2 = DirectLabel(text = "Test2", text_scale = 0.1) l3 = DirectLabel(text = "Test3", text_scale = 0.1) self.channels.addItem(b1) self.channels.addItem(b2) self.channels.addItem(l1) self.channels.addItem(l2) self.channels.addItem(l3) for fruit in ['apple', 'pear', 'banana', 'orange', 'cake', 'chocolate']: l = DirectLabel(text = fruit, text_scale = 0.1) self.channels.addItem(l) # need to add the chat stuff # i guess have like a chat manager which will hold an array of 'chat_instances' # and the chat manager can sort out which is displayed and which channel the text is sent from/received to # a bit more thinking needs to be done i guess # can discuss sometime (not really that important now :P) # also i guess the layout and shit will need to be sorted (for whoever is doing the designing) # current games list (need to implement this) # it should send a query to the master server to get the current list (just ip's atmo i guess) # options shit aswell needs to be sorted # maybe just an overlay or something # functionality for the host button (popup an overlay that will be able to set options and then 'start_game' button # then should auto connect and go to lobby (will be same as for all clients, except have a couple of different buttons i guess) # close game instead of disconnect, start game instead of ready (greyed until all others are ready), kick button i suppose # once the options are set the 'server_inst' should be started on the local computer (which will broadcast to master server, once host can successfully connect) # then game client will move to pregame state (connect to the server, and wait for others and ready) else: self.entry = DirectEntry( focusInCommand = self.clearText, frameSize = (-3, 3, -.5, 1), initialText = self.ip, parent = self.buttons[0], pos = (0, -0.6, -1.5), text_align = TextNode.ACenter, ) self.hide() def refreshStart(self): self.refreshButton["state"] = DGG.DISABLED if self.showbase.authCon.getConnected(): self.servers = [] self.showbase.authCon.sendData('serverQuery') self.showbase.taskMgr.doMethodLater(0.25, self.queryServers, 'Server Query') def queryServers(self, task): finished = False temp = self.showbase.authCon.getData() for package in temp: if len(package) == 2: # Handle Server Query if package[0] == 'server': self.servers.append(package[1]) print package[1] elif package[0] == 'final': self.refreshButton["state"] = DGG.NORMAL finished = True else: self.showbase.authCon.passData(package) if finished: return task.done return task.cont def joinChat(self): pass # Let the client mini auth with the lobby server(lobby_loop) by "Logging into the chat" # Since everything will be in the main menu? like a main chat window.. something similar to HoN i guess? # When the player opens the Join game by button, a list will be send from the lobby server telling it what games are active. # Then the player picks one and it connects via the host name/ip or whatever. # While this is busy happening the client stays connected to the lobby server. def joinServer(self): if self.showbase.online: self.ip = '127.0.0.1' else: self.ip = self.entry.get() self.status.setText('Attempting to join server @ ' + self.ip + '...') # attempt to connect to the game server self.showbase.client = Client(self.showbase, self.ip, 9099, compress = True) if self.showbase.client.getConnected(): print 'Connected to server, Awaiting authentication...' self.showbase.client.sendData(('username', self.showbase.username)) self.showbase.taskMgr.add(self.authorizationListener, 'Authorization Listener') else: self.status.setText('Could not Connect...') def authorizationListener(self, task): temp = self.showbase.client.getData() auth = False if temp != []: for package in temp: if len(package) == 2: if package[0] == 'auth': print 'Authentication Successful' auth = True elif package[0] == 'fail': self.status.setText('Authentication failed on server...') return task.done else: self.showbase.client.passData(package) if auth: self.showbase.startPregame() return task.done return task.again def clearText(self): self.entry.enterText('') def hide(self): self.showbase.taskMgr.remove('Server Query Timeout') self.background.hide() for b in self.buttons: b.hide() self.status.hide() if self.showbase.online: self.chat.hide() self.channels.hide() else: self.entry.hide() def show(self): self.background.show() for b in self.buttons: b.show() self.status.show() if self.showbase.online: self.chat.show() self.channels.show() else: self.entry.show()
class Chat(object): """Handles all chat.""" def __init__(self, game): self.game = game self.lines = [] self.whisperTarget = None props = base.win.getProperties() ratio = float(props.getXSize()) / props.getYSize() self.frame = DirectFrame(frameColor=(0, 0, 0, 0), frameSize=(0, 1, 0, 1), pos=(-ratio, 0, -1)) self.text = OnscreenText( text="", pos=(0.01, 0.45), scale=0.05, fg=(1, 1, 1, 1), bg=(0, 0, 0, 0.2), parent=self.frame, align=TextNode.ALeft, mayChange=True, ) self.entry = DirectEntry( parent=self.frame, text="", scale=0.05, pos=(0.01, 0, 0.02), initialText="", width=26, numLines=1 ) self.targetText = OnscreenText( text="", pos=(1.34, 0.025), scale=0.05, fg=(1, 1, 1, 1), bg=(0, 0, 0, 0.4), parent=self.frame, align=TextNode.ALeft, mayChange=True, ) base.accept("t", self.startChatting) base.accept("shift-t", self.startChatting) base.accept("y", self.startWhispering) base.accept("shift-y", self.startWhispering) base.accept("arrow_up", lambda: self.changeTarget(1)) base.accept("shift-arrow_up", lambda: self.changeTarget(1)) base.accept("arrow_down", lambda: self.changeTarget(-1)) base.accept("shift-arrow_down", lambda: self.changeTarget(-1)) base.accept("enter", self.sendChat) base.accept("shift-enter", self.sendChat) def startChatting(self): if not self.game.isChatting: self.game.isChatting = True # focus on the DirectEntry self.entry["focus"] = 1 # reset whisper target (just in case) self.whisperTarget = None # enable UI mode if self.game.camera is not None: self.game.camera.showMouse() def startWhispering(self): if not self.game.isChatting: if not self.game.characters: self.addLine("<<System>> Nobody to whisper!") else: self.startChatting() self.changeTarget(0) def changeTarget(self, amt): if self.game.isChatting: targets = self.game.characters.keys() targets.sort() # find target (or the closest id before target, or 0) index = 0 match = False for i in range(len(targets)): if targets[i] < self.whisperTarget: index = i elif targets[i] == self.whisperTarget: index = i match = True break else: break # if not found but going back 1 anyway, set amt to 0 if not match and amt == -1: amt = 0 # set new whisper target index = (index + amt) % len(targets) self.whisperTarget = targets[index] self.targetText.setText("to: " + str(self.game.characters[self.whisperTarget].name)) def sendChat(self): if self.game.isChatting: message = self.entry.get().strip() if len(message) > 0: # figure out target target = "" if self.whisperTarget in self.game.characters: target = self.game.characters[self.whisperTarget].name # submit message self.game.main.cManager.sendRequest(Constants.C_CHAT, {"message": message, "target": target}) # stop chatting self.stopChatting() def stopChatting(self): if self.game.isChatting: self.game.isChatting = False # disable chat entry self.entry["focus"] = 0 # clear text box self.entry.enterText("") # remove whisper target self.whisperTarget = None self.targetText.setText("") # disable UI mode if self.game.camera is not None: self.game.camera.hideMouse() def addLine(self, line): self.lines.append(line) self.text.setText("\n".join(self.lines[-8:]))
class Start(DirectObject): def __init__(self, main): DirectObject.__init__(self) self.showbase = main self.background = DirectFrame( frameSize=(-1, 1, -1, 1), frameTexture='media/gui/login/bg.png', parent=self.showbase.render2d, ) self.username = "******" self.server = "localhost" self.loginScreen("Press 'Enter' to login") # draws the login screen self.usernameBox['focus'] = 1 # sets the cursor to the username field by default self.accept('tab', self.cycleLoginBox) self.accept('shift-tab', self.cycleLoginBox) # enables the user to cycle through the text fields with the tab key # this is a standard feature on most login forms self.accept('enter', self.attemptConnect) # submits the login form, or you can just click the Login button # checking variable to stop multiple presses of the button spawn multiple tasks self.requestAttempt = False self.updateStatus("Type Server and Connect!") def cleanup(self): self.ignoreAll() self.removeAllTasks() self.background.destroy() self.usernameText.destroy() self.usernameBox.destroy() self.serverText.destroy() self.serverBox.destroy() self.loginButton.destroy() self.quitButton.destroy() self.statusText.destroy() def loginScreen(self, statusText): # creates a basic login screen that asks for a username/password boxloc = Vec3(0.0, 0.0, 0.0) # all items in the login form will have a position relative to this # this makes it easier to shift the entire form around once we have # some graphics to display with it without having to change the # positioning of every form element # p is the position of the form element relative to the boxloc # coordinates set above it is changed for every form element p = boxloc + Vec3(-0.22, 0.09, 0.0) self.usernameText = OnscreenText(text="Username:"******"Username: "******"", pos=p, scale=.04, initialText=self.username, numLines=1) # Username textbox where you type in your username p = boxloc + Vec3(-0.22, 0.0, 0.0) self.serverText = OnscreenText(text="Server:", pos=p, scale=0.05, bg=(0, 0, 0, 1), fg=(1, 1, 1, 1), align=TextNode.ARight) # "Server: " text that appears beside the server box p = boxloc + Vec3(-0.2, 0.0, 0.0) self.serverBox = DirectEntry(text="", pos=p, scale=.04, initialText=self.server, numLines=1) # server textbox where you type in the server p = boxloc + Vec3(0, 0, -0.090) self.loginButton = DirectButton(text="Login", pos=p, scale=0.048, relief=DGG.GROOVE, command=self.attemptConnect) # The 'Quit' button that will trigger the Quit function # when clicked p = boxloc + Vec3(1.20, 0, -0.9) self.quitButton = DirectButton(text="Quit", pos=p, scale=0.048, relief=DGG.GROOVE, command=self.showbase.quit) # The 'Quit' button that will trigger the Quit function # when clicked p = boxloc + Vec3(0, -0.4, 0) self.statusText = OnscreenText(text=statusText, pos=p, scale=0.043, fg=(1, 0.5, 0, 1), align=TextNode.ACenter) # A simple text object that you can display an error/status messages # to the user def updateStatus(self, statusText): self.statusText.setText(statusText) # all this does is change the status text. def checkBoxes(self): # checks to make sure the user inputed a username and server: # if they didn't it will spit out an error message self.updateStatus("") if self.usernameBox.get() == "": if self.serverBox.get() == "": self.updateStatus( "You must enter a username and server before connecting.") else: self.updateStatus("You must specify a username") self.serverBox['focus'] = 0 self.usernameBox['focus'] = 1 return False elif self.serverBox.get() == "": self.updateStatus("You must enter a server") self.usernameBox['focus'] = 0 self.serverBox['focus'] = 1 return False # if both boxes are filled then return True return True def attemptConnect(self): if self.checkBoxes(): self.updateStatus("Attempting to connect...") self.joinServer(self.serverBox.get(), self.usernameBox.get()) def joinServer(self, serverIp, username): self.ip = serverIp self.showbase.username = username self.updateStatus('Attempting to join server: ' + serverIp) # attempt to connect to the game server self.showbase.client = Client(self.ip, 9099, compress=True) if self.showbase.client.connected: print 'Connected to server, Awaiting authentication...' self.showbase.client.sendData(('username', self.showbase.username)) self.showbase.taskMgr.add(self.authorizationListener, 'Authorization Listener') else: self.updateStatus('Could not Connect...') def authorizationListener(self, task): temp = self.showbase.client.getData() auth = False if temp: for package in temp: if len(package) == 2: if package[0] == 'auth': print 'Authentication Successful' auth = True elif package[0] == 'fail': self.updateStatus('Username already taken...') return task.done else: self.showbase.client.passData(package) if auth: self.showbase.goToLobby() return task.done return task.again def cycleLoginBox(self): # function is triggered by the tab key so you can cycle between # the two input fields like on most login screens if self.serverBox['focus'] == 1: self.serverBox['focus'] = 0 self.usernameBox['focus'] = 1 elif self.usernameBox['focus'] == 1: self.usernameBox['focus'] = 0 self.serverBox['focus'] = 1
class Login(object): def __init__(self, main): self.main = main self.frame = None self.title = None self.error = None self.username = None self.userTextbox = None self.password = None self.passTextbox = None self.cpassword = None self.cpassTextbox = None self.submitBtn = None self.registerBtn = None self.cancelBtn = None # login screen def createLoginWindow(self): self.frame = DirectFrame(frameColor = (0, 0, 0, 1), frameSize = (-1.35, 1.35, -1, 1), pos = (0, 0, 0)) self.title = OnscreenText(text = 'Login', pos = (0, 0.3), scale = 0.15, fg = (1, 0.5, 0.5, 1), align = TextNode.ACenter, parent = self.frame, mayChange = False) # username self.username = OnscreenText(text = 'Username:'******'', scale = 0.05, pos = (0.1, 0, 0), initialText = '[username]', numLines = 1, focus = 1, focusInCommand = self.userTextFocus, focusOutCommand = self.userTextBlur) # password self.password = OnscreenText(text = 'Password:'******'', scale = 0.05, pos = (0.1, 0, -0.2), initialText = '[password]', numLines = 1, focus = 0, focusInCommand = self.passTextFocus, focusOutCommand = self.passTextBlur) # buttons self.submitBtn = DirectButton(self.frame, # parent text = 'Login', scale = 0.08, command = self.clickedSubmit, pos = (0.8, 0.0, -0.90), text_bg = (1, 0.5, 0.5, 1), relief = None) self.registerBtn = DirectButton(self.frame, # parent text = 'Register', scale = 0.08, command = self.clickedRegister, pos = (0.5, 0.0, -0.90), text_bg = (1, 0.5, 0.5, 1), relief = None) self.cancelBtn = DirectButton(self.frame, # parent text = 'Cancel', scale = 0.08, command = self.clickedCancel, pos = (0.2, 0.0, -0.90), text_bg = (1, 0.5, 0.5, 1), relief = None) def destroyLoginWindow(self): self.frame.destroy() self.frame = None self.title = None self.error = None self.username = None self.userTextbox = None self.password = None self.passTextbox = None self.submitBtn = None self.registerBtn = None self.cancelBtn = None # register screen def createRegisterWindow(self): self.frame = DirectFrame(frameColor = (0, 0, 0, 1), frameSize = (-1.35, 1.35, -1, 1), pos = (0, 0, 0)) self.title = OnscreenText(text = 'Register', pos = (0, 0.3), scale = 0.15, fg = (1, 0.5, 0.5, 1), align = TextNode.ACenter, parent = self.frame, mayChange = False) # username self.username = OnscreenText(text = 'Username:'******'', scale = 0.05, pos = (0.1, 0, 0), initialText = '[username]', numLines = 1, focus = 1, focusInCommand = self.userTextFocus, focusOutCommand = self.userTextBlur) # password self.password = OnscreenText(text = 'Password:'******'', scale = 0.05, pos = (0.1, 0, -0.2), initialText = '[password]', numLines = 1, focus = 0, focusInCommand = self.passTextFocus, focusOutCommand = self.passTextBlur) # confirm password self.cpassword = OnscreenText(text = 'Confirm Password:'******'', scale = 0.05, pos = (0.1, 0, -0.4), initialText = '[confirm password]', numLines = 1, focus = 0, focusInCommand = self.cpassTextFocus, focusOutCommand = self.cpassTextBlur) # buttons self.registerBtn = DirectButton(self.frame, # parent text = 'Register', scale = 0.08, command = self.clickedRegRegister, pos = (0.8, 0.0, -0.90), text_bg = (1, 0.5, 0.5, 1), relief = None) self.cancelBtn = DirectButton(self.frame, # parent text = 'Cancel', scale = 0.08, command = self.clickedRegCancel, pos=(0.2, 0.0, -0.90), text_bg = (1, 0.5, 0.5, 1), relief = None) def destroyRegisterWindow(self): self.frame.destroy() self.frame = None self.title = None self.error = None self.username = None self.userTextbox = None self.password = None self.passTextbox = None self.cpassword = None self.cpassTextbox = None self.registerBtn = None self.cancelBtn = None # error message helper def displayError(self, msg): if self.frame is None: return if self.error is not None: self.error.destroy() self.error = OnscreenText(text = msg, pos = (0, -0.65), scale = 0.06, fg = (1, 0.5, 0.5, 1), align = TextNode.ACenter, parent = self.frame, mayChange = False) # userTextbox handlers def userTextFocus(self): if self.userTextbox.get() == '[username]': self.userTextbox.enterText('') def userTextBlur(self): if self.userTextbox.get().strip() == '': self.userTextbox.enterText('[username]') # passTextbox handlers def passTextFocus(self): if self.passTextbox.get() == '[password]': self.passTextbox.enterText('') def passTextBlur(self): if self.passTextbox.get().strip() == '': self.passTextbox.enterText('[password]') # cpassTextbox handlers def cpassTextFocus(self): if self.cpassTextbox.get() == '[confirm password]': self.cpassTextbox.enterText('') def cpassTextBlur(self): if self.cpassTextbox.get().strip() == '': self.cpassTextbox.enterText('[confirm password]') # login button handlers def clickedSubmit(self): username = self.userTextbox.get().strip() password = self.passTextbox.get().strip() if username != '' and password != '': self.main.cManager.sendRequest(Constants.C_AUTH, {'username': username, 'password': password}) else: self.displayError('Please enter a username and password.') def clickedRegister(self): self.destroyLoginWindow() self.createRegisterWindow() def clickedCancel(self): exit() # register button handlers def clickedRegRegister(self): username = self.userTextbox.get().strip() password = self.passTextbox.get().strip() cpass = self.cpassTextbox.get().strip() if username != '': if password != '': if cpass == password: self.main.cManager.sendRequest(Constants.C_REGISTER, {'username': username, 'password': password}) self.destroyRegisterWindow() self.createLoginWindow() else: self.displayError('Your passwords do not match.') else: self.displayError('Please enter a password.') else: self.displayError('Please enter a username.') def clickedRegCancel(self): self.destroyRegisterWindow() self.createLoginWindow()
class MyApp(ShowBase): def __init__(self): """ Initialize the MyApp class, including defining the GUI objects and layout. Inherits from ShowBase. """ # Because MyApp inherits from ShowBase, ShowBase needs to be initialized also (?) ShowBase.__init__(self) # doesn't disable the mouse, only disables the default setting of the mouse controlling the camera # can't import base and showbase at the same time. showbase is moreimportant right now. #base.disableMouse() # prints the coords of direct gui objects (DGO) when 'P' key is pressed or LMB is clicked self.accept("p", self.getDGOcoords) self.accept( "mouse1", self.getDGOcoords ) # only catches mouse when clicked on not gui elements >:| # add frmChatBox self.frmChatBox = DirectFrame(frameColor=(0, 255, 0, 1), frameSize=(-0.5, 0.5, -0.25, 0.25), pos=(0, 0, 0)) ### Add some gui objects and parent them to 'frmChatBox'. They move relative to 'frmChatBox', but are positioned relative to aspect2d. WHY?? ### Solution might be to create the frame at 0,0,0 and the DGOs relative to it (currently at 0,0,0) THEN move the frame. ### TODO: get mouse coords on screen to help with sizing DGOs? # add button btnClear = DirectButton(pos=(-0.15, 0, -0.95), text=("Clear", "CLEAR", "Clear", "disabled"), scale=.05, command=self.clearText, parent=self.frmChatBox) # add text entry box self.txtEntry = DirectEntry(text="", pos=(-0.99, 0, -0.95), scale=.05, command=self.setTextBox, initialText="Type Something", numLines=2, focus=1, parent=self.frmChatBox) # add button btnCommit = DirectButton(pos=(-0.35, 0, -0.95), text=("Commit", "COMMIT", "Commit", "disabled"), scale=.05, command=self.changeText, parent=self.frmChatBox) # define some text to be used in bk_text = "This is my Demo" # add text label, not parented to 'frmChatBox' self.lblLabel = DirectLabel(text=bk_text, pos=(0.95, 0, -0.95), scale=0.07, text_fg=(1, 0.5, 0.5, 1), text_bg=(0, 0, 0, 1), textMayChange=1) def changeText(self): """ Gets the text from input box "txtEntry" and sets it as the text of label "lblLabel" """ bk_text = self.txtEntry.get() self.lblLabel['text'] = bk_text def setTextBox(self, textEntered): """ Sets the text of label "textObject" to the value passed """ self.textObject['text'] = textEntered def clearText(self): """ Clears the text entry box """ self.txtEntry.enterText('') def getDGOcoords(self): """ Prints the coordinates of DirectGUI objects """ for child in self.frmChatBox.getChildren(): if "Direct" in str(child): print child, " position = ", child.getPos() print child, " scale = ", child.getScale() print "-" * 10
class DeveloperConsole(InteractiveInterpreter, DirectObject): """The name says it all.""" def __init__(self): sys.stdout = PseudoFile(self.writeOut) sys.stderr = PseudoFile(self.writeErr) tpErr = TextProperties() tpErr.setTextColor(1, 0.5, 0.5, 1) TextPropertiesManager.getGlobalPtr().setProperties("err", tpErr) #font = loader.loadFont("cmss12") self.frame = DirectFrame(parent = base.a2dTopCenter, text_align = TextNode.ALeft, text_pos = (-base.getAspectRatio() + TEXT_MARGIN[0], TEXT_MARGIN[1]), text_scale = 0.05, text_fg = (1, 1, 1, 1), frameSize = (-2.0, 2.0, -0.5, 0.0), frameColor = (0, 0, 0, 0.5), text = '')#, text_font = font) self.entry = DirectEntry(parent = base.a2dTopLeft, command = self.command, scale = 0.05, width = 1000.0, pos = (-0.02, 0, -0.48), relief = None, text_pos = (1.5, 0, 0), text_fg = (1, 1, 0.5, 1), rolloverSound = None, clickSound = None)#, text_font = font) self.otext = OnscreenText(parent = self.entry, scale = 1, align = TextNode.ALeft, pos = (1, 0, 0), fg = (1, 1, 0.5, 1), text = ':')#, font = font) self.lines = [''] * 9 self.commands = [] # All previously sent commands self.cscroll = None # Index of currently navigated command, None if current self.command = '' # Currently entered command self.block = '' # Temporarily stores a block of commands self.hide() self.initialized = False def prevCommand(self): if self.hidden: return if len(self.commands) == 0: return if self.cscroll == None: self.cscroll = len(self.commands) self.command = self.entry.get() elif self.cscroll <= 0: return else: self.commands[self.cscroll] = self.entry.get() self.cscroll -= 1 self.entry.set(self.commands[self.cscroll]) self.entry.setCursorPosition(len(self.commands[self.cscroll])) def nextCommand(self): if self.hidden: return if len(self.commands) == 0: return if self.cscroll == None: return self.commands[self.cscroll] = self.entry.get() self.cscroll += 1 if self.cscroll >= len(self.commands): self.cscroll = None self.entry.set(self.command) self.entry.setCursorPosition(len(self.command)) else: self.entry.set(self.commands[self.cscroll]) self.entry.setCursorPosition(len(self.commands[self.cscroll])) def writeOut(self, line, copy = True): if copy: sys.__stdout__.write(line) lines = line.split('\n') firstline = lines.pop(0) self.lines[-1] += firstline self.lines += lines self.frame['text'] = '\n'.join(self.lines[-9:]) def writeErr(self, line, copy = True): if copy: sys.__stderr__.write(line) line = '\1err\1%s\2' % line lines = line.split('\n') firstline = lines.pop(0) self.lines[-1] += firstline self.lines += lines self.frame['text'] = '\n'.join(self.lines[-9:]) def command(self, text): if not self.hidden: self.cscroll = None self.command = '' self.entry.set('') self.entry['focus'] = True self.writeOut(self.otext['text'] + ' ' + text + '\n', False) if text != '' and (len(self.commands) == 0 or self.commands[-1] != text): self.commands.append(text) # Insert plugins into the local namespace locals = __main__.__dict__ #locals['manager'] = self.manager #for plugin in self.manager.named.keys(): # locals[plugin] = self.manager.named[plugin] locals['panda3d'] = panda3d # Run it and print the output. if not self.initialized: InteractiveInterpreter.__init__(self, locals = locals) self.initialized = True try: if self.runsource(self.block + '\n' + text) and text != '': self.otext['text'] = '.' self.block += '\n' + text else: self.otext['text'] = ':' self.block = '' except Exception: # Not just "except", it will also catch SystemExit # Whoops! Print out a traceback. self.writeErr(traceback.format_exc()) def toggle(self): if self.hidden: self.show() else: self.hide() def show(self): self.accept('arrow_up', self.prevCommand) self.accept('arrow_up-repeat', self.prevCommand) self.accept('arrow_down', self.nextCommand) self.accept('arrow_down-repeat', self.nextCommand) self.hidden = False self.entry['focus'] = True self.frame.show() self.entry.show() self.otext.show() def hide(self): self.ignoreAll() self.hidden = True self.entry['focus'] = False self.frame.hide() self.entry.hide() self.otext.hide() def destroy(self): sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ self.ignoreAll() self.frame.destroy() self.entry.destroy() self.otext.destroy()
class Login(): def __init__(self, showbase): self.showbase = showbase self.background = DirectFrame( frameSize=(-1, 1, -1, 1), frameTexture='media/gui/login/bg.png', parent=self.showbase.render2d, ) ### CONFIG LOADER ### config = ConfigParser.RawConfigParser() config.read('master.cfg') self.LOGIN_IP = config.get('MASTER SERVER CONNECTION', 'masterIp') self.LOGIN_PORT = config.getint('MASTER SERVER CONNECTION', 'masterPort') config = ConfigParser.RawConfigParser() config.read('client.cfg') self.storeUsername = config.getint('USERDATA', 'storeUsername') if self.storeUsername == 1: self.username = config.get('USERDATA', 'username') else: self.username = '' self.storePassword = config.getint('USERDATA', 'storePassword') if self.storePassword == 1: self.password = config.get('USERDATA', 'password') else: self.password = '' ### CONFIG END ### self.loginScreen("Press 'Enter' to login") # draws the login screen self.usernameBox['focus'] = 1 # sets the cursor to the username field by default self.showbase.accept('tab', self.cycleLoginBox) self.showbase.accept('shift-tab', self.cycleLoginBox) # enables the user to cycle through the text fields with the tab key # this is a standard feature on most login forms self.showbase.accept('enter', self.attemptLogin) # submits the login form, or you can just click the Login button # checking variable to stop multiple presses of the button spawn multiple tasks self.requestAttempt = False self.showbase.authCon = Client(self.showbase, self.LOGIN_IP, self.LOGIN_PORT, compress=True) if not self.showbase.authCon.getConnected(): self.updateStatus( "Could not connect to the Login server\nOFFLINE MODE") self.showbase.online = False def updateConfig(self): config = ConfigParser.RawConfigParser() config.read('client.cfg') config.set('USERDATA', 'storeUsername', self.usernameStoreBox["indicatorValue"]) config.set('USERDATA', 'storePassword', self.passwordStoreBox["indicatorValue"]) if self.usernameStoreBox["indicatorValue"] == 1: config.set('USERDATA', 'username', self.usernameBox.get()) if self.passwordStoreBox["indicatorValue"] == 1: config.set('USERDATA', 'password', self.passwordBox.get()) with open('client.cfg', 'wb') as configfile: config.write(configfile) def loginScreen(self, statusText): # creates a basic login screen that asks for a username/password boxloc = Vec3(0.0, 0.0, 0.0) # all items in the login form will have a position relative to this # this makes it easier to shift the entire form around once we have # some graphics to display with it without having to change the # positioning of every form element # p is the position of the form element relative to the boxloc # coordinates set above it is changed for every form element p = boxloc + Vec3(-0.22, 0.09, 0.0) self.usernameText = OnscreenText(text="Username:"******"Username: "******"", pos=p, scale=.04, initialText=self.username, numLines=1) # Username textbox where you type in your username p = boxloc + Vec3(0.4, 0.0, 0.09) self.usernameStoreBox = DirectCheckButton( text="Save Username?", pos=p, scale=.04, indicatorValue=self.storeUsername) # Toggle to save/not save your username p = boxloc + Vec3(-0.22, 0.0, 0.0) self.passwordText = OnscreenText(text="Password:"******"Password: "******"", pos=p, scale=.04, initialText=self.password, numLines=1, obscured=1) # Password textbox where you type in your password # Note - obscured = 1 denotes that all text entered will be replaced # with a * like a standard password box p = boxloc + Vec3(0.4, 0.0, 0.0) self.passwordStoreBox = DirectCheckButton( text="Save Password?", pos=p, scale=.04, indicatorValue=self.storePassword) # Toggle to save/not save your username p = boxloc + Vec3(0, 0, -0.090) self.loginButton = DirectButton(text="Login", pos=p, scale=0.048, relief=DGG.GROOVE, command=self.attemptLogin) # The 'Quit' button that will trigger the Quit function # when clicked p = boxloc + Vec3(0.95, 0, -0.9) self.createAccButton = DirectButton(text="Create Account", scale=0.050, pos=p, relief=DGG.GROOVE, command=self.attemptCreateAccount) # Made a quick button for adding accounts. Its fugly p = boxloc + Vec3(1.20, 0, -0.9) self.quitButton = DirectButton(text="Quit", pos=p, scale=0.048, relief=DGG.GROOVE, command=self.showbase.quit) # The 'Quit' button that will trigger the Quit function # when clicked p = boxloc + Vec3(0, -0.4, 0) self.statusText = OnscreenText(text=statusText, pos=p, scale=0.043, fg=(1, 0.5, 0, 1), align=TextNode.ACenter) # A simple text object that you can display an error/status messages # to the user def updateStatus(self, statusText): self.statusText.setText(statusText) # all this does is change the status text. def checkBoxes(self): # checks to make sure the user inputed a username and password: # if they didn't it will spit out an error message self.updateStatus("") if self.usernameBox.get() == "": if self.passwordBox.get() == "": self.updateStatus( "You must enter a username and password before logging in." ) else: self.updateStatus("You must specify a username") self.passwordBox['focus'] = 0 self.usernameBox['focus'] = 1 return False elif self.passwordBox.get() == "": self.updateStatus("You must enter a password") self.usernameBox['focus'] = 0 self.passwordBox['focus'] = 1 return False # if both boxes are filled then return True return True def attemptLogin(self): if self.checkBoxes(): self.showbase.username = self.usernameBox.get() self.updateStatus("Attempting to login...") self.request(self.usernameBox.get(), self.passwordBox.get(), 'client') def attemptCreateAccount(self): if self.checkBoxes(): self.updateStatus("Attempting to create account and login...") self.request(self.usernameBox.get(), self.passwordBox.get(), 'create') def request(self, username, password, request): if not self.requestAttempt: # attempt to connect again if it failed on startup if self.showbase.authCon.getConnected(): self.requestAttempt = True self.loginButton["state"] = DGG.DISABLED self.createAccButton["state"] = DGG.DISABLED self.showbase.authCon.sendData((request, (username, password))) self.showbase.username = username self.showbase.online = True self.showbase.taskMgr.doMethodLater(0.2, self.responseReader, 'Update Login') else: # client not connected to login/auth server so display message self.updateStatus("Offline Mode") self.showbase.username = username self.showbase.online = False self.updateConfig() self.showbase.startMainmenu() def responseReader(self, task): if task.time > 2.5: self.loginButton["state"] = DGG.NORMAL self.createAccButton["state"] = DGG.NORMAL self.updateStatus("Timeout from Login server") return task.done else: temp = self.showbase.authCon.getData() for package in temp: if len(package) == 2: print "Received: " + str(package) print "Connected to login server" if package[0] == 'loginFailed': print "Login failed: ", package[1] if package[1] == 'username': self.updateStatus("Username Doesnt Exist") self.passwordBox.set("") self.usernameBox.set("") self.passwordBox['focus'] = 0 self.usernameBox['focus'] = 1 elif package[1] == 'password': self.updateStatus("Password Incorrect") self.passwordBox.set("") self.usernameBox['focus'] = 0 self.passwordBox['focus'] = 1 elif package[1] == 'logged': self.updateStatus("Username already logged in") self.requestAttempt = False self.loginButton["state"] = DGG.NORMAL self.createAccButton["state"] = DGG.NORMAL return task.done elif package[0] == 'loginValid': print "Login valid: ", package[1] self.updateStatus(package[1]) self.updateConfig() self.showbase.startMainmenu() return task.done elif package[0] == 'createFailed': print "Create failed: ", package[1] if package[1] == 'exists': self.updateStatus("Username Already Exists") self.passwordBox.set("") self.usernameBox.set("") self.passwordBox['focus'] = 0 self.usernameBox['focus'] = 1 self.requestAttempt = False self.loginButton["state"] = DGG.NORMAL self.createAccButton["state"] = DGG.NORMAL return task.done elif package[0] == 'createSuccess': print "Create success", package[1] self.updateStatus("Account Created Successfully") self.requestAttempt = False self.attemptLogin() return task.done return task.cont def cycleLoginBox(self): # function is triggered by the tab key so you can cycle between # the two input fields like on most login screens if self.passwordBox['focus'] == 1: self.passwordBox['focus'] = 0 self.usernameBox['focus'] = 1 elif self.usernameBox['focus'] == 1: self.usernameBox['focus'] = 0 self.passwordBox['focus'] = 1 # IMPORTANT: When you change the focus to one of the text boxes, # you have to unset the focus on the other textbox. If you do not # do this Panda seems to get confused. def hide(self): self.background.destroy() self.usernameText.destroy() self.usernameBox.destroy() self.usernameStoreBox.destroy() self.passwordText.destroy() self.passwordBox.destroy() self.passwordStoreBox.destroy() self.loginButton.destroy() self.quitButton.destroy() self.createAccButton.destroy() self.statusText.destroy() self.showbase.ignore('tab') self.showbase.ignore('shift-tab') self.showbase.ignore('enter')
class panda3dIOClass( DirectObject.DirectObject ): # set gui key to None if you want to call toggleConsole from outside this class gui_key = CONSOLE_TOGGLE_KEY autocomplete_key = CONSOLE_AUTOCOMPLETE_KEY autohelp_key = CONSOLE_AUTOHELP_KEY scroll_up_repeat_key = CONSOLE_SCROLL_UP_KEY + "-repeat" scroll_down_repeat_key = CONSOLE_SCROLL_DOWN_KEY + "-repeat" # change size of text and number of characters on one line # scale of frame ( must be small (0.0x) scale = PANDA3D_CONSOLE_SCALE # to define a special font, if loading fails the default font is used (without warning) font = PANDA3D_CONSOLE_FONT fontWidth = PANDA3D_CONSOLE_FONT_WIDTH # frame position and size (vertical & horizontal) h_pos = PANDA3D_CONSOLE_HORIZONTAL_POS h_size = PANDA3D_CONSOLE_HORIZONTAL_SIZE # v_size + v_pos should not exceed 2.0, else parts of the interface will not be visible # space above the frame ( must be below 2.0, best between 0.0 and 1.0 ) v_pos = PANDA3D_CONSOLE_VERTICAL_POS # vertical size of the frame ( must be at max 2.0, best between 0.5 and 2.0 ) v_size = PANDA3D_CONSOLE_VERTICAL_SIZE linelength = int((h_size/scale - 5) / fontWidth) print "max number of characters on a length:", linelength numlines = int(v_size/scale - 5) defaultTextColor = (0.0,0.0,0.0,1.0) autoCompleteColor = (0.9,0.9,0.9,1.0) def __init__( self, parent ): self.parent = parent # line wrapper self.linewrap = textwrap.TextWrapper() self.linewrap.width = self.linelength # calculate window size left = (self.h_pos) / self.scale right = (self.h_pos + self.h_size) / self.scale bottom = (self.v_pos) / self.scale top = (self.v_pos + self.v_size) /self.scale # panda3d interface self.consoleFrame = DirectFrame ( relief = DGG.GROOVE , frameColor = (200, 200, 200, 0.5) , scale=self.scale , frameSize = (0, self.h_size / self.scale, 0, self.v_size / self.scale) ) self.windowEvent( base.win ) # try to load the defined font try: fixedWidthFont = loader.loadFont(self.font) except: print "pandaInteractiveConsole.py :: could not load the defined font %s" % str(self.font) fixedWidthFont = DGG.getDefaultFont() # if font is not valid use default font if not fixedWidthFont.isValid(): if self.font is None: print "pandaInteractiveConsole.py :: could not load the defined font %s" % str(self.font) fixedWidthFont = DGG.getDefaultFont() # text entry line self.consoleEntry = DirectEntry ( self.consoleFrame , text = "" , command = self.onEnterPress , width = self.h_size/self.scale - 2 , pos = (1, 0, 1.5) , initialText = "" , numLines = 1 , focus = 1 , entryFont = fixedWidthFont) # output lines self.consoleOutputList = list() for i in xrange( self.numlines ): label = OnscreenText( parent = self.consoleFrame , text = "" , pos = (1, -i+3+self.numlines) , align=TextNode.ALeft , mayChange=1 , scale=1.0 , fg = self.defaultTextColor ) label.setFont( fixedWidthFont ) self.consoleOutputList.append( label ) # list of the last commands of the user self.userCommandList = list() self.userCommandListLength = 100 for i in xrange(self.userCommandListLength): self.userCommandList.append('') self.userCommandPos = 0 # buffer for data self.textBuffer = list() self.textBufferLength = 1000 for i in xrange(self.textBufferLength): self.textBuffer.append(['', DEFAULT_COLOR]) self.textBufferPos = self.textBufferLength-self.numlines # toggle the window at least once to activate the events self.toggleConsole() self.toggleConsole() # call the help-command on start self.onEnterPress("help") # write a string to the panda3d console def write( self, printString, color=defaultTextColor ): # remove not printable characters (which can be input by console input) printString = re.sub( r'[^%s]' % re.escape(string.printable[:95]), "", printString) splitLines = self.linewrap.wrap(printString) for line in splitLines: self.textBuffer.append( [line, color] ) self.textBuffer.pop(0) self.updateOutput() def updateOutput( self ): for lineNumber in xrange(self.numlines): lineText, color = self.textBuffer[lineNumber + self.textBufferPos] self.consoleOutputList[lineNumber].setText( lineText ) self.consoleOutputList[lineNumber]['fg'] = color # toggle the gui console def toggleConsole( self ): self.consoleFrame.toggleVis() hidden = self.consoleFrame.isHidden() self.consoleEntry['focus'] != hidden if hidden: self.ignoreAll() self.accept( self.gui_key, self.toggleConsole ) #playerController.enableInput() #unpause("v") else: self.ignoreAll() #playerController.disableInput() #pause("v") self.accept( CONSOLE_SCROLL_UP_KEY, self.scroll, [-5] ) self.accept( self.scroll_up_repeat_key, self.scroll, [-5] ) self.accept( CONSOLE_SCROLL_DOWN_KEY, self.scroll, [5] ) self.accept( self.scroll_down_repeat_key, self.scroll, [5] ) self.accept( 'window-event', self.windowEvent) self.accept( CONSOLE_PREVIOUS_COMMAND_KEY , self.scrollCmd, [ 1] ) self.accept( CONSOLE_NEXT_COMMAND_KEY, self.scrollCmd, [-1] ) self.accept( self.gui_key, self.toggleConsole ) #self.accept( self.autocomplete_key, self.autocomplete ) #self.accept( self.autohelp_key, self.autohelp ) # accept v, c and x, where c & x copy's the whole console text #messenger.toggleVerbose() #for osx use ('meta') if sys.platform == 'darwin': self.accept( 'meta', self.unfocus ) self.accept( 'meta-up', self.focus ) self.accept( 'meta-c', self.copy ) self.accept( 'meta-x', self.cut ) self.accept( 'meta-v', self.paste ) #for windows use ('control') if sys.platform == 'win32' or sys.platform == 'linux2': self.accept( 'control', self.unfocus ) self.accept( 'control-up', self.focus ) self.accept( 'control-c', self.copy ) self.accept( 'control-x', self.cut ) self.accept( 'control-v', self.paste ) # def autohelp( self ): # currentText = self.consoleEntry.get() # currentPos = self.consoleEntry.guiItem.getCursorPosition() # self.parent.autohelp( currentText, currentPos ) def focus( self ): self.consoleEntry['focus'] = 1 def unfocus( self ): self.consoleEntry['focus'] = 0 def copy( self ): copy = self.consoleEntry.get() clipboard.setText( copy ) def paste( self ): oldCursorPos = self.consoleEntry.guiItem.getCursorPosition() clipboardText = clipboard.getText() # compose new text line oldText = self.consoleEntry.get() newText = oldText[0:oldCursorPos] + clipboardText + oldText[oldCursorPos:] clipboardTextLines = newText.split(os.linesep) for i in xrange( len(clipboardTextLines)-1 ): currentLine = clipboardTextLines[i] # we only want printable characters currentLine = re.sub( r'[^' + re.escape(string.printable[:95]) + ']', "", currentLine) # set new text and position self.consoleEntry.set( currentLine ) self.onEnterPress( currentLine ) currentLine = clipboardTextLines[-1] currentLine = re.sub( r'[^' + re.escape(string.printable[:95]) + ']', "", currentLine) self.consoleEntry.set( currentLine ) self.consoleEntry.setCursorPosition( len(self.consoleEntry.get()) ) self.focus() def cut( self ): clipboard.setText( self.consoleEntry.get() ) self.consoleEntry.enterText('') self.focus() def scroll( self, step ): self.textBufferPos += step self.textBufferPos = min( self.textBufferLength-self.numlines, max( 0, self.textBufferPos ) ) self.updateOutput() def scrollCmd( self, step ): oldCmdPos = self.userCommandPos self.userCommandPos += step self.userCommandPos = min( self.userCommandListLength-1, max( 0, self.userCommandPos ) ) self.userCommandList[oldCmdPos] = self.consoleEntry.get() newCmd = self.userCommandList[self.userCommandPos] self.consoleEntry.set( newCmd ) self.consoleEntry.setCursorPosition( len(newCmd) ) def onEnterPress( self, textEntered ): # set to last message self.textBufferPos = self.textBufferLength-self.numlines # clear line self.consoleEntry.enterText('') self.focus() # add text entered to user command list & remove oldest entry self.userCommandList.insert( 1, textEntered ) self.userCommandList[0] = '' self.userCommandList.pop( -1 ) self.userCommandPos = 0 # call the interpreter to handle the input interpreter = cliClass() result = interpreter.interpreter(textEntered) # write the entered text to the output self.write(textEntered, (0.0, 0.0, 1, 1)) print textEntered # write each line seperately to the output for line in result.split('\n'): line = " " + line self.write(line, (0, 0, 0, 1)) print line def windowEvent( self, window ): """ This is a special callback. It is called when the panda window is modified. """ wp = window.getProperties() width = wp.getXSize() / float(wp.getYSize()) height = wp.getYSize() / float(wp.getXSize()) if width > height: height = 1.0 else: width = 1.0 # aligned to center consolePos = Vec3(-self.h_size/2, 0, -self.v_size/2) # aligned to left bottom #consolePos = Vec3(-width+self.h_pos, 0, -height+self.v_pos) # aligned to right top #consolePos = Vec3(width-self.h_size, 0, height-self.v_size) # set position self.consoleFrame.setPos( consolePos )
class AdminPage(BookPage): def __init__(self, book): BookPage.__init__(self, book, 'Admin Panel') self.fsm = ClassicFSM( 'AdminPage', [ State('off', self.enterOff, self.exitOff), State('basePage', self.enterBasePage, self.exitBasePage), State('kickSection', self.enterKickSection, self.exitKickSection), #State('clickOnToon', self.enterClickOnToon, self.exitClickOnToon), State('sysMsgSection', self.enterSysMsgSection, self.exitSysMsgSection) ], 'off', 'off') self.fsm.enterInitialState() def load(self): BookPage.load(self) icons = loader.loadModel('phase_4/models/gui/tfa_images.bam') self.icon = icons.find('**/hq-dialog-image') icons.detachNode() def enterOff(self): pass def exitOff(self): pass def enter(self): BookPage.enter(self) self.fsm.request('basePage') def exit(self): self.fsm.requestFinalState() BookPage.exit(self) def unload(self): del self.book del self.fsm BookPage.unload(self) def enterSysMsgSection(self): geom = CIGlobals.getDefaultBtnGeom() self.infoLbl = OnscreenText( text="Inform all online players about something.", pos=(0, 0.45)) self.msgEntry = DirectEntry( initialText="System Message...", scale=0.055, width=15, numLines=4, command=self.sendSystemMessageCommand, focusInCommand=base.localAvatar.chatInput.disableKeyboardShortcuts, focusOutCommand=base.localAvatar.chatInput.enableKeyboardShortcuts, pos=(-0.4, 0, 0)) self.sendBtn = DirectButton( geom=geom, text_scale=0.04, relief=None, scale=1.0, text="Send", pos=(0, 0, -0.35), text_pos=(0, -0.01), command=self.sendSystemMessageCommand, ) self.cancelBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text="Cancel", pos=(-0.45, 0.15, -0.55), text_pos=(0, -0.01), command=self.fsm.request, extraArgs=['basePage']) # Occasionally, extra arguments are sent and this extra variable must be here to capture them. def sendSystemMessageCommand(self, _=None): msg = self.msgEntry.get() DISTRICT_WIDE_MSG(msg) self.fsm.request('basePage') def exitSysMsgSection(self): self.infoLbl.destroy() del self.infoLbl self.msgEntry.destroy() del self.msgEntry self.sendBtn.destroy() del self.sendBtn self.cancelBtn.destroy() del self.cancelBtn def enterKickSection(self): geom = CIGlobals.getDefaultBtnGeom() self.infoLbl = OnscreenText(text="Kick or Ban?", pos=(0, 0.45)) self.kickBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text="Kick", pos=(0, 0, 0.1), text_pos=(0, -0.01), command=self.book.finishedResume, extraArgs=[KickBanDialog, [0]]) self.banBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text="Ban", pos=(0, 0, 0.0), text_pos=(0, -0.01), command=self.book.finishedResume, extraArgs=[KickBanDialog, [1]]) self.cancelBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text="Cancel", pos=(-0.45, 0.15, -0.45), text_pos=(0, -0.01), command=self.fsm.request, extraArgs=['basePage']) def exitKickSection(self): self.banBtn.destroy() del self.banBtn self.infoLbl.destroy() del self.infoLbl self.cancelBtn.destroy() del self.cancelBtn self.kickBtn.destroy() del self.kickBtn def enterBasePage(self): geom = CIGlobals.getDefaultBtnGeom() self.ghostBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text="Toggle Ghost", pos=(-0.45, 0.15, 0.5), text_pos=(0, -0.01), command=TOGGLE_GHOST) self.bgBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text="Toggle Background", pos=(-0.45, 0.15, 0.40), text_pos=(0, -0.01), command=self.toggleBackground) self.idBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text="Toggle Player Ids", pos=(-0.45, 0.15, 0.3), text_pos=(0, -0.01), command=TOGGLE_PLAYER_IDS) self.kickBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text="Kick/Ban Player", pos=(0.45, 0.15, 0.5), text_pos=(0, -0.01), command=self.openKickPage) self.systemMsgBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text="System Message", pos=(-0.45, 0.15, 0.1), text_pos=(0, -0.01), command=self.openSysMsgPage) self.oobeBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text="Toggle OOBE", pos=(-0.45, 0.15, 0.2), text_pos=(0, -0.01), command=base.oobe) self.directBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text="Start DIRECT", pos=(-0.45, 0.15, 0.1), text_pos=(0, -0.01), command=self.doStartDirect) self.pstatsBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text="Toggle PStats", pos=(-0.45, 0.15, 0.0), text_pos=(0, -0.01), command=self.togglePStats) self.pingBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text="Toggle Ping", pos=(-0.45, 0.15, -0.1), text_pos=(0, -0.01), command=base.cr.togglePing) self.tokenBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text="Modify Access Level", pos=(0.45, 0.15, 0.4), text_pos=(0, -0.01), command=self.book.finishedResume, extraArgs=[AdminTokenDialog, []]) self.worldBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text="Give World Access", pos=(0.45, 0.15, 0.3), text_pos=(0, -0.01), command=self.book.finishedResume, extraArgs=[WorldAccessDialog, []]) self.allGagsBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text="Restock All Gags", pos=(0.45, 0.15, 0.2), text_pos=(0, -0.01), command=SEND_REQ_UNLOCK_GAGS) self.allLaffBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text="Refill Laff", pos=(0.45, 0.15, 0.1), text_pos=(0, -0.01), command=SEND_REQ_REFILL_LAFF) self.physDbgBtn = DirectButton(geom=geom, text_scale=0.039, relief=None, scale=1.0, text="Toggle Physics Debug", pos=(0.45, 0.15, 0.0), text_pos=(0, -0.01), command=self.togglePhysDbg) self.analyzeBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text="Analyze Scene", pos=(0.45, 0.15, -0.1), text_pos=(0, -0.01), command=self.doAnalyzeScene) self.listBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text="List Scene", pos=(0.45, 0.15, -0.2), text_pos=(0, -0.01), command=render.ls) self.noClipBtn = DirectButton(geom=geom, text_scale=0.04, relief=None, scale=1.0, text="Toggle No Clip", pos=(0.45, 0.15, -0.3), text_pos=(0, -0.01), command=self.toggleNoClip) base.cr.playGame.getPlace().maybeUpdateAdminPage() del geom def doStartDirect(self): base.startTk() base.startDirect() def doAnalyzeScene(self): render.analyze() ls = LineStream() sga = SceneGraphAnalyzer() sga.addNode(render.node()) sga.write(ls) text = "" while ls.isTextAvailable(): text += ls.getLine() + "\n" self.acceptOnce('analyzedone', self.__handleAnalyzeDone) self.analyzeDlg = GlobalDialog(message=text, style=Ok, doneEvent='analyzedone', text_scale=0.05) self.analyzeDlg.show() def __handleAnalyzeDone(self): self.analyzeDlg.cleanup() del self.analyzeDlg def toggleNoClip(self): ncl = not base.localAvatar.walkControls.controller.noClip base.localAvatar.walkControls.controller.noClip = ncl if ncl: base.cr.myDistrict.systemMessage("No Clip Enabled") else: base.cr.myDistrict.systemMessage("No Clip Disabled") def togglePhysDbg(self): base.setPhysicsDebug(not base.physicsDbgFlag) def togglePStats(self): if PStatClient.isConnected(): PStatClient.disconnect() else: # in production, show stats viewer on the server if base.config.GetBool("pstats-view-on-server", False): PStatClient.connect("127.0.0.1" if not metadata.IS_PRODUCTION else "gameserver.coginvasion.online") else: PStatClient.connect("127.0.0.1") def toggleBackground(self): if render.isHidden(): render.show() else: render.hide() if self.book.isBackgroundHidden(): self.book.show() self.book.setBackgroundHidden(False) else: self.book.hide() self.book.setBackgroundHidden(True) def openKickPage(self): self.fsm.request('kickSection') def openSysMsgPage(self): self.fsm.request('sysMsgSection') def exitBasePage(self): self.noClipBtn.destroy() del self.noClipBtn self.systemMsgBtn.destroy() del self.systemMsgBtn self.idBtn.destroy() del self.idBtn self.kickBtn.destroy() del self.kickBtn self.bgBtn.destroy() del self.bgBtn self.ghostBtn.destroy() del self.ghostBtn self.oobeBtn.destroy() del self.oobeBtn self.tokenBtn.destroy() del self.tokenBtn self.worldBtn.destroy() del self.worldBtn self.allGagsBtn.destroy() del self.allGagsBtn self.allLaffBtn.destroy() del self.allLaffBtn self.physDbgBtn.destroy() del self.physDbgBtn self.analyzeBtn.destroy() del self.analyzeBtn if hasattr(self, 'analyzeDlg'): self.ignore('analyzedone') self.analyzeDlg.cleanup() del self.analyzeDlg self.directBtn.destroy() del self.directBtn self.listBtn.destroy() del self.listBtn self.pstatsBtn.destroy() del self.pstatsBtn self.pingBtn.destroy() del self.pingBtn