def destroy(self):
        self.ignoreAll()
        self.dayClickCallback = None
        self.monthLeftArrow.destroy()
        self.monthRightArrow.destroy()
        for day in self.guiDays:
            if day is not None:
                day.destroy()
            day = None

        self.filterList.destroy()
        DirectFrame.destroy(self)
        return
Exemple #2
0
class PartyPlanner(DirectFrame, FSM):
    notify = DirectNotifyGlobal.directNotify.newCategory('PartyPlanner')

    def __init__(self, doneEvent=None):
        FSM.__init__(self, 'PartyPlannerFSM')
        DirectFrame.__init__(self)
        self.doneEvent = doneEvent
        self.stateArray = [
            'Off', 'Welcome', 'PartyEditor', 'Date', 'Time', 'Invitation',
            'Farewell'
        ]
        self.partyTime = base.cr.toontownTimeManager.getCurServerDateTime()
        self.partyNowTime = base.cr.toontownTimeManager.getCurServerDateTime()
        minutesToNextFifteen = 15 - self.partyTime.minute % 15
        self.cleanPartyTime = self.partyTime + timedelta(
            minutes=minutesToNextFifteen, seconds=-self.partyTime.second)
        self.partyTime = self.cleanPartyTime
        self.guests = []
        self.isPrivate = False
        self.selectedCalendarGuiDay = None
        self.gui = loader.loadModel('phase_4/models/parties/partyPlannerGUI')
        self.partyDuration = timedelta(hours=PartyGlobals.DefaultPartyDuration)
        self.timeTypeToMaxValue = {'hour': 23, 'minute': 59}
        self.timeTypeToChangeAmount = {
            'hour': (1, -1),
            'minute': (15, -15),
            'ampm': (1, -1)
        }
        self.partyInfo = None
        self.asapMinuteRounding = base.config.GetInt(
            'party-asap-minute-rounding',
            PartyGlobals.PartyPlannerAsapMinuteRounding)
        self.load()
        self.request('Welcome')

    def enterWelcome(self, *args):
        self.prevButton['state'] = DirectGuiGlobals.DISABLED
        self.prevButton.hide()
        self.nextButton['state'] = DirectGuiGlobals.NORMAL
        self.welcomePage.show()
        self.partyPlannerHead.reparentTo(self.welcomePage)
        self.partyPlannerHead.startBlink()
        self.partyPlannerHead.startLookAround()
        self.nametagNP.reparentTo(self.welcomePage)
        self.chatNP.reparentTo(self.welcomePage)

    def exitWelcome(self):
        self.welcomePage.hide()
        self.prevButton.show()
        self.partyPlannerHead.stopBlink()
        self.partyPlannerHead.stopLookAround()

    def enterPartyEditor(self, *args):
        self.prevButton['state'] = DirectGuiGlobals.NORMAL
        self.nextButton['state'] = DirectGuiGlobals.DISABLED
        self.nextButton.hide()
        self.partyEditorPage.show()
        self.partyEditor.request('Idle')

    def exitPartyEditor(self):
        self.partyEditor.request('Hidden')
        self.partyEditorPage.hide()

    def enterGuests(self, *args):
        self.prevButton['state'] = DirectGuiGlobals.NORMAL
        self.nextButton['state'] = DirectGuiGlobals.NORMAL
        self.nextButton.show()
        self.guestPage.show()

    def exitGuests(self):
        self.guests = []
        for friendCheckBox in self.friendList['items']:
            if friendCheckBox['indicatorValue']:
                self.guests.append(friendCheckBox.getPythonTag('id'))

        self.guestPage.hide()

    def enterDate(self, *args):
        self.prevButton.show()
        self.prevButton['state'] = DirectGuiGlobals.NORMAL
        if self.selectedCalendarGuiDay is None:
            self.nextButton['state'] = DirectGuiGlobals.DISABLED
            self.nextButton.hide()
            self.makePartyNowButton.show()
        self.datePage.show()

    def exitDate(self):
        self.datePage.hide()
        self.nextButton.show()
        if self.selectedCalendarGuiDay is not None:
            self.partyTime = self.cleanPartyTime
            self.alterPartyTime(year=self.selectedCalendarGuiDay.myDate.year,
                                month=self.selectedCalendarGuiDay.myDate.month,
                                day=self.selectedCalendarGuiDay.myDate.day)
        else:
            self.partyNowTime = self.calcAsapTime()
            self.partyTime = self.partyNowTime

    def calcAsapTime(self):
        curServerTime = base.cr.toontownTimeManager.getCurServerDateTime()
        baseTime = curServerTime
        baseTime = baseTime.replace(baseTime.year,
                                    baseTime.month,
                                    baseTime.day,
                                    baseTime.hour,
                                    baseTime.minute,
                                    second=0,
                                    microsecond=0)
        minute = curServerTime.minute
        remainder = minute % self.asapMinuteRounding
        if remainder:
            baseTime += timedelta(minutes=self.asapMinuteRounding - remainder)
        else:
            baseTime += timedelta(minutes=self.asapMinuteRounding)
        return baseTime

    def enterTime(self, *args):
        self.prevButton.show()
        self.prevButton['state'] = DirectGuiGlobals.NORMAL
        self.nextButton.show()
        self.timePage.show()
        self.timePageRecapToontownTimeLabel2[
            'text'] = '%s' % PartyUtils.formatDateTime(self.partyTime)
        self.timePageRecapLocalTimeLabel['text'] = '%s%s' % (
            TTLocalizer.PartyPlannerTimeLocalTime,
            PartyUtils.formatDateTime(self.partyTime, inLocalTime=True))

    def exitTime(self):
        self.timePage.hide()
        self.nextButton.show()

    def enterInvitation(self, *args):
        self.prevButton['state'] = DirectGuiGlobals.NORMAL
        self.nextButton.hide()
        defaultInviteTheme = PartyGlobals.InviteTheme.GenericMale
        if hasattr(base.cr, 'newsManager') and base.cr.newsManager:
            if ToontownGlobals.VICTORY_PARTY_HOLIDAY in base.cr.newsManager.getHolidayIdList(
            ):
                defaultInviteTheme = PartyGlobals.InviteTheme.VictoryParty
            elif ToontownGlobals.KARTING_TICKETS_HOLIDAY in base.cr.newsManager.getHolidayIdList(
            ) or ToontownGlobals.CIRCUIT_RACING_EVENT in base.cr.newsManager.getHolidayIdList(
            ):
                defaultInviteTheme = PartyGlobals.InviteTheme.Racing
            elif ToontownGlobals.VALENTINES_DAY in base.cr.newsManager.getHolidayIdList(
            ):
                defaultInviteTheme = PartyGlobals.InviteTheme.Valentoons
        if self.partyInfo is not None:
            del self.partyInfo
        activityList = self.partyEditor.partyEditorGrid.getActivitiesOnGrid()
        decorationList = self.partyEditor.partyEditorGrid.getDecorationsOnGrid(
        )
        endTime = self.partyTime + self.partyDuration
        self.partyInfo = PartyInfo(0, 0, self.partyTime.year,
                                   self.partyTime.month, self.partyTime.day,
                                   self.partyTime.hour, self.partyTime.minute,
                                   endTime.year, endTime.month, endTime.day,
                                   endTime.hour, endTime.minute,
                                   self.isPrivate, defaultInviteTheme,
                                   activityList, decorationList, 0)
        if self.noFriends or len(self.getInvitees()) == 0:
            self.inviteVisual.setNoFriends(True)
            self.invitationTitleLabel[
                'text'] = TTLocalizer.PartyPlannerConfirmTitleNoFriends
            self.inviteButton[
                'text'] = TTLocalizer.PartyPlannerInviteButtonNoFriends
            self.selectedInviteThemeLabel.stash()
            self.nextThemeButton.stash()
            self.prevThemeButton.stash()
            self.setInviteTheme(defaultInviteTheme)
        else:
            self.inviteVisual.setNoFriends(False)
            self.invitationTitleLabel[
                'text'] = TTLocalizer.PartyPlannerConfirmTitle
            self.inviteButton['text'] = TTLocalizer.PartyPlannerInviteButton
            self.selectedInviteThemeLabel.unstash()
            self.nextThemeButton.unstash()
            self.prevThemeButton.unstash()
            self.setInviteTheme(defaultInviteTheme)
        self.inviteVisual.updateInvitation(base.localAvatar.getName(),
                                           self.partyInfo)
        self.invitationPage.show()

    def __prevTheme(self):
        self.nextThemeButton.show()
        prevTheme = self.currentInvitationTheme - 1
        while prevTheme not in self.inviteThemes:
            prevTheme -= 1
            if prevTheme == self.currentInvitationTheme:
                self.notify.warning('No previous invite theme found.')
                break
            elif prevTheme < 0:
                prevTheme = len(self.inviteVisual.inviteThemesIdToInfo) - 1

        self.setInviteTheme(prevTheme)

    def __nextTheme(self):
        self.prevThemeButton.show()
        nextTheme = self.currentInvitationTheme + 1
        while nextTheme not in self.inviteThemes:
            nextTheme += 1
            if nextTheme == self.currentInvitationTheme:
                self.notify.warning('No next invite theme found.')
                break
            elif nextTheme >= len(self.inviteVisual.inviteThemesIdToInfo):
                nextTheme = 0

        self.setInviteTheme(nextTheme)

    def setInviteTheme(self, themeNumber):
        self.currentInvitationTheme = themeNumber
        self.selectedInviteThemeLabel['text'] = '%s %s (%d/%d)' % (
            self.inviteVisual.inviteThemesIdToInfo[self.currentInvitationTheme]
            [1], TTLocalizer.PartyPlannerInvitationTheme,
            self.inviteThemes.index(self.currentInvitationTheme) + 1,
            len(self.inviteThemes))
        self.partyInfo.inviteTheme = self.currentInvitationTheme
        self.inviteVisual.updateInvitation(base.localAvatar.getName(),
                                           self.partyInfo)

    def exitInvitation(self):
        self.invitationPage.hide()
        self.nextButton.show()

    def enterFarewell(self, goingBackAllowed):
        self.farewellPage.show()
        if goingBackAllowed:
            self.prevButton.show()
        else:
            self.prevButton.hide()
        self.nextButton.hide()
        self.partyPlannerHead.reparentTo(self.farewellPage)
        self.partyPlannerHead.startBlink()
        self.partyPlannerHead.startLookAround()
        self.nametagNP.reparentTo(self.farewellPage)
        self.chatNP.reparentTo(self.farewellPage)

    def exitFarewell(self):
        self.farewellPage.hide()
        self.nextButton.show()
        self.prevButton.show()
        self.partyPlannerHead.stopBlink()
        self.partyPlannerHead.stopLookAround()

    def load(self):
        self.frame = DirectFrame(parent=aspect2d,
                                 geom=self.gui.find('**/background'),
                                 relief=None,
                                 scale=0.85,
                                 pos=(0.05, 0.0, 0.1))
        self.titleScale = TTLocalizer.PPtitleScale
        self._createNavButtons()
        self.welcomePage = self._createWelcomePage()
        self.welcomePage.hide()
        self.datePage = self._createDatePage()
        self.datePage.hide()
        self.timePage = self._createTimePage()
        self.timePage.hide()
        self.guestPage = self._createGuestPage()
        self.guestPage.hide()
        self.partyEditorPage = self._createPartyEditorPage()
        self.partyEditorPage.hide()
        self.invitationPage = self._createInvitationPage()
        self.invitationPage.hide()
        self.farewellPage = self._createFarewellPage()
        self.farewellPage.hide()

    def _createNavButtons(self):
        self.quitButton = DirectButton(
            parent=self.frame,
            relief=None,
            geom=(self.gui.find('**/cancelButton_up'),
                  self.gui.find('**/cancelButton_down'),
                  self.gui.find('**/cancelButton_rollover')),
            command=self.__acceptExit)
        self.nextButton = DirectButton(
            parent=self.frame,
            relief=None,
            geom=(self.gui.find('**/bottomNext_button/nextButton_up'),
                  self.gui.find('**/bottomNext_button/nextButton_down'),
                  self.gui.find('**/bottomNext_button/nextButton_rollover')),
            command=self.__nextItem,
            state=DirectGuiGlobals.DISABLED)
        self.prevButton = DirectButton(
            parent=self.frame,
            relief=None,
            geom=(
                self.gui.find('**/bottomPrevious_button/previousButton_up'),
                self.gui.find('**/bottomPrevious_button/previousButton_down'),
                self.gui.find(
                    '**/bottomPrevious_button/previousButton_rollover')),
            command=self.__prevItem,
            state=DirectGuiGlobals.DISABLED)
        self.currentItem = None

    def __createNametag(self, parent):
        if self.nametagGroup == None:
            self.nametagGroup = NametagGroup()
            interfaceFont = OTPGlobals.getInterfaceFont()
            self.nametagGroup.setFont(interfaceFont)
            self.nametagGroup.setChatFont(interfaceFont)
            self.nametagGroup.setActive(False)
            self.nametagGroup.setAvatar(self.partyPlannerHead)
            self.nametagGroup.manage(base.marginManager)
            nametagColor = NametagGlobals.NametagColors[
                NametagGlobals.CCNonPlayer]
            self.nametagGroup.setNametagColor(nametagColor)
            chatColor = NametagGlobals.ChatColors[NametagGlobals.CCNonPlayer]
            self.nametagGroup.setChatColor(chatColor)
            nametag2d = self.nametagGroup.getNametag2d()
            nametag2d.hideNametag()
            nametag2d.hideChat()
            self.nametagNode = NametagFloat2d()
            self.nametagNode.hideChat()
            self.nametagGroup.add(self.nametagNode)
            self.nametagGroup.setText(
                base.cr.partyManager.getPartyPlannerName())
            self.nametagNP = parent.attachNewNode(self.nametagNode)
            nametagPos = self.gui.find(
                '**/step_01_partymanPeteNametag_locator').getPos()
            self.nametagNP.setPosHprScale(nametagPos[0], 0, nametagPos[2], 0,
                                          0, 0, 0.1, 1, 0.1)
            self.chatNode = NametagFloat2d()
            self.chatNode.hideNametag()
            self.chatNode.showThought()
            self.nametagGroup.add(self.chatNode)
            self.nametagGroup.setChatText(TTLocalizer.PartyPlannerInstructions)
            self.chatNP = parent.attachNewNode(self.chatNode)
            chatPos = self.gui.find(
                '**/step_01_partymanPeteText_locator').getPos()
            self.chatNP.setPosHprScale(chatPos[0], 0, chatPos[2], 0, 0, 0,
                                       0.08, 1, 0.08)
            self.nametagGroup.updateAll()

    def clearNametag(self):
        if self.nametagGroup != None:
            self.nametagGroup.unmanage(base.marginManager)
            self.nametagGroup.remove(self.nametagNode)
            self.nametagGroup.remove(self.chatNode)
            self.nametagNP.removeNode()
            self.chatNP.removeNode()
            del self.nametagNP
            del self.chatNP
            del self.nametagNode
            del self.chatNode
            self.nametagGroup.setAvatar(NodePath())
            self.nametagGroup.destroy()
            self.nametagGroup = None

    def _createWelcomePage(self):
        self.nametagGroup = None
        page = DirectFrame(self.frame)
        page.setName('PartyPlannerWelcomePage')
        self.welcomeTitleLabel = DirectLabel(
            parent=page,
            relief=None,
            text=TTLocalizer.PartyPlannerWelcomeTitle,
            pos=self.gui.find('**/title_locator').getPos(),
            scale=self.titleScale)
        self.partyPlannerHead = ToonHead.ToonHead()
        partyPlannerStyle = base.cr.partyManager.getPartyPlannerStyle()
        self.partyPlannerHead.setupHead(partyPlannerStyle, forGui=True)
        self.partyPlannerHead.setPos(
            self.gui.find('**/step_01_partymanPete_locator').getPos())
        animal = partyPlannerStyle.getAnimal()
        if animal == 'cat' or animal == 'pig':
            headScale = 0.4
        elif animal == 'dog' or animal == 'bear':
            headScale = 0.45
        elif animal == 'rabbit':
            headScale = 0.35
        else:
            headScale = 0.3
        self.partyPlannerHead.setScale(headScale)
        self.partyPlannerHead.setH(180.0)
        self.partyPlannerHead.reparentTo(page)
        self.__createNametag(page)
        return page

    def _createDatePage(self):
        page = DirectFrame(self.frame)
        page.setName('PartyPlannerDatePage')
        self.createDateTitleLabel = DirectLabel(
            parent=page,
            relief=None,
            text=TTLocalizer.PartyPlannerDateTitle,
            pos=self.gui.find('**/title_locator').getPos(),
            scale=self.titleScale)
        pos = self.gui.find('**/step_06_sendInvitation_locator').getPos()
        self.makePartyNowButton = DirectButton(
            parent=page,
            relief=None,
            geom=(self.gui.find('**/send_up'), self.gui.find('**/send_down'),
                  self.gui.find('**/send_rollover')),
            text=TTLocalizer.PartyPlannerPartyNow,
            text_pos=(pos[0], pos[2]),
            text_scale=0.05,
            command=self.__doMakePartyNow)
        curServerDate = base.cr.toontownTimeManager.getCurServerDateTime()
        self.calendarGuiMonth = CalendarGuiMonth(
            page,
            curServerDate,
            scale=0.95,
            pos=(-0.05, 0.0, -0.33),
            dayClickCallback=self._dayClickCallback,
            onlyFutureDaysClickable=True)
        return page

    def __doMakePartyNow(self):
        self.request('Invitation')

    def _dayClickCallback(self, calendarGuiDay):
        self.selectedCalendarGuiDay = calendarGuiDay
        self.nextButton['state'] = DirectGuiGlobals.NORMAL
        self.makePartyNowButton.hide()
        self.nextButton.show()

    def alterPartyTime(self,
                       year=None,
                       month=None,
                       day=None,
                       hour=None,
                       minute=None):
        self.partyTime = datetime(year=self.positiveTime('year', year),
                                  month=self.positiveTime('month', month),
                                  day=self.positiveTime('day', day),
                                  hour=self.positiveTime('hour', hour),
                                  minute=self.positiveTime('minute', minute),
                                  tzinfo=self.partyTime.tzinfo)

    def positiveTime(self, type, amount):
        if amount is None:
            return getattr(self.partyTime, type)
        if type == 'hour' or type == 'minute':
            if amount < 0:
                return self.timeTypeToMaxValue[
                    type] + 1 + self.timeTypeToChangeAmount[type][1]
            if amount > self.timeTypeToMaxValue[type]:
                return 0
        return amount

    def _createTimePage(self):
        page = DirectFrame(self.frame)
        page.setName('PartyPlannerTimePage')
        self.createTimeTitleLabel = DirectLabel(
            parent=page,
            relief=None,
            text=TTLocalizer.PartyPlannerTimeTitle,
            pos=self.gui.find('**/title_locator').getPos(),
            scale=self.titleScale)
        self.clockImage = DirectFrame(
            parent=page,
            relief=None,
            geom=self.gui.find('**/toontownTime_background'))
        self.timePageToontownLabel = DirectLabel(
            parent=page,
            relief=None,
            text=TTLocalizer.PartyPlannerTimeToontown,
            pos=self.gui.find('**/step_03_toontown_locator').getPos(),
            scale=0.15,
            text_fg=(1.0, 0.0, 0.0, 1.0),
            text_font=ToontownGlobals.getSignFont())
        self.timePageTimeLabel = DirectLabel(
            parent=page,
            relief=None,
            text=TTLocalizer.PartyPlannerTimeTime,
            pos=self.gui.find('**/step_03_time_locator').getPos(),
            scale=0.15,
            text_fg=(1.0, 0.0, 0.0, 1.0),
            text_font=ToontownGlobals.getSignFont())
        self.timePageRecapLabel = DirectLabel(
            parent=page,
            relief=None,
            text=TTLocalizer.PartyPlannerTimeRecap,
            pos=self.gui.find('**/step_03_partyDateAndTime_locator').getPos(),
            scale=0.09)
        self.timePageRecapToontownTimeLabel1 = DirectLabel(
            parent=page,
            relief=None,
            text=TTLocalizer.PartyPlannerTimeToontownTime,
            pos=self.gui.find('**/step_03_toontownTime_locator').getPos(),
            scale=0.06)
        self.timePageRecapToontownTimeLabel2 = DirectLabel(
            parent=page,
            relief=None,
            text='%s' % PartyUtils.formatDateTime(self.partyTime),
            pos=self.gui.find(
                '**/step_03_toontownDateAndTime_loactor').getPos(),
            textMayChange=True,
            scale=0.06)
        self.timePageRecapLocalTimeLabel = DirectLabel(
            parent=page,
            relief=None,
            text='%s%s' %
            (TTLocalizer.PartyPlannerTimeLocalTime,
             PartyUtils.formatDateTime(self.partyTime, inLocalTime=True)),
            pos=self.gui.find('**/step_03_localDateAndTime_loactor').getPos(),
            textMayChange=True,
            scale=0.06,
            text_fg=(1.0, 0.0, 0.0, 1.0))
        self.timeInputHourLabel, self.timeInputHourUpButton, self.timeInputHourDownButton = self.getTimeWidgets(
            page, 'hour')
        self.timeInputMinuteLabel, self.timeInputMinuteUpButton, self.timeInputMinuteDownButton = self.getTimeWidgets(
            page, 'minute')
        self.timeInputAmPmLabel, self.timeInputAmPmUpButton, self.timeInputAmPmDownButton = self.getTimeWidgets(
            page, 'ampm')
        self.timePagecolonLabel = DirectLabel(
            parent=page,
            relief=None,
            text=':',
            pos=self.gui.find('**/step_03_colon_locator').getPos(),
            scale=0.15)
        return page

    def getTimeWidgets(self, page, type):
        if type == 'ampm':
            data = self.getCurrentAmPm()
        else:
            data = getattr(self.partyTime, type)
            if data == 0 and type == 'minute':
                data = '00'
            else:
                if type == 'hour':
                    data = data % 12
                    if data == 0:
                        data = 12
                data = '%d' % data
        label = DirectLabel(parent=page,
                            relief=None,
                            text='%s' % data,
                            textMayChange=True,
                            pos=self.gui.find('**/step_03_%s_locator' %
                                              type).getPos(),
                            scale=0.12)

        def changeValue(self, amount):
            if type == 'ampm':
                self.alterPartyTime(hour=(self.partyTime.hour + 12) % 24)
                newAmount = self.getCurrentAmPm()
                label['text'] = newAmount
            else:
                if type == 'hour':
                    newAmount = getattr(self.partyTime, type) + amount
                    newAmount = newAmount % 12
                    if self.timeInputAmPmLabel[
                            'text'] == TTLocalizer.PartyTimeFormatMeridiemPM:
                        newAmount = newAmount % 12 + 12
                    self.alterPartyTime(hour=newAmount)
                elif type == 'minute':
                    newAmount = getattr(self.partyTime, type) + amount
                    self.alterPartyTime(minute=newAmount)
                else:
                    PartyPlanner.notify.error(
                        'Invalid type for changeValue in PartyPlanner: %s' %
                        type)
                newAmount = getattr(self.partyTime, type)
                if newAmount < 10 and type == 'minute':
                    label['text'] = '0%d' % newAmount
                else:
                    if type == 'hour':
                        newAmount = newAmount % 12
                        if newAmount == 0:
                            newAmount = 12
                    label['text'] = '%d' % newAmount
            self.timePageRecapToontownTimeLabel2[
                'text'] = '%s' % PartyUtils.formatDateTime(self.partyTime)
            self.timePageRecapLocalTimeLabel['text'] = '%s%s' % (
                TTLocalizer.PartyPlannerTimeLocalTime,
                PartyUtils.formatDateTime(self.partyTime, inLocalTime=True))

        upButton = DirectButton(
            parent=page,
            relief=None,
            geom=(self.gui.find('**/%sButtonUp_up' % type),
                  self.gui.find('**/%sButtonUp_down' % type),
                  self.gui.find('**/%sButtonUp_rollover' % type)),
            command=changeValue,
            extraArgs=[self, self.timeTypeToChangeAmount[type][0]])
        downButton = DirectButton(
            parent=page,
            relief=None,
            geom=(self.gui.find('**/%sButtonDown_up' % type),
                  self.gui.find('**/%sButtonDown_down' % type),
                  self.gui.find('**/%sButtonDown_rollover' % type)),
            command=changeValue,
            extraArgs=[self, self.timeTypeToChangeAmount[type][1]])
        return (label, upButton, downButton)

    def getCurrentAmPm(self):
        if self.partyTime.hour < 12:
            return TTLocalizer.PartyTimeFormatMeridiemAM
        else:
            return TTLocalizer.PartyTimeFormatMeridiemPM

    def _createGuestPage(self):
        page = DirectFrame(self.frame)
        page.setName('PartyPlannerGuestPage')
        self.guestTitleLabel = DirectLabel(
            parent=page,
            relief=None,
            text=TTLocalizer.PartyPlannerGuestTitle,
            pos=self.gui.find('**/title_locator').getPos(),
            scale=self.titleScale)
        self.guestBackgroundLabel = DirectLabel(
            parent=page,
            relief=None,
            image=self.gui.find('**/guestListBackground_flat'),
            scale=(1.2, 1.0, 1.0))
        self.friendList = ScrolledFriendList(page,
                                             self.gui,
                                             makeItemsCheckBoxes=True)
        if len(base.localAvatar.friendsList) == 0:
            self.noFriends = True
        else:
            self.noFriends = False
            for friendPair in base.localAvatar.friendsList:
                self.friendList.addFriend(determineFriendName(friendPair),
                                          friendPair[0])

            self.friendList.scrollTo(0)
        pos = self.gui.find('**/step_04_partyWillBe_locator').getPos()
        self.publicPrivateLabel = DirectLabel(
            parent=page,
            relief=None,
            text=TTLocalizer.PartyPlannerPublicPrivateLabel,
            text_align=TextNode.ACenter,
            text_scale=0.065,
            pos=pos)
        self.publicDescriptionLabel = DirectLabel(
            parent=page,
            relief=None,
            text=TTLocalizer.PartyPlannerPublicDescription,
            text_align=TextNode.ACenter,
            text_scale=TTLocalizer.PPpbulicDescriptionLabel,
            pos=(pos[0] - 0.52, pos[1], pos[2]))
        self.publicDescriptionLabel.stash()
        self.privateDescriptionLabel = DirectLabel(
            parent=page,
            relief=None,
            text=TTLocalizer.PartyPlannerPrivateDescription,
            text_align=TextNode.ACenter,
            text_scale=TTLocalizer.PPprivateDescriptionLabel,
            pos=(pos[0] + 0.55, pos[1], pos[2]))
        self.privateDescriptionLabel.stash()
        pos = self.gui.find('**/step_04_public_locator').getPos()
        self.publicButton = DirectButton(
            parent=page,
            relief=None,
            geom=(self.gui.find('**/publicButton_up'),
                  self.gui.find('**/publicButton_down'),
                  self.gui.find('**/publicButton_rollover'),
                  self.gui.find('**/publicButton_inactive')),
            text=TTLocalizer.PartyPlannerPublic,
            text_pos=(pos[0], pos[2]),
            text_scale=TTLocalizer.PPpublicButton,
            command=self.__doTogglePublicPrivate)
        self.publicButton['state'] = DirectGuiGlobals.DISABLED
        self.publicButton.bind(DirectGuiGlobals.ENTER, self.__enterPublic)
        self.publicButton.bind(DirectGuiGlobals.EXIT, self.__exitPublic)
        pos = self.gui.find('**/step_04_private_locator').getPos()
        self.privateButton = DirectButton(
            parent=page,
            relief=None,
            geom=(self.gui.find('**/privateButton_up'),
                  self.gui.find('**/privateButton_down'),
                  self.gui.find('**/privateButton_rollover'),
                  self.gui.find('**/privateButton_inactive')),
            text=TTLocalizer.PartyPlannerPrivate,
            text_pos=(pos[0], pos[2]),
            text_scale=TTLocalizer.PPprivateButton,
            command=self.__doTogglePublicPrivate)
        self.privateButton.bind(DirectGuiGlobals.ENTER, self.__enterPrivate)
        self.privateButton.bind(DirectGuiGlobals.EXIT, self.__exitPrivate)
        self.checkAllButton = DirectButton(
            parent=page,
            relief=None,
            geom=(self.gui.find('**/checkAllButton_up'),
                  self.gui.find('**/checkAllButton_down'),
                  self.gui.find('**/checkAllButton_rollover')),
            command=self.__doCheckAll)
        self.uncheckAllButton = DirectButton(
            parent=page,
            relief=None,
            geom=(self.gui.find('**/uncheckAllButton_up'),
                  self.gui.find('**/uncheckAllButton_down'),
                  self.gui.find('**/uncheckAllButton_rollover')),
            command=self.__doUncheckAll)
        return page

    def __doCheckAll(self):
        for friendBox in self.friendList['items']:
            friendBox['indicatorValue'] = True

    def __doUncheckAll(self):
        for friendBox in self.friendList['items']:
            friendBox['indicatorValue'] = False

    def __enterPrivate(self, mouseEvent):
        self.privateDescriptionLabel.unstash()

    def __exitPrivate(self, mouseEvent):
        self.privateDescriptionLabel.stash()

    def __enterPublic(self, mouseEvent):
        self.publicDescriptionLabel.unstash()

    def __exitPublic(self, mouseEvent):
        self.publicDescriptionLabel.stash()

    def __doTogglePublicPrivate(self):
        if self.isPrivate:
            self.isPrivate = False
            self.privateButton['state'] = DirectGuiGlobals.NORMAL
            self.publicButton['state'] = DirectGuiGlobals.DISABLED
        else:
            self.isPrivate = True
            self.privateButton['state'] = DirectGuiGlobals.DISABLED
            self.publicButton['state'] = DirectGuiGlobals.NORMAL

    def _createPartyEditorPage(self):
        page = DirectFrame(self.frame)
        page.setName('PartyPlannerEditorPage')
        self.LayoutTitleLabel = DirectLabel(
            parent=page,
            relief=None,
            text=TTLocalizer.PartyPlannerEditorTitle,
            pos=self.gui.find('**/title_locator').getPos() +
            Point3(0.0, 0.0, 0.075),
            scale=self.titleScale)
        self.costLabel = DirectLabel(parent=page,
                                     pos=(-0.74, 0.0, 0.17),
                                     relief=None,
                                     text=TTLocalizer.PartyPlannerTotalCost %
                                     0,
                                     text_align=TextNode.ACenter,
                                     scale=TTLocalizer.PPcostLabel,
                                     textMayChange=True)
        self.partyGridBackground = DirectFrame(
            parent=page, relief=None, geom=self.gui.find('**/partyGrid_flat'))
        self.partyGroundsLabel = DirectLabel(
            parent=page,
            relief=None,
            text=TTLocalizer.PartyPlannerPartyGrounds,
            text_font=ToontownGlobals.getSignFont(),
            text_fg=VBase4(1.0, 0.0, 0.0, 1.0),
            text_scale=TTLocalizer.PPpartyGroundsLabel,
            pos=self.gui.find('**/step_05_partyGrounds_text_locator').getPos(),
            scale=0.1)
        self.activityBackground = DirectFrame(
            parent=page,
            relief=None,
            geom=self.gui.find('**/activitiesDecorations_flat1'),
            pos=(0.0, 0.0, 0.04))
        pos = self.gui.find('**/step_05_instructions_locator').getPos()
        self.instructionLabel = DirectLabel(
            parent=page,
            relief=None,
            text=' ',
            text_pos=(pos[0], pos[2]),
            text_scale=TTLocalizer.PPinstructionLabel,
            textMayChange=True,
            geom=self.gui.find('**/instructions_flat'))
        self.elementTitleLabel = DirectLabel(
            parent=page,
            relief=None,
            text=' ',
            pos=self.gui.find(
                '**/step_05_activitiesName_text_locator').getPos() +
            Point3(0.0, 0.0, 0.04),
            text_scale=TTLocalizer.PPelementTitleLabel,
            textMayChange=True)
        self.elementPriceNode = TextNode('ElementPrice')
        self.elementPriceNode.setAlign(TextNode.ALeft)
        self.elementPriceNode.setTextColor(0.0, 0.0, 0.0, 1.0)
        self.elementPriceNode.setFont(ToontownGlobals.getToonFont())
        self.elementPrice = page.attachNewNode(self.elementPriceNode)
        self.elementPrice.setScale(TTLocalizer.PPelementPriceNode)
        self.elementPrice.setPos(
            self.gui.find('**/step_05_activityPrice_text_locator').getPos() +
            Point3(-0.02, 0.0, 0.04))
        self.elementDescriptionNode = TextNode('ElementDescription')
        self.elementDescriptionNode.setAlign(TextNode.ACenter)
        self.elementDescriptionNode.setWordwrap(8)
        self.elementDescriptionNode.setFont(ToontownGlobals.getToonFont())
        self.elementDescriptionNode.setTextColor(0.0, 0.0, 0.0, 1.0)
        self.elementDescription = page.attachNewNode(
            self.elementDescriptionNode)
        self.elementDescription.setScale(TTLocalizer.PPelementDescription)
        self.elementDescription.setPos(
            self.gui.find(
                '**/step_05_activityDescription_text_locator').getPos() +
            Point3(0.0, 0.0, 0.04))
        self.totalMoney = base.localAvatar.getTotalMoney()
        catalogGui = loader.loadModel('phase_5.5/models/gui/catalog_gui')
        self.beanBank = DirectLabel(parent=page,
                                    relief=None,
                                    text=str(self.totalMoney),
                                    text_align=TextNode.ARight,
                                    text_scale=0.075,
                                    text_fg=(0.95, 0.95, 0, 1),
                                    text_shadow=(0, 0, 0, 1),
                                    text_pos=(0.495, -0.53),
                                    text_font=ToontownGlobals.getSignFont(),
                                    textMayChange=True,
                                    image=catalogGui.find('**/bean_bank'),
                                    image_scale=(0.65, 0.65, 0.65),
                                    scale=0.9,
                                    pos=(-0.75, 0.0, 0.6))
        catalogGui.removeNode()
        del catalogGui
        self.accept(localAvatar.uniqueName('moneyChange'), self.__moneyChange)
        self.accept(localAvatar.uniqueName('bankMoneyChange'),
                    self.__moneyChange)
        self.partyEditor = PartyEditor(self, page)
        self.partyEditor.request('Hidden')
        pos = self.gui.find('**/step_05_add_text_locator').getPos()
        self.elementBuyButton = DirectButton(
            parent=page,
            relief=None,
            text=TTLocalizer.PartyPlannerBuy,
            text_pos=(pos[0], pos[2]),
            text_scale=TTLocalizer.PPelementBuyButton,
            geom=(self.gui.find('**/add_up'), self.gui.find('**/add_down'),
                  self.gui.find('**/add_rollover')),
            geom3_color=VBase4(0.5, 0.5, 0.5, 1.0),
            textMayChange=True,
            pos=(0.0, 0.0, 0.04),
            command=self.partyEditor.buyCurrentElement)
        return page

    def okWithPartyGroundsLayout(self):
        self.__nextItem()

    def setNextButtonState(self, enabled):
        if enabled:
            self.nextButton['state'] = DirectGuiGlobals.NORMAL
            self.nextButton.show()
        else:
            self.nextButton['state'] = DirectGuiGlobals.DISABLED
            self.nextButton.hide()

    def _createInvitationPage(self):
        self.__handleHolidays()
        page = DirectFrame(self.frame)
        page.setName('PartyPlannerInvitationPage')
        self.invitationTitleLabel = DirectLabel(
            parent=page,
            relief=None,
            text=TTLocalizer.PartyPlannerConfirmTitle,
            textMayChange=True,
            pos=self.gui.find('**/title_locator').getPos(),
            scale=self.titleScale)
        self.invitationBackground = DirectFrame(
            parent=page,
            relief=None,
            geom=self.gui.find('**/invitationBackground'))
        self.inviteVisual = InviteVisual(page)
        self.selectedInviteThemeLabel = DirectLabel(
            parent=page,
            relief=None,
            pos=self.gui.find('**/step_06_theme_locator').getPos(),
            text='',
            text_scale=0.06,
            textMayChange=True)
        self.nextThemeButton = DirectButton(
            parent=page,
            relief=None,
            geom=(self.gui.find('**/topNext_button/nextButton_up'),
                  self.gui.find('**/topNext_button/nextButton_down'),
                  self.gui.find('**/topNext_button/nextButton_rollover')),
            command=self.__nextTheme)
        self.prevThemeButton = DirectButton(
            parent=page,
            relief=None,
            geom=(self.gui.find('**/topPrevious_button/previousButton_up'),
                  self.gui.find('**/topPrevious_button/previousButton_down'),
                  self.gui.find(
                      '**/topPrevious_button/previousButton_rollover')),
            command=self.__prevTheme)
        pos = self.gui.find('**/step_06_sendInvitation_locator').getPos()
        self.inviteButton = DirectButton(
            parent=page,
            relief=None,
            geom=(self.gui.find('**/send_up'), self.gui.find('**/send_down'),
                  self.gui.find('**/send_rollover')),
            text=TTLocalizer.PartyPlannerInviteButton,
            textMayChange=True,
            text_scale=0.05,
            text_pos=(pos[0], pos[2]),
            command=self.__handleComplete)
        return page

    def __handleHolidays(self):
        self.inviteThemes = range(len(PartyGlobals.InviteTheme))
        if hasattr(base.cr, 'newsManager') and base.cr.newsManager:
            holidayIds = base.cr.newsManager.getHolidayIdList()
            if ToontownGlobals.VALENTINES_DAY not in holidayIds:
                self.inviteThemes.remove(PartyGlobals.InviteTheme.Valentoons)
            if ToontownGlobals.VICTORY_PARTY_HOLIDAY not in holidayIds:
                self.inviteThemes.remove(PartyGlobals.InviteTheme.VictoryParty)
            if ToontownGlobals.WINTER_DECORATIONS not in holidayIds and ToontownGlobals.WACKY_WINTER_DECORATIONS not in holidayIds:
                self.inviteThemes.remove(PartyGlobals.InviteTheme.Winter)

    def _createFarewellPage(self):
        page = DirectFrame(self.frame)
        page.setName('PartyPlannerFarewellPage')
        self.confirmTitleLabel = DirectLabel(
            parent=page,
            relief=None,
            text=TTLocalizer.PartyPlannerConfirmationAllOkTitle,
            textMayChange=True,
            pos=self.gui.find('**/title_locator').getPos(),
            scale=self.titleScale)
        pos = self.gui.find('**/step_07_close_text_locator').getPos()
        self.closePlannerButton = DirectButton(
            parent=page,
            relief=None,
            geom=(self.gui.find('**/close_up'), self.gui.find('**/close_down'),
                  self.gui.find('**/close_rollover')),
            text=TTLocalizer.PartyPlannerClosePlanner,
            text_scale=0.055,
            text_pos=(pos[0], pos[2]),
            command=self.__acceptExit)
        return page

    def close(self):
        self.ignore('addPartyResponseReceived')
        self.ignore(localAvatar.uniqueName('moneyChange'))
        self.ignore(localAvatar.uniqueName('bankMoneyChange'))
        self.timeInputHourUpButton.destroy()
        self.timeInputHourDownButton.destroy()
        self.timeInputMinuteUpButton.destroy()
        self.timeInputMinuteDownButton.destroy()
        self.timeInputAmPmUpButton.destroy()
        self.timeInputAmPmDownButton.destroy()
        self.privateButton.destroy()
        self.publicButton.destroy()
        self.makePartyNowButton.destroy()
        self.checkAllButton.destroy()
        self.uncheckAllButton.destroy()
        self.elementBuyButton.destroy()
        self.nextThemeButton.destroy()
        self.prevThemeButton.destroy()
        self.inviteButton.destroy()
        self.closePlannerButton.destroy()
        if hasattr(self, 'frame') and not self.frame.isEmpty():
            messenger.send(self.doneEvent)
            self.hide()
            self.cleanup()
            self.friendList.removeAndDestroyAllItems()
            self.friendList.destroy()
            self.calendarGuiMonth.destroy()
            self.frame.destroy()
        self.partyPlannerHead.delete()
        self.partyPlannerHead.removeNode()
        self.clearNametag()
        self.partyEditor.request('Cleanup')
        self.partyEditor = None
        self.destroy()
        del self

    def __handleComplete(self):
        self.inviteButton['state'] = DirectGuiGlobals.DISABLED
        self.prevButton['state'] = DirectGuiGlobals.DISABLED
        endTime = self.partyTime + self.partyDuration
        hostId = base.localAvatar.doId
        self.partyActivities = self.partyEditor.partyEditorGrid.getActivitiesOnGrid(
        )
        decorations = self.partyEditor.partyEditorGrid.getDecorationsOnGrid()
        invitees = self.getInvitees()
        self.accept('addPartyResponseReceived', self.processAddPartyResponse)
        base.cr.partyManager.sendAddParty(
            hostId, self.partyTime.strftime('%Y-%m-%d %H:%M:%S'),
            endTime.strftime('%Y-%m-%d %H:%M:%S'), self.isPrivate,
            self.currentInvitationTheme, self.partyActivities, decorations,
            invitees)

    def getInvitees(self):
        invitees = []
        for friendBox in self.friendList['items']:
            if friendBox['indicatorValue']:
                invitees.append(friendBox.getPythonTag('id'))

        return invitees

    def processAddPartyResponse(self, hostId, errorCode):
        self.notify.debug(
            'processAddPartyResponse : hostId=%d errorCode=%s' %
            (hostId, PartyGlobals.AddPartyErrorCode.getString(errorCode)))
        goingBackAllowed = False
        if errorCode == PartyGlobals.AddPartyErrorCode.AllOk:
            goingBackAllowed = False
            self.confirmTitleLabel[
                'text'] = TTLocalizer.PartyPlannerConfirmationAllOkTitle
            if self.noFriends or len(self.getInvitees()) == 0:
                confirmRecapText = TTLocalizer.PartyPlannerConfirmationAllOkTextNoFriends
            else:
                confirmRecapText = TTLocalizer.PartyPlannerConfirmationAllOkText
        elif errorCode == PartyGlobals.AddPartyErrorCode.ValidationError:
            self.confirmTitleLabel[
                'text'] = TTLocalizer.PartyPlannerConfirmationErrorTitle
            confirmRecapText = TTLocalizer.PartyPlannerConfirmationValidationErrorText
        elif errorCode == PartyGlobals.AddPartyErrorCode.DatabaseError:
            self.confirmTitleLabel[
                'text'] = TTLocalizer.PartyPlannerConfirmationErrorTitle
            confirmRecapText = TTLocalizer.PartyPlannerConfirmationDatabaseErrorText
        elif errorCode == PartyGlobals.AddPartyErrorCode.TooManyHostedParties:
            goingBackAllowed = False
            self.confirmTitleLabel[
                'text'] = TTLocalizer.PartyPlannerConfirmationErrorTitle
            confirmRecapText = TTLocalizer.PartyPlannerConfirmationTooManyText
        self.nametagGroup.setChatText(confirmRecapText)
        self.request('Farewell', goingBackAllowed)

    def __acceptExit(self):
        self.notify.debug('__acceptExit')
        if hasattr(self, 'frame'):
            self.hide()
            messenger.send(self.doneEvent)

    def __nextItem(self):
        messenger.send('wakeup')
        if self.state == 'Guests':
            self.selectedCalendarGuiDay = None
            self.calendarGuiMonth.clearSelectedDay()
        if self.state == 'Time':
            if self.partyTime < base.cr.toontownTimeManager.getCurServerDateTime(
            ):
                self.okChooseFutureTimeEvent = 'okChooseFutureTimeEvent'
                self.acceptOnce(self.okChooseFutureTimeEvent,
                                self.okChooseFutureTime)
                self.chooseFutureTimeDialog = TTDialog.TTGlobalDialog(
                    dialogName=self.uniqueName('chooseFutureTimeDialog'),
                    doneEvent=self.okChooseFutureTimeEvent,
                    message=TTLocalizer.PartyPlannerChooseFutureTime,
                    style=TTDialog.Acknowledge)
                self.chooseFutureTimeDialog.show()
        self.requestNext()

    def okChooseFutureTime(self):
        if hasattr(self, 'chooseFutureTimeDialog'):
            self.chooseFutureTimeDialog.cleanup()
            del self.chooseFutureTimeDialog
        if hasattr(self, 'okChooseFutureTimeEvent'):
            self.ignore(self.okChooseFutureTimeEvent)

    def __prevItem(self):
        messenger.send('wakeup')
        if self.state == 'Date' and self.noFriends:
            self.request('PartyEditor')
        if self.state == 'Invitation' and self.selectedCalendarGuiDay is None:
            self.request('Guests')
        self.requestPrev()

    def __moneyChange(self, newMoney):
        if hasattr(self, 'totalMoney'):
            self.totalMoney = base.localAvatar.getTotalMoney()
        if hasattr(self, 'beanBank'):
            self.beanBank['text'] = str(int(self.totalMoney))
