Exemple #1
0
class SettingsCategoryCont(Container):
    __notifyevents__ = ['OnExternalDragInitiated', 'OnExternalDragEnded']

    def ApplyAttributes(self, attributes):
        Container.ApplyAttributes(self, attributes)
        self.structureProfileController = attributes.structureProfileController
        self.structureBrowserController = attributes.structureBrowserController
        self.ChangeSignalConnection(connect=True)
        self.categoryID = self.structureBrowserController.GetSelectedCategory()
        self.categoryTypeCont = CategoryTypeCont(parent=self)
        self.settingsParent = ScrollContainer(parent=self, name='profileParent', align=uiconst.TOALL)
        self.fillUnderlay = FillThemeColored(bgParent=self.settingsParent, colorType=uiconst.COLORTYPE_UIBASECONTRAST)
        self.settingSections = []
        self.LoadCurrentCategory()
        self.draggingNodes = False
        sm.RegisterNotify(self)

    def ChangeSignalConnection(self, connect = True):
        signalAndCallback = [(self.structureBrowserController.on_category_selected, self.LoadCategorySettings)]
        ChangeSignalConnect(signalAndCallback, connect)

    def SetCurrentCategoryID(self, categoryID):
        self.categoryID = categoryID

    def LoadCategorySettings(self, categoryID):
        self.SetCurrentCategoryID(categoryID)
        self.LoadCurrentCategory()

    def LoadCurrentCategory(self):
        self.categoryTypeCont.SetCategoryName(self.categoryID)
        settingsForCategory = structures.SETTINGS_BY_CATEGORY[self.categoryID]
        self.settingsParent.Flush()
        self.settingSections = []
        settingsCont = ContainerAutoSize(parent=self.settingsParent, name='settingsCont', align=uiconst.TOTOP)
        for settingID in settingsForCategory:
            s = SettingSection(parent=settingsCont, align=uiconst.TOTOP, structureProfileController=self.structureProfileController, settingID=settingID)
            self.settingSections.append(s)

    def OnExternalDragInitiated(self, dragSource, dragData):
        if AreGroupNodes(dragData):
            self.draggingNodes = True
            self._DragChanged(initiated=True)

    def OnExternalDragEnded(self):
        if self.draggingNodes:
            self._DragChanged(initiated=False)
        self.draggingNodes = False

    def _DragChanged(self, initiated):
        for s in self.settingSections:
            s.DragChanged(initiated)

    def Close(self):
        self.settingSections = []
        self.ChangeSignalConnection(connect=False)
        self.structureProfileController = None
        self.structureBrowserController = None
        Container.Close(self)
class ConditionsContainer(Container):
    def ApplyAttributes(self, attributes):
        Container.ApplyAttributes(self, attributes)
        self.uiEntries = {}
        self._ConstructLayout()

    def _ConstructLayout(self):
        button = Button(parent=self,
                        label='Refresh Conditions',
                        func=self.FetchData,
                        align=uiconst.TOTOP,
                        padBottom=4)
        self.scrollContainer = ScrollContainer(
            name='achievementScrollContainer',
            align=uiconst.TOALL,
            parent=self)

    def FlushData(self):
        self.uiEntries = {}
        self.scrollContainer.Flush()

    def AddElement(self, conditionText, conditionCount):
        self.uiEntries[conditionText] = ConditionsEntry(
            align=uiconst.TOTOP,
            parent=self.scrollContainer,
            conditionText=conditionText,
            conditionCount=conditionCount)

    def UpdateStats(self, characterStats):
        for uiEntry in self.uiEntries.itervalues():
            uiEntry.SetConditionText(uiEntry.conditionText, '-')

        for condText, condCount in characterStats.iteritems():
            uiEntry = self.uiEntries.get(condText, None)
            if not uiEntry:
                continue
            uiEntry.SetConditionText(condText, condCount)

    def FetchData(self, *args):
        userStats = sm.GetService('achievementSvc').GetDebugStatsFromCharacter(
            force=True)
        self.UpdateStats(userStats)
