Exemple #1
0
class PodGuideNavigation(Container):
    clipChildren = True

    def ApplyAttributes(self, attributes):
        Container.ApplyAttributes(self, attributes)
        Fill(bgParent=self, color=(1, 1, 1, 0.03))
        categories = attributes.categories
        self.callback = attributes.callback
        self.flowCont = FlowContainer(name='flowCont',
                                      parent=self,
                                      align=uiconst.TOBOTTOM,
                                      autoHeight=True,
                                      centerContent=True,
                                      contentSpacing=(10, 0))
        self.LoadCategories(categories)

    def LoadCategories(self, categories, *args):
        self.flowCont.Flush()
        tempAllTerms = GetTerms()
        for eachCategorID, eachCategoryInfo in categories.iteritems():
            catInfo = eachCategoryInfo['categoryInfo']
            categoryNameID = catInfo.groupName
            categoryName = GetByMessageID(categoryNameID)
            megaMenuOptions = []
            for eachSubGroup in eachCategoryInfo.get('subgroups', []):
                groupNameID = eachSubGroup.groupName
                groupName = GetByMessageID(groupNameID)
                termsInGroup = tempAllTerms.get(eachSubGroup.groupID, [])
                termsInfoList = []
                for eachTerm in termsInGroup:
                    termTitleID = eachTerm.termTitleID
                    termName = GetByMessageID(termTitleID)
                    termsInfoList.append({
                        'text': termName,
                        'callback': self.callback,
                        'args': eachTerm.termID
                    })

                megaMenuGroup = {
                    'headerInfo': {
                        'groupName': groupName
                    },
                    'entryInfoList': termsInfoList
                }
                megaMenuOptions.append(megaMenuGroup)

            NavigationButtonInWindow(
                parent=self.flowCont,
                megaMenuOptions=megaMenuOptions,
                categoryInfo={'categoryName': categoryName})

    def Close(self, *args):
        Container.Close(self, *args)
        uicore.megaMenuManager.CloseMegaMenu()
class AurumStoreContainer(Container):
    default_name = 'AurumStoreContainer'
    default_state = uiconst.UI_NORMAL

    def ApplyAttributes(self, attributes):
        Container.ApplyAttributes(self, attributes)
        self.store = sm.GetService('vgsService').GetStore()
        self.tagsByCategoryId = {}
        self.selectedRootCategoryId = None
        self.selectedCategoryId = None
        self.activeTagsByRootCategoryId = {}
        self.page = None
        Fill(bgParent=self, color=BACKGROUND_COLOR)
        self.CreateRedeemingPanelLayout()
        self.CreateBaseLayout()
        self.CreateHeaderLayout()
        self.CreateContentLayout()
        self.SetFilterOptions()
        self.currentAurBalance = 0
        self._OnResize()

    def _OnResize(self, *args):
        top, left, width, height = self.GetAbsolute()
        contentWidth = min(MAX_CONTENT_WIDTH, width)
        self.leftContainer.width = (width - contentWidth) / 2
        self.contentContainer.width = contentWidth
        self.rightContainer.width = width - self.leftContainer.width - contentWidth
        self.redeemingPanel.width = width
        if hasattr(self, 'grid'):
            self.grid.SetParentWidth(self.contentContainer.width)
        self.SetSidebarContentMask()

    def CreateHeaderLayout(self):
        contentContainer = Container(parent=self.headerContainer,
                                     align=uiconst.TOTOP,
                                     height=CAPTION_HEIGHT,
                                     top=CAPTION_OFFSET)
        LogoHomeButton(parent=self.headerContainer,
                       align=uiconst.TOPLEFT,
                       onClick=self.OnClickHomeButton)
        ExitButton(
            parent=self.headerContainer,
            align=uiconst.TOPRIGHT,
            onClick=uicore.cmd.ToggleAurumStore,
            top=4,
            left=10,
            hint=localization.GetByLabel('UI/VirtualGoodsStore/ExitStore'))
        self.aurButton = HeaderBuyAurButton(parent=contentContainer,
                                            align=uiconst.TORIGHT,
                                            onClick=self._BuyAurum,
                                            padding=(4, 0, 4, 0),
                                            left=6)
        cont = Container(name='AurContainer',
                         parent=contentContainer,
                         align=uiconst.TORIGHT,
                         width=200,
                         padRight=8)
        self.aurLabel = AurLabelHeader(parent=cont,
                                       align=uiconst.CENTERRIGHT,
                                       height=32,
                                       amount=100,
                                       padTop=1)

    def _BuyAurum(self):
        sm.GetService('audio').SendUIEvent('store_aur')
        sm.GetService('viewState').GetView(
            ViewState.VirtualGoodsStore)._LogBuyAurum('TopButton')
        uicore.cmd.BuyAurumOnline()

    def SetSidebarContentMask(self):
        for container in (self.leftContainer, self.rightContainer):
            container.Flush()
            GradientSprite(name='OfferSlipGradient',
                           align=uiconst.TOTOP,
                           parent=container,
                           rgbData=((0.0, BACKGROUND_COLOR[:3]), ),
                           alphaData=((0.0, CONTENT_SLIP_UNDER_AREA_OPACITY),
                                      (0.5, 1.0), (1.0, 1.0)),
                           height=self.topContainer.height +
                           self.filterContainer.height + HEADER_PADDING,
                           rotation=math.pi / 2)

    def CreateBaseLayout(self):
        wholeWidthContainer = Container(parent=self,
                                        name='WholeWindowContainer',
                                        align=uiconst.TOALL)
        self.leftContainer = Container(parent=wholeWidthContainer,
                                       name='LeftSideBar',
                                       align=uiconst.TOLEFT)
        self.rightContainer = Container(parent=wholeWidthContainer,
                                        name='RightSideBar',
                                        align=uiconst.TORIGHT)
        self.contentContainer = Container(parent=wholeWidthContainer,
                                          name='Content',
                                          align=uiconst.TOLEFT)
        self.topContainer = ContainerAutoSize(name='Top Container',
                                              parent=self.contentContainer,
                                              align=uiconst.TOTOP)
        Fill(name='SlipUnderLayer',
             bgParent=self.topContainer,
             color=BACKGROUND_COLOR)
        self.headerContainer = Container(parent=self.topContainer,
                                         name='Header',
                                         align=uiconst.TOTOP,
                                         bgColor=HEADER_BG_COLOR,
                                         height=HEADER_HEIGHT,
                                         clipChildren=True)
        self.categoryContainer = Container(parent=self.topContainer,
                                           name='Categories',
                                           align=uiconst.TOTOP,
                                           height=CATEGORIES_HEIGHT,
                                           padTop=HEADER_PADDING,
                                           state=uiconst.UI_PICKCHILDREN)
        self.subCategoryContainer = Container(name='SubCategories',
                                              parent=self.topContainer,
                                              align=uiconst.TOTOP,
                                              padTop=HEADER_PADDING,
                                              bgColor=TAG_COLOR,
                                              state=uiconst.UI_PICKCHILDREN,
                                              clipChildren=True)
        self.subCategoryButtonContainer = FlowContainer(
            name='SubCategoryButtons',
            parent=self.subCategoryContainer,
            centerContent=True,
            align=uiconst.TOTOP,
            contentSpacing=(1, 0),
            state=uiconst.UI_PICKCHILDREN)
        self.filterContainer = Container(name='Filter',
                                         parent=self.contentContainer,
                                         align=uiconst.TOTOP,
                                         padTop=HEADER_PADDING,
                                         state=uiconst.UI_PICKCHILDREN,
                                         height=CATEGORIES_HEIGHT)

    def CreateContentLayout(self):
        self.contentScroll = OfferScrollContainer(parent=self.contentContainer,
                                                  align=uiconst.TOALL)
        self.banner = BannerReel(parent=self.contentScroll,
                                 align=uiconst.TOTOP,
                                 bannerWidth=MAX_CONTENT_WIDTH,
                                 bannerHeight=AD_HEIGHT)
        self.grid = OfferGrid(parent=self.contentScroll,
                              align=uiconst.TOTOP,
                              contentSpacing=(CONTENT_PADDING,
                                              CONTENT_PADDING),
                              padBottom=CONTENT_PADDING,
                              columns=OFFER_COLUMNS,
                              incrementSize=OFFER_COLUMNS)
        for x in xrange(4 * OFFER_COLUMNS):
            offer = VgsOffer(parent=self.grid,
                             width=MAX_OFFER_IMAGE_SIZE,
                             height=MAX_OFFER_IMAGE_SIZE,
                             align=uiconst.NOALIGN)

        self.contentScroll.RegisterContentLoader(self.grid)

    def CreateRedeemingPanelLayout(self):
        instructionText = '<url=localsvc:service=vgsService&method=ShowRedeemUI>%s</url>' % (
            localization.GetByLabel(
                'UI/RedeemWindow/ClickToInitiateRedeeming'), )
        self.redeemingPanel = RedeemPanel(
            parent=self,
            align=uiconst.TOBOTTOM,
            dragEnabled=False,
            instructionText=instructionText,
            redeemButtonBackgroundColor=REDEEM_BUTTON_BACKGROUND_COLOR,
            redeemButtonFillColor=REDEEM_BUTTON_FILL_COLOR)
        self.redeemingPanel.UpdateDisplay()

    def SelectCategory(self, categoryId):
        self.selectedRootCategoryId = categoryId
        for button in self.categoryButtons:
            if button.isActive and button.categoryId != categoryId:
                button.SetActive(False)

    def SelectSubCategory(self, subcategoryId):
        self.selectedCategoryId = subcategoryId
        for button in self.subcategoryButtons:
            if button.isActive and button.categoryId != subcategoryId:
                button.SetActive(False)

    def OnClickCategory(self, categoryId):
        self.LoadCategoryPage(categoryId)

    @RunThreadOnce(THREAD_KEY_LOAD_PAGE)
    def LoadCategoryPage(self, categoryId):
        if self.page == PAGE_CATEGORY and self.selectedRootCategoryId == categoryId and self.selectedCategoryId is None:
            return
        logger.debug('Loading category page: %s', categoryId)
        self.SelectCategory(categoryId)
        categoriesById = self.store.GetCategories()
        category = categoriesById[categoryId]
        subcategories = [
            categoriesById[subCatId] for subCatId in category.subcategories
        ]
        subcategories = localization.util.Sort(subcategories,
                                               key=lambda c: c.name)
        self.SetSubCategories(subcategories)
        self.SelectSubCategory(None)
        self.SetOffersAndTags(categoryId)
        self.page = PAGE_CATEGORY

    def OnClickSubCategory(self, subcategoryId):
        self.LoadSubCategoryPage(subcategoryId)

    @RunThreadOnce(THREAD_KEY_LOAD_PAGE)
    def LoadSubCategoryPage(self, subcategoryId):
        if self.page == PAGE_SUBCATEGORY and self.selectedCategoryId == subcategoryId:
            return
        logger.debug('Loading sub category page: %s', subcategoryId)
        self.selectedCategoryId = subcategoryId
        self.SetOffersAndTags(subcategoryId)
        self.SelectSubCategory(subcategoryId)
        self.page = PAGE_SUBCATEGORY

    def SetOffersAndTags(self, categoryId):
        tags = self.store.GetTagsByCategoryId(categoryId)
        self.SetFilterTags(tags)
        tagIds = self.filterBar.GetSelectedFilterTagIds()
        offers = self.store.GetFilteredOffers(categoryId, tagIds)
        self.HideBanner()
        self.SetOffers(offers)

    @RunThreadOnce(THREAD_KEY_LOAD_PAGE)
    def OnClickHomeButton(self):
        self.LoadLandingPage()

    def LoadLandingPage(self):
        logger.debug('LoadLandingPage')
        if self.page == PAGE_HOME:
            return
        logger.debug('Loading landing page')
        self._SetSubCategories(None)
        self.SelectCategory(None)
        self.SelectSubCategory(None)
        self.SetFilterTags([])
        self.ShowBanner()
        offers = self.store.GetOffers().values()
        self.SetOffers(offers)
        self.page = PAGE_HOME

    @RunThreadOnce('VGS.ShowBanner')
    def ShowBanner(self):
        if self.banner.HasBanners() and not self.banner.display:
            self.banner.top = 0
            self.banner.display = True
            self.SetSubCategories(None)
            uicore.animations.MoveInFromTop(self.banner,
                                            amount=self.banner.height,
                                            sleep=True)

    @RunThreadOnce('VGS.HideBanner')
    def HideBanner(self):
        uicore.animations.MoveOutTop(self.banner,
                                     amount=self.banner.height,
                                     sleep=True)
        self.banner.top = 0
        self.banner.display = False

    @postponeUntilFocus
    def SetAUR(self, amount):
        logger.debug('SetAUR %s', amount)
        uicore.animations.MorphScalar(
            self,
            'currentAurBalance',
            startVal=self.currentAurBalance,
            endVal=amount,
            curveType=uiconst.ANIM_SMOOTH,
            duration=1.5,
            callback=lambda: self.SetCurrentAurBalance(amount))

    def SetCurrentAurBalance(self, amount):
        self._currentAurBalance = amount
        self.aurLabel.SetAmount(self._currentAurBalance)

    def GetCurrentAurBalance(self):
        return self._currentAurBalance

    currentAurBalance = property(GetCurrentAurBalance, SetCurrentAurBalance)

    def SetCategories(self, categories):
        logger.debug('SetCategories %s', categories)
        self.categoryContainer.Flush()
        searchContainer = Container(name='SearchBox',
                                    parent=self.categoryContainer,
                                    width=SEARCH_BOX_WIDTH,
                                    align=uiconst.TORIGHT)
        categoryButtonsContainer = GridContainer(name='ButtonGrid',
                                                 parent=self.categoryContainer,
                                                 align=uiconst.TOALL,
                                                 columns=len(categories),
                                                 lines=1)
        tagById = self.store.GetTags()
        self.categoryButtons = []
        for category in categories:
            button = CategoryButton(parent=categoryButtonsContainer,
                                    categoryId=category.id,
                                    label=category.name,
                                    align=uiconst.TOALL,
                                    onClick=self.OnClickCategory,
                                    padRight=1)
            self.categoryButtons.append(button)
            tags = []
            for tagId in category.tagIds:
                tag = tagById.get(tagId)
                if tag:
                    tags.append(Tag(tag.id, tag.name))

            self.tagsByCategoryId[category.id] = tags

        iconContainer = Container(name='SearchIconContainer',
                                  parent=searchContainer,
                                  width=CATEGORIES_HEIGHT,
                                  align=uiconst.TOLEFT,
                                  bgColor=CATEGORY_COLOR)
        Sprite(parent=iconContainer,
               texturePath='res:/UI/Texture/Vgs/Search_icon.png',
               width=32,
               height=32,
               align=uiconst.CENTER)
        self.searchEdit = SinglelineEdit(parent=searchContainer,
                                         align=uiconst.TORIGHT,
                                         pos=(0, 0, SEARCH_BOX_WIDTH -
                                              CATEGORIES_HEIGHT - 2, 0),
                                         fontsize=16,
                                         padding=(1, 0, 0, 0),
                                         OnChange=self.Search,
                                         bgColor=TAG_COLOR)
        self.searchEdit.ShowClearButton(
            icon='res:/UI/Texture/Icons/73_16_45.png')
        self.searchEdit.SetHistoryVisibility(False)
        self.searchEdit.sr.background.Hide()

    @RunThreadOnce(THREAD_KEY_LOAD_PAGE)
    def Search(self, searchString):
        self.page = PAGE_SEARCH
        self.HideBanner()
        self.SelectSubCategory(None)
        self.SelectCategory(None)
        self._SetSubCategories(None)
        self.SetFilterTags([])
        sm.GetService('viewState').GetView(
            ViewState.VirtualGoodsStore).Search(searchString)

    @RunThreadOnce('VGS.SetSubCategories')
    def SetSubCategories(self, subcategories):
        self._SetSubCategories(subcategories)

    def _SetSubCategories(self, subcategories):
        self.subCategoryButtonContainer.Flush()
        self.subcategoryButtons = []
        if subcategories is None:
            if self.subCategoryContainer.height > 0:
                uicore.animations.MorphScalar(
                    self.subCategoryContainer,
                    attrName='height',
                    startVal=self.subCategoryContainer.height,
                    endVal=0,
                    duration=0.5,
                    callback=self.SetSidebarContentMask)
        else:
            if int(self.subCategoryContainer.height) != CATEGORIES_HEIGHT:
                uicore.animations.MorphScalar(
                    self.subCategoryContainer,
                    attrName='height',
                    startVal=self.subCategoryContainer.height,
                    endVal=CATEGORIES_HEIGHT,
                    duration=0.5,
                    sleep=False,
                    callback=self.SetSidebarContentMask)
            for subcategory in subcategories:
                button = SubCategoryButton(
                    parent=self.subCategoryButtonContainer,
                    label=subcategory.name,
                    align=uiconst.NOALIGN,
                    height=CATEGORIES_HEIGHT,
                    categoryId=subcategory.id,
                    onClick=self.OnClickSubCategory)
                self.subcategoryButtons.append(button)

    def SetOffers(self, offers):
        if self.selectedCategoryId is None and self.selectedRootCategoryId is None:
            specialOffers = [o for o in offers if o.label is not None]
            notSpecialOffers = [o for o in offers if o.label is None]
            offers = SortOffers(specialOffers)
            offers.extend(SortOffers(notSpecialOffers))
        else:
            offers = SortOffers(offers)
        self.grid.SetOffers(offers)

    def SetFilterOptions(self):
        self.filterContainer.Flush()
        Fill(name='SlipUnderLayer',
             bgParent=self.filterContainer,
             color=BACKGROUND_COLOR,
             opacity=CONTENT_SLIP_UNDER_AREA_OPACITY,
             padTop=-HEADER_PADDING * 2)
        options = [(localization.GetByLabel(
            'UI/VirtualGoodsStore/Sorting/ByPriceAscending'),
                    SORT_PRICE_ASCENDING),
                   (localization.GetByLabel(
                       'UI/VirtualGoodsStore/Sorting/ByPriceDescending'),
                    SORT_PRICE_DESCENDING),
                   (localization.GetByLabel(
                       'UI/VirtualGoodsStore/Sorting/ByNameAscending'),
                    SORT_NAME_ASCENDING),
                   (localization.GetByLabel(
                       'UI/VirtualGoodsStore/Sorting/ByNameDescending'),
                    SORT_NAME_DESCENDING)]
        self.filterCombo = VgsFilterCombo(parent=self.filterContainer,
                                          align=uiconst.TORIGHT,
                                          options=options,
                                          callback=self.OnSortOrderChanged,
                                          select=GetSortOrder(),
                                          padding=(4, 2, 0, 4))
        self.filterBar = VgsOfferFilterBar(
            parent=self.filterContainer, onFilterChanged=self.OnFilterChanged)

    def SetFilterTags(self, tags):
        activeTags = self.activeTagsByRootCategoryId.get(
            self.GetSelectedRootCategoryId(), {})
        self.subCategoryContainer.state = uiconst.UI_PICKCHILDREN
        self.filterBar.SetTags(tags, activeTags)

    def OnSortOrderChanged(self, combo, key, value):
        settings.user.ui.Set('VgsOfferSortOrder', value)
        sm.GetService('viewState').GetView(
            ViewState.VirtualGoodsStore)._LogFilterChange(value)
        self.SetOffers(self.grid.GetOffers())

    def OnFilterChanged(self):
        tagIds = self.filterBar.GetSelectedFilterTagIds()
        rootCategoryId = self.GetSelectedRootCategoryId()
        self.activeTagsByRootCategoryId[rootCategoryId] = tagIds
        offers = self.store.GetFilteredOffers(
            self.selectedCategoryId or rootCategoryId, tagIds)
        self.SetOffers(offers)

    def GetSelectedCategoryId(self):
        return self.selectedCategoryId

    def GetSelectedRootCategoryId(self):
        return self.selectedRootCategoryId

    def OnMouseWheel(self, dz):
        self.contentScroll.OnMouseWheel(dz)
