def sign_cb(parent): thanks = open(eng.curr_path + 'assets/thanks.txt').readlines() shuffle(thanks) text = '\n\n'.join(thanks[:3]) txt = OnscreenText(text, parent=parent, scale=.2, fg=(0, 0, 0, 1), pos=(.245, 0)) bounds = lambda: txt.getTightBounds() while bounds()[1][0] - bounds()[0][0] > .48: scale = txt.getScale()[0] txt.setScale(scale - .01, scale - .01) bounds = txt.getTightBounds() height = bounds[1][2] - bounds[0][2] txt.setZ(.06 + height / 2)
class ScrollText(): def __init__(self, text='', align=TextNode.ALeft, scale=(1, 1), font=None, font_size=12, parent=None, frameColor=(0.33, 0.33, 0.33, .66), frameSize=(0, 0.5, -1.0, 0)): if parent is None: parent = aspect2d self.parent = parent self.frame = DirectScrolledFrame( parent=parent, frameColor=frameColor, state=DGG.DISABLED, frameSize=frameSize, relief=DGG.FLAT, scrollBarWidth=scale[0] * font_size, horizontalScroll_relief=DGG.FLAT, verticalScroll_relief=DGG.FLAT, ) self.text = OnscreenText(parent=self.frame.getCanvas(), text=text, align=align, scale=tuple(scale * font_size), font=font) bounds = self.text.getTightBounds() self.frame['canvasSize'] = [ 0, bounds[1][0] - bounds[0][0], -bounds[1][2] + bounds[0][2], 0 ] self.text.setPos(-bounds[0][0], -bounds[1][2]) self.frame.setPos(0, 0, 0) def destroy(self): self.frame.destroy() def reparent_to(self, parent): self.frame.reparent_to(parent)
class HostMenu(DirectObject): def __init__(self): self.defaultBtnMap = base.loader.loadModel("gui/button_map") self.buttonGeom = ( self.defaultBtnMap.find("**/button_ready"), self.defaultBtnMap.find("**/button_click"), self.defaultBtnMap.find("**/button_rollover"), self.defaultBtnMap.find("**/button_disabled")) defaultFont = loader.loadFont('gui/eufm10.ttf') self.logFrame = DirectScrolledFrame( canvasSize = (0, base.a2dRight * 2, -5, 0), frameSize = (0, base.a2dRight * 2, (base.a2dBottom+.2) * 2, 0), frameColor = (0.1, 0.1, 0.1, 1)) self.logFrame.reparentTo(base.a2dTopLeft) # create the info and server debug output self.textscale = 0.1 self.txtinfo = OnscreenText( scale = self.textscale, pos = (0.1, -0.1), text = "", align = TextNode.ALeft, fg = (0.1,1.0,0.15,1), bg = (0, 0, 0, 0), shadow = (0, 0, 0, 1), shadowOffset = (-0.02, -0.02)) self.txtinfo.setTransparency(1) self.txtinfo.reparentTo(self.logFrame.getCanvas()) # create a close Server button self.btnBackPos = Vec3(0.4, 0, 0.2) self.btnBackScale = 0.25 self.btnBack = DirectButton( # Scale and position scale = self.btnBackScale, pos = self.btnBackPos, # Text text = "Quit Server", text_scale = 0.45, text_pos = (0, -0.1), text_fg = (0.82,0.85,0.87,1), text_shadow = (0, 0, 0, 1), text_shadowOffset = (-0.02, -0.02), text_font = defaultFont, # Frame geom = self.buttonGeom, frameColor = (0, 0, 0, 0), relief = 0, pressEffect = False, # Functionality command = self.back, rolloverSound = None, clickSound = None) self.btnBack.setTransparency(1) self.btnBack.reparentTo(base.a2dBottomLeft) # catch window resizes and recalculate the aspectration self.accept("window-event", self.recalcAspectRatio) self.accept("addLog", self.addLog) def show(self): self.logFrame.show() self.btnBack.show() def hide(self): self.logFrame.hide() self.btnBack.hide() def back(self): self.hide() base.messenger.send("stop_server") self.addLog("Quit Server!") def addLog(self, text): self.txtinfo.appendText(text + "\n") textbounds = self.txtinfo.getTightBounds() self.logFrame["canvasSize"] = (0, textbounds[1].getX(), textbounds[0].getZ(), 0) def recalcAspectRatio(self, window): """get the new aspect ratio to resize the mainframe""" # set the mainframe size to the window borders again self.logFrame["frameSize"] = ( 0, base.a2dRight * 2, (base.a2dBottom+.2) * 2, 0)
class Query: def __init__(self, scale, font, color, text_size, suggestions_text_size, query_delay): self.scale = scale self.font = font self.color = color self.text_size = text_size self.suggestions_text_size = suggestions_text_size self.query_delay = query_delay self.background = None self.prefix = None self.query = None self.suggestions = None self.owner = None self.current_selection = None self.current_list = [] self.completion_task = None self.max_columns = 4 self.max_lines = 3 self.max_elems = self.max_columns * self.max_lines def do_query(self, text): body = None if self.current_selection is not None: if self.current_selection < len(self.current_list): body = self.current_list[self.current_selection][1] else: text = self.query.get() body = self.owner.get_object(text) self.owner.select_object(body) self.close() def close(self): self.background.destroy() self.background = None self.prefix.destroy() self.prefix = None self.query.destroy() self.query = None self.suggestions.destroy() self.suggestions = None self.current_selection = None self.current_list = [] if self.completion_task is not None: taskMgr.remove(self.completion_task) self.completion_task = None def escape(self, event): self.close() def update_suggestions(self): if self.current_selection is not None: page = self.current_selection // self.max_elems else: page = 0 start = page * self.max_elems end = min(start + self.max_elems - 1, len(self.current_list) - 1) suggestions = "" for i in range(start, end + 1): if i != start and ((i - start) % self.max_columns) == 0: suggestions += '\n' if i == self.current_selection: suggestions += "\1md_bold\1%s\2" % self.current_list[i][0] else: suggestions += self.current_list[i][0] suggestions += '\t' self.suggestions.setText(suggestions) def completion(self, event): text = self.query.get() if text != '': self.current_list = self.owner.list_objects(text) else: self.current_list = [] self.current_selection = None if self.completion_task is not None: taskMgr.remove(self.completion_task) self.completion_task = taskMgr.doMethodLater(self.query_delay, self.update_suggestions, 'completion task', extraArgs=[]) def select(self, event): modifiers = event.getModifierButtons() if modifiers.isDown(KeyboardButton.shift()): incr = -1 else: incr = 1 if self.current_selection is not None: new_selection = self.current_selection + incr else: new_selection = 0 if new_selection < 0: new_selection = len(self.current_list) - 1 if new_selection >= len(self.current_list): new_selection = 0 self.current_selection = new_selection self.update_suggestions() def open_query(self, owner): self.owner = owner bg_color = LColor(*self.color) bg_color[3] = 0.2 scale3 = LVector3(self.scale[0], 1.0, self.scale[1]) self.background = DirectFrame( frameColor=bg_color, frameSize=(-1 / self.scale[0], 1.0 / self.scale[0], 0.15 + self.scale[1] * self.text_size, 0.0), parent=base.a2dBottomLeft) self.prefix = OnscreenText( text=_("Target name:"), font=self.font, fg=self.color, align=TextNode.ALeft, parent=base.a2dBottomLeft, scale=tuple(self.scale * self.text_size), pos=(0, .15), ) bounds = self.prefix.getTightBounds() length = bounds[1][0] - bounds[0][ 0] + self.scale[0] * self.text_size / 2 self.query = DirectEntry(text="", text_fg=self.color, scale=tuple(scale3 * self.text_size), command=self.do_query, parent=base.a2dBottomLeft, frameColor=(0, 0, 0, 0), pos=(length, 0, .15), initialText="", numLines=1, width=200, entryFont=self.font, focus=1, suppressKeys=1) self.query.bind("press-escape-", self.escape) self.query.bind("press-tab-", self.select) self.query.accept(self.query.guiItem.getTypeEvent(), self.completion) self.query.accept(self.query.guiItem.getEraseEvent(), self.completion) pos = self.prefix.getPos() bounds = self.query.getBounds() llz = bounds[2] / self.text_size self.suggestions = OnscreenText( text="", font=self.font, fg=self.color, align=TextNode.ALeft, mayChange=True, parent=base.a2dBottomLeft, scale=tuple(self.scale * self.suggestions_text_size), pos=(pos[0], pos[1] + llz), )
def setupGUI(self): """ Builds the GUI based on the JSON description """ # stores the GUI labels self.guiLabels = [] # stores ALL the widgets in order of focus (even if they cannot get focus) self.focusOrder = [] # DirectFrame that will contain the GUI self.myFrame = None # frame to hold the form (left, right, bottom, top) # Find out window dimensions ratio = self.config.world.camera.ratio frameSize = (-ratio, ratio, -1.0, 1.0) # centered pos = (0, 1.0, 0) # background colour try: colour = self.config.color_background except: colour = self.colours['dark_grey'] # guiLabels colour labelColour = getattr(self.config.settings, 'color_label', (1.0, 1.0, 1.0, 1.0)) # global scale of the frame scale = self.config.settings.scale # canvas with scrolling capabilities self.myFrame = DirectScrolledFrame( canvasSize=(frameSize[0], frameSize[1], 50 * frameSize[2], frameSize[3]), frameColor=colour, frameSize=frameSize, pos=pos) # reparent the frame to the hudNP so we can hide it easily self.myFrame.reparentTo(self.hudNP) # read title or set to a default value title = getattr(self.config.settings, "title", "Introduce your data") # title of the frame label = OnscreenText(text=title, pos=(0, frameSize[3] - scale * 2.5), scale=scale * 1.5, fg=labelColour, align=TextNode.ACenter, mayChange=1) label.reparentTo(self.myFrame.getCanvas()) # max length in characters of a label (will split in lines if bigger) maxLabel = self.config.settings.maxlabel maxwidth = 0 # position of the first label and widget lastYpos = frameSize[3] - scale * 4 for count, i in enumerate(self.config.input): # create label in several lines up to 15 chars # split the string in several lines up to 15 chars printOut("Creating element: %s" % i.label, 2) splitWords = splitString(str(i.label) + ':', maxLabel) for s in splitWords: lastYpos -= 1.1 * scale label2 = OnscreenText(text=s, pos=(0, lastYpos), scale=scale, fg=labelColour, align=TextNode.ARight, mayChange=1) bounds = label2.getTightBounds() width = abs(bounds[0][0] - bounds[1][1]) if (width > maxwidth): maxwidth = width label2.reparentTo(self.myFrame.getCanvas()) self.guiLabels.append(label2) # for each label, create a widget matching the YAML widgetYpos = lastYpos if (str(i.type) == 'TextEntry'): widget = DirectEntry(text="", scale=scale, cursorKeys=1, command=self.setText, extraArgs=[], pos=(0.05, 1, widgetYpos), numLines=1, focus=0) elif (str(i.type) == 'Option'): widget = DirectOptionMenu(text="options", scale=1.05 * scale, items=i.tuple_values, popupMarkerBorder=(1, 0), initialitem=0, command=self.optionMenu, extraArgs=[], pos=(0.05, 1, widgetYpos), text_scale=(0.7, 0.7), text_pos=(0.3, 0.1)) elif (str(i.type) == 'TickBox'): widget = DirectCheckButton(text="", scale=scale, command=self.tickBoxClicked, extraArgs=[], pos=(scale + 0.04, 1, widgetYpos + scale / 3.0)) widget.clicked = getattr(i, 'default', False) # order of creation widget['extraArgs'] = [widget] self.focusOrder.append(widget) widget.reparentTo(self.myFrame.getCanvas()) # distance to next widget lastYpos -= scale # adjust X position based on the largest word for l in self.guiLabels: #adjust X position l.setX(frameSize[0] + maxwidth + 0.05) for w in self.focusOrder: w.setX(w['pos'][0] + frameSize[0] + maxwidth + 0.10) # add a button to save the values and advance from the FORM (exit this state) lastYpos -= 2 * scale pad0 = (0.9, 0.7) #self.saveButton = DirectButton( parent = self.myFrame, # text="Save", pad=pad0, scale=0.05, # pos=(frameSize[1] - 10*0.05, 0, lastYpos), command=self.savePressed # ) #self.finishButton = DirectButton ( parent = self.myFrame, # text="Finish", pad=pad0, scale=0.05, # pos=(frameSize[1] - 5*0.05,0,lastYpos), command=self.finishPressed # ) #self.finishButton["state"] = DGG.DISABLED #self.clearButton = DirectButton ( parent = self.myFrame, # text="Clear", pad=pad0, scale=0.05, # pos=(frameSize[1] - 15*0.05,0,lastYpos), command=self.clearButton # ) self.nextButton = DirectButton(parent=self.myFrame, text="Next", pad=pad0, scale=0.05, pos=(frameSize[1] - 10 * 0.05, 0, -0.9), command=self.nextPressed) # resize canvas to fit in height self.myFrame['canvasSize'] = (frameSize[0], frameSize[1], lastYpos, frameSize[3])
class ChatHandler(DirectObject, Chat): def __init__(self, cr): base.messenger.send("registerLoadEvent", ["loadChatDone"]) Chat.__init__(self, base.a2dTopRight) self.cr = cr self.frmChat.setPos( -self.frmChat["frameSize"][1], self.frmChat.getY(), self.frmChat.getZ()) self.btnToggleChat.hide() self.btnToggleChat.setPos( -self.btnToggleChat["frameSize"][1], self.btnToggleChat.getY(), self.btnToggleChat.getZ()) self.btnToggleChatOrigTextFG = self.btnToggleChat.component("text1").fg self.btnToggleChat["sortOrder"] = 990 self.frmChat["sortOrder"] = 990 self.txtMessage["focusInCommand"] = self.focusInCommandFunc self.txtMessage["focusOutCommand"] = self.focusOutCommandFunc self.txtMessage["command"] = self.sendMessage tpMgr = TextPropertiesManager.getGlobalPtr() tpBold = TextProperties() font = loader.loadFont("assets/fonts/OldaniaADFStd-Bold.otf") tpBold.setFont(font) tpMgr.setProperties("bold", tpBold) self.lblMessages = OnscreenText( text="\1bold\1Messages:\2", scale = 0.05, pos = (self.frmMessages["canvasSize"][0], -0.05), align = TextNode.ALeft, wordwrap = 14, parent = self.frmMessages.getCanvas()) self.accept("sendMessage", self.sendMessage) self.accept("setText", self.addMessage) self.accept("toggleChat", self.toggleChat) self.hide() def start(self, roomZone): self.msg = self.cr.createDistributedObject( className = "DMessage", zoneId = roomZone) self.frmChat.show() self.btnToggleChat.show() base.messenger.send("loadChatDone") def destroy(self): self.ignoreAll() self.frmChat.removeNode() self.btnToggleChat.removeNode() def toggleChat(self): """Toggle the visibility of the chat frame and set the buttons text accordingly""" base.messenger.send("playSFXSlide") if self.frmChat.isHidden(): self.frmChat.show() btnName = self.btnToggleChat["text"] if btnName.endswith("*"): self.btnToggleChat["text_fg"] = self.btnToggleChatOrigTextFG self.btnToggleChat["text"] = btnName[:-1] else: self.frmChat.hide() def focusInCommandFunc(self): base.messenger.send("disableOtherKeyboardInput") self.clearText() def focusOutCommandFunc(self): base.messenger.send("enableOtherKeyboardInput") self.setDefaultText() def clearText(self): """ Write an empty string in the textbox """ self.txtMessage.enterText("") def setDefaultText(self): """ Write the default message in the textbox """ self.txtMessage.enterText("Your Message") def sendMessage(self, args=None): """ Send the text written in the message textbox to the clients """ txtMsg = self.txtMessage.get() if txtMsg.strip() == "": return sentText = "\1bold\1{}:\2 {}".format(self.cr.getMyName(), self.txtMessage.get()) self.msg.b_sendText(sentText) self.txtMessage.enterText("") def addMessage(self, message): """Add the given message to the chat messages frame and add a * to the toggle buttons text if the chat is hidden""" if self.frmChat.isHidden(): self.btnToggleChat["text_fg"] = (0.2,0.2,1,1) self.btnToggleChat["text"] += "*" self.lblMessages["text"] = "{}\n{}".format( self.lblMessages["text"], message) # get the size of the written text textbounds = self.lblMessages.getTightBounds() # resize the canvas. This will make the scrollbars dis-/appear, # dependent on if the canvas is bigger than the frame size. self.frmMessages["canvasSize"] = ( -0.38, textbounds[1].getX(), textbounds[0].getZ(), 0) self.frmMessages.setCanvasSize()
class Window(): texture = None def __init__(self, title_text, scale, parent=None, child=None, transparent=False, owner=None): self.title_text = title_text self.scale = scale self.title_size = settings.ui_font_size self.owner = owner self.child = None self.last_pos = None self.title_color = (1, 1, 1, 1) self.title_pad = tuple(self.scale * 2) if parent is None: parent = aspect2d self.parent = parent if transparent: frameColor = (0, 0, 0, 0) else: frameColor = (0.5, 0.5, 0.5, 1) self.pad = 0 self.event_handler = DirectObject() self.button_thrower = base.buttonThrowers[0].node() self.event_handler.accept("wheel_up-up", self.mouse_wheel_event, extraArgs = [-1]) self.event_handler.accept("wheel_down-up", self.mouse_wheel_event, extraArgs = [1]) self.scrollers = [] # if Window.texture is None: # Window.texture = loader.loadTexture('textures/futureui1.png') # image_scale = (scale[0] * Window.texture.get_x_size(), 1, scale[1] * Window.texture.get_y_size()) self.frame = DirectFrame(parent=parent, state=DGG.NORMAL, frameColor=frameColor)#, image=self.texture, image_scale=image_scale) self.title_frame = DirectFrame(parent=self.frame, state=DGG.NORMAL, frameColor=(.5, .5, .5, 1)) self.title = OnscreenText(text=self.title_text, style=Plain, fg=self.title_color, scale=tuple(self.scale * self.title_size), parent=self.title_frame, pos=(0, 0), align=TextNode.ALeft, font=None, mayChange=True) bounds = self.title.getTightBounds() self.title_frame['frameSize'] = [0, bounds[1][0] - bounds[0][0] + self.title_pad[0] * 2, 0, bounds[1][2] - bounds[0][2] + self.title_pad[1] * 2] self.title.setPos( -bounds[0][0] + self.title_pad[0], -bounds[0][2] + self.title_pad[1]) self.close_frame = DirectFrame(parent=self.frame, state=DGG.NORMAL, frameColor=(.5, .5, .5, 1)) self.close = OnscreenText(text='X', style=Plain, fg=self.title_color, scale=tuple(self.scale * self.title_size), parent=self.close_frame, pos=(0, 0), align=TextNode.ACenter, font=None, mayChange=True) bounds = self.close.getTightBounds() self.close_frame['frameSize'] = [0, bounds[1][0] - bounds[0][0] + self.title_pad[0] * 2, self.title_frame['frameSize'][2], self.title_frame['frameSize'][3]] self.close.setPos( -bounds[0][0] + self.title_pad[0], -bounds[0][2] + self.title_pad[1]) self.frame.setPos(0, 0, 0) self.title_frame.bind(DGG.B1PRESS, self.start_drag) self.title_frame.bind(DGG.B1RELEASE, self.stop_drag) self.close_frame.bind(DGG.B1PRESS, self.close_window) self.set_child(child) def set_child(self, child): if child is not None: self.child = child child.reparent_to(self.frame) self.update() def update(self): if self.child is not None: frame_size = list(self.child.frame['frameSize']) if frame_size is not None: frame_size[0] -= self.pad frame_size[1] += self.pad frame_size[2] += self.pad frame_size[3] -= self.pad self.frame['frameSize'] = frame_size if self.frame['frameSize'] is not None: width = self.frame['frameSize'][1] - self.frame['frameSize'][0] title_size = self.title_frame['frameSize'] title_size[0] = 0 title_size[1] = width self.title_frame['frameSize'] = title_size self.close_frame.setPos(width - self.close_frame['frameSize'][1], 0, 0) def register_scroller(self, scroller): self.scrollers.append(scroller) def mouse_wheel_event(self, dir): # If the user is scrolling a scroll-bar, don't try to scroll the scrolled-frame too. region = base.mouseWatcherNode.getOverRegion() if region is not None: widget = base.render2d.find("**/*{0}".format(region.name)) if widget.is_empty() or isinstance(widget.node(), PGSliderBar) or isinstance(widget.getParent().node(), PGSliderBar): return # Get the mouse-position if not base.mouseWatcherNode.hasMouse(): return mouse_pos = base.mouseWatcherNode.getMouse() found_scroller = None # Determine whether any of the scrolled-frames are under the mouse-pointer for scroller in self.scrollers: bounds = scroller['frameSize'] pos = scroller.get_relative_point(base.render2d, Point3(mouse_pos.get_x() ,0, mouse_pos.get_y())) if pos.x > bounds[0] and pos.x < bounds[1] and \ pos.z > bounds[2] and pos.z < bounds[3]: found_scroller = scroller break if found_scroller is not None: if not found_scroller.verticalScroll.isHidden(): self.do_mouse_scroll(found_scroller.verticalScroll, dir, None) else: self.do_mouse_scroll(found_scroller.horizontalScroll, dir, None) def do_mouse_scroll(self, obj, dir, data): if isinstance(obj, DirectSlider) or isinstance(obj, DirectScrollBar): obj.setValue(obj.getValue() + dir * obj["pageSize"] * 0.1) def start_drag(self, event): if base.mouseWatcherNode.has_mouse(): mpos = base.mouseWatcherNode.get_mouse() self.drag_start = self.frame.parent.get_relative_point(render2d, Point3(mpos.get_x() ,0, mpos.get_y())) - self.frame.getPos() taskMgr.add(self.drag, "drag", -1) def drag(self, task): if base.mouseWatcherNode.has_mouse(): mpos = base.mouseWatcherNode.get_mouse() current_pos = self.frame.parent.get_relative_point(render2d, Point3(mpos.get_x() ,0, mpos.get_y())) self.frame.set_pos(current_pos - self.drag_start) return task.again def close_window(self, event=None): if self.owner is not None: self.owner.window_closed(self) self.destroy() def stop_drag(self, event): taskMgr.remove("drag") self.last_pos = self.frame.getPos() def destroy(self): if self.frame is not None: self.frame.destroy() self.frame = None self.scrollers = [] self.event_handler.ignore_all() def getPos(self): return self.frame.getPos() def setPos(self, pos): self.frame.setPos(pos)
class Window(): texture = None def __init__(self, title, scale, parent=None, child=None, transparent=False, owner=None): self.scale = scale self.owner = owner self.last_pos = None self.title_text = title self.title_color = (1, 1, 1, 1) self.title_pad = tuple(self.scale * 2) if parent is None: parent = aspect2d self.parent = parent if transparent: frameColor = (0, 0, 0, 0) else: frameColor = (0, 0, 0, 1) self.pad = 0 # if Window.texture is None: # Window.texture = loader.loadTexture('textures/futureui1.png') # image_scale = (scale[0] * Window.texture.get_x_size(), 1, scale[1] * Window.texture.get_y_size()) self.frame = DirectFrame( parent=parent, state=DGG.NORMAL, frameColor=frameColor ) #, image=self.texture, image_scale=image_scale) self.title_frame = DirectFrame(parent=self.frame, state=DGG.NORMAL, frameColor=(.5, .5, .5, 1)) self.title = OnscreenText(text=self.title_text, style=Plain, fg=self.title_color, scale=tuple(self.scale * 14), parent=self.title_frame, pos=(0, 0), align=TextNode.ALeft, font=None, mayChange=True) bounds = self.title.getTightBounds() self.title_frame['frameSize'] = [ 0, bounds[1][0] - bounds[0][0] + self.title_pad[0] * 2, 0, bounds[1][2] - bounds[0][2] + self.title_pad[1] * 2 ] self.title.setPos(-bounds[0][0] + self.title_pad[0], -bounds[0][2] + self.title_pad[1]) self.close_frame = DirectFrame(parent=self.frame, state=DGG.NORMAL, frameColor=(.5, .5, .5, 1)) self.close = OnscreenText(text='X', style=Plain, fg=self.title_color, scale=tuple(self.scale * 14), parent=self.close_frame, pos=(0, 0), align=TextNode.ACenter, font=None, mayChange=True) bounds = self.close.getTightBounds() self.close_frame['frameSize'] = [ 0, bounds[1][0] - bounds[0][0] + self.title_pad[0] * 2, self.title_frame['frameSize'][2], self.title_frame['frameSize'][3] ] self.close.setPos(-bounds[0][0] + self.title_pad[0], -bounds[0][2] + self.title_pad[1]) self.frame.setPos(0, 0, 0) self.title_frame.bind(DGG.B1PRESS, self.start_drag) self.title_frame.bind(DGG.B1RELEASE, self.stop_drag) self.close_frame.bind(DGG.B1PRESS, self.close_window) self.set_child(child) def set_child(self, child): if child is not None: self.child = child child.reparent_to(self.frame) self.update() def update(self): if self.child is not None: frame_size = self.child.frame['frameSize'] if frame_size is not None: frame_size[0] -= self.pad frame_size[1] += self.pad frame_size[2] += self.pad frame_size[3] -= self.pad self.frame['frameSize'] = frame_size if self.frame['frameSize'] is not None: width = self.frame['frameSize'][1] - self.frame['frameSize'][0] title_size = self.title_frame['frameSize'] title_size[0] = 0 title_size[1] = width self.title_frame['frameSize'] = title_size self.close_frame.setPos(width - self.close_frame['frameSize'][1], 0, 0) def start_drag(self, event): if base.mouseWatcherNode.has_mouse(): mpos = base.mouseWatcherNode.get_mouse() self.drag_start = self.frame.parent.get_relative_point( render2d, Point3(mpos.get_x(), 0, mpos.get_y())) - self.frame.getPos() taskMgr.add(self.drag, "drag", -1) def drag(self, task): if base.mouseWatcherNode.has_mouse(): mpos = base.mouseWatcherNode.get_mouse() current_pos = self.frame.parent.get_relative_point( render2d, Point3(mpos.get_x(), 0, mpos.get_y())) self.frame.set_pos(current_pos - self.drag_start) return task.again def close_window(self, event=None): if self.owner is not None: self.owner.window_closed(self) self.destroy() def stop_drag(self, event): taskMgr.remove("drag") self.last_pos = self.frame.getPos() def destroy(self): if self.frame is not None: self.frame.destroy() self.frame = None def getPos(self): return self.frame.getPos() def setPos(self, pos): self.frame.setPos(pos)
class HostMenu(DirectObject): def __init__(self): self.defaultBtnMap = base.loader.loadModel("gui/button_map") self.buttonGeom = (self.defaultBtnMap.find("**/button_ready"), self.defaultBtnMap.find("**/button_click"), self.defaultBtnMap.find("**/button_rollover"), self.defaultBtnMap.find("**/button_disabled")) defaultFont = loader.loadFont('gui/eufm10.ttf') self.logFrame = DirectScrolledFrame( canvasSize=(0, base.a2dRight * 2, -5, 0), frameSize=(0, base.a2dRight * 2, (base.a2dBottom + .2) * 2, 0), frameColor=(0.1, 0.1, 0.1, 1)) self.logFrame.reparentTo(base.a2dTopLeft) # create the info and server debug output self.textscale = 0.1 self.txtinfo = OnscreenText(scale=self.textscale, pos=(0.1, -0.1), text="", align=TextNode.ALeft, fg=(0.1, 1.0, 0.15, 1), bg=(0, 0, 0, 0), shadow=(0, 0, 0, 1), shadowOffset=(-0.02, -0.02)) self.txtinfo.setTransparency(1) self.txtinfo.reparentTo(self.logFrame.getCanvas()) # create a close Server button self.btnBackPos = Vec3(0.4, 0, 0.2) self.btnBackScale = 0.25 self.btnBack = DirectButton( # Scale and position scale=self.btnBackScale, pos=self.btnBackPos, # Text text="Quit Server", text_scale=0.45, text_pos=(0, -0.1), text_fg=(0.82, 0.85, 0.87, 1), text_shadow=(0, 0, 0, 1), text_shadowOffset=(-0.02, -0.02), text_font=defaultFont, # Frame geom=self.buttonGeom, frameColor=(0, 0, 0, 0), relief=0, pressEffect=False, # Functionality command=self.back, rolloverSound=None, clickSound=None) self.btnBack.setTransparency(1) self.btnBack.reparentTo(base.a2dBottomLeft) # catch window resizes and recalculate the aspectration self.accept("window-event", self.recalcAspectRatio) self.accept("addLog", self.addLog) def show(self): self.logFrame.show() self.btnBack.show() def hide(self): self.logFrame.hide() self.btnBack.hide() def back(self): self.hide() base.messenger.send("stop_server") self.addLog("Quit Server!") def addLog(self, text): self.txtinfo.appendText(text + "\n") textbounds = self.txtinfo.getTightBounds() self.logFrame["canvasSize"] = (0, textbounds[1].getX(), textbounds[0].getZ(), 0) def recalcAspectRatio(self, window): """get the new aspect ratio to resize the mainframe""" # set the mainframe size to the window borders again self.logFrame["frameSize"] = (0, base.a2dRight * 2, (base.a2dBottom + .2) * 2, 0)