class NotificationSettingList(Container):
    def ApplyAttributes(self, attributes):
        Container.ApplyAttributes(self, attributes)
        self.lastVerticalBarEnabledStatus = False
        self.notificationSettingHandler = NotificationSettingHandler()
        self.notificationSettingData = self.notificationSettingHandler.LoadSettings(
        )
        self.isDeveloperMode = attributes.get('developerMode', False)
        self._SetupUI()

    def _SetupUI(self):
        self.settingsDescriptionRowContainer = Container(name='Settings',
                                                         height=16,
                                                         align=uiconst.TOTOP,
                                                         parent=self,
                                                         padding=(5, 5, 10, 0))
        EveLabelMediumBold(
            name='Settings',
            align=uiconst.TOLEFT,
            parent=self.settingsDescriptionRowContainer,
            text=localization.GetByLabel(
                'Notifications/NotificationSettings/CategorySubscriptions'),
            bold=True)
        Sprite(
            name='popupIcon',
            parent=self.settingsDescriptionRowContainer,
            align=uiconst.TORIGHT,
            texturePath=
            'res:/UI/Texture/classes/Notifications/settingsPopupIcon.png',
            width=16,
            heigh=16,
            hint=localization.GetByLabel(
                'Notifications/NotificationSettings/PopupVisibilityTooltip'))
        Sprite(
            name='visibilityIcon',
            parent=self.settingsDescriptionRowContainer,
            align=uiconst.TORIGHT,
            texturePath=
            'res:/UI/Texture/classes/Notifications/settingsVisibleIcon.png',
            width=16,
            heigh=16,
            hint=localization.GetByLabel(
                'Notifications/NotificationSettings/HistoryVisibilityTooltip'),
            padding=(0, 0, 6, 0))
        self._MakeSeperationLine(self)
        self.scrollList = ScrollContainer(name='scrollContainer',
                                          parent=self,
                                          align=uiconst.TOALL,
                                          padding=(5, 5, 5, 5))
        self.scrollList.OnScrolledVertical = self.VerticalScrollInject

    def _MakeSeperationLine(self, parent):
        Line(name='topLine',
             parent=parent,
             align=uiconst.TOTOP,
             weight=1,
             padBottom=2,
             opacity=0.3)

    def VerticalScrollInject(self, scrollTo):
        self.AdjustCategoryHeaderForScrollBar()

    def AdjustCategoryHeaderForScrollBar(self):
        if self.lastVerticalBarEnabledStatus == self.scrollList.verticalScrollBar.display:
            return
        if self.scrollList.verticalScrollBar.display:
            self.settingsDescriptionRowContainer.padRight = 10 + self.scrollList.verticalScrollBar.width
        else:
            self.settingsDescriptionRowContainer.padRight = 10
        self.lastVerticalBarEnabledStatus = self.scrollList.verticalScrollBar.display

    def _GetGroupScrollEntries(self):
        entries = []
        for group, list in notificationConst.groupTypes.iteritems():
            groupName = localization.GetByLabel(
                notificationConst.groupNamePathsNewNotifications[group])
            entries.append(
                self.GetGroupEntry(fakeID=group, groupName=groupName))

        return entries

    def PopulateScroll(self):
        entries = self._GetGroupScrollEntries()
        entries.sort(key=lambda entr: entr.data.GetLabel().lower())
        for entry in entries:
            self.scrollList.children.append(entry)

    def ReloadScroll(self):
        self.notificationSettingHandler = NotificationSettingHandler()
        self.notificationSettingData = self.notificationSettingHandler.LoadSettings(
        )
        self.scrollList.Flush()
        self.PopulateScroll()

    def GetGroupEntry(self, fakeID, groupName):
        from eve.client.script.ui.control.treeData import TreeData
        rawNotificationList = notificationConst.groupTypes[fakeID]
        groupSettings = {}
        self.AppendEntryData(
            data=groupSettings,
            visibilityChecked=self.notificationSettingHandler.
            GetVisibilityStatusForGroup(fakeID, self.notificationSettingData),
            showPopupChecked=self.notificationSettingHandler.
            GetShowPopupStatusForGroup(fakeID, self.notificationSettingData),
            isGroup=True,
            id=fakeID)
        childrenData = []
        for notification in rawNotificationList:
            settingLabel = notificationConst.notificationToSettingDescription.get(
                notification, None)
            settingName = localization.GetByLabel(settingLabel)
            params = {}
            setting = self.notificationSettingData[notification]
            self.AppendEntryData(data=params,
                                 visibilityChecked=setting.showAtAll,
                                 showPopupChecked=setting.showPopup,
                                 isGroup=False,
                                 id=notification)
            notificationData = TreeData(label=settingName,
                                        parent=None,
                                        isRemovable=False,
                                        settings=params,
                                        settingsID=notification)
            childrenData.append(notificationData)

        childrenData.sort(key=lambda childData: childData.GetLabel().lower())
        data = TreeData(label=groupName,
                        parent=None,
                        children=childrenData,
                        icon=None,
                        isRemovable=False,
                        settings=groupSettings)
        entry = TreeViewSettingsItem(level=0,
                                     eventListener=self,
                                     data=data,
                                     settingsID=fakeID,
                                     defaultExpanded=False)
        return entry

    def AppendEntryData(self, data, visibilityChecked, showPopupChecked,
                        isGroup, id):
        data.update({
            NotificationSettingEntityDeco.VISIBILITY_CHECKED_KEY:
            visibilityChecked,
            NotificationSettingEntityDeco.POPUP_CHECKED_KEY:
            showPopupChecked,
            NotificationSettingEntityDeco.VISIBILITY_CHANGED_CALLBACK_KEY:
            self.OnVisibilityEntryChangedNew,
            NotificationSettingEntityDeco.POPUP_CHANGED_CALLBACK_KEY:
            self.OnShowPopupEntryChangedNew,
            NotificationSettingEntityDeco.GETMENU_CALLBACK:
            self.GetMenuForEntry,
            'isGroup':
            isGroup,
            'id':
            id
        })

    def OnVisibilityEntryChangedNew(self, isGroup, id, checked):
        if not isGroup:
            self._setVisibilitySettingForNotification(id, checked)

    def OnShowPopupEntryChangedNew(self, isGroup, id, checked):
        if not isGroup:
            self._setPopupSettingForNotification(id, checked)

    def _setVisibilitySettingForNotification(self, id, on):
        notificationData = self.notificationSettingData[id]
        notificationData.showAtAll = on
        self.SaveAllData()

    def _setPopupSettingForNotification(self, id, on):
        notificationData = self.notificationSettingData[id]
        notificationData.showPopup = on
        self.SaveAllData()

    def SaveAllData(self):
        self.notificationSettingHandler.SaveSettings(
            self.notificationSettingData)

    def GetMenuForEntry(self, isGroup, nodeID):
        if isGroup or not self.isDeveloperMode:
            return []
        else:
            return [('spawnNotification %s' % nodeID,
                     self.OnSpawnNotificationClick, [nodeID])]

    def OnSpawnNotificationClick(self, notificationID):
        mapper = NotificationFormatMapper()
        newFormatter = mapper.GetFormatterForType(notificationID)
        if newFormatter:
            import blue
            data = newFormatter.MakeSampleData()
            sm.ScatterEvent('OnNotificationReceived',
                            123,
                            notificationID,
                            98000001,
                            blue.os.GetWallclockTime(),
                            data=data)
        else:
            from notifications.client.development.notificationDevUI import FakeNotificationMaker
            maker = FakeNotificationMaker()
            counter = 1
            agentStartID = 3008416
            someAgentID = agentStartID + counter
            senderID = 98000001
            corpStartID = 1000089
            someCorp = corpStartID + counter
            maker.ScatterSingleNotification(counter, notificationID, senderID,
                                            someAgentID, someCorp)