class Lobby(Window):
    __guid__ = 'form.Lobby'
    __notifyevents__ = ['OnCharNowInStation',
     'OnCharNoLongerInStation',
     'OnProcessStationServiceItemChange',
     'OnAgentMissionChange',
     'OnStandingSet',
     'OnCorporationChanged',
     'OnCorporationMemberChanged',
     'OnPrimaryViewChanged',
     'OnSetDevice']
    default_windowID = 'lobby'
    default_top = 16
    default_width = 223
    default_captionLabelPath = 'UI/Station/StationServices'
    default_pinned = True
    selectedGroupButtonID = None

    @staticmethod
    def default_height(*args):
        return uicore.desktop.height - 100

    @staticmethod
    def default_left(*args):
        return uicore.desktop.width - Lobby.default_width - 16

    def OnPrimaryViewChanged(self, oldViewInfo, newViewInfo):
        """
        Since the view states happen so late in all transitions we
        need to rehook the function and label to the station mode button.
        """
        self.UpdateCQButton(newViewInfo.name)

    def OnSetDevice(self):
        bottom = self.top + self.height
        if bottom > uicore.desktop.height:
            self.height = max(self.default_minSize[1], uicore.desktop.height - self.top)
        right = self.left + self.width
        if right > uicore.desktop.width:
            self.width = max(self.default_minSize[0], uicore.desktop.width - self.left)

    def ApplyAttributes(self, attributes):
        self.viewState = sm.GetService('viewState')
        if not settings.user.ui.Get('stationservicebtns', 1):
            minWidth = BIGBUTTONSIZE + (BIGBUTTONSIZE + BUTTONGAP) * 3 + 14
            minHeight = 495
        else:
            minWidth = SMALLBUTTONSIZE + (SMALLBUTTONSIZE + BUTTONGAP) * 5 + 10
            minHeight = 470
        self.default_minSize = (minWidth, minHeight)
        Window.ApplyAttributes(self, attributes)
        self.stationSvc = sm.GetService('station')
        self.guestScroll = None
        self.sr.serviceAccessCache = {}
        self.SetWndIcon(None)
        self.HideHeader()
        self.scope = 'station'
        self.MakeUnKillable()
        self.MakeUnstackable()
        self.SetTopparentHeight(0)
        main = self.sr.main
        main.clipChildren = True
        self.corpLogoParent = Container(name='corpLogoParent', align=uiconst.TOTOP, height=160, parent=main)
        self.corpName = CaptionLabel(parent=main, align=uiconst.TOTOP, name='corpName', uppercase=False)
        self.undockparent = Container(name='undockparent', align=uiconst.TOTOP, height=78, parent=main)
        self.AddCQButton(parent=self.undockparent)
        self.AddUndockButton(parent=self.undockparent)
        EveLabelMedium(text=localization.GetByLabel('UI/Station/StationServices'), align=uiconst.TOTOP, parent=main, bold=True, padding=(6, 6, 6, 0))
        self.serviceButtons = FlowContainer(name='serviceButtons', align=uiconst.TOTOP, parent=main, contentSpacing=(BUTTONGAP, BUTTONGAP), padding=(6, 6, 3, 6))
        btnGroup = ToggleButtonGroup(name='btnGroup', parent=main, align=uiconst.TOTOP, height=32, padding=(6, 6, 6, 6), idx=-1, callback=self.OnButtonGroupSelection)
        self.mainButtonGroup = btnGroup
        self.guestsPanel = Container(name=GUESTSPANEL, parent=main, padding=const.defaultPadding)
        self.quickFilter = QuickFilterEdit(name='quickFilterEdit', parent=self.guestsPanel)
        self.quickFilter.ReloadFunction = lambda : self.ShowGuests()
        self.guestScroll = BasicDynamicScroll(parent=self.guestsPanel, padTop=const.defaultPadding + self.quickFilter.height)
        guestSettingsMenu = UtilMenu(menuAlign=uiconst.TOPRIGHT, parent=self.guestsPanel, align=uiconst.TOPRIGHT, GetUtilMenu=self.SettingMenu, texturePath='res:/UI/Texture/SettingsCogwheel.png', width=18, height=18, iconSize=18)
        self.userType = settings.user.ui.Get('guestCondensedUserList', False)
        self.agentsPanel = Container(name=AGENTSPANEL, parent=main, padding=const.defaultPadding)
        self.agentFinderBtn = Button(label=localization.GetByLabel('UI/AgentFinder/AgentFinder'), parent=self.agentsPanel, align=uiconst.CENTERTOP, func=uicore.cmd.OpenAgentFinder)
        self.agentScroll = Scroll(parent=self.agentsPanel, padTop=const.defaultPadding + self.agentFinderBtn.height)
        self.officesPanel = Container(name=OFFICESPANEL, parent=main, padding=const.defaultPadding)
        self.officesButtons = FlowContainer(name='officesButtons', align=uiconst.TOTOP, parent=self.officesPanel, contentSpacing=(4, 4), centerContent=True)
        self.officesScroll = Scroll(parent=self.officesPanel, padTop=const.defaultPadding)
        agentsButton = btnGroup.AddButton(AGENTSPANEL, '<center>' + localization.GetByLabel('UI/Station/Lobby/Agents'), self.agentsPanel, btnClass=LobbyToggleButtonGroupButton, hint=localization.GetByLabel('Tooltips/StationServices/AgentsTab_descrtiption'))
        agentsButton.name = 'stationInformationTabAgents'
        guestsButton = btnGroup.AddButton(GUESTSPANEL, '<center>' + localization.GetByLabel('UI/Station/Lobby/Guests'), self.guestsPanel, btnClass=LobbyToggleButtonGroupButton, hint=localization.GetByLabel('Tooltips/StationServices/GuestsTab_description'))
        guestsButton.counter = CounterBox(parent=guestsButton, align=uiconst.TOPRIGHT, left=2, top=-5)
        self.guestsButton = guestsButton
        btnGroup.AddButton(OFFICESPANEL, '<center>' + localization.GetByLabel('UI/Station/Lobby/Offices'), self.officesPanel, btnClass=LobbyToggleButtonGroupButton, hint=localization.GetByLabel('Tooltips/StationServices/OfficesTab_description'))
        activePanel = settings.user.ui.Get('stationsLobbyTabs', AGENTSPANEL)
        if settings.char.windows.Get('dockshipsanditems', 0):
            self.inventoryPanel = Container(name=INVENTORYPANEL, parent=main)
            self.sr.shipsContainer = Container(parent=self.inventoryPanel, state=uiconst.UI_HIDDEN, padding=const.defaultPadding)
            self.sr.itemsContainer = Container(parent=self.inventoryPanel, state=uiconst.UI_HIDDEN, padding=const.defaultPadding)
            tabs = [[localization.GetByLabel('UI/Station/Ships'),
              self.sr.shipsContainer,
              self,
              'lobby_ships'], [localization.GetByLabel('UI/Station/Items'),
              self.sr.itemsContainer,
              self,
              'lobby_items']]
            self.inventoryTabs = TabGroup(name='inventoryPanel', parent=self.inventoryPanel, idx=0)
            self.inventoryTabs.Startup(tabs, 'lobbyInventoryPanel', autoselecttab=True, UIIDPrefix='lobbyInventoryPanelTab')
            self.invButton = btnGroup.AddButton(INVENTORYPANEL, '<center>' + localization.GetByLabel('UI/Station/Lobby/Hangars'), self.inventoryPanel, btnClass=LobbyToggleButtonGroupButton, hint='<b>%s</b><br>%s' % (localization.GetByLabel('Tooltips/StationServices/Hangars'), localization.GetByLabel('Tooltips/StationServices/Hangars_description')))
        elif activePanel == INVENTORYPANEL:
            activePanel = AGENTSPANEL
        btnGroup.SelectByID(activePanel)
        myDefaultView = 'hangar' if session.userid % 2 == 1 else 'station'
        curView = collections.namedtuple('FakeViewInfo', ['name'])(settings.user.ui.Get('defaultDockingView', myDefaultView))
        self.OnPrimaryViewChanged(curView, curView)
        self.LoadOwnerInfo()
        self.LoadServiceButtons()
        if self.destroyed:
            return
        sm.RegisterNotify(self)
        self.UpdateGuestTabText()

    def OnButtonGroupSelection(self, buttonID):
        settings.user.ui.Set('stationsLobbyTabs', buttonID)
        self.selectedGroupButtonID = buttonID
        if buttonID == AGENTSPANEL:
            self.ShowAgents()
        elif buttonID == GUESTSPANEL:
            self.ShowGuests()
        elif buttonID == OFFICESPANEL:
            self.ShowOffices()
        elif buttonID == INVENTORYPANEL:
            if not len(self.sr.shipsContainer.children):
                self.LayoutShipsAndItems()

    def SettingMenu(self, menuParent):
        showCompact = settings.user.ui.Get('guestCondensedUserList', False)
        menuParent.AddCheckBox(text=localization.GetByLabel('UI/Chat/ShowCompactMemberList'), checked=bool(showCompact), callback=(self.ShowGuests, not showCompact))

    def AddCQButton(self, parent):
        """
        Creates the undock button at the bottom of the lobby
        """
        scale = 1.0
        self.cqCont = Container(name='cqCont', align=uiconst.TOLEFT_PROP, width=0.5, parent=parent, state=uiconst.UI_PICKCHILDREN, padding=3)
        width = 63 * scale
        height = 34 * scale
        self.cqSpriteCont = Container(name='cq', align=uiconst.CENTERTOP, width=width, height=height, top=3, parent=self.cqCont, state=uiconst.UI_NORMAL)
        self.cqSprites = []
        spacing = 30 * scale
        for i in xrange(3):
            s = Sprite(parent=self.cqSpriteCont, texturePath='res:/UI/Texture/classes/Lobby/{0}.png'.format(i + 1), align=uiconst.CENTERTOP, width=-width, height=height, left=0, state=uiconst.UI_DISABLED)
            s.color = COLOR_CQ
            self.cqSprites.insert(0, s)

        self.cqLabel = EveLabelMedium(parent=self.cqCont, align=uiconst.CENTERTOP, top=8 + height, width=100)
        self.UpdateCQButton()
        if gfxsettings.Get(gfxsettings.MISC_LOAD_STATION_ENV):
            self.cqSpriteCont.OnClick = self.OnCQClicked
            self.cqSpriteCont.OnMouseEnter = self.OnCQMouseEnter
            self.cqSpriteCont.OnMouseExit = self.OnCQMouseExit
        else:
            self.cqSpriteCont.hint = localization.GetByLabel('UI/Station/CannotEnterCaptainsQuarters')
            for s in self.cqSprites:
                s.opacity = 0.2

    def OnCQClicked(self, *args):
        self.OnCQMouseExit()
        for i, s in enumerate(self.cqSprites):
            uicore.animations.SpGlowFadeIn(s, glowColor=(0.8, 0.8, 0.1, 0.3), glowExpand=1, loops=1, duration=1.0, curveType=uiconst.ANIM_WAVE, timeOffset=(3 - i) * 0.1)

        if self.IsInCQ():
            self.EnterHangar()
        else:
            self.EnterCQ()

    def OnCQMouseEnter(self, *args):
        self.AnimateCQSprites((0.8, 1, 1))

    def OnCQMouseExit(self, *args):
        self.AnimateCQSprites(COLOR_CQ[:3])

    def AnimateCQSprites(self, endColor):
        for i, s in enumerate(self.cqSprites):
            uicore.animations.SpColorMorphTo(s, startColor=(s.color.r, s.color.g, s.color.b), endColor=endColor, duration=0.1)

    def UpdateCQButton(self, viewName = None):
        isInCQ = False
        if viewName is not None:
            isInCQ = viewName == 'station'
        else:
            isInCQ = self.IsInCQ()
        if isInCQ:
            self.cqLabel.text = '<center>' + localization.GetByLabel('UI/Commands/EnterHangar') + '</center>'
        else:
            self.cqLabel.text = '<center>' + localization.GetByLabel('UI/Commands/EnterCQ') + '</center>'
        self.cqCont.height = self.cqLabel.height + self.cqSpriteCont.height + 6

    def IsInCQ(self):
        viewStateSvc = sm.GetService('viewState')
        currentView = viewStateSvc.GetCurrentView()
        if currentView is not None and currentView.name == 'station':
            return True
        else:
            return False

    def AddUndockButton(self, parent):
        """
        Creates the undock button at the bottom of the lobby
        """
        scale = 1.0
        self.undockCont = Container(name='undockCont', align=uiconst.TORIGHT_PROP, width=0.5, parent=parent, state=uiconst.UI_PICKCHILDREN, padding=3)
        width = 63 * scale
        height = 34 * scale
        self.undockSpriteCont = Container(name='undock', align=uiconst.CENTERTOP, width=width, height=height, top=3, parent=self.undockCont, state=uiconst.UI_NORMAL)
        self.undockSprites = []
        spacing = 30 * scale
        for i in xrange(3):
            s = Sprite(parent=self.undockSpriteCont, texturePath='res:/UI/Texture/classes/Lobby/{0}.png'.format(i + 1), align=uiconst.CENTERTOP, width=width, height=height, left=0, state=uiconst.UI_DISABLED)
            s.color = COLOR_UNDOCK
            self.undockSprites.append(s)

        self.undockLabel = EveLabelMedium(parent=self.undockCont, align=uiconst.CENTERTOP, top=8 + height, width=100)
        self.UpdateUndockButton()
        self.undockCont.height = self.undockLabel.height + height + 6
        self.undockSpriteCont.OnClick = self.OnUndockClicked
        self.undockSpriteCont.OnMouseEnter = self.OnUndockMouseEnter
        self.undockSpriteCont.OnMouseExit = self.OnUndockMouseExit

    def OnUndockClicked(self, *args):
        if sm.GetService('station').PastUndockPointOfNoReturn():
            return
        uthread.new(self.AttemptToUndock).context = 'UndockButtonThread'

    def LockCQButton(self):
        self.cqCont.opacity = 0.5
        self.cqCont.state = uiconst.UI_DISABLED

    def UnlockCQButton(self):
        self.cqCont.opacity = 1.0
        self.cqCont.state = uiconst.UI_NORMAL

    def AttemptToUndock(self):
        exiting = sm.GetService('station').Exit()
        if exiting:
            self.LockCQButton()

    def OnUndockMouseEnter(self, *args):
        self.AnimateUndockSprites((1, 1, 0.8))

    def OnUndockMouseExit(self, *args):
        self.AnimateUndockSprites(COLOR_UNDOCK[:3])

    def AnimateUndockSprites(self, endColor):
        if sm.GetService('station').PastUndockPointOfNoReturn():
            return
        for i, s in enumerate(self.undockSprites):
            uicore.animations.SpColorMorphTo(s, startColor=(s.color.r, s.color.g, s.color.b), endColor=endColor, duration=0.1)

    def SetUndockProgress(self, undockProgress):
        if undockProgress is None:
            self.UpdateUndockButton()
            return
        i = int(undockProgress * 3)
        if i < 3:
            self.UpdateUndockButton()
            uicore.animations.SpGlowFadeIn(self.undockSprites[i], glowColor=(1.0, 1.0, 0.8, 0.2), glowExpand=1, loops=1, duration=0.2)
        else:
            self.undockLabel.text = '<center>' + localization.GetByLabel('UI/Station/UndockingConfirmed') + '</center>'
            for i, s in enumerate(self.undockSprites):
                uicore.animations.StopAllAnimations(s)
                s.glowColor = (0, 0, 0, 0)
                uicore.animations.SpColorMorphTo(s, startColor=(1, 0.8, 0), endColor=(1, 0, 0), loops=1000, duration=1, curveType=uiconst.ANIM_WAVE, timeOffset=i * 0.1 - 0.5, includeAlpha=False)
                uicore.animations.SpGlowFadeIn(s, glowColor=(1.0, 1.0, 0.8, 0.2), glowExpand=1, loops=1000, duration=1, curveType=uiconst.ANIM_WAVE, timeOffset=i * 0.1)

    def UpdateUndockButton(self):
        if self.stationSvc.exitingstation:
            self.undockLabel.text = '<center>' + localization.GetByLabel('UI/Station/AbortUndock') + '</center>'
            self.LockCQButton()
        else:
            self.undockLabel.text = '<center>' + localization.GetByLabel('UI/Neocom/UndockBtn') + '</center>'
            self.UnlockCQButton()

    def EnterCQ(self, *args):
        if self.viewState.HasActiveTransition():
            return
        sm.GetService('cmd').CmdEnterCQ()

    def EnterHangar(self, *args):
        if self.viewState.HasActiveTransition():
            return
        sm.GetService('cmd').CmdEnterHangar()

    def OnScale_(self, *args):
        return
        height = 0
        for each in self.sr.main.children:
            if each.align in (uiconst.TOTOP, uiconst.TOBOTTOM):
                height += each.padTop + each.height + each.padBottom

        height += 160
        self.SetMinSize([self.minsize[0], height])

    def LayoutShipsAndItems(self):
        self.sr.itemsContainer.Flush()
        itemsContainer = invCont.StationItems(name='stationItems', parent=self.sr.itemsContainer, showControls=True, state=uiconst.UI_NORMAL)
        self.sr.shipsContainer.Flush()
        shipsContainer = invCont.StationShips(name='stationShips', parent=self.sr.shipsContainer, showControls=True, state=uiconst.UI_NORMAL)
        self.invButton.OnDropData = itemsContainer.OnDropData
        self.sr.itemsContainer.OnDropData = itemsContainer.OnDropData
        self.sr.shipsContainer.OnDropData = shipsContainer.OnDropData

    def OnProcessStationServiceItemChange(self, stationID, solarSystemID, serviceID, stationServiceItemID, isEnabled):
        if self.destroyed or stationID != eve.session.stationid:
            return
        for icon in self.serviceButtons.children:
            if hasattr(icon, 'stationServiceIDs') and serviceID in icon.stationServiceIDs:
                self.SetServiceButtonState(icon, [serviceID])

    def OnAgentMissionChange(self, actionID, agentID, tutorialID = None):
        """
        When a mission is declined or completed, that might change which agents
        are available, so update that portion of the lobby if it is displayed.
        """
        if self.selectedGroupButtonID == AGENTSPANEL:
            self.ShowAgents()

    def OnCorporationChanged(self, corpID, change):
        blue.pyos.synchro.Yield()
        self.LoadButtons()

    def OnStandingSet(self, fromID, toID, rank):
        """
        Notification that a standing has been set directly (probably from the
        debug admin window).  Might need to update agent availability.
        """
        if self.selectedGroupButtonID == AGENTSPANEL:
            self.ShowAgents()

    def SetServiceButtonState(self, button, serviceIDs):
        for serviceID in serviceIDs:
            currentstate = sm.GetService('station').GetServiceState(serviceID)
            if currentstate is not None:
                if self.sr.serviceAccessCache.has_key(serviceID):
                    del self.sr.serviceAccessCache[serviceID]
                if not currentstate.isEnabled:
                    button.Disable()
                    button.serviceStatus = localization.GetByLabel('UI/Station/Lobby/Disabled')
                    button.serviceEnabled = False
                else:
                    button.Enable()
                    button.serviceStatus = localization.GetByLabel('UI/Station/Lobby/Enabled')
                    button.serviceEnabled = True

    def LoadServiceButtons(self):
        parent = self.serviceButtons
        parent.Flush()
        services = sm.GetService('station').GetStationServiceInfo()
        serviceMask = eve.stationItem.serviceMask
        icon = None
        stationservicebtns = settings.user.ui.Get('stationservicebtns', 1)
        btnsize = BIGBUTTONSIZE
        if stationservicebtns:
            btnsize = SMALLBUTTONSIZE
        haveServices = []
        for service in services:
            hasStationService = False
            combinedServiceMask = sum(service.serviceIDs)
            if serviceMask & combinedServiceMask > 0:
                hasStationService = True
                if service.name == 'navyoffices':
                    if not sm.GetService('facwar').CheckStationElegibleForMilitia():
                        hasStationService = False
                elif service.name == 'securityoffice':
                    if not sm.GetService('securityOfficeSvc').CanAccessServiceInStation(session.stationid2):
                        hasStationService = False
            if hasStationService or -1 in service.serviceIDs:
                haveServices.append(service)

        for service in reversed(haveServices):
            button = BigButton(parent=parent, width=btnsize, height=btnsize, name=service.name, align=uiconst.NOALIGN)
            button.Startup(btnsize, btnsize, iconOpacity=0.75)
            button.cmdStr = service.command
            button.stationServiceIDs = service.serviceIDs
            button.displayName = service.label
            button.OnClick = (self.OnSvcBtnClick, button)
            button.serviceStatus = localization.GetByLabel('UI/Station/Lobby/Enabled')
            button.serviceEnabled = True
            if hasattr(service, 'iconID'):
                button.SetTexturePath(service.iconID)
            else:
                button.SetTexturePath(service.texturePath)
            self.SetServiceButtonState(button, service.serviceIDs)
            button.LoadTooltipPanel = self.LoadServiceButtonTooltipPanel

    def LoadServiceButtonTooltipPanel(self, tooltipPanel, tooltipOwner, *args):
        tooltipPanel.LoadGeneric3ColumnTemplate()
        command = uicore.cmd.commandMap.GetCommandByName(tooltipOwner.cmdStr)
        tooltipPanel.AddCommandTooltip(command)
        if not tooltipOwner.serviceEnabled:
            tooltipPanel.AddLabelMedium(text=localization.GetByLabel('UI/Station/Lobby/Disabled'), color=(1, 0, 0, 1), bold=True, colSpan=tooltipPanel.columns)

    def OnSvcBtnClick(self, btn, *args):
        self.CheckCanAccessService(btn.name)
        sm.GetService('station').LoadSvc(btn.name)

    def CheckCanAccessService(self, serviceName):
        services = sm.GetService('station').GetStationServiceInfo()
        for service in services:
            if service.name == serviceName:
                corpStationMgr = None
                now = blue.os.GetWallclockTime()
                for stationServiceID in service.serviceIDs:
                    doCheck = 1
                    time, result = (None, None)
                    if self.sr.serviceAccessCache.has_key(stationServiceID):
                        time, result = self.sr.serviceAccessCache[stationServiceID]
                        if time + const.MIN * 5 > now:
                            doCheck = 0
                    if doCheck:
                        if corpStationMgr is None:
                            corpStationMgr = sm.GetService('corp').GetCorpStationManager()
                        try:
                            corpStationMgr.DoStandingCheckForStationService(stationServiceID)
                            self.sr.serviceAccessCache[stationServiceID] = (now, None)
                        except Exception as e:
                            self.sr.serviceAccessCache[stationServiceID] = (now, e)
                            sys.exc_clear()

                    time, result = self.sr.serviceAccessCache[stationServiceID]
                    if result is not None:
                        raise result

    def LoadButtons(self):
        if self.destroyed:
            return
        btns = []
        officeExists = sm.GetService('corp').GetOffice() is not None
        canRent = session.corprole & const.corpRoleCanRentOffice == const.corpRoleCanRentOffice
        canMove = session.corprole & const.corpRoleDirector == const.corpRoleDirector
        if canRent and not officeExists:
            rentLabel = localization.GetByLabel('UI/Station/Lobby/RentOffice')
            btns.append([rentLabel, self.RentOffice, None])
        if canMove and officeExists:
            btns.append([localization.GetByLabel('UI/Station/Hangar/UnrentOffice'), self.UnrentOffice, None])
        if canMove:
            isHQHere = sm.GetService('corp').GetCorporation().stationID == session.stationid2
            if not isHQHere:
                hqLabel = localization.GetByLabel('UI/Station/Lobby/MoveHeadquartersHere')
                btns.append([hqLabel, self.SetHQ, None])
            if not officeExists and sm.GetService('corp').HasCorpImpoundedItemsAtStation():
                btns.append([localization.GetByLabel('UI/Inventory/ReleaseItems'), self.ReleaseImpoundedItems, None])
        if sm.GetService('corp').DoesCharactersCorpOwnThisStation():
            mgmtLabel = localization.GetByLabel('UI/Station/Lobby/StationManagement')
            btns.append([mgmtLabel, self.OpenStationManagement, None])
        if self.destroyed:
            return
        self.officesButtons.Flush()
        for label, func, args in btns:
            Button(parent=self.officesButtons, label=label, func=func, args=args, align=uiconst.NOALIGN)

    def ReleaseImpoundedItems(self, *args):
        corpStationMgr = sm.GetService('corp').GetCorpStationManager()
        cost = corpStationMgr.GetQuoteForGettingCorpJunkBack()
        if eve.Message('CrpJunkAcceptCost', {'cost': FmtAmt(cost)}, uiconst.YESNO) != uiconst.ID_YES:
            return
        corpStationMgr.PayForReturnOfCorpJunk(cost)
        sm.GetService('corp').hasImpoundedItemsCacheTime = None
        self.LoadButtons()

    def UnrentOffice(self, *args):
        items = invCtrl.StationCorpHangar(divisionID=None).GetItems()
        asked = False
        if len([ item for item in items if item.ownerID == session.corpid ]):
            asked = True
            if eve.Message('crpUnrentOfficeWithContent', {}, uiconst.YESNO) != uiconst.ID_YES:
                return
        if not asked:
            if eve.Message('crpUnrentOffice', {}, uiconst.YESNO) != uiconst.ID_YES:
                return
        corpStationMgr = sm.GetService('corp').GetCorpStationManager()
        sm.GetService('corp').hasImpoundedItemsCacheTime = None
        corpStationMgr.CancelRentOfOffice()

    def OpenStationManagement(self, *args):
        uthread.new(uicore.cmd.OpenStationManagement)

    def LoadOwnerInfo(self):
        parent = self.corpLogoParent
        parent.Flush()
        corpID = eve.stationItem.ownerID
        size = 128 if CheckCorpID(corpID) else 64
        logo = GetLogoIcon(itemID=corpID, parent=parent, acceptNone=False, state=uiconst.UI_DISABLED, pos=(0,
         8,
         size,
         size), align=uiconst.CENTERTOP)
        InfoIcon(typeID=const.typeCorporation, itemID=corpID, left=const.defaultPadding, top=20, align=uiconst.TOPRIGHT, parent=parent, idx=0)
        self.corpLogoParent.height = logo.top + logo.height
        if not CheckCorpID(corpID):
            self.corpName.text = '<center>' + cfg.eveowners.Get(corpID).name
            self.corpName.display = True
        else:
            self.corpName.display = False

    def ImVisible(self):
        return bool(self.state != uiconst.UI_HIDDEN and not self.IsCollapsed() and not self.IsMinimized())

    def Load(self, key):
        pass

    @telemetry.ZONE_METHOD
    def OnCharNowInStation(self, rec):
        if self.destroyed or not session.stationid2:
            return
        self.UpdateGuestTabText()
        if self.selectedGroupButtonID == GUESTSPANEL:
            charID, corpID, allianceID, warFactionID = rec
            cfg.eveowners.Prime([charID])
            if self.destroyed:
                return
            newcharinfo = cfg.eveowners.Get(charID)
            idx = 0
            for each in self.guestScroll.GetNodes():
                if each.charID == charID:
                    return
                if CaseFoldCompare(each.info.name, newcharinfo.name) > 0:
                    break
                idx += 1

            filteredGuest = None
            guestFilter = self.quickFilter.GetValue()
            if len(guestFilter):
                filteredGuest = NiceFilter(self.quickFilter.QuickFilter, newcharinfo.name)
            if filteredGuest or len(guestFilter) == 0:
                entry = GetListEntry(self.userEntry, {'charID': charID,
                 'info': newcharinfo,
                 'label': newcharinfo.name,
                 'corpID': corpID,
                 'allianceID': allianceID,
                 'warFactionID': warFactionID})
                self.guestScroll.AddNodes(idx, [entry])

    @telemetry.ZONE_METHOD
    def OnCharNoLongerInStation(self, rec):
        if self.destroyed or not session.stationid2:
            return
        self.UpdateGuestTabText()
        charID, corpID, allianceID, warFactionID = rec
        if self.selectedGroupButtonID == GUESTSPANEL:
            for entry in self.guestScroll.GetNodes():
                if entry.charID == charID:
                    self.guestScroll.RemoveNodes([entry])
                    return

    def ShowGuests(self, condensed = None, *args):
        if self.selectedGroupButtonID != GUESTSPANEL:
            return
        if condensed is not None:
            settings.user.ui.Set('guestCondensedUserList', condensed)
        self.SetGuestEntryType()
        guests = sm.GetService('station').GetGuests()
        owners = []
        for charID in guests.keys():
            if charID not in owners:
                owners.append(charID)

        cfg.eveowners.Prime(owners)
        guestsNames = [ KeyVal(name=cfg.eveowners.Get(charID).name, charID=charID) for charID in guests ]
        guestFilter = self.quickFilter.GetValue()
        if len(guestFilter):
            guestsNames = NiceFilter(self.quickFilter.QuickFilter, guestsNames)
        if self.destroyed:
            return
        scrolllist = []
        for guest in guestsNames:
            charID = guest.charID
            corpID, allianceID, warFactionID = guests[charID]
            charinfo = cfg.eveowners.Get(charID)
            scrolllist.append((charinfo.name.lower(), GetListEntry(self.userEntry, {'charID': charID,
              'info': charinfo,
              'label': charinfo.name,
              'corpID': corpID,
              'allianceID': allianceID,
              'warFactionID': warFactionID})))

        scrolllist = SortListOfTuples(scrolllist)
        self.guestScroll.Clear()
        self.guestScroll.AddNodes(0, scrolllist)
        self.UpdateGuestTabText()

    def UpdateGuestTabText(self):
        numGuests = len(sm.GetService('station').GetGuests())
        self.guestsButton.counter.text = numGuests

    def SetGuestEntryType(self):
        if settings.user.ui.Get('guestCondensedUserList', False):
            self.userEntry = 'ChatUserSimple'
        else:
            self.userEntry = 'User'

    def ShowAgents(self):
        try:
            agentsSvc = sm.GetService('agents')
            journalSvc = sm.GetService('journal')
            facWarSvc = sm.StartService('facwar')
            standingSvc = sm.StartService('standing')
            epicArcStatusSvc = sm.RemoteSvc('epicArcStatus')
            if self.selectedGroupButtonID != AGENTSPANEL:
                return
            agentMissions = journalSvc.GetMyAgentJournalDetails()[:1][0]
            agentsInStation = agentsSvc.GetAgentsByStationID()[session.stationid2]
            relevantAgents = []
            missionStateDict = {}
            for each in agentMissions:
                missionState, importantMission, missionType, missionName, agentID, expirationTime, bookmarks, remoteOfferable, remoteCompletable, contentID = each
                agent = agentsSvc.GetAgentByID(agentID)
                missionStateDict[agentID] = missionState
                if missionState not in (const.agentMissionStateAllocated, const.agentMissionStateOffered) or agent.agentTypeID in (const.agentTypeGenericStorylineMissionAgent,
                 const.agentTypeStorylineMissionAgent,
                 const.agentTypeEventMissionAgent,
                 const.agentTypeCareerAgent,
                 const.agentTypeEpicArcAgent):
                    relevantAgents.append(agentID)

            localRelevantAgents = []
            for agent in agentsInStation:
                if agent.agentID in relevantAgents:
                    localRelevantAgents.append(agent.agentID)

            if self.destroyed:
                return
            scrolllist = []
            sortlist = []
            for agentID in relevantAgents:
                if not eve.rookieState or agentID in const.rookieAgentList:
                    if agentID not in localRelevantAgents:
                        missionState = missionStateDict.get(agentID)
                        sortlist.append((cfg.eveowners.Get(agentID).name, GetListEntry('AgentEntry', {'charID': agentID,
                          'missionState': missionState})))

            if sortlist:
                agentLabel = localization.GetByLabel('UI/Station/Lobby/AgentsOfInterest')
                scrolllist.append(GetListEntry('Header', {'label': agentLabel}))
                scrolllist += SortListOfTuples(sortlist)
            unavailableAgents = []
            availableAgents = []
            for agent in agentsInStation:
                if agent.agentID in const.rookieAgentList:
                    continue
                if not eve.rookieState or agent.agentID in const.rookieAgentList:
                    isLimitedToFacWar = False
                    if agent.agentTypeID == const.agentTypeFactionalWarfareAgent and facWarSvc.GetCorporationWarFactionID(agent.corporationID) != session.warfactionid:
                        isLimitedToFacWar = True
                    if agent.agentTypeID in (const.agentTypeResearchAgent,
                     const.agentTypeBasicAgent,
                     const.agentTypeEventMissionAgent,
                     const.agentTypeCareerAgent,
                     const.agentTypeFactionalWarfareAgent):
                        standingIsValid = standingSvc.CanUseAgent(agent.factionID, agent.corporationID, agent.agentID, agent.level, agent.agentTypeID)
                        haveMissionFromAgent = agent.agentID in relevantAgents
                        if not isLimitedToFacWar and (standingIsValid or haveMissionFromAgent):
                            availableAgents.append(agent.agentID)
                        else:
                            unavailableAgents.append(agent.agentID)
                    elif agent.agentTypeID == const.agentTypeEpicArcAgent:
                        standingIsValid = standingSvc.CanUseAgent(agent.factionID, agent.corporationID, agent.agentID, agent.level, agent.agentTypeID)
                        haveMissionFromAgent = agent.agentID in relevantAgents
                        epicAgentAvailable = False
                        if haveMissionFromAgent:
                            epicAgentAvailable = True
                        elif standingIsValid:
                            if agent.agentID in relevantAgents or epicArcStatusSvc.AgentHasEpicMissionsForCharacter(agent.agentID):
                                epicAgentAvailable = True
                        if epicAgentAvailable:
                            availableAgents.append(agent.agentID)
                        else:
                            unavailableAgents.append(agent.agentID)
                    if agent.agentTypeID == const.agentTypeAura:
                        if sm.GetService('experimentClientSvc').IsTutorialEnabled():
                            availableAgents.append(agent.agentID)
                    elif agent.agentTypeID in (const.agentTypeGenericStorylineMissionAgent, const.agentTypeStorylineMissionAgent):
                        if agent.agentID in localRelevantAgents:
                            availableAgents.append(agent.agentID)
                        else:
                            unavailableAgents.append(agent.agentID)

            if availableAgents:
                availableLabel = localization.GetByLabel('UI/Station/Lobby/AvailableToYou')
                scrolllist.append(GetListEntry('Header', {'label': availableLabel}))
                sortlist = []
                for agentID in availableAgents:
                    missionState = missionStateDict.get(agentID)
                    sortlist.append((cfg.eveowners.Get(agentID).name, GetListEntry('AgentEntry', {'charID': agentID,
                      'missionState': missionState})))

                scrolllist += SortListOfTuples(sortlist)
            if unavailableAgents:
                unavailableLabel = localization.GetByLabel('UI/Station/Lobby/NotAvailableToYou')
                scrolllist.append(GetListEntry('Header', {'label': unavailableLabel}))
                sortlist = []
                for agentID in unavailableAgents:
                    missionState = missionStateDict.get(agentID)
                    sortlist.append((cfg.eveowners.Get(agentID).name, GetListEntry('AgentEntry', {'charID': agentID,
                      'missionState': missionState})))

                scrolllist += SortListOfTuples(sortlist)
            if self.destroyed:
                return
            self.agentScroll.Load(fixedEntryHeight=40, contentList=scrolllist)
        except:
            log.LogException()
            sys.exc_clear()

    def InteractWithAgent(self, agentID, *args):
        sm.StartService('agents').InteractWith(agentID)

    def SetHQ(self, *args):
        if sm.GetService('godma').GetType(eve.stationItem.stationTypeID).isPlayerOwnable == 1:
            raise UserError('CanNotSetHQAtPlayerOwnedStation')
        if eve.Message('MoveHQHere', {}, uiconst.YESNO) == uiconst.ID_YES:
            sm.GetService('corp').GetCorpStationManager().MoveCorpHQHere()

    def RentOffice(self, *args):
        if not self.sr.Get('isRentOfficeOpening') or not self.sr.isRentOfficeOpening:
            self.sr.isRentOfficeOpening = 1
            try:
                cost = sm.GetService('corp').GetCorpStationManager().GetQuoteForRentingAnOffice()
                if eve.Message('AskPayOfficeRentalFee', {'cost': cost,
                 'duration': const.rentalPeriodOffice * const.DAY}, uiconst.YESNO) == uiconst.ID_YES:
                    officeID = sm.GetService('corp').GetCorpStationManager().RentOffice(cost)
                    if officeID:
                        office = sm.GetService('corp').GetOffice()
                        invCache = sm.GetService('invCache')
                        invCache.InvalidateLocationCache(officeID)
                        if office is not None:
                            folder = invCache.GetInventoryFromId(office.officeFolderID, locationID=session.stationid2)
                            folder.List()
                            wnd = InventoryWindow.GetIfOpen()
                            if not wnd:
                                InventoryWindow.OpenOrShow()
                uthread.new(self.LoadButtons)
                if self.selectedGroupButtonID == OFFICESPANEL:
                    self.ShowOffices()
            finally:
                self.sr.isRentOfficeOpening = 0

    def ShowShips(self):
        if self.sr.shipsContainer is None:
            return
        self.mainButtonGroup.SelectByID(INVENTORYPANEL)
        self.inventoryTabs.ShowPanel(self.sr.shipsContainer)

    def ShowItems(self):
        if self.sr.itemsContainer is None:
            return
        self.mainButtonGroup.SelectByID(INVENTORYPANEL)
        self.inventoryTabs.ShowPanel(self.sr.itemsContainer)

    def ReloadOfficesIfVisible(self):
        if self.selectedGroupButtonID == OFFICESPANEL:
            self.ShowOffices()

    def ShowOffices(self):
        if self.selectedGroupButtonID != OFFICESPANEL:
            return
        self.LoadButtons()
        corpsWithOffices = sm.GetService('corp').GetCorporationsWithOfficesAtStation()
        cfg.corptickernames.Prime([ c.corporationID for c in corpsWithOffices ])
        scrolllist = []
        for corp in corpsWithOffices:
            data = KeyVal()
            data.corpName = corp.corporationName
            data.corpID = corp.corporationID
            data.corporation = corp
            scrolllist.append((data.corpName.lower(), GetListEntry('OfficeEntry', data=data)))

        scrolllist = SortListOfTuples(scrolllist)
        numUnrentedOffices = self.GetNumberOfUnrentedOffices()
        availOfficesLabel = localization.GetByLabel('UI/Station/Lobby/NumAvailableOffices', numOffices=numUnrentedOffices)
        scrolllist.insert(0, GetListEntry('Header', {'label': availOfficesLabel}))
        if not self.destroyed:
            self.officesScroll.Load(contentList=scrolllist)

    def GetNumberOfUnrentedOffices(self):
        return sm.GetService('corp').GetCorpStationManager().GetNumberOfUnrentedOffices()

    def OnCorporationMemberChanged(self, corporationID, memberID, change):
        if memberID == session.charid:
            self.LoadButtons()

    def StopAllBlinkButtons(self):
        for each in self.serviceButtons.children:
            if hasattr(each, 'Blink'):
                each.Blink(0)

    def BlinkButton(self, whatBtn):
        for each in self.serviceButtons.children:
            if each.name.lower() == whatBtn.lower():
                each.Blink(blinks=40)
