class UnoGameCardDeck(DirectFrame): def __init__(self, ug): DirectFrame.__init__(self, relief=None, sortOrder=50, parent=base.a2dBottomCenter) self.initialiseoptions(UnoGameCardDeck) self.container = DirectFrame(parent=self, relief=None) self.title = None self.cards = [] self.cardBtns = [] self.numCards = 0 self.unoGame = ug self.deck = None self.cardToFollowGui = None self.holiday = base.cr.holidayManager.getHoliday() self.gui = None self.loadCards() return def loadCards(self): self.gui = loader.loadModel( "phase_4/models/minigames/mg_uno_game_cards.egg") if self.holiday == HolidayType.CHRISTMAS: cards = self.gui.find( '**/mg_uno_numcards_green_7').getParent().getChildren() for child in cards: child.setTexture( loader.loadTexture('winter/maps/uno/%s.png' % (child.getName())), 1) def updateCardToFollowGui(self): self.deleteCardToFollowGui() if self.unoGame.cardToFollow[-2:] == str(UGG.CARD_BLUE): self.cardToFollowGui = OnscreenImage( image=self.getCard('mg_uno_numcards_blue_blank'), parent=base.a2dRightCenter) elif self.unoGame.cardToFollow[-2:] == str(UGG.CARD_RED): self.cardToFollowGui = OnscreenImage( image=self.getCard('mg_uno_numcards_red_blank'), parent=base.a2dRightCenter) elif self.unoGame.cardToFollow[-2:] == str(UGG.CARD_GREEN): self.cardToFollowGui = OnscreenImage( image=self.getCard('mg_uno_numcards_green_blank'), parent=base.a2dRightCenter) elif self.unoGame.cardToFollow[-2:] == str(UGG.CARD_YELLOW): self.cardToFollowGui = OnscreenImage( image=self.getCard('mg_uno_numcards_yellow_blank'), parent=base.a2dRightCenter) if self.cardToFollowGui: self.cardToFollowGui.setScale(0.25, 0.3, 0.3) self.cardToFollowGui.setPos(-0.175, 0, -0.75) def deleteCardToFollowGui(self): if self.cardToFollowGui: self.cardToFollowGui.destroy() self.cardToFollowGui = None def getCard(self, cardType): cards = loader.loadModel( "phase_4/models/minigames/mg_uno_game_cards.egg") card = cards.find('**/' + cardType) if self.holiday == HolidayType.CHRISTMAS: holidayTexture = loader.loadTexture('winter/maps/uno/%s.png' % (card.getName())) card.setTexture(holidayTexture, 1) return card def generate(self): self.container["image"] = "phase_4/maps/mg_uno_card_deck.png" self.container.setTransparency(True) self.container.setZ(-0.456) self.container.setSx(2) self.container.setSz(1) gui = loader.loadModel("phase_3.5/models/gui/friendslist_gui.bam") numItemsVisible = 5 itemHeight = -0.25 self.deck = DirectScrolledList( itemFrame_relief=DGG.SUNKEN, decButton_pos=(0.35, 0, -0.02), decButton_geom=(gui.find('**/Horiz_Arrow_UP'), gui.find('**/Horiz_Arrow_DN'), gui.find('**/Horiz_Arrow_Rllvr'), gui.find('**/Horiz_Arrow_UP')), decButton_relief=None, decButton_hpr=(0, 0, 90), incButton_pos=(0.35, 0, 1.95), incButton_geom=(gui.find('**/Horiz_Arrow_UP'), gui.find('**/Horiz_Arrow_DN'), gui.find('**/Horiz_Arrow_Rllvr'), gui.find('**/Horiz_Arrow_UP')), incButton_hpr=(0, 0, -90), incButton_relief=None, pos=(-0.936, 0, -0.41), hpr=(0, 0, 90), scale=0.97, numItemsVisible=numItemsVisible, forceHeight=itemHeight, itemFrame_frameSize=(-0.2, 0.2, -0.37, 1.5), itemFrame_pos=(0.35, 0, 0.4), itemFrame_borderWidth=(0.02, 0.02), ) def disable(self): if self.deck: self.deck.destroy() self.deck = None for btn in self.cardBtns: btn.destroy() del btn self.deleteCardToFollowGui() return def delete(self): DirectFrame.destroy(self) self.disable() self.gui.removeNode() self.gui = None self.cards = None self.title = None self.container = None self.cardBtns = None self.numCards = None self.unoGame = None self.deck = None return def drawCard(self, id): card = self.getCard(UGG.cardId2cardTex[id]) card.setScale(0.225, 0.3, 0.3) card.setR(-90) cardBtn = DirectButton(geom=card, relief=None, scale=(0.3, 0.3, 0.23), command=self.placeCard) cardBtn.setPythonTag('id', id) cardBtn['extraArgs'] = [id, cardBtn] cardBtn['state'] = DGG.DISABLED if not self.deck: self.generate() self.deck.addItem(cardBtn) self.cardBtns.append(cardBtn) self.enableAll(self.unoGame.cardToFollow) # Scroll to the card we just added to the deck. self.deck.scrollTo(len(self.cardBtns)) card.removeNode() del card def enableAll(self, cardToFollow=None): for btn in self.cardBtns: if cardToFollow != None: if (cardToFollow == btn.getPythonTag('id') or cardToFollow[:2] == btn.getPythonTag('id')[:2] or cardToFollow[-2:] == btn.getPythonTag('id')[-2:] or btn.getPythonTag('id') == str(UGG.CARD_WILD) or btn.getPythonTag('id') == str( UGG.CARD_WILD_DRAW_FOUR)): btn['state'] = DGG.NORMAL else: btn['state'] = DGG.DISABLED else: btn['state'] = DGG.NORMAL def disableAll(self): for btn in self.cardBtns: btn['state'] = DGG.DISABLED def placeCard(self, id, btn): self.deck.removeItem(btn) self.cardBtns.remove(btn) self.disableAll() self.unoGame.d_requestPlaceCard(id)
class DropDownMenu(DirectObject): ALeft = 0 ACenter = 1 ARight = 2 ENone = 0 EFade = 1 ESlide = 2 EStretch = 3 PLeft = 0 PRight = 1 PBottom = 2 PTop = 3 parents = (('a2dBottomLeft', 'a2dLeftCenter', 'a2dTopLeft'), ('a2dTopRight', 'a2dRightCenter', 'a2dBottomRight'), ('a2dBottomLeft', 'a2dBottomCenter', 'a2dBottomRight'), ('a2dTopLeft', 'a2dTopCenter', 'a2dTopRight')) def __init__(self, items, parent=None, sidePad=.0, edgePos=PTop, align=ALeft, effect=ENone, buttonThrower=None, font=None, baselineOffset=.0, scale=.05, itemHeight=1., leftPad=.0, separatorHeight=.5, underscoreThickness=1, BGColor=(0, 0, 0, .7), BGBorderColor=(1, .85, .4, 1), separatorColor=(1, 1, 1, 1), frameColorHover=(1, .85, .4, 1), frameColorPress=(0, 1, 0, 1), textColorReady=(1, 1, 1, 1), textColorHover=(0, 0, 0, 1), textColorPress=(0, 0, 0, 1), textColorDisabled=(.5, .5, .5, 1), draggable=False, onMove=None): ''' sidePad : additional space on the left and right of the text item edgePos : menu bar position on the screen, use DropDownMenu.PLeft, PRight, PBottom, or PTop align : menu items alignment on menu bar, use DropDownMenu.ALeft, ACenter, or ARight effect : the drop down appearance effect, use DropDownMenu.ENone, EFade, ESlide, or EStretch draggable : menu bar's draggability status onMove : a function which will be called after changing edge position Read the remaining options documentation in PopupMenu class. ''' self.parent = parent if parent else getattr( base, DropDownMenu.parents[edgePos][align]) self.BT = buttonThrower if buttonThrower else base.buttonThrowers[ 0].node() self.menu = self.parent.attachNewNode('dropdownmenu-%s' % id(self)) self.font = font if font else TextNode.getDefaultFont() self.baselineOffset = baselineOffset self.scale = scale self.itemHeight = itemHeight self.sidePad = sidePad self.edgePos = edgePos self.alignment = align self.effect = effect self.leftPad = leftPad self.underscoreThickness = underscoreThickness self.separatorHeight = separatorHeight self.BGColor = BGColor self.BGBorderColor = BGBorderColor self.separatorColor = separatorColor self.frameColorHover = frameColorHover self.frameColorPress = frameColorPress self.textColorReady = textColorReady self.textColorHover = textColorHover self.textColorPress = textColorPress self.textColorDisabled = textColorDisabled self.draggable = draggable self.onMove = onMove self.dropDownMenu = self.whoseDropDownMenu = None self.gapFromEdge = gapFromEdge = .008 texMargin = self.font.getTextureMargin() * self.scale * .25 b = DirectButton(parent=NodePath(''), text='^|g_', text_font=self.font, scale=self.scale) fr = b.node().getFrame() b.getParent().removeNode() baselineToCenter = (fr[2] + fr[3]) * self.scale LH = (fr[3] - fr[2]) * self.itemHeight * self.scale baselineToTop = (fr[3] * self.itemHeight * self.scale / LH) / (1. + self.baselineOffset) baselineToBot = LH / self.scale - baselineToTop self.height = LH + .01 l, r, b, t = 0, 5, -self.height, 0 self.menuBG = DirectFrame(parent=self.menu, frameColor=BGColor, frameSize=(l, r, b, t), state=DGG.NORMAL, suppressMouse=1) if self.draggable: self.setDraggable(1) LSborder = LineSegs() LSborder.setThickness(2) LSborder.setColor(0, 0, 0, 1) LSborder.moveTo(l, 0, b) LSborder.drawTo(r, 0, b) self.menuBG.attachNewNode(LSborder.create()) self.itemsParent = self.menu.attachNewNode('menu items parent') x = sidePad * self.scale + gapFromEdge for t, menuItemsGenerator in items: underlinePos = t.find('_') t = t.replace('_', '') b = DirectButton( parent=self.itemsParent, text=t, text_font=self.font, pad=(sidePad, 0), scale=self.scale, pos=(x, 0, -baselineToTop * self.scale - gapFromEdge), text_fg=textColorReady, # text color when mouse over text2_fg=textColorHover, # text color when pressed text1_fg=textColorPress, # framecolor when pressed frameColor=frameColorPress, command=self.__createMenu, extraArgs=[True, menuItemsGenerator], text_align=TextNode.ALeft, relief=DGG.FLAT, rolloverSound=0, clickSound=0) b['extraArgs'] += [b.getName()] b.stateNodePath[2].setColor( *frameColorHover) # framecolor when mouse over b.stateNodePath[0].setColor(0, 0, 0, 0) # framecolor when ready fr = b.node().getFrame() b['frameSize'] = (fr[0], fr[1], -baselineToBot, baselineToTop) self.accept(DGG.ENTER + b.guiId, self.__createMenu, [False, menuItemsGenerator, b.getName()]) if underlinePos > -1: tn = TextNode('') tn.setFont(self.font) tn.setText(t[:underlinePos + 1]) tnp = NodePath(tn.getInternalGeom()) underlineXend = tnp.getTightBounds()[1][0] tnp.removeNode() tn.setText(t[underlinePos]) tnp = NodePath(tn.getInternalGeom()) b3 = tnp.getTightBounds() underlineXstart = underlineXend - (b3[1] - b3[0])[0] tnp.removeNode() LSunder = LineSegs() LSunder.setThickness(underscoreThickness) LSunder.moveTo(underlineXstart + texMargin, 0, -.7 * baselineToBot) LSunder.drawTo(underlineXend - texMargin, 0, -.7 * baselineToBot) underline = b.stateNodePath[0].attachNewNode(LSunder.create()) underline.setColor(Vec4(*textColorReady), 1) underline.copyTo(b.stateNodePath[1], 10).setColor(Vec4(*textColorPress), 1) underline.copyTo(b.stateNodePath[2], 10).setColor(Vec4(*textColorHover), 1) self.accept('alt-' + t[underlinePos].lower(), self.__createMenu, [True, menuItemsGenerator, b.getName()]) x += (fr[1] - fr[0]) * self.scale self.width = x - 2 * gapFromEdge self.align(align) self.setEdgePos(edgePos) self.minZ = base.a2dBottom + self.height if edgePos == DropDownMenu.PBottom else None viewPlaneNode = PlaneNode('cut menu') viewPlaneNode.setPlane(Plane(Vec3(0, 0, -1), Point3(0, 0, -LH))) self.clipPlane = self.menuBG.attachNewNode(viewPlaneNode) def __createMenu(self, clicked, menuItemsGenerator, DBname, crap=None): itself = self.dropDownMenu and self.whoseDropDownMenu == DBname if not (clicked or self.dropDownMenu) or (not clicked and itself): return self.__removeMenu() if clicked and itself: return # removes any context menu if clicked: self.__removePopupMenu() self.dropDownMenu = PopupMenu( items=menuItemsGenerator(), parent=self.parent, buttonThrower=self.BT, font=self.font, baselineOffset=self.baselineOffset, scale=self.scale, itemHeight=self.itemHeight, leftPad=self.leftPad, separatorHeight=self.separatorHeight, underscoreThickness=self.underscoreThickness, BGColor=self.BGColor, BGBorderColor=self.BGBorderColor, separatorColor=self.separatorColor, frameColorHover=self.frameColorHover, frameColorPress=self.frameColorPress, textColorReady=self.textColorReady, textColorHover=self.textColorHover, textColorPress=self.textColorPress, textColorDisabled=self.textColorDisabled, minZ=self.minZ) self.acceptOnce(self.dropDownMenu.BTprefix + 'destroyed', setattr, [self, 'dropDownMenu', None]) self.whoseDropDownMenu = DBname item = self.menu.find('**/%s' % DBname) fr = item.node().getFrame() #~ if self.edgePos==DropDownMenu.PLeft: #~ x=max(fr[1],self.dropDownMenu.menu.getX(item)) #~ z=fr[2] #~ elif self.edgePos==DropDownMenu.PRight: #~ x=min(fr[0],self.dropDownMenu.menu.getX(item)) #~ z=fr[2]-self.dropDownMenu.maxWidth #~ elif self.edgePos in (DropDownMenu.PBottom,DropDownMenu.PTop): #~ x=fr[1]-self.dropDownMenu.maxWidth if self.alignment==DropDownMenu.ARight else fr[0] #~ z=fr[2] if self.edgePos==DropDownMenu.PTop else fr[3]+self.dropDownMenu.height if self.edgePos == DropDownMenu.PLeft: x = max(fr[1], self.dropDownMenu.menu.getX(item)) z = fr[3] - (self.height - self.gapFromEdge) / self.scale elif self.edgePos == DropDownMenu.PRight: x = min(fr[0], self.dropDownMenu.menu.getX(item)) z = fr[3] - (self.height - self.gapFromEdge ) / self.scale - self.dropDownMenu.maxWidth elif self.edgePos in (DropDownMenu.PBottom, DropDownMenu.PTop): x = fr[ 1] - self.dropDownMenu.maxWidth if self.alignment == DropDownMenu.ARight else fr[ 0] z = fr[3] - ( self.height - self.gapFromEdge ) / self.scale if self.edgePos == DropDownMenu.PTop else fr[2] + ( self.height) / self.scale + self.dropDownMenu.height self.dropDownMenu.menu.setPos(item, x, 0, z) if self.effect == DropDownMenu.EFade: self.dropDownMenu.menu.colorScaleInterval( .3, Vec4(1), Vec4(1, 1, 1, 0), blendType='easeIn').start() elif self.effect == DropDownMenu.ESlide: pos = self.dropDownMenu.menu.getPos() if self.edgePos == DropDownMenu.PTop: startPos = Point3(0, 0, self.dropDownMenu.height * self.scale) elif self.edgePos == DropDownMenu.PBottom: startPos = Point3(0, 0, -self.dropDownMenu.height * self.scale) elif self.edgePos == DropDownMenu.PLeft: startPos = Point3(-self.dropDownMenu.maxWidth * self.scale, 0, 0) elif self.edgePos == DropDownMenu.PRight: startPos = Point3(self.dropDownMenu.maxWidth * self.scale, 0, 0) self.dropDownMenu.menu.posInterval(.3, pos, pos + startPos, blendType='easeIn').start() self.dropDownMenu.menu.setClipPlane(self.clipPlane) elif self.effect == DropDownMenu.EStretch: if self.edgePos == DropDownMenu.PTop: startHpr = Vec3(0, -90, 0) elif self.edgePos == DropDownMenu.PBottom: dz = self.dropDownMenu.height * self.scale for c in asList(self.dropDownMenu.menu.getChildren()): c.setZ(c.getZ() + dz) self.dropDownMenu.menu.setZ(self.dropDownMenu.menu, -dz) startHpr = Vec3(0, 90, 0) elif self.edgePos == DropDownMenu.PLeft: startHpr = Vec3(90, 0, 0) elif self.edgePos == DropDownMenu.PRight: dx = self.dropDownMenu.maxWidth * self.scale for c in asList(self.dropDownMenu.menu.getChildren()): c.setX(c.getX() - dx) self.dropDownMenu.menu.setX(self.dropDownMenu.menu, dx) startHpr = Vec3(-90, 0, 0) self.dropDownMenu.menu.hprInterval(.3, Vec3(0), startHpr, blendType='easeIn').start() def __removeMenu(self): if self.dropDownMenu: self.dropDownMenu.destroy() self.dropDownMenu = None def __removePopupMenu(self): menuEvents = messenger.find('menu-') if menuEvents: menuEvent = menuEvents.keys() activeMenu = menuEvents[menuEvent[0]].values()[0][0].im_self activeMenu.destroy(delParents=True) def __reverseItems(self): tmp = NodePath('') self.itemsParent.getChildren().reparentTo(tmp) children = asList(tmp.getChildren()) for c in reversed(children): c.reparentTo(self.itemsParent) tmp.removeNode() x = self.sidePad * self.scale + self.gapFromEdge for c in asList(self.itemsParent.getChildren()): c.setX(x) fr = c.node().getFrame() x += (fr[1] - fr[0]) * self.scale def __startDrag(self, crap): taskMgr.add(self.__drag, 'dragging menu bar', extraArgs=[Point2(base.mouseWatcherNode.getMouse())]) self.__removePopupMenu() self.origBTprefix = self.BT.getPrefix() self.BT.setPrefix('dragging menu bar') def __drag(self, origMpos): if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() if mpos != origMpos: x, y = mpos.getX(), mpos.getY(), deltas = [x + 1, 1 - x, y + 1, 1 - y] closestEdge = deltas.index(min(deltas)) if closestEdge != self.edgePos: self.setEdgePos(closestEdge) return Task.cont def __stopDrag(self, crap): taskMgr.remove('dragging menu bar') self.BT.setPrefix(self.origBTprefix) def destroy(self): self.__removeMenu() self.ignoreAll() self.menu.removeNode() def isDraggable(self): ''' Returns menu bar's draggable status ''' return self.draggable def setDraggable(self, d): ''' Sets menu bar's draggable status ''' self.draggable = d if d: self.menuBG.bind(DGG.B1PRESS, self.__startDrag) self.menuBG.bind(DGG.B1RELEASE, self.__stopDrag) else: self.menuBG.unbind(DGG.B1PRESS) self.menuBG.unbind(DGG.B1RELEASE) def align(self, align=None): ''' Aligns menu text on menu bar. Use one of DropDownMenu.ALeft, DropDownMenu.ACenter, or DropDownMenu.ARight. ''' self.parent = getattr( base, DropDownMenu.parents[self.edgePos] [self.alignment if align is None else align]) self.menu.reparentTo(self.parent) if align is not None: self.itemsParent.setX(-.5 * self.width * align) self.menuBG.setX(-.5 * (5 - self.width) * align) self.alignment = align def setEdgePos(self, edge): ''' Sticks menu bar to 4 possible screen edges : DropDownMenu.PLeft, DropDownMenu.PRight, DropDownMenu.PBottom, or DropDownMenu.PTop. ''' lastEdge = self.edgePos reverseItems = lastEdge == DropDownMenu.PLeft self.edgePos = edge self.itemsParent.setZ(0) self.menuBG.setSz(1) alignment = None if self.edgePos == DropDownMenu.PLeft: self.menu.setR(-90) if self.alignment != DropDownMenu.ACenter: alignment = 2 - self.alignment self.__reverseItems() self.minZ = None else: if self.edgePos == DropDownMenu.PRight: self.menu.setR(90) self.minZ = None elif self.edgePos == DropDownMenu.PBottom: self.menu.setR(0) self.menuBG.setSz(-1) self.itemsParent.setZ(-self.menuBG.node().getFrame()[2]) self.minZ = base.a2dBottom + self.height elif self.edgePos == DropDownMenu.PTop: self.menu.setR(0) self.minZ = None if reverseItems: if self.alignment != DropDownMenu.ACenter: alignment = 2 - self.alignment self.__reverseItems() self.align(alignment) if callable(self.onMove): self.onMove()