Exemple #4
0
 def Flush(self):
     ScrollContainer.Flush(self)
     self.contentHeight = 0
class ControlCatalogWindow(Window):
    default_windowID = 'ControlCatalogWindow'
    default_topParentHeight = 0
    default_caption = 'UI Control Catalog'
    default_width = 900
    default_height = 800

    def ApplyAttributes(self, attributes):
        Window.ApplyAttributes(self, attributes)
        self.entriesByID = {}
        self.currClassData = None
        self.currSampleNum = 1
        self.numSamples = 0
        uthread.new(self.ConstuctLayout)

    def ConstuctLayout(self):
        self.leftCont = DragResizeCont(
            name='leftCont',
            parent=self.sr.main,
            align=uiconst.TOLEFT_PROP,
            settingsID='ControlCatalogWindowLeftCont')
        self.infoCont = ContainerAutoSize(name='infoCont',
                                          parent=self.sr.main,
                                          align=uiconst.TOTOP,
                                          padding=6)
        self.topCont = DragResizeCont(
            name='topCont',
            parent=self.sr.main,
            align=uiconst.TOTOP_PROP,
            settingsID='ControlCatalogWindowSampleCont',
            minSize=0.3,
            maxSize=0.9,
            defaultSize=0.5,
            clipChildren=True)
        tabCont = ContainerAutoSize(name='tabCont',
                                    parent=self.topCont.mainCont,
                                    align=uiconst.TOBOTTOM)
        self.mainButtonGroup = ButtonGroup(name='mainButtonGroup',
                                           parent=self.sr.main)
        self.editCont = Container(name='editCont', parent=self.sr.main)
        GradientSprite(bgParent=self.leftCont,
                       rotation=0,
                       rgbData=[(0, (1.0, 1.0, 1.3))],
                       alphaData=[(0.8, 0.0), (1.0, 0.05)])
        self.controlScroll = ScrollContainer(parent=self.leftCont)
        self.PopulateScroll()
        self.leftButtonGroup = ButtonGroup(name='leftButtonGroup',
                                           parent=self.leftCont,
                                           idx=0)
        self.ConstructLeftButtonGroup()
        self.classNameLabel = Label(parent=self.infoCont,
                                    align=uiconst.TOTOP,
                                    fontsize=15,
                                    bold=True)
        self.classDocLabel = EveLabelSmall(parent=self.infoCont,
                                           align=uiconst.TOTOP)
        GradientSprite(align=uiconst.TOTOP,
                       parent=self.infoCont,
                       rotation=-math.pi / 2,
                       height=16,
                       padding=(-4, -10, -4, 0),
                       rgbData=[(0, (1.0, 1.0, 1.3))],
                       alphaData=[(0.0, 0.0), (1.0, 0.03)])
        GradientSprite(align=uiconst.TOTOP,
                       parent=tabCont,
                       state=uiconst.UI_DISABLED,
                       rotation=math.pi / 2,
                       height=16,
                       padding=(-4, 0, -4, -10),
                       rgbData=[(0, (1.0, 1.0, 1.3))],
                       alphaData=[(0.0, 0.0), (1.0, 0.03)])
        self.sampleNameLabel = EveLabelSmall(parent=tabCont,
                                             align=uiconst.TOTOP,
                                             padBottom=5)
        self.tabs = ToggleButtonGroup(parent=Container(parent=tabCont,
                                                       align=uiconst.TOTOP,
                                                       height=16),
                                      align=uiconst.CENTER,
                                      height=16,
                                      callback=self.OnTabSelected)
        sampleParent = Container(name='sampleParent',
                                 parent=self.topCont.mainCont,
                                 clipChildren=True)
        self.sampleCont = ContainerAutoSize(name='sampleCont',
                                            parent=sampleParent,
                                            align=uiconst.CENTER)
        self.codeEdit = EditPlainText(parent=self.editCont,
                                      align=uiconst.TOALL,
                                      fontcolor=(1, 1, 1, 1),
                                      ignoreTags=True)
        self.codeEdit.OnKeyDown = self.OnCodeEditKeyDown
        self.ConstructMainButtonGroup()
        uthread.new(self._SpyOnSampleCodeReloadThread)

    def OnSampleFileReload(self, path):
        self.PopulateScroll()
        self.SetSelectedControl(self.currClassData)

    def _SpyOnSampleCodeReloadThread(self):
        try:
            from eve.common.modules.sake.platform.win32.win32api import Waitables
            from eve.common.modules.sake.autocompile import SpyFolder

            class ControlCatalogSpyFolder(SpyFolder):
                def __init__(self, callback, *args, **kw):
                    SpyFolder.__init__(self, *args, **kw)
                    self.callback = callback

                def process_folder(self, path):
                    try:
                        self.callback(path)
                    except Exception as e:
                        log.LogException(e)

            spy = ControlCatalogSpyFolder(
                self.OnSampleFileReload, Waitables(),
                (os.path.abspath(os.path.dirname(__file__)), ))
            while not self.destroyed:
                spy.waitables.Wait(0)
                blue.pyos.synchro.Sleep(50)

        except ImportError:
            pass

    def ConstructLeftButtonGroup(self):
        for label, func in (('Browse', self.BrowseControls), ):
            self.leftButtonGroup.AddButton(label, func)

    def ConstructMainButtonGroup(self):
        for label, func, hint in (('Reload', self.ReloadSamples,
                                   'Reload all sample code [ctrl+s]'),
                                  ('Edit module', self.OpenModuleCodeInEditor,
                                   'Open module containing class in editor'),
                                  ('Edit samples', self.OpenSampleCodeInEditor,
                                   'Open sample code in editor')):
            self.mainButtonGroup.AddButton(label, func, hint=hint)

    def OpenSampleCodeInEditor(self, *args):
        self.currClassData.OpenSampleCodeInEditor()

    def BrowseControls(self, *args):
        controlData.BrowseControls()

    def OpenModuleCodeInEditor(self, *args):
        self.currClassData.OpenModuleCodeInEditor()

    def PopulateScroll(self):
        self.controlScroll.Flush()
        for data in controlData.GetControlData():
            TreeViewEntry(parent=self.controlScroll,
                          data=data,
                          eventListener=self)
            if self.currClassData and self.currClassData.GetID() == data.GetID(
            ):
                self.currClassData = data

    def RegisterID(self, entry, entryID):
        if entryID in self.entriesByID:
            raise ValueError('Same entry registered again: %s' % entryID)
        self.entriesByID[entryID] = entry

    def UnregisterID(self, entryID):
        self.entriesByID.pop(entryID)

    def OnTreeViewClick(self, selected):
        if selected.data.HasChildren():
            selected.ToggleChildren()
        else:
            for entry in self.entriesByID.values():
                entry.UpdateSelectedState((selected.data.GetID(), ))

            self.currSampleNum = 1
            self.SetSelectedControl(selected.data)

    def SetSelectedControl(self, data):
        self.codeEdit.Clear()
        self.sampleCont.Flush()
        self.codeEdit.SetText(data.GetCode(), html=False)
        self.currClassData = data
        self.UpdateInfoCont()
        self.ReloadSamples()

    def UpdateInfoCont(self):
        cls = self.currClassData.GetBaseClass()
        if not hasattr(cls, '__module__'):
            raise RuntimeError(
                'Unable to identify sample class. IMPORTANT: Make sure the first line in the example imports the example class itself.'
            )
        self.classNameLabel.text = '<center>' + cls.__module__ + '.' + cls.__name__
        doc = cls.__doc__ or ''
        self.classDocLabel.text = '<center>' + doc.strip()
        if 'depricated' in doc.lower():
            self.classNameLabel.text = '<color=red>' + self.classNameLabel.text
            self.classDocLabel.text = '<color=red>' + self.classDocLabel.text

    def GetCodeText(self):
        return self.codeEdit.GetAllText()

    def ReloadSamples(self, *args):
        numSamples = controlData.GetNumSamples(self.GetCodeText())
        if numSamples != self.numSamples:
            self.numSamples = numSamples
            self.ReconstructTabs()
        self.tabs.SelectByID(self.currSampleNum)

    def ReconstructTabs(self):
        self.tabs.ClearButtons()
        for i in xrange(1, self.numSamples + 1):
            self.tabs.AddButton(i, 'Sample %s' % i)

        self.tabs.width = self.numSamples * 65

    def OnTabSelected(self, sampleNum):
        self.currSampleNum = sampleNum
        self.ReloadCurrentSample()

    def ReloadCurrentSample(self):
        self.sampleCont.Flush()
        uicore.animations.FadeTo(self.sampleCont, 0.0, 1.0, 0.1)
        if self.numSamples:
            exec(self.GetCodeText() + '\n', globals())
            exec 'Sample%s(parent=self.sampleCont)' % self.currSampleNum
            sampleName = None
            exec 'sampleName = Sample%s.__doc__' % self.currSampleNum
            if sampleName:
                self.sampleNameLabel.Show()
                self.sampleNameLabel.text = '<center>' + sampleName
            else:
                self.sampleNameLabel.Hide()
                self.sampleNameLabel.text = ''

    def OnCodeEditKeyDown(self, key, flag):
        if uicore.uilib.Key(uiconst.VK_CONTROL) and key == uiconst.VK_S:
            self.ReloadSamples()
        else:
            return EditPlainText.OnKeyDown(self.codeEdit, key, flag)