Exemple #4
0
class LobbyWnd(Window):
    __guid__ = 'form.LobbyWnd'
    __notifyevents__ = [
        'OnCharNowInStation', 'OnCharNoLongerInStation',
        'OnCharacterEnteredStructure', 'OnCharacterLeftStructure',
        'OnProcessStationServiceItemChange', 'OnAgentMissionChange',
        'OnStandingSet', 'OnCorporationChanged', 'OnCorporationMemberChanged',
        'OnPrimaryViewChanged', 'OnSetDevice', 'OnStructureServiceUpdated'
    ]
    default_windowID = 'lobbyWnd'
    default_top = 16
    default_width = 223
    default_captionLabelPath = 'UI/Station/StationServices'
    default_pinned = True
    undockCont = None
    undock_button_is_locked = False
    selectedGroupButtonID = None

    @staticmethod
    def default_height(*args):
        return uicore.desktop.height - 100

    @staticmethod
    def default_left(*args):
        return uicore.desktop.width - LobbyWnd.default_width - 16

    def OnPrimaryViewChanged(self, oldViewInfo, newViewInfo):
        self.UpdateDockedModeBtn(newViewInfo.name)

    def OnSetDevice(self):
        bottom = self.top + self.height
        if bottom > uicore.desktop.height:
            self.height = max(self.default_minSize[1],
                              uicore.desktop.height - self.top)
        right = self.left + self.width
        if right > uicore.desktop.width:
            self.width = max(self.default_minSize[0],
                             uicore.desktop.width - self.left)

    def _SetDefaultMinSize(self):
        def GetMinSize(btnSize, numInRow, padding):
            return btnSize + (btnSize + BUTTONGAP) * numInRow + padding

        btnSize = self.GetServiceBtnSize()
        if not settings.user.ui.Get('stationservicebtns', 1):
            minWidth = GetMinSize(btnSize, 3, 14)
            minHeight = 495
        else:
            minWidth = GetMinSize(btnSize, 5, 10)
            minHeight = 470
        self.default_minSize = (minWidth, minHeight)

    def ApplyAttributes(self, attributes):
        self.viewState = sm.GetService('viewState')
        self.scope = 'station'
        self.userType = settings.user.ui.Get('guestCondensedUserList', False)
        self._SetDefaultMinSize()
        Window.ApplyAttributes(self, attributes)
        self.controller = attributes.controller
        self.SetGuestEntryType()
        self.guestScroll = None
        self.SetWndIcon(None)
        self.HideHeader()
        self.MakeUnKillable()
        self.MakeUnstackable()
        self.SetTopparentHeight(0)
        self.sr.main.clipChildren = True
        self.BuildTopSection()
        self._AddStationServices()
        btnGroup = self._AddPanelToggleBtnCont()
        self._AddGuestPanel()
        self._AddAgentPanel()
        self._AddOfficePanel()
        self._AddToggleBtns()
        activePanel = settings.user.ui.Get('stationsLobbyTabs', AGENTSPANEL)
        if settings.char.windows.Get('dockshipsanditems', 0):
            self._AddInventoryPanel(btnGroup)
        elif activePanel == INVENTORYPANEL:
            activePanel = AGENTSPANEL
        btnGroup.SelectByID(activePanel)
        self._SetCorrectViewState()
        self.LoadOwnerInfo()
        self.LoadServiceButtons()
        if self.destroyed:
            return
        sm.RegisterNotify(self)
        self.UpdateGuestTabText()

    def BuildTopSection(self):
        self.corpLogoParent = Container(name='corpLogoParent',
                                        align=uiconst.TOTOP,
                                        height=160,
                                        parent=self.sr.main)
        self.corpName = CaptionLabel(parent=self.sr.main,
                                     align=uiconst.TOTOP,
                                     name='corpName',
                                     uppercase=False)
        self.undockparent = Container(name='undockparent',
                                      align=uiconst.TOTOP,
                                      height=86,
                                      parent=self.sr.main)
        self.AddDockedModeButton()
        self.AddControlButton()
        self.AddUndockButton()

    def _AddStationServices(self):
        EveLabelMedium(text=GetByLabel('UI/Station/StationServices'),
                       align=uiconst.TOTOP,
                       parent=self.sr.main,
                       bold=True,
                       padding=(6, 6, 6, 0))
        self.serviceButtons = FlowContainer(name='serviceButtons',
                                            align=uiconst.TOTOP,
                                            parent=self.sr.main,
                                            contentSpacing=(BUTTONGAP,
                                                            BUTTONGAP),
                                            padding=(6, 6, 3, 6))

    def _AddGuestPanel(self):
        self.guestsPanel = Container(name=GUESTSPANEL,
                                     parent=self.sr.main,
                                     padding=const.defaultPadding)
        self.quickFilter = QuickFilterEdit(name='quickFilterEdit',
                                           parent=self.guestsPanel)
        self.quickFilter.ReloadFunction = lambda: self.ShowGuests()
        self.guestScroll = BasicDynamicScroll(parent=self.guestsPanel,
                                              padTop=const.defaultPadding +
                                              self.quickFilter.height)
        guestSettingsMenu = UtilMenu(
            menuAlign=uiconst.TOPRIGHT,
            parent=self.guestsPanel,
            align=uiconst.TOPRIGHT,
            GetUtilMenu=self.SettingMenu,
            texturePath='res:/UI/Texture/SettingsCogwheel.png',
            width=18,
            height=18,
            iconSize=18)

    def _AddAgentPanel(self):
        self.agentsPanel = Container(name=AGENTSPANEL,
                                     parent=self.sr.main,
                                     padding=const.defaultPadding)
        self.agentFinderBtn = Button(
            label=GetByLabel('UI/AgentFinder/AgentFinder'),
            parent=self.agentsPanel,
            align=uiconst.CENTERTOP,
            func=uicore.cmd.OpenAgentFinder)
        self.agentScroll = Scroll(parent=self.agentsPanel,
                                  padTop=const.defaultPadding +
                                  self.agentFinderBtn.height)

    def _AddPanelToggleBtnCont(self):
        btnGroup = ToggleButtonGroup(name='btnGroup',
                                     parent=self.sr.main,
                                     align=uiconst.TOTOP,
                                     height=32,
                                     padding=6,
                                     idx=-1,
                                     callback=self.OnButtonGroupSelection,
                                     autoHeight=True)
        self.mainButtonGroup = btnGroup
        return btnGroup

    def _AddToggleBtns(self):
        btnGroup = self.mainButtonGroup
        agentsButton = btnGroup.AddButton(
            AGENTSPANEL,
            '<center>' + GetByLabel('UI/Station/Lobby/Agents'),
            self.agentsPanel,
            btnClass=LobbyToggleButtonGroupButton,
            hint=GetByLabel('Tooltips/StationServices/AgentsTab_descrtiption'))
        agentsButton.name = 'stationInformationTabAgents'
        guestsButton = btnGroup.AddButton(
            GUESTSPANEL,
            '<center>' + GetByLabel('UI/Station/Lobby/Guests'),
            self.guestsPanel,
            btnClass=LobbyToggleButtonGroupButton,
            hint=GetByLabel('Tooltips/StationServices/GuestsTab_description'))
        guestsButton.counter = CounterBox(parent=guestsButton,
                                          align=uiconst.TOPRIGHT,
                                          left=2,
                                          top=-5)
        self.guestsButton = guestsButton
        btnGroup.AddButton(
            OFFICESPANEL,
            '<center>' + GetByLabel('UI/Station/Lobby/Offices'),
            self.officesPanel,
            btnClass=LobbyToggleButtonGroupButton,
            hint=GetByLabel('Tooltips/StationServices/OfficesTab_description'))

    def _AddOfficePanel(self):
        self.officesPanel = Container(name=OFFICESPANEL,
                                      parent=self.sr.main,
                                      padding=const.defaultPadding)
        self.officesButtons = FlowContainer(name='officesButtons',
                                            align=uiconst.TOTOP,
                                            parent=self.officesPanel,
                                            contentSpacing=(4, 4),
                                            centerContent=True)
        self.officesScroll = Scroll(parent=self.officesPanel,
                                    padTop=const.defaultPadding)

    def _AddInventoryPanel(self, btnGroup):
        self.inventoryPanel = Container(name=INVENTORYPANEL,
                                        parent=self.sr.main)
        self.sr.shipsContainer = Container(parent=self.inventoryPanel,
                                           state=uiconst.UI_HIDDEN,
                                           padding=const.defaultPadding)
        self.sr.itemsContainer = Container(parent=self.inventoryPanel,
                                           state=uiconst.UI_HIDDEN,
                                           padding=const.defaultPadding)
        tabs = [[
            GetByLabel('UI/Station/Ships'), self.sr.shipsContainer, self,
            'lobby_ships'
        ],
                [
                    GetByLabel('UI/Station/Items'), self.sr.itemsContainer,
                    self, 'lobby_items'
                ]]
        self.inventoryTabs = TabGroup(name='inventoryPanel',
                                      parent=self.inventoryPanel,
                                      idx=0)
        self.inventoryTabs.Startup(tabs,
                                   'lobbyInventoryPanel',
                                   autoselecttab=True,
                                   UIIDPrefix='lobbyInventoryPanelTab')
        hint = '<b>%s</b><br>%s' % (
            GetByLabel('Tooltips/StationServices/Hangars'),
            GetByLabel('Tooltips/StationServices/Hangars_description'))
        self.invButton = btnGroup.AddButton(
            INVENTORYPANEL,
            '<center>' + GetByLabel('UI/Station/Lobby/Hangars'),
            self.inventoryPanel,
            btnClass=LobbyToggleButtonGroupButton,
            hint=hint)

    def LoadOwnerInfo(self):
        parent = self.corpLogoParent
        parent.Flush()
        corpID = self.controller.GetOwnerID()
        size = 128 if CheckCorpID(corpID) else 64
        logo = GetLogoIcon(itemID=corpID,
                           parent=parent,
                           acceptNone=False,
                           state=uiconst.UI_DISABLED,
                           pos=(0, 8, size, size),
                           align=uiconst.CENTERTOP)
        InfoIcon(typeID=const.typeCorporation,
                 itemID=corpID,
                 left=const.defaultPadding,
                 top=20,
                 align=uiconst.TOPRIGHT,
                 parent=parent,
                 idx=0)
        parent.height = logo.top + logo.height
        if CheckCorpID(corpID):
            self.corpName.display = False
        else:
            self.corpName.text = '<center>' + cfg.eveowners.Get(corpID).name
            self.corpName.display = True

    def GetServiceBtnSize(self):
        stationservicebtns = settings.user.ui.Get('stationservicebtns', 1)
        if stationservicebtns:
            return SMALLBUTTONSIZE
        else:
            return BIGBUTTONSIZE

    def LoadServiceButtons(self):
        parent = self.serviceButtons
        parent.Flush()
        haveServices = self.GetCurrentStationServices()
        btnsize = self.GetServiceBtnSize()
        for serviceInfo in reversed(haveServices):
            button = StationServiceBtn(
                parent=parent,
                pos=(0, 0, btnsize, btnsize),
                name=serviceInfo.name,
                align=uiconst.NOALIGN,
                serviceInfo=serviceInfo,
                callback=self.OnSvcBtnClick,
                serviceStatus=GetByLabel('UI/Station/Lobby/Enabled'),
                serviceEnabled=True)
            self.SetServiceButtonState(button, serviceInfo.serviceID)
            button.LoadTooltipPanel = self.LoadServiceButtonTooltipPanel

    def ReloadServiceButtons(self):
        self.controller.GetServicesInStation()
        for icon in self.serviceButtons.children:
            self.SetServiceButtonState(icon, icon.serviceID)

    def SetServiceButtonState(self, button, serviceID):
        currentstate = self.controller.GetCurrentStateForService(serviceID)
        if currentstate is None:
            return
        self.controller.RemoveServiceFromCache(serviceID)
        if currentstate.isEnabled:
            button.EnableBtn()
        else:
            button.DisableBtn()

    def OnSvcBtnClick(self, btn, *args):
        self.CheckCanAccessService(btn.name)
        sm.GetService('station').LoadSvc(btn.name)

    def CheckCanAccessService(self, serviceName):
        serviceData = stationServiceConst.serviceDataByNameID.get(serviceName)
        if serviceData is None:
            return
        for stationServiceID in serviceData.maskServiceIDs:
            result = self.controller.PerformAndGetErrorForStandingCheck(
                stationServiceID)
            if result is not None:
                raise result

    def LoadServiceButtonTooltipPanel(self, tooltipPanel, tooltipOwner, *args):
        tooltipPanel.LoadGeneric3ColumnTemplate()
        command = uicore.cmd.commandMap.GetCommandByName(tooltipOwner.cmdStr)
        tooltipPanel.AddCommandTooltip(command)
        if not tooltipOwner.serviceEnabled:
            tooltipPanel.AddLabelMedium(
                text=GetByLabel('UI/Station/Lobby/Disabled'),
                color=(1, 0, 0, 1),
                bold=True,
                colSpan=tooltipPanel.columns)

    def GetCurrentStationServices(self):
        return self.controller.GetServicesInStation()

    def _SetCorrectViewState(self):
        myDefaultView = 'hangar' if session.userid % 2 == 1 else 'station'
        curView = collections.namedtuple('FakeViewInfo', ['name'])(
            settings.user.ui.Get('defaultDockingView', myDefaultView))
        self.OnPrimaryViewChanged(curView, curView)

    def OnButtonGroupSelection(self, buttonID):
        settings.user.ui.Set('stationsLobbyTabs', buttonID)
        self.selectedGroupButtonID = buttonID
        if buttonID == AGENTSPANEL:
            self.ShowAgents()
        elif buttonID == GUESTSPANEL:
            self.ShowGuests()
        elif buttonID == OFFICESPANEL:
            self.ShowOffices()
        elif buttonID == INVENTORYPANEL:
            if not len(self.sr.shipsContainer.children):
                self.LayoutShipsAndItems()

    def SettingMenu(self, menuParent):
        showCompact = settings.user.ui.Get('guestCondensedUserList', False)
        menuParent.AddCheckBox(
            text=GetByLabel('UI/Chat/ShowCompactMemberList'),
            checked=bool(showCompact),
            callback=self.ChangeGuestEntryType)

    def ChangeGuestEntryType(self, *args):
        showCompact = settings.user.ui.Get('guestCondensedUserList', False)
        settings.user.ui.Set('guestCondensedUserList', not showCompact)
        self.SetGuestEntryType()
        self.ShowGuests()

    def SetGuestEntryType(self):
        if settings.user.ui.Get('guestCondensedUserList', False):
            self.userEntry = 'ChatUserSimple'
        else:
            self.userEntry = 'User'

    def _GetNumLobbyBtns(self):
        if self.controller.IsControlable():
            return 3
        else:
            return 2

    def AddControlButton(self):
        if not self.controller.IsControlable():
            return
        width = 1.0 / self._GetNumLobbyBtns()
        self.takeControlBtn = ControlBtn(parent=self.undockparent,
                                         name='dockedModeBtn',
                                         padding=3,
                                         callback=self.TakeControl,
                                         width=width)
        self.takeControlBtn.SetBtnLabel(
            GetByLabel('UI/Commands/TakeStructureControl'))
        if not self.controller.CanTakeControl():
            self.takeControlBtn.DisableBtn()

    def TakeControl(self, *args):
        charInControl = self.controller.GetCharInControl()
        if charInControl:
            ConfirmTakeControl.Open(controller=self.controller,
                                    charInControl=charInControl)
        else:
            self.controller.TakeControl()

    def AddDockedModeButton(self):
        width = 1.0 / self._GetNumLobbyBtns()
        self.dockedModeBtn = DockedModeBtn(
            parent=self.undockparent,
            name='dockedModeBtn',
            padding=3,
            callback=self.OnDockModeClicked,
            isMouseOverDisabledFunc=sm.GetService(
                'station').PastUndockPointOfNoReturn(),
            width=width)
        self.UpdateDockedModeBtn()
        if self.controller.IsRestrictedByGraphicsSettings():
            self.dockedModeBtn.DisableBtn()
            textPath = self.controller.GetDisabledDockingModeHint()
            if textPath:
                self.dockedModeBtn.SetBtnHint(GetByLabel(textPath))
        else:
            self.dockedModeBtn.EnableBtn()

    def UpdateDockedModeBtn(self, viewName=None):
        textPath = self.controller.GetDockedModeTextPath(viewName)
        text = '<center>%s</center>' % GetByLabel(textPath)
        self.dockedModeBtn.SetBtnLabel(text)
        self.dockedModeBtn.AdjustBtnHeight()

    def OnDockModeClicked(self, *args):
        self.controller.ChangeDockedMode(self.viewState)

    def OnUndockClicked(self, *args):
        if self.controller.InProcessOfUndocking():
            return
        uthread.new(self.AttemptToUndock).context = 'UndockButtonThread'

    def AddUndockButton(self):
        width = 1.0 / self._GetNumLobbyBtns()
        self.undockBtn = UndockBtn(parent=self.undockparent,
                                   name='undockBtn',
                                   padding=3,
                                   callback=self.OnUndockClicked,
                                   width=width)
        self.UpdateUndockButton()
        self.undockBtn.AdjustBtnHeight()
        if self.undock_button_is_locked:
            self._DisableUndockButton()

    def UpdateUndockButton(self):
        if self.controller.IsExiting():
            text = GetByLabel('UI/Station/AbortUndock')
            self.LockDockedModeButton()
        else:
            text = GetByLabel('UI/Neocom/UndockBtn')
            self.UnlockDockedModeButton()
        self.undockBtn.SetBtnLabel('<center>%s</center>' % text)

    def LockUndockButton(self):
        self.undock_button_is_locked = True
        self._DisableUndockButton()

    def _DisableUndockButton(self):
        if self.undockBtn is not None:
            self.undockBtn.LockBtn()

    def UnlockUndockButton(self):
        self.undock_button_is_locked = False
        self._EnableUndockButton()

    def _EnableUndockButton(self):
        if self.undockBtn is not None:
            self.undockBtn.UnlockBtn()

    def LockDockedModeButton(self, *args):
        self.dockedModeBtn.LockBtn()

    def UnlockDockedModeButton(self, *args):
        self.dockedModeBtn.UnlockBtn()

    def SetUndockProgress(self, undockProgress):
        if undockProgress is None:
            self.UpdateUndockButton()
            return
        i = int(undockProgress * 3)
        if i < 3:
            self.UpdateUndockButton()
            self.undockBtn.AnimateArrow(arrowIdx=i)
        else:
            text = '<center>%s</center>' % GetByLabel(
                'UI/Station/UndockingConfirmed')
            self.undockBtn.StartConfirmedAnimation()

    def UpdateGuestTabText(self):
        numGuests = len(self.controller.GetGuests())
        self.guestsButton.counter.text = numGuests

    def AttemptToUndock(self):
        exiting = self.controller.Undock()
        if exiting:
            self.LockDockedModeButton()

    def LayoutShipsAndItems(self):
        self.sr.itemsContainer.Flush()
        stationItemsClass, stationShipsClass = self.controller.GetStationItemsAndShipsClasses(
        )
        itemID = self.controller.GetItemID()
        itemsContainer = stationItemsClass(name='stationItems',
                                           parent=self.sr.itemsContainer,
                                           showControls=True,
                                           state=uiconst.UI_NORMAL,
                                           itemID=itemID)
        self.sr.shipsContainer.Flush()
        shipsContainer = stationShipsClass(name='stationShips',
                                           parent=self.sr.shipsContainer,
                                           showControls=True,
                                           state=uiconst.UI_NORMAL,
                                           itemID=itemID)
        self.invButton.OnDropData = itemsContainer.OnDropData
        self.sr.itemsContainer.OnDropData = itemsContainer.OnDropData
        self.sr.shipsContainer.OnDropData = shipsContainer.OnDropData

    def ShowOffices(self):
        if self.selectedGroupButtonID != OFFICESPANEL:
            return
        self.LoadButtons()
        corpsWithOffices = self.controller.CorpsWithOffices()
        cfg.corptickernames.Prime([c.corporationID for c in corpsWithOffices])
        scrolllist = []
        for corp in corpsWithOffices:
            corpName = corp.corporationName
            data = KeyVal(corpName=corpName,
                          corpID=corp.corporationID,
                          corporation=corp)
            entry = GetListEntry(data=data, decoClass=OfficeEntry)
            scrolllist.append((corpName.lower(), entry))

        scrolllist = SortListOfTuples(scrolllist)
        numUnrentedOffices = self.controller.GetNumberOfUnrentedOffices()
        if numUnrentedOffices is not None:
            availOfficesLabel = GetByLabel(
                'UI/Station/Lobby/NumAvailableOffices',
                numOffices=numUnrentedOffices)
            scrolllist.insert(
                0, GetListEntry('Header', {'label': availOfficesLabel}))
        if not self.destroyed:
            self.officesScroll.Load(contentList=scrolllist)

    def LoadButtons(self):
        if self.destroyed:
            return
        btns = []
        officeExists = self.controller.DoesOfficeExist()
        canRent = self.controller.CanRent()
        canUnrent = self.controller.CanUnrent()
        canMoveHQ = self.controller.CanMoveHQ()
        hqAllowed = self.controller.IsHqAllowed()
        if canRent and not officeExists:
            rentLabel = GetByLabel('UI/Station/Lobby/RentOffice')
            btns.append([rentLabel, self.RentOffice, None])
        if canUnrent and officeExists:
            btns.append([
                GetByLabel('UI/Station/Hangar/UnrentOffice'),
                self.UnrentOffice, None
            ])
        if canMoveHQ and hqAllowed:
            isHQHere = self.controller.IsMyHQ()
            if not isHQHere:
                hqLabel = GetByLabel('UI/Station/Lobby/MoveHeadquartersHere')
                btns.append([hqLabel, self.SetHQ, None])
            if not officeExists and self.controller.HasCorpImpountedItems():
                btns.append([
                    GetByLabel('UI/Inventory/ReleaseItems'),
                    self.ReleaseImpoundedItems, None
                ])
        if self.controller.MyCorpIsOwner():
            mgmtLabel = GetByLabel('UI/Station/Lobby/StationManagement')
            btns.append([mgmtLabel, self.OpenStationManagement, None])
        if self.destroyed:
            return
        self.officesButtons.Flush()
        for label, func, args in btns:
            Button(parent=self.officesButtons,
                   label=label,
                   func=func,
                   args=args,
                   align=uiconst.NOALIGN)

    def RentOffice(self, *args):
        if self.sr.isRentOfficeOpening:
            return
        self.sr.isRentOfficeOpening = 1
        try:
            cost = self.controller.GetCostForOpeningOffice()
            if eve.Message('AskPayOfficeRentalFee', {
                    'cost': cost,
                    'duration': const.rentalPeriodOffice * const.DAY
            }, uiconst.YESNO) == uiconst.ID_YES:
                officeID = self.controller.RentOffice(cost)
                if officeID:
                    self.InvalidateOfficeInvCache(officeID)
            uthread.new(self.LoadButtons)
            if self.selectedGroupButtonID == OFFICESPANEL:
                self.ShowOffices()
        finally:
            self.sr.isRentOfficeOpening = 0

    def InvalidateOfficeInvCache(self, officeID):
        office = self.controller.GetMyCorpOffice()
        invCache = sm.GetService('invCache')
        invCache.InvalidateLocationCache(officeID)
        if office is not None:
            itemID = self.controller.GetItemID()
            folder = invCache.GetInventoryFromId(office.officeFolderID,
                                                 locationID=itemID)
            folder.List()
            wnd = InventoryWindow.GetIfOpen()
            if not wnd:
                InventoryWindow.OpenOrShow()

    def UnrentOffice(self, *args):
        corpHasItemsInStation = self.controller.CorpHasItemsInstaton()
        if corpHasItemsInStation:
            if eve.Message('crpUnrentOfficeWithContent', {},
                           uiconst.YESNO) != uiconst.ID_YES:
                return
        elif eve.Message('crpUnrentOffice', {},
                         uiconst.YESNO) != uiconst.ID_YES:
            return
        self.controller.UnrentOffice()

    def SetHQ(self, *args):
        self.controller.SetHQ()

    def ReleaseImpoundedItems(self, *args):
        cost = self.controller.GetCostForGettingCorpJunkBack()
        if eve.Message('CrpJunkAcceptCost', {'cost': FmtAmt(cost)},
                       uiconst.YESNO) != uiconst.ID_YES:
            return
        self.controller.ReleaseImpoundedItems(cost)
        self.LoadButtons()

    def OpenStationManagement(self, *args):
        uthread.new(self.controller.OpenStationMgmt)

    def ReloadOfficesIfVisible(self):
        if self.selectedGroupButtonID == OFFICESPANEL:
            self.ShowOffices()

    def _FindAvailableAndUnavailableAgents(self, agentsInStation,
                                           localRelevantAgents,
                                           relevantAgents):
        epicArcStatusSvc = sm.RemoteSvc('epicArcStatus')
        facWarSvc = sm.StartService('facwar')
        standingSvc = sm.StartService('standing')
        unavailableAgents = []
        availableAgents = []
        for agent in agentsInStation:
            if agent.agentID in const.rookieAgentList:
                continue
            isLimitedToFacWar = False
            if agent.agentTypeID == const.agentTypeFactionalWarfareAgent and facWarSvc.GetCorporationWarFactionID(
                    agent.corporationID) != session.warfactionid:
                isLimitedToFacWar = True
            normalAgants = (const.agentTypeResearchAgent,
                            const.agentTypeBasicAgent,
                            const.agentTypeEventMissionAgent,
                            const.agentTypeCareerAgent,
                            const.agentTypeFactionalWarfareAgent)
            if agent.agentTypeID in normalAgants:
                standingIsValid = self._CheckCanUseAgent(agent, standingSvc)
                haveMissionFromAgent = agent.agentID in relevantAgents
                if not isLimitedToFacWar and (standingIsValid
                                              or haveMissionFromAgent):
                    availableAgents.append(agent.agentID)
                else:
                    unavailableAgents.append(agent.agentID)
            elif agent.agentTypeID == const.agentTypeEpicArcAgent:
                standingIsValid = self._CheckCanUseAgent(agent, standingSvc)
                haveMissionFromAgent = agent.agentID in relevantAgents
                epicAgentAvailable = False
                if haveMissionFromAgent:
                    epicAgentAvailable = True
                elif standingIsValid:
                    if agent.agentID in relevantAgents or epicArcStatusSvc.AgentHasEpicMissionsForCharacter(
                            agent.agentID):
                        epicAgentAvailable = True
                if epicAgentAvailable:
                    availableAgents.append(agent.agentID)
                else:
                    unavailableAgents.append(agent.agentID)
            if agent.agentTypeID == const.agentTypeAura:
                if sm.GetService('experimentClientSvc').IsTutorialEnabled():
                    availableAgents.append(agent.agentID)
            elif agent.agentTypeID in (
                    const.agentTypeGenericStorylineMissionAgent,
                    const.agentTypeStorylineMissionAgent):
                if agent.agentID in localRelevantAgents:
                    availableAgents.append(agent.agentID)
                else:
                    unavailableAgents.append(agent.agentID)

        return (availableAgents, unavailableAgents)

    def _CheckCanUseAgent(self, agent, standingSvc):
        return standingSvc.CanUseAgent(agent.factionID, agent.corporationID,
                                       agent.agentID, agent.level,
                                       agent.agentTypeID)

    def ShowAgents(self):
        if self.selectedGroupButtonID != AGENTSPANEL:
            return
        try:
            agentsSvc = sm.GetService('agents')
            journalSvc = sm.GetService('journal')
            agentMissions = journalSvc.GetMyAgentJournalDetails()[:1][0]
            agentsInStation = self.controller.GetAgents()
            relevantAgents = []
            missionStateDict = {}
            for each in agentMissions:
                missionState, importantMission, missionType, missionName, agentID, expirationTime, bookmarks, remoteOfferable, remoteCompletable, contentID = each
                agent = agentsSvc.GetAgentByID(agentID)
                missionStateDict[agentID] = missionState
                onGoingMission = (const.agentMissionStateAllocated,
                                  const.agentMissionStateOffered)
                specialAgents = (const.agentTypeGenericStorylineMissionAgent,
                                 const.agentTypeStorylineMissionAgent,
                                 const.agentTypeEventMissionAgent,
                                 const.agentTypeCareerAgent,
                                 const.agentTypeEpicArcAgent)
                if missionState not in onGoingMission or agent.agentTypeID in specialAgents:
                    relevantAgents.append(agentID)

            localRelevantAgents = []
            for agent in agentsInStation:
                if agent.agentID in relevantAgents:
                    localRelevantAgents.append(agent.agentID)

            if self.destroyed:
                return
            scrolllist = []
            sortlist = []
            for agentID in relevantAgents:
                if not eve.rookieState or agentID in const.rookieAgentList:
                    if agentID not in localRelevantAgents:
                        entryWithSortValue = self.GetAgentEntryWithSortValue(
                            agentID, missionStateDict)
                        sortlist.append(entryWithSortValue)

            if sortlist:
                agentLabel = GetByLabel('UI/Station/Lobby/AgentsOfInterest')
                scrolllist.append(GetListEntry('Header',
                                               {'label': agentLabel}))
                scrolllist += SortListOfTuples(sortlist)
            agentList, unavailableAgents = self._FindAvailableAndUnavailableAgents(
                agentsInStation, localRelevantAgents, relevantAgents)
            agentInfo = [('UI/Station/Lobby/AvailableToYou', agentList),
                         ('UI/Station/Lobby/NotAvailableToYou',
                          unavailableAgents)]
            for labelPath, agentList in agentInfo:
                if agentList:
                    text = GetByLabel(labelPath)
                    scrolllist.append(GetListEntry('Header', {'label': text}))
                    sortlist = []
                    for agentID in agentList:
                        entryWithSortValue = self.GetAgentEntryWithSortValue(
                            agentID, missionStateDict)
                        sortlist.append(entryWithSortValue)

                    scrolllist += SortListOfTuples(sortlist)

            if self.destroyed:
                return
            self.agentScroll.Load(fixedEntryHeight=40, contentList=scrolllist)
        except:
            log.LogException()
            sys.exc_clear()

    def GetAgentEntryWithSortValue(self, agentID, missionStateDict):
        missionState = missionStateDict.get(agentID)
        sortValue = cfg.eveowners.Get(agentID).name
        entry = GetListEntry('AgentEntry', {
            'charID': agentID,
            'missionState': missionState
        })
        return (sortValue, entry)

    def ShowGuests(self, *args):
        if self.selectedGroupButtonID != GUESTSPANEL:
            return
        guests = self.controller.GetGuests()
        ownerIDs = guests.keys()
        cfg.eveowners.Prime(ownerIDs)
        guestFilter = self.quickFilter.GetValue()
        if len(guestFilter):
            filterData = [
                KeyVal(name=cfg.eveowners.Get(charID).name, charID=charID)
                for charID in ownerIDs
            ]
            filterGuests = NiceFilter(self.quickFilter.QuickFilter, filterData)
            ownerIDs = [each.charID for each in filterGuests]
        if self.destroyed:
            return
        scrolllist = []
        for charID in ownerIDs:
            if charID not in guests:
                continue
            corpID, allianceID, warFactionID = guests[charID]
            charinfo = cfg.eveowners.Get(charID)
            sortValue = charinfo.name.lower()
            data = {
                'charID': charID,
                'info': charinfo,
                'label': charinfo.name,
                'corpID': corpID,
                'allianceID': allianceID,
                'warFactionID': warFactionID
            }
            entry = GetListEntry(self.userEntry, data)
            scrolllist.append((sortValue, entry))

        scrolllist = SortListOfTuples(scrolllist)
        self.guestScroll.Clear()
        self.guestScroll.AddNodes(0, scrolllist)
        self.UpdateGuestTabText()

    def OnCharNowInStation(self, rec):
        self.CharacterAdded(*rec)

    def OnCharNoLongerInStation(self, rec):
        self.CharacterRemoved(rec[0])

    def OnCharacterEnteredStructure(self, characterID, corporationID,
                                    allianceID, factionID):
        self.CharacterAdded(characterID, corporationID, allianceID, factionID)

    def OnCharacterLeftStructure(self, characterID):
        self.CharacterRemoved(characterID)

    @telemetry.ZONE_METHOD
    def CharacterAdded(self, characterID, corporationID, allianceID,
                       factionID):
        if not self.IsLobbyBeAvailable():
            return
        self.UpdateGuestTabText()
        if self.selectedGroupButtonID != GUESTSPANEL:
            return
        cfg.eveowners.Prime([characterID])
        if self.destroyed:
            return
        newcharinfo = cfg.eveowners.Get(characterID)
        idx = 0
        for each in self.guestScroll.GetNodes():
            if each.charID == characterID:
                return
            if CaseFoldCompare(each.info.name, newcharinfo.name) > 0:
                break
            idx += 1

        filteredGuest = None
        guestFilter = self.quickFilter.GetValue()
        if len(guestFilter):
            filteredGuest = NiceFilter(self.quickFilter.QuickFilter,
                                       newcharinfo.name)
        if filteredGuest or len(guestFilter) == 0:
            data = {
                'charID': characterID,
                'info': newcharinfo,
                'label': newcharinfo.name,
                'corpID': corporationID,
                'allianceID': allianceID,
                'warFactionID': factionID
            }
            entry = GetListEntry(self.userEntry, data)
            self.guestScroll.AddNodes(idx, [entry])

    @telemetry.ZONE_METHOD
    def CharacterRemoved(self, characterID):
        if not self.IsLobbyBeAvailable():
            return
        self.UpdateGuestTabText()
        if self.selectedGroupButtonID != GUESTSPANEL:
            return
        for entry in self.guestScroll.GetNodes():
            if entry.charID == characterID:
                self.guestScroll.RemoveNodes([entry])
                return

    def IsLobbyBeAvailable(self):
        if self.destroyed:
            return False
        if not (session.stationid2 or IsDockedInStructure()):
            return False
        return True

    def OnProcessStationServiceItemChange(self, stationID, solarSystemID,
                                          maskServiceID, stationServiceItemID,
                                          isEnabled):
        if not self.IsLobbyBeAvailable():
            return
        for icon in self.serviceButtons.children:
            if hasattr(icon, 'maskStationServiceIDs'
                       ) and maskServiceID in icon.maskStationServiceIDs:
                serviceID = stationServiceConst.serviceIdByMaskId[
                    maskServiceID]
                self.SetServiceButtonState(icon, serviceID)

    def OnStructureServiceUpdated(self):
        self.ReloadServiceButtons()

    def OnAgentMissionChange(self, actionID, agentID, tutorialID=None):
        if self.selectedGroupButtonID == AGENTSPANEL:
            self.ShowAgents()

    def OnStandingSet(self, fromID, toID, rank):
        if self.selectedGroupButtonID == AGENTSPANEL:
            self.ShowAgents()

    def OnCorporationChanged(self, corpID, change):
        blue.pyos.synchro.Sleep(750)
        self.LoadButtons()

    def OnCorporationMemberChanged(self, corporationID, memberID, change):
        if memberID == session.charid:
            self.LoadButtons()

    def OnPrimaryViewChanged(self, oldViewInfo, newViewInfo):
        self.UpdateDockedModeBtn(newViewInfo.name)

    def StopAllBlinkButtons(self):
        for each in self.serviceButtons.children:
            if hasattr(each, 'Blink'):
                each.Blink(0)

    def BlinkButton(self, whatBtn):
        for each in self.serviceButtons.children:
            if each.name.lower() == whatBtn.lower():
                each.Blink(blinks=40)