class JukeboxGui(DirectObject):
    notify = directNotify.newCategory('JukeboxGui')
    CLOSE_EVENT = 'JukeboxGui_CLOSE_EVENT'
    SONG_SELECT_EVENT = 'JukeboxGui_SONG_SELECT_EVENT'
    QUEUE_SELECT_EVENT = 'JukeboxGui_QUEUE_SELECT_EVENT'
    ADD_SONG_CLICK_EVENT = 'JukeboxGui_ADD_SONG_CLICK_EVENT'
    MOVE_TO_TOP_CLICK_EVENT = 'JukeboxGUI_MOVE_TO_TOP_EVENT'

    def __init__(self, phaseToMusicData):
        self._loaded = False
        self._timerGui = None
        self._windowFrame = None
        self.phaseToMusicData = phaseToMusicData

    def load(self):
        if self.isLoaded():
            return
        guiNode = loader.loadModel('phase_13/models/parties/jukeboxGUI')
        self._timerGui = PartyUtils.getNewToontownTimer()
        self._windowFrame = DirectFrame(image=guiNode.find('**/background'),
                                        relief=None,
                                        pos=(0, 0, 0),
                                        scale=0.7)
        self._songFrame = DirectFrame(
            image=guiNode.find('**/songTitle_background'),
            parent=self._windowFrame,
            relief=None)
        self._currentlyPlayingLabel = self.__createLabel(
            guiNode,
            'currentlyPlaying',
            parent=self._windowFrame,
            text=TTLocalizer.JukeboxCurrentlyPlayingNothing,
            scale=TTLocalizer.JGcurrentlyPlayingLabel)
        self._songNameLabel = self.__createLabel(
            guiNode,
            'songName',
            parent=self._windowFrame,
            text=TTLocalizer.JukeboxCurrentSongNothing,
            scale=TTLocalizer.JGsongNameLabel)
        self._queueList, self._queueLabel = self.__createLabeledScrolledList(
            guiNode,
            'queue',
            label=TTLocalizer.JukeboxQueueLabel,
            parent=self._windowFrame)
        self._songsList, self._songsLabel = self.__createLabeledScrolledList(
            guiNode,
            'songs',
            label=TTLocalizer.JukeboxSongsLabel,
            parent=self._windowFrame)
        pos = guiNode.find('**/addButton_text_locator').getPos()
        self._addSongButton = self.__createButton(
            guiNode,
            'addSongButton',
            parent=self._windowFrame,
            command=self.__handleAddSongButtonClick,
            image3_color=Vec4(0.6, 0.6, 0.6, 0.6),
            text=TTLocalizer.JukeboxAddSong,
            text_align=TextNode.ACenter,
            text_pos=(pos[0], pos[2]),
            text_scale=TTLocalizer.JGaddSongButton)
        self._closeButton = self.__createButton(
            guiNode,
            'can_cancelButton',
            parent=self._windowFrame,
            command=self.__handleCloseButtonClick)
        pos = guiNode.find('**/close_text_locator').getPos()
        self._closeButton = self.__createButton(
            guiNode,
            'close',
            parent=self._windowFrame,
            command=self.__handleCloseButtonClick,
            text=TTLocalizer.JukeboxClose,
            text_align=TextNode.ACenter,
            text_pos=(pos[0], pos[2]),
            text_scale=0.08)
        self._moveToTopButton = self.__createButton(
            guiNode, 'moveToTop', command=self.__handleMoveToTopButtonClick)
        guiNode.removeNode()
        self._loaded = True

    def __createButton(self, guiNode, imagePrefix, parent=hidden, **kwargs):
        return DirectButton(parent=parent,
                            relief=None,
                            image=(guiNode.find('**/%s_up' % imagePrefix),
                                   guiNode.find('**/%s_down' % imagePrefix),
                                   guiNode.find('**/%s_rollover' %
                                                imagePrefix)),
                            **kwargs)

    def __createLabel(self, guiNode, locatorPrefix, parent=hidden, **kwargs):
        return DirectLabel(parent=parent,
                           relief=None,
                           pos=guiNode.find('**/%s_text_locator' %
                                            locatorPrefix).getPos(),
                           **kwargs)

    def __createLabeledScrolledList(self,
                                    guiNode,
                                    namePrefix,
                                    label,
                                    parent=hidden,
                                    **kwargs):
        return (DirectScrolledList(
            parent=parent,
            relief=None,
            incButton_image=(guiNode.find('**/%sButtonDown_up' % namePrefix),
                             guiNode.find('**/%sButtonDown_down' % namePrefix),
                             guiNode.find('**/%sButtonDown_rollover' %
                                          namePrefix)),
            incButton_relief=None,
            incButton_image3_color=Vec4(0.6, 0.6, 0.6, 0.6),
            decButton_image=(guiNode.find('**/%sButtonUp_up' % namePrefix),
                             guiNode.find('**/%sButtonUp_down' % namePrefix),
                             guiNode.find('**/%sButtonUp_rollover' %
                                          namePrefix)),
            decButton_relief=None,
            decButton_image3_color=Vec4(0.6, 0.6, 0.6, 0.6),
            image=guiNode.find('**/%s_background' % namePrefix),
            itemFrame_relief=None,
            itemFrame_pos=guiNode.find('**/%sList_locator' %
                                       namePrefix).getPos(),
            itemFrame_scale=0.07,
            numItemsVisible=TTLocalizer.JGnumItemsVisible,
            items=[],
            **kwargs),
                self.__createLabel(guiNode,
                                   namePrefix,
                                   parent=parent,
                                   text=label,
                                   text_fg=(0.5, 1.0, 1.0, 1.0),
                                   text_shadow=(0.0, 0.0, 0.0, 1.0),
                                   scale=0.12))

    def enable(self, timer=0):
        if not self.isLoaded():
            self.load()
            phase = 13
            tunes = self.phaseToMusicData[13]
            for filename, info in tunes.items():
                self.addToSongList(info[0], phase, filename, info[1])

            for phase, tunes in self.phaseToMusicData.items():
                if phase == 13:
                    continue
                for filename, info in tunes.items():
                    self.addToSongList(info[0], phase, filename, info[1])

        self._windowFrame.show()
        if timer > 0:
            self._timerGui.setTime(timer)
            self._timerGui.countdown(timer)
            self._timerGui.show()

    def disable(self):
        self._windowFrame.hide()
        self._timerGui.hide()

    def unload(self):
        self.ignoreAll()
        if not self.isLoaded():
            return
        if self._windowFrame is not None:
            self._windowFrame.destroy()
            self._windowFrame = None
            self._moveToTopButton.destroy()
            del self._moveToTopButton
        if self._timerGui is not None:
            self._timerGui.destroy()
            self._timerGui = None
        self._loaded = False

    def isLoaded(self):
        return self._loaded

    def addToSongList(self, text, phase, filename, length):
        listItem = DirectScrolledListItem(
            relief=None,
            parent=self._songsList,
            text=text,
            text_align=TextNode.ALeft,
            text_pos=(0.0, 0.0, 0.0),
            text_scale=TTLocalizer.JGlistItem,
            text_fg=(0.0, 0.0, 0.0, 1.0),
            text1_fg=(1.0, 1.0, 1.0, 1.0),
            text1_bg=(0.0, 0.0, 1.0, 1.0),
            text2_fg=(0.0, 0.0, 1.0, 1.0),
            text3_bg=(0.0, 0.8, 0.0, 1.0),
            command=self.__handleSongListItemSelect,
            extraArgs=[])
        listItem.setPythonTag('value', (phase, filename, length))
        self._songsList.addItem(listItem)
        return listItem

    def __handleCloseButtonClick(self):
        self.disable()
        messenger.send(JukeboxGui.CLOSE_EVENT)

    def __handleMoveToTopButtonClick(self):
        messenger.send(JukeboxGui.MOVE_TO_TOP_CLICK_EVENT)

    def __handleSongListItemSelect(self):
        pass

    def __handleAddSongButtonClick(self):
        if hasattr(self._songsList, 'currentSelected'):
            song = self._songsList.currentSelected
            messenger.send(
                JukeboxGui.ADD_SONG_CLICK_EVENT,
                [song['text'], song.getPythonTag('value')])

    def disableAddSongButton(self):
        self._addSongButton['state'] = DirectGuiGlobals.DISABLED

    def enableAddSongButton(self):
        self._addSongButton['state'] = DirectGuiGlobals.NORMAL

    def addSongToQueue(self, text, highlight=False, moveToTopButton=False):
        listItem = DirectLabel(relief=None,
                               parent=self._queueList,
                               text=text,
                               text_align=TextNode.ALeft,
                               text_pos=(0.0, 0.0, 0.0),
                               text_scale=TTLocalizer.JGlistItem)
        self._queueList.addItem(listItem)
        if highlight:
            listItem['text_fg'] = (0.0, 0.5, 0.0, 1.0)
            self._addSongButton['text'] = TTLocalizer.JukeboxReplaceSong
            listItem.setPythonTag('highlighted', True)
        if moveToTopButton and len(self._queueList['items']) > 1:
            self._moveToTopButton.reparentTo(listItem)
            self._moveToTopButton.setScale(self._windowFrame, 1.0)
            self._moveToTopButton.setPos(10.0, 0.0, 0.25)
            self._queueList.scrollTo(len(self._queueList['items']) - 1)
        return listItem

    def popSongFromQueue(self):
        if len(self._queueList['items']) > 0:
            item = self._queueList['items'][0]
            self._queueList.removeItem(item)
            if self._moveToTopButton.getParent() == item:
                self._moveToTopButton.reparentTo(hidden)
            if self._moveToTopButton.getParent() == item:
                self._moveToTopButton.reparentTo(hidden)
            if item.getPythonTag('highlighted') == True:
                self._addSongButton['text'] = TTLocalizer.JukeboxAddSong
            item.removeNode()
            return item

    def setSongCurrentlyPlaying(self, phase, filename):
        songs = self.phaseToMusicData.get(phase / 1)
        if songs:
            songName = songs.get(filename)
            if songName:
                self._songNameLabel['text'] = songName
                self._currentlyPlayingLabel[
                    'text'] = TTLocalizer.JukeboxCurrentlyPlaying

    def clearSongCurrentlyPlaying(self):
        self._currentlyPlayingLabel[
            'text'] = TTLocalizer.JukeboxCurrentlyPlayingNothing
        self._songNameLabel['text'] = TTLocalizer.JukeboxCurrentSongNothing

    def pushQueuedItemToTop(self, item):
        self._queueList['items'].remove(item)
        self._queueList['items'].insert(0, item)
        if self._moveToTopButton.getParent() == item:
            self._moveToTopButton.reparentTo(hidden)
        self._queueList.refresh()