Exemple #6
0
class BehaviorDebugWindow(Window):
    default_windowID = 'BehaviorDebugWindow'
    default_topParentHeight = 0
    default_caption = 'Behavior Debug Tool'
    default_width = 600
    default_height = 500
    default_stackID = 'BehaviorDebugStack'

    def ApplyAttributes(self, attributes):
        Window.ApplyAttributes(self, attributes)
        self.taskMap = {}
        self.controller = None
        self.buttonCont = Container(parent=self.sr.main,
                                    name='buttonbar',
                                    align=uiconst.TOTOP,
                                    height=24,
                                    clipChildren=True)
        GradientSprite(bgParent=self.buttonCont,
                       rotation=-math.pi / 2,
                       rgbData=[(0, (1.0, 1.0, 1.3))],
                       alphaData=[(0.6, 0.0), (1.0, 0.05)])
        self.CreateToolbar()
        self.leftCont = DragResizeCont(
            name='leftCont',
            parent=self.sr.main,
            align=uiconst.TOLEFT_PROP,
            settingsID='BehaviorDebugWindowLeftContent',
            minSize=0.2,
            maxSize=0.8,
            defaultSize=0.5)
        GradientSprite(bgParent=self.leftCont,
                       rotation=0,
                       rgbData=[(0, (1.0, 1.0, 1.3))],
                       alphaData=[(0.8, 0.0), (1.0, 0.05)])
        self.mainScroll = ScrollContainer(name='behaviortree',
                                          parent=self.leftCont.mainCont,
                                          align=uiconst.TOALL,
                                          padding=(4, 4, 4, 4))
        self.blackboardScroll = ScrollContainer(name='blackboards',
                                                parent=self.sr.main,
                                                padding=(4, 4, 4, 4))
        GradientSprite(bgParent=self.blackboardScroll,
                       rotation=0,
                       rgbData=[(0, (1.0, 1.0, 1.3))],
                       alphaData=[(0.8, 0.0), (1.0, 0.05)])

    def Reset(self):
        self.taskMap = {}
        self.nodeCount = 0
        self.mainScroll.Flush()

    def CreateToolbarButton(self, func, label):
        Button(name=label,
               label=label,
               parent=self.buttonCont,
               align=uiconst.TOLEFT,
               padding=(8, 4, 0, 4),
               height=16,
               func=func)

    def CreateToolbar(self):
        for label, func in (('Reset Tree', self.OnClickReset),
                            ('Unblock Reset', self.OnClickUnblockReset),
                            ('Clear Item Blackboard', self.OnClickClearItemBB),
                            ('Clear Group Blackboard',
                             self.OnClickClearGroupBB)):
            self.CreateToolbarButton(func, label)

    def OnClickReset(self, _):
        sm.GetService('slash').SlashCmd('/behavior reset %d' %
                                        self.controller.itemID)

    def OnClickClearItemBB(self, _):
        sm.GetService('slash').SlashCmd('/behavior blackboard item %d clear' %
                                        self.controller.itemID)

    def OnClickClearGroupBB(self, _):
        sm.GetService('slash').SlashCmd('/behavior blackboard group %d clear' %
                                        self.controller.itemID)

    def OnClickUnblockReset(self, _):
        sm.GetService('slash').SlashCmd('/behavior unblock %d' %
                                        self.controller.itemID)

    def SetBlackboardValue(self, blackboardScope, messageName, messageValue):
        logger.warn('scope %s', blackboardScope)
        scopeText = 'item' if blackboardScope[0] == 'item' else 'group'
        format = [{
            'type': 'edit',
            'setvalue': str(messageValue),
            'label': 'Value',
            'key': 'value',
            'maxLength': 100,
            'setfocus': 1,
            'frame': 0
        }]
        returnValue = HybridWnd(format,
                                'Set Blackboard Value',
                                1,
                                None,
                                uiconst.OKCANCEL,
                                icon=uiconst.OKCANCEL,
                                minW=300,
                                minH=120,
                                unresizeAble=False)
        if returnValue is not None:
            messageValue = returnValue['value']
            sm.GetService('slash').SlashCmd(
                '/behavior blackboard %s %d set message=%s value=%s' %
                (scopeText, self.controller.itemID, messageName, ''.join(
                    messageValue.split())))

    def SetController(self, controller):
        self.controller = controller
        self.SetCaption('%s' % self.controller.itemID)

    def LoadBehaviorTree(self, treeData):
        self.Reset()
        for taskData in treeData:
            self.AddEntry(taskData)

    def UpdateStatuses(self, taskStatuses):
        for taskId, entry in self.taskMap.iteritems():
            entry.SetStatus(taskStatuses[taskId])

    def UpdateTasksSeen(self, tasksSeen):
        for taskId, entry in self.taskMap.iteritems():
            if taskId in tasksSeen:
                entry.EnableStepped()
            else:
                entry.DisableStepped()

    def LoadEvents(self, events):
        doReset = False
        for time, name, data in events:
            if name == 'Reset':
                doReset = True

        if doReset:
            self.ResetStatusToInvalid()

    def ResetStatusToInvalid(self):
        for entry in self.taskMap.itervalues():
            entry.SetStatus(TaskInvalidStatus)

    def LoadBlackboard(self, blackboards):
        self.blackboardScroll.Flush()
        for scopeType, scopeText in [
            ('item', 'Item Blackboard: <color=lightgreen>%d</color>'),
            ('entity_group',
             'Entity Group Blackboard: <color=lightgreen>%d</color>')
        ]:
            for scope, channels in blackboards.iteritems():
                if scopeType == scope[0]:
                    self.CreateBlackboard(scopeText % scope[1], channels,
                                          scope)

    def CloseByUser(self, *args):
        logger.debug('closing debugger')
        self.controller.Disconnect()
        self.Close()

    def AddEntry(self, taskDict):
        task = Bundle(taskDict)
        task.attributes = Bundle(taskDict['attributes'])
        entry = BehaviorTreeEntry(parent=self.mainScroll,
                                  indent=task.depth,
                                  text='<color=lightgreen>%s</color> %s' %
                                  (task.attributes.name, task.type)
                                  if 'name' in task.attributes else task.type,
                                  color=STATUS_MAP[task.status].color,
                                  taskID=task.id,
                                  task=task,
                                  window=self)
        entry.SetBgColor(len(self.mainScroll.mainCont.children) % 2 == 0)
        entry.DisableStepped()
        self.taskMap[entry.taskID] = entry

    def CreateBlackboard(self, scopeText, channels, scope):
        grid = LayoutGrid(columns=3,
                          parent=self.blackboardScroll,
                          align=uiconst.TOTOP,
                          cellPadding=3,
                          cellSpacing=4)
        row = grid.AddRow(bgColor=(1, 1, 1, 0.1))
        headerLabel = eveLabel.EveLabelMediumBold(text=scopeText,
                                                  align=uiconst.CENTERLEFT,
                                                  state=uiconst.UI_NORMAL)
        headerLabel.GetMenu = lambda: [(
            'Copy Scope', blue.pyos.SetClipboardData(str(scope)))]
        row.AddCell(cellObject=headerLabel, colSpan=3, bpColor=(1, 1, 1, 0.05))
        for message, time, value in sorted(channels):
            row = grid.AddRow(bgColor=(1, 1, 1, 0.05))
            row.AddCell(cellObject=CopyLabelSmallBold(text=message,
                                                      align=uiconst.CENTERLEFT,
                                                      color=(0.4, 0.8, 1.0),
                                                      messageName=message,
                                                      messageValue=value,
                                                      wnd=self,
                                                      blackboardScope=scope))
            row.AddCell(cellObject=eveLabel.EveLabelSmallBold(
                text=FmtDate(time, 'nl') if time else str(time),
                align=uiconst.CENTERLEFT))
            row.AddCell(cellObject=CopyLabelSmallBold(text=str(value),
                                                      align=uiconst.CENTERLEFT,
                                                      color=(0.4, 0.8, 1.0),
                                                      messageName=message,
                                                      messageValue=value,
                                                      wnd=self,
                                                      blackboardScope=scope))

        Container(parent=self.blackboardScroll, height=16, align=uiconst.TOTOP)
class SkillExtractorWindow(Window):
    __guid__ = 'form.SkillExtractorWindow'
    __notifyevents__ = ['OnSessionChanged']
    default_width = 350
    default_height = 500
    default_minSize = (default_width, default_height)
    default_windowID = 'SkillExtractorWindow'
    default_captionLabelPath = 'UI/SkillTrading/SkillExtractorWindowCaption'
    default_iconNum = 'res:/UI/Texture/WindowIcons/augmentations.png'
    default_topParentHeight = 0
    default_clipChildren = True
    default_isCollapseable = False
    default_isPinable = False
    default_isStackable = False

    @classmethod
    def OpenOrReload(cls, *args, **kwargs):
        if cls.IsOpen():
            wnd = cls.GetIfOpen()
            if wnd.controller.isCompleted:
                wnd.Close()
                wnd = cls.Open(*args, **kwargs)
            else:
                wnd.controller.itemID = kwargs.get('itemID')
                wnd.Maximize()
        else:
            cls.Open(*args, **kwargs)

    def ApplyAttributes(self, attributes):
        super(SkillExtractorWindow, self).ApplyAttributes(attributes)
        self.controller = SkillExtractorController(attributes.itemID)
        self.filterSettings = SkillFilterSettings()
        self.Layout()
        self.Reload()
        self.filterSettings.onUpdate.connect(self.UpdateNoContentMessage)
        self.controller.onUpdate.connect(self.OnUpdate)
        self.controller.onSkillListUpdate.connect(self.Reload)
        sm.GetService('audio').SendUIEvent('st_activate_skill_extractor_play')

    def Layout(self):
        self.HideHeader()
        self.contentCont = Container(parent=self.GetMainArea(),
                                     align=uiconst.TOALL)
        topCont = Container(parent=self.contentCont,
                            align=uiconst.TOTOP,
                            height=90,
                            top=10)
        SkillExtractorBar(parent=topCont,
                          align=uiconst.CENTER,
                          state=uiconst.UI_NORMAL,
                          width=250,
                          controller=self.controller)
        middleCont = Container(parent=self.contentCont,
                               align=uiconst.TOALL,
                               padding=(8, 0, 8, 8))
        self.filterCont = Container(parent=middleCont,
                                    align=uiconst.TOTOP,
                                    height=26,
                                    opacity=0.0)
        SkillFilterMenu(
            parent=self.filterCont,
            align=uiconst.CENTERRIGHT,
            settings=self.filterSettings,
            hint=localization.GetByLabel('UI/SkillTrading/FilterSettings'))
        SkillFilterEdit(parent=self.filterCont,
                        align=uiconst.CENTERRIGHT,
                        left=20,
                        filterSettings=self.filterSettings)
        self.skillScroll = ScrollContainer(parent=middleCont,
                                           align=uiconst.TOALL,
                                           showUnderlay=True,
                                           opacity=0.0)
        self.loadingPanel = Container(parent=middleCont,
                                      align=uiconst.CENTER,
                                      state=uiconst.UI_DISABLED,
                                      width=250,
                                      height=150)
        LoadingWheel(parent=self.loadingPanel, align=uiconst.CENTERTOP)
        text = localization.GetByLabel('UI/SkillTrading/LoadingSkills')
        EveHeaderMedium(parent=self.loadingPanel,
                        align=uiconst.TOTOP,
                        top=50,
                        text='<center>%s</center>' % text)
        self.messagePanel = ContainerAutoSize(parent=self.GetMainArea(),
                                              align=uiconst.CENTER,
                                              alignMode=uiconst.TOTOP,
                                              width=300,
                                              opacity=0.0,
                                              idx=0)

    def Reload(self):
        uthread.new(self._Reload)

    def _Reload(self):
        self.AnimShowLoading()
        self.CheckShipAndShowMessage()
        self.entryDataList = self._GenerateSkillEntries(self.controller.skills)
        self._FlushAndPopulateSkillScroll(self.entryDataList)
        self.UpdateNoContentMessage()
        self.AnimHideLoading()

    def AnimShowLoading(self):
        self.skillScroll.Disable()
        self.filterCont.Disable()
        animations.FadeIn(self.loadingPanel)
        animations.FadeOut(self.skillScroll, duration=0.3)
        animations.FadeOut(self.filterCont, duration=0.3, sleep=True)

    def AnimHideLoading(self):
        self.skillScroll.Enable()
        self.filterCont.Enable()
        animations.FadeOut(self.loadingPanel)
        animations.FadeIn(self.skillScroll)
        animations.FadeIn(self.filterCont)

    def _GenerateSkillEntries(self, skills):
        skillDataByGroupID = itertoolsext.bucket(
            skills,
            keyprojection=lambda s: evetypes.GetGroupID(s.typeID),
            valueprojection=lambda s: SkillEntryData(s, self.controller, self.
                                                     filterSettings))
        groups = [
            SkillGroupData(gid, self.filterSettings, children=data)
            for gid, data in skillDataByGroupID.iteritems()
        ]
        return sorted(groups, key=lambda x: x.GetLabel().lower())

    def _FlushAndPopulateSkillScroll(self, groups):
        self.skillScroll.Flush()
        for groupData in groups:
            SkillGroupEntry(parent=self.skillScroll,
                            data=groupData,
                            defaultExpanded=False)
            blue.pyos.BeNice()

    def OnUpdate(self):
        self.UpdateNoContentMessage()
        self.CheckCompletedAndShowMessage()

    def UpdateNoContentMessage(self):
        self.skillScroll.HideNoContentHint()
        if all((data.isFiltered for data in self.entryDataList)):
            emptyHint = localization.GetByLabel('UI/SkillTrading/NoSkillsHint')
            self.skillScroll.ShowNoContentHint(emptyHint)

    def CheckCompletedAndShowMessage(self):
        if self.controller.isCompleted:
            self.PrepareCompleteMessage()
            self.AnimShowMessage()

    def PrepareCompleteMessage(self):
        self.messagePanel.Flush()
        text = localization.GetByLabel(
            'UI/SkillTrading/CompleteMessageCaption')
        EveCaptionMedium(parent=self.messagePanel,
                         align=uiconst.TOTOP,
                         text='<center>%s</center>' % text)
        text = localization.GetByLabel('UI/SkillTrading/CompleteMessageMain',
                                       amount=self.controller.SKILL_POINT_GOAL,
                                       injector=invconst.typeSkillInjector)
        EveLabelMedium(parent=self.messagePanel,
                       align=uiconst.TOTOP,
                       top=4,
                       text='<center>%s</center>' % text)
        iconCont = Container(parent=self.messagePanel,
                             align=uiconst.TOTOP,
                             top=8,
                             height=64)
        Icon(parent=iconCont,
             align=uiconst.CENTER,
             left=-40,
             typeID=invconst.typeSkillInjector,
             size=64,
             state=uiconst.UI_DISABLED)
        Sprite(
            parent=iconCont,
            align=uiconst.CENTER,
            state=uiconst.UI_DISABLED,
            texturePath='res:/UI/Texture/classes/skilltrading/arrow_right.png',
            width=32,
            height=32,
            opacity=0.6)
        Sprite(parent=iconCont,
               align=uiconst.CENTER,
               state=uiconst.UI_DISABLED,
               left=40,
               texturePath='res:/UI/Texture/WindowIcons/itemHangar.png',
               width=64,
               height=64)
        text = localization.GetByLabel('UI/SkillTrading/CompleteMessageTail',
                                       injector=invconst.typeSkillInjector)
        EveLabelMedium(parent=self.messagePanel,
                       align=uiconst.TOTOP,
                       top=8,
                       text='<center>%s</center>' % text)
        buttonCont = Container(parent=self.messagePanel,
                               align=uiconst.TOTOP,
                               top=16,
                               height=40)
        Button(parent=buttonCont,
               align=uiconst.CENTER,
               label=localization.GetByLabel('UI/Common/Done'),
               func=self.Close)

    def CheckShipAndShowMessage(self):
        if self.controller.isCompleted:
            return
        ship = sm.GetService('godma').GetItem(session.shipid)
        if ship.groupID != const.groupCapsule:
            self.PrepareShipMessage()
            self.AnimShowMessage()
        else:
            self.AnimHideMessage()

    def PrepareShipMessage(self):
        self.messagePanel.Flush()
        text = 'Must Be In Capsule'
        EveCaptionMedium(parent=self.messagePanel,
                         align=uiconst.TOTOP,
                         text='<center>%s</center>' % text)
        text = 'A direct connection to your capsule is required in order to extract skill points. Please leave your active ship to continue.'
        EveLabelMedium(parent=self.messagePanel,
                       align=uiconst.TOTOP,
                       top=4,
                       text='<center>%s</center>' % text)
        buttonCont = Container(parent=self.messagePanel,
                               align=uiconst.TOTOP,
                               top=16,
                               height=40)
        Button(parent=buttonCont,
               align=uiconst.CENTER,
               label='Leave Current Ship',
               func=self.LeaveShip,
               args=())

    def AnimShowMessage(self):
        self.contentCont.Disable()
        animations.FadeTo(self.contentCont,
                          startVal=self.contentCont.opacity,
                          endVal=0.1)
        animations.FadeIn(self.messagePanel)

    def AnimHideMessage(self):
        self.contentCont.Enable()
        animations.FadeTo(self.contentCont,
                          startVal=self.contentCont.opacity,
                          endVal=1.0)
        animations.FadeOut(self.messagePanel)

    def Close(self, *args, **kwargs):
        super(SkillExtractorWindow, self).Close(*args, **kwargs)
        self.controller.Close()

    def OnSessionChanged(self, isRemote, sess, change):
        if 'stationid2' in change:
            self.Close()
        elif 'shipid' in change:
            self.CheckShipAndShowMessage()

    def LeaveShip(self):
        ship = sm.GetService('godma').GetItem(session.shipid)
        sm.StartService('station').TryLeaveShip(ship)
        self.AnimHideMessage()