class BattleStrongholdsQueue(BattleStrongholdsQueueMeta, LobbySubView, ClanEmblemsHelper, IGlobalListener):
    __sound_env__ = BattleQueueEnv
    itemsCache = dependency.descriptor(IItemsCache)
    ANIMATION_DEFAULT_DURATION = 5

    def __init__(self, _=None):
        super(BattleStrongholdsQueue, self).__init__()
        self.__timerCallback = None
        self.__startAnimationTime = None
        self.__animationDuration = self.ANIMATION_DEFAULT_DURATION
        self.__groups = []
        self.__battleQueueVO = {}
        self.__imagesFetchCoordinator = ImagesFetchCoordinator()
        self._blur = CachedBlur()
        return

    @prbEntityProperty
    def prbEntity(self):
        return None

    def exitClick(self):
        self.prbEntity.exitFromQueue()

    def onClanEmblem32x32Received(self, clanDbID, emblem):
        clanEmblem = getTextureLinkByID(self.getMemoryTexturePath(emblem)) if emblem else None
        self.__battleQueueVO['myClanIcon'] = clanEmblem or ''
        self.as_setTypeInfoS(self.__battleQueueVO)
        self.prbEntity.getMatchmakingInfo(callback=self.__onMatchmakingInfo)
        return

    def onEscape(self):
        dialogsContainer = self.app.containerManager.getContainer(WindowLayer.TOP_WINDOW)
        if not dialogsContainer.getView(criteria={POP_UP_CRITERIA.VIEW_ALIAS: VIEW_ALIAS.LOBBY_MENU}):
            self.fireEvent(events.LoadViewEvent(SFViewLoadParams(VIEW_ALIAS.LOBBY_MENU)), scope=EVENT_BUS_SCOPE.LOBBY)

    def onStartBattle(self):
        self.__stopUpdateScreen()

    def onStrongholdMaintenance(self, showWindow):
        self.__showBattleRoom()

    def onUnitFlagsChanged(self, flags, timeLeft):
        if not self.prbEntity.canShowStrongholdsBattleQueue():
            self.__showBattleRoom()

    def onUpdateHeader(self, header, isFirstBattle, isUnitFreezed):
        self.__battleQueueVO['title'] = self.__getTitle()
        self.as_setTypeInfoS(self.__battleQueueVO)
        self.__requestClanIcon()

    def _populate(self):
        super(BattleStrongholdsQueue, self)._populate()
        self._blur.enable()
        self.addListener(events.GameEvent.SHOW_EXTERNAL_COMPONENTS, self._onShowExternals, scope=EVENT_BUS_SCOPE.GLOBAL)
        self.addListener(events.GameEvent.HIDE_EXTERNAL_COMPONENTS, self._onHideExternals, scope=EVENT_BUS_SCOPE.GLOBAL)
        self.startPrbListening()
        self.addListener(events.StrongholdEvent.STRONGHOLD_ON_TIMER, self.__onMatchmakingTimerChanged, scope=EVENT_BUS_SCOPE.STRONGHOLD)
        g_playerEvents.onArenaCreated += self.onStartBattle
        if self.prbEntity is not None:
            permissions = self.prbEntity.getPermissions()
            self.as_showExitS(permissions.canStopBattleQueue())
        self.as_showWaitingS('')
        self.__battleQueueVO = self.__getBattleQueueVO()
        self.__requestClanIcon()
        MusicControllerWWISE.play()
        return

    def _dispose(self):
        self.__stopUpdateScreen()
        g_playerEvents.onArenaCreated -= self.onStartBattle
        self.stopPrbListening()
        self.removeListener(events.StrongholdEvent.STRONGHOLD_ON_TIMER, self.__onMatchmakingTimerChanged, scope=EVENT_BUS_SCOPE.STRONGHOLD)
        self.__imagesFetchCoordinator.fini()
        self.removeListener(events.GameEvent.SHOW_EXTERNAL_COMPONENTS, self._onShowExternals, scope=EVENT_BUS_SCOPE.GLOBAL)
        self.removeListener(events.GameEvent.HIDE_EXTERNAL_COMPONENTS, self._onHideExternals, scope=EVENT_BUS_SCOPE.GLOBAL)
        self._blur.fini()
        super(BattleStrongholdsQueue, self)._dispose()

    def __getBattleQueueVO(self):
        return {'iconLabel': constants.ARENA_GUI_TYPE_LABEL.LABELS[constants.ARENA_GUI_TYPE.SORTIE_2],
         'title': self.__getTitle(),
         'leagueIcon': '',
         'myClanIcon': '',
         'myClanName': '',
         'myClanElo': text_styles.highTitleDisabled('--'),
         'myClanRating': ''}

    def __requestClanIcon(self):
        myClanIcon = self.__battleQueueVO['myClanIcon']
        if not myClanIcon:
            entity = self.prbEntity
            if entity is not None and entity.isStrongholdSettingsValid():
                clan = entity.getStrongholdSettings().getHeader().getClan()
                self.requestClanEmblem32x32(clan.getId())
                self.__battleQueueVO['myClanName'] = getClanTag(clan.getTag(), clan.getColor())
        return

    def __getTitle(self):
        entity = self.prbEntity
        if entity is not None and entity.isStrongholdSettingsValid():
            header = entity.getStrongholdSettings().getHeader()
            if header.isSortie():
                level = int2roman(header.getMaxLevel())
                title = makeString(FORTIFICATIONS.STRONGHOLDINFO_SORTIE) % {'level': level}
            else:
                direction = vo_converters.getDirection(header.getDirection())
                title = makeString(FORTIFICATIONS.STRONGHOLDINFO_STRONGHOLD) % {'direction': direction}
        else:
            title = ''
        return title

    @async
    @process
    def __parseClanData(self, clanData, serviceLeaguesEnabled, callback):
        updateData = {}
        myClanName = getClanTag(clanData.get('tag'), clanData.get('color') or '')
        if myClanName:
            updateData['myClanName'] = myClanName
        myClanIcon = yield self.__imagesFetchCoordinator.fetchImageByUrl(clanData.get('emblem'), oneUse=False)
        if myClanIcon:
            updateData['myClanIcon'] = myClanIcon
        leagueIcon = yield self.__imagesFetchCoordinator.fetchImageByUrl(clanData.get('back_emblem'), oneUse=False)
        if leagueIcon:
            updateData['leagueIcon'] = leagueIcon
        if serviceLeaguesEnabled:
            myClanRating = clanData.get('position')
            if isinstance(myClanRating, int):
                textStyle = text_styles.highTitle
                updateData['myClanRating'] = textStyle(backport.getNiceNumberFormat(myClanRating))
            else:
                textStyle = text_styles.highTitleDisabled
                updateData['myClanRating'] = textStyle('--')
        else:
            textStyle = text_styles.highTitleDisabled
        myClanElo = clanData.get('elo')
        if isinstance(myClanElo, int):
            updateData['myClanElo'] = textStyle(backport.getNiceNumberFormat(myClanElo))
        callback(updateData)

    @async
    @process
    def __parseGroupsData(self, groupsData, callback):
        groups = []
        for group in groupsData:
            clans = []
            for clan in group.get('clans', []):
                clanVO = {'title': makeString(FORTIFICATIONS.BATTLEQUEUE_CLANPOSITION, position='--'),
                 'clanName': getClanTag(clan.get('tag'), clan.get('color') or ''),
                 'clanElo': '--',
                 'tooltip': ''}
                leagueIconUrl = clan.get('back_emblem')
                if leagueIconUrl:
                    clanVO['leagueIcon'] = yield self.__imagesFetchCoordinator.fetchImageByUrl(clan.get('back_emblem'), oneUse=False)
                    if not clanVO['leagueIcon']:
                        callback([])
                        return
                clanVO['clanIcon'] = yield self.__imagesFetchCoordinator.fetchImageByUrl(clan.get('emblem'), oneUse=False)
                if not clanVO['clanIcon']:
                    callback([])
                    return
                elo = clan.get('elo')
                if isinstance(elo, int):
                    clanVO['clanElo'] = backport.getNiceNumberFormat(elo)
                position = clan.get('position')
                if isinstance(position, int):
                    position = backport.getNiceNumberFormat(position)
                    clanVO['title'] = makeString(FORTIFICATIONS.BATTLEQUEUE_CLANPOSITION, position=position)
                clans.append(clanVO)

            groups.append({'title': group.get('title'),
             'leagues': clans})

        callback(groups)

    @process
    def __onMatchmakingInfo(self, response):
        if response.getCode() == ResponseCodes.NO_ERRORS and response.getData():
            data = response.getData()
            self.__animationDuration = data.get('animation_time', self.ANIMATION_DEFAULT_DURATION)
            groupsData = data.get('groups', [])
            updateData = yield self.__parseClanData(data.get('clan', {}), bool(groupsData))
            self.__battleQueueVO.update(updateData)
            self.as_setTypeInfoS(self.__battleQueueVO)
            self.__groups = yield self.__parseGroupsData(groupsData)

    def __stopUpdateScreen(self):
        if self.__timerCallback is not None:
            BigWorld.cancelCallback(self.__timerCallback)
            self.__timerCallback = None
        return

    def __onMatchmakingTimerChanged(self, event):
        data = event.ctx
        if data['dtime'] > 0 and data['textid'] in (TOOLTIPS.STRONGHOLDS_TIMER_SQUADINQUEUE, FORTIFICATIONS.ROSTERINTROWINDOW_INTROVIEW_FORTBATTLES_NEXTTIMEOFBATTLESOON):
            timerLabel = i18n.makeString(FORTIFICATIONS.BATTLEQUEUE_WAITBATTLE)
            currentTime = data['dtime']
        else:
            _, unit = self.prbEntity.getUnit()
            currentTime = 0
            if unit:
                timestamp = unit.getModalTimestamp()
                if timestamp:
                    currentTime = max(0, int(time_utils.getServerUTCTime() - timestamp))
            if data['isSortie'] or data['isFirstBattle']:
                timerLabel = i18n.makeString(FORTIFICATIONS.BATTLEQUEUE_SEARCHENEMY)
            else:
                timerLabel = i18n.makeString(FORTIFICATIONS.BATTLEQUEUE_WAITBATTLE)
        timeLabel = '%d:%02d' % divmod(currentTime, 60)
        self.as_setTimerS(timerLabel, timeLabel)
        n = len(self.__groups)
        if n != 0:
            self.as_hideWaitingS()
            if self.__startAnimationTime is None:
                self.__startAnimationTime = time_utils.getCurrentTimestamp()
            i, r = divmod(int(time_utils.getCurrentTimestamp() - self.__startAnimationTime), self.__animationDuration)
            if r == 0:
                self.as_setLeaguesS(self.__groups[i % n])
        return

    @staticmethod
    def __showBattleRoom():
        g_eventDispatcher.loadStrongholds()
        g_eventDispatcher.loadHangar()

    def _onHideExternals(self, _):
        self._blur.disable()

    def _onShowExternals(self, _):
        self._blur.enable()
class BattleQueue(BattleQueueMeta, LobbySubView):
    __sound_env__ = BattleQueueEnv

    def __init__(self, _=None):
        super(BattleQueue, self).__init__()
        self.__createTime = 0
        self.__timerCallback = None
        self.__provider = None
        self._blur = CachedBlur()
        return

    @prbEntityProperty
    def prbEntity(self):
        return None

    def onEscape(self):
        dialogsContainer = self.app.containerManager.getContainer(WindowLayer.TOP_WINDOW)
        if not dialogsContainer.getView(criteria={POP_UP_CRITERIA.VIEW_ALIAS: VIEW_ALIAS.LOBBY_MENU}):
            self.fireEvent(events.LoadViewEvent(SFViewLoadParams(VIEW_ALIAS.LOBBY_MENU)), scope=EVENT_BUS_SCOPE.LOBBY)

    def startClick(self):
        if self.__provider is not None:
            self.__provider.forceStart()
        return

    def exitClick(self):
        self.prbEntity.exitFromQueue()

    def onStartBattle(self):
        self.__stopUpdateScreen()

    def _populate(self):
        super(BattleQueue, self)._populate()
        self._blur.enable()
        self.addListener(events.GameEvent.SHOW_EXTERNAL_COMPONENTS, self._onShowExternals, scope=EVENT_BUS_SCOPE.GLOBAL)
        self.addListener(events.GameEvent.HIDE_EXTERNAL_COMPONENTS, self._onHideExternals, scope=EVENT_BUS_SCOPE.GLOBAL)
        g_playerEvents.onArenaCreated += self.onStartBattle
        self.__updateQueueInfo()
        self.__updateTimer()
        self.__updateClientState()
        MusicControllerWWISE.play()

    def _dispose(self):
        self.__stopUpdateScreen()
        g_playerEvents.onArenaCreated -= self.onStartBattle
        self.removeListener(events.GameEvent.SHOW_EXTERNAL_COMPONENTS, self._onShowExternals, scope=EVENT_BUS_SCOPE.GLOBAL)
        self.removeListener(events.GameEvent.HIDE_EXTERNAL_COMPONENTS, self._onHideExternals, scope=EVENT_BUS_SCOPE.GLOBAL)
        self._blur.fini()
        super(BattleQueue, self)._dispose()

    def __updateClientState(self):
        if self.prbEntity is None:
            return
        else:
            permissions = self.prbEntity.getPermissions()
            if not permissions.canExitFromQueue():
                self.as_showExitS(False)
            guiType = prb_getters.getArenaGUIType(queueType=self.__provider.getQueueType())
            title = MENU.loading_battletypes(guiType)
            description = MENU.loading_battletypes_desc(guiType)
            if guiType != constants.ARENA_GUI_TYPE.UNKNOWN and guiType in constants.ARENA_GUI_TYPE_LABEL.LABELS:
                iconlabel = constants.ARENA_GUI_TYPE_LABEL.LABELS[guiType]
            else:
                iconlabel = 'neutral'
            if self.__provider.needAdditionalInfo():
                additional = self.__provider.additionalInfo()
            else:
                additional = ''
            vehicle = g_currentVehicle.item
            textLabel = self.__provider.getTankInfoLabel()
            tankName = vehicle.shortUserName
            iconPath = self.__provider.getTankIcon(vehicle)
            layoutStr = self.__provider.getLayoutStr()
            self.as_setTypeInfoS({'iconLabel': iconlabel,
             'title': title,
             'description': description,
             'additional': additional,
             'tankLabel': text_styles.main(textLabel),
             'tankIcon': iconPath,
             'tankName': tankName,
             'layoutStr': layoutStr})
            return

    def __stopUpdateScreen(self):
        if self.__timerCallback is not None:
            BigWorld.cancelCallback(self.__timerCallback)
            self.__timerCallback = None
        if self.__provider is not None:
            self.__provider.stop()
            self.__provider = None
        return

    def __updateQueueInfo(self):
        if self.prbEntity is None:
            return
        else:
            qType = self.prbEntity.getQueueType()
            self.__provider = _providerFactory(self, qType)
            self.__provider.start()
            return

    def __updateTimer(self):
        self.__timerCallback = None
        self.__timerCallback = BigWorld.callback(1, self.__updateTimer)
        textLabel = text_styles.main(makeString(MENU.PREBATTLE_TIMERLABEL))
        timeLabel = '%d:%02d' % divmod(self.__createTime, 60)
        if self.__provider is not None and self.__provider.needAdditionalInfo():
            timeLabel = text_styles.concatStylesToSingleLine(timeLabel, '*')
        self.as_setTimerS(textLabel, timeLabel)
        self.__createTime += 1
        return

    def _getProvider(self):
        return self.__provider

    def _onHideExternals(self, _):
        self._blur.disable()

    def _onShowExternals(self, _):
        self._blur.enable()
예제 #3
0
class MapsTrainingView(MapsTrainingBaseView, IGlobalListener):
    __slots__ = ('__selectedMap', '__selectedScenario', '__ctxVehicleType',
                 '__ctxSide', '__ctxShowAnimation', '__tooltipData',
                 '__account', '__mapsConfig', '__isDataLoaded', '__blur',
                 '__blurRectId', '__packer', '__hangarCameraManager',
                 '__tickCallback', '__preferences', '__markerPosOffset',
                 '__finalizationInProgress')
    _TACTICAL_MAPS_CONFIG_PATH = 'scripts/maps_training_tactical_maps.xml'
    _SCENARIO_COUNT = len(VEHICLE_TYPE.ALL_TYPES) * len(VEHICLE_TYPE.ALL_TEAMS)
    _UPDATE_TICK_RATE = 0.1
    _MEDIUM_TANK_OFFSET = 1.26959
    _MAX_MAP_DIFFICULTY = 3
    _DEFAULT_MAP_DIFFICULTY = 3
    _DISABLED_MAP_GROUP_ID = 2
    _COMMON_SOUND_SPACE = MAPS_TRAINING_SOUND_SPACE
    lobbyContext = dependency.descriptor(ILobbyContext)
    itemsCache = dependency.descriptor(IItemsCache)
    mapsTrainingController = dependency.descriptor(IMapsTrainingController)
    hangarSpace = dependency.descriptor(IHangarSpace)
    c11nService = dependency.descriptor(ICustomizationService)

    def __init__(self, *args, **kwargs):
        super(MapsTrainingView, self).__init__(
            viewResource=R.views.lobby.maps_training.MapsTrainingPage(),
            viewModel=MapsTrainingViewModel())
        self.__selectedMap = None
        self.__selectedScenario = 0
        self.__ctxVehicleType = ''
        self.__ctxSide = 0
        self.__ctxShowAnimation = False
        self.__tooltipData = {}
        self.__account = BigWorld.player()
        self.__mapsConfig = TacticalMapsConfigReader.readXml(
            self._TACTICAL_MAPS_CONFIG_PATH)
        self.__isDataLoaded = False
        self.__blur = CachedBlur(blurAnimRepeatCount=1, blurRadius=0.1)
        self.__blurRectId = None
        self.__packer = getDefaultBonusPacker()
        self.__hangarCameraManager = None
        self.__tickCallback = None
        self.__preferences = self.mapsTrainingController.preferences
        self.__markerPosOffset = 0.0
        self.__finalizationInProgress = False
        self.__initFromCtx(kwargs.get('ctx', {}))
        return

    def showByCtx(self, ctx):
        self.__initFromCtx(ctx)
        if self.__isDataLoaded and self.__selectedMap:
            with self.viewModel.transaction() as model:
                self.__updateAllSelections(model)
        self.show()

    def createToolTipContent(self, event, contentID):
        if contentID == R.views.lobby.maps_training.ScenarioTooltip():
            geometryID = ArenaType.g_geometryNamesToIDs[self.__selectedMap]
            data = self.__account.mapsTraining.getGeometryData(geometryID)
            mapConfig = self.__mapsConfig.getMapConfig(self.__selectedMap)
            scenario = mapConfig.scenarios[int(event.getArgument('scenario'))]
            _, vehicleName = self.__getVehicleForScenario(scenario)
            return ScenarioTooltip(
                scenario.vehicleType, scenario.team, self.__selectedMap,
                list(self.__getTargets(scenario)), vehicleName,
                data[scenario.vehicleType][scenario.team]['completed'],
                self.__getRewards(geometryID, 'scenarioComplete'))
        return super(MapsTrainingView,
                     self).createToolTipContent(event=event,
                                                contentID=contentID)

    def createToolTip(self, event):
        tooltipId = event.getArgument('tooltipId', '')
        if not tooltipId:
            return super(MapsTrainingView, self).createToolTip(event)
        window = backport.BackportTooltipWindow(
            self.__tooltipData.get(tooltipId), self.getParentWindow())
        window.load()
        return window

    def _onLoading(self, *args, **kwargs):
        super(MapsTrainingView, self)._onLoading(*args, **kwargs)
        self.__finalizationInProgress = False
        if self.hangarSpace.spaceInited:
            self.__hangarCameraManager = self.hangarSpace.space.getCameraManager(
            )
        self.mapsTrainingController.requestInitialDataFromServer(
            self.__fillData)

    def _finalize(self):
        self.__finalizationInProgress = True
        self.__blur.fini()
        if self.__tickCallback is not None:
            BigWorld.cancelCallback(self.__tickCallback)
        if not self.__selectedMap:
            MapsTrainingSound.onSelectedMap(True)
        if self.prbEntity is not None and not self.prbEntity.isInQueue():
            g_currentPreviewVehicle.selectNoVehicle()
            g_currentPreviewVehicle.resetAppearance()
        super(MapsTrainingView, self)._finalize()
        return

    def __initFromCtx(self, ctx):
        selectedMap = ctx.get('map', '')
        self.__ctxVehicleType = ctx.get('vehicleType', '')
        self.__ctxSide = ctx.get('side', 0)
        self.__ctxShowAnimation = ctx.get('showAnimation', False)
        if self.__selectedMap != selectedMap and not selectedMap:
            MapsTrainingSound.onSelectedMap(False)
        self.__selectedMap = selectedMap

    def _addListeners(self):
        super(MapsTrainingView, self)._addListeners()
        self.viewModel.onMenu += self.__onMenu
        self.viewModel.onSelect += self.__onSelect
        self.viewModel.onScenarioSelect += self.__onScenarioSelect
        self.viewModel.onBack += self.__onBack
        self.viewModel.onBlurRectUpdated += self.__onBlurRectUpdated
        self.startGlobalListening()
        self.viewModel.onFilteringChange += self.__filterChangeHandler
        self.viewModel.onInfoClicked += self.__clickInfoHandler
        self.hangarSpace.onSpaceCreate += self.__onHangarSpaceCreate
        g_currentPreviewVehicle.onChangeStarted += self.__onPreviewVehicleChangeStarted
        g_currentPreviewVehicle.onChanged += self.__onPreviewVehicleChanged
        self.c11nService.onVisibilityChanged += self.__onC11nVisibilityChanged

    def _removeListeners(self):
        super(MapsTrainingView, self)._removeListeners()
        self.stopGlobalListening()
        self.viewModel.onMenu -= self.__onMenu
        self.viewModel.onSelect -= self.__onSelect
        self.viewModel.onScenarioSelect -= self.__onScenarioSelect
        self.viewModel.onBack -= self.__onBack
        self.viewModel.onBlurRectUpdated -= self.__onBlurRectUpdated
        self.viewModel.onFilteringChange -= self.__filterChangeHandler
        self.viewModel.onInfoClicked -= self.__clickInfoHandler
        self.hangarSpace.onSpaceCreate -= self.__onHangarSpaceCreate
        g_currentPreviewVehicle.onChangeStarted -= self.__onPreviewVehicleChangeStarted
        g_currentPreviewVehicle.onChanged -= self.__onPreviewVehicleChanged
        self.c11nService.onVisibilityChanged -= self.__onC11nVisibilityChanged

    def __onHangarSpaceCreate(self):
        self.__hangarCameraManager = self.hangarSpace.space.getCameraManager()

    def __onBack(self):
        self.__selectedMap = ''
        self.__selectedScenario = 0
        self.__blur.disable()
        with self.viewModel.transaction() as model:
            model.setIsMapSelected(False)
            model.setIncompleteFilter(self.__preferences.incompleteFilter)
            model.setTitleFilter(self.__preferences.titleFilter)
        MapsTrainingSound.onSelectedMap(False)
        self.mapsTrainingController.reset()

    @staticmethod
    def __onMenu():
        g_eventBus.handleEvent(events.LoadViewEvent(
            SFViewLoadParams(VIEW_ALIAS.LOBBY_MENU)),
                               scope=EVENT_BUS_SCOPE.LOBBY)

    def __onSelect(self, args):
        self.__selectedMap = str(args.get('id'))
        with self.viewModel.transaction() as model:
            model.setIsMapSelected(True)
            MapsTrainingSound.onSelectedMap(True)
            self.__updateAllSelections(model)

    def __onScenarioSelect(self, args):
        self.__selectedScenario = int(args.get('id'))
        with self.viewModel.transaction() as model:
            self.__updateSelectedScenario(model)

    def __updateSelectedMap(self, model):
        isMapSelected = bool(self.__selectedMap)
        model.setIsMapSelected(isMapSelected)
        if isMapSelected:
            mapConfig = self.__mapsConfig.getMapConfig(self.__selectedMap)
            geometryID = ArenaType.g_geometryNamesToIDs[self.__selectedMap]
            data = self.__account.mapsTraining.getGeometryData(geometryID)
            serverConfig = self.mapsTrainingController.getConfig()
            trainingMaps = serverConfig['maps']
            mapModel = model.selectedMapModel
            mapModel.setId(self.__selectedMap)
            mapModel.setImage(
                R.images.gui.maps.icons.map.dyn('c_{}'.format(
                    self.__selectedMap))())
            mapModel.setGroupId(trainingMaps[geometryID] - 1)
            scenarioModels = mapModel.getScenarios()
            scenarioModels.clear()
            for scenario in mapConfig.scenarios:
                scenarioModel = MapsTrainingScenarioModel()
                scenarioModel.setTeam(scenario.team)
                scenarioModel.setScenarioNum(
                    SCENARIO_INDEXES[scenario.team, scenario.vehicleType])
                scenarioModel.setVehicleType(scenario.vehicleType)
                scenarioModel.setIsComplete(
                    data[scenario.vehicleType][scenario.team]['completed'])
                scenarioBonuses = self.__getRewards(geometryID,
                                                    'scenarioComplete')
                bonusArray = scenarioModel.getRewards()
                self.__fillBonusArray(bonusArray, scenarioBonuses)
                scenarioModels.addViewModel(scenarioModel)

            isNotComplete = any(
                (not data[scenario.vehicleType][scenario.team]['completed']
                 for scenario in mapConfig.scenarios))
            mapBonuses = self.__getRewards(geometryID, 'mapComplete')
            finalBonusArray = mapModel.getRewards()
            finalBonusArray.clear()
            if isNotComplete:
                self.__fillBonusArray(finalBonusArray, mapBonuses)
        self.mapsTrainingController.setSelectedMap(self.__selectedMap)

    def __getRewards(self, geometryID, stage):
        config = self.mapsTrainingController.getConfig()
        finalBonuses = []
        mapRewardsConfig = config['rewards'][geometryID][stage]
        for rewardName, rewardData in mapRewardsConfig.iteritems():
            finalBonuses.extend(getNonQuestBonuses(rewardName, rewardData))

        return finalBonuses

    def __fillBonusArray(self, bonusArray, bonusesData):
        for bonus in bonusesData:
            bonusList = self.__packer.pack(bonus)
            bonusTooltipList = self.__packer.getToolTip(bonus)
            for bonusIndex, item in enumerate(bonusList):
                item.setIndex(bonusIndex)
                tooltipId = str(len(self.__tooltipData))
                item.setTooltipId(tooltipId)
                bonusArray.addViewModel(item)
                self.__tooltipData[tooltipId] = bonusTooltipList[bonusIndex]

    def __updateSelectedScenario(self, model):
        mapConfig = self.__mapsConfig.getMapConfig(self.__selectedMap)
        scenario = mapConfig.scenarios[self.__selectedScenario]
        if scenario.team != self.mapsTrainingController.getSelectedTeam():
            self.mapsTrainingController.setSelectedTeam(scenario.team)
        self.__markerPosOffset = self._MEDIUM_TANK_OFFSET if scenario.vehicleType == VEHICLE_TYPE.MEDIUM else 0.0
        vehicle, vehicleName = self.__getVehicleForScenario(scenario)
        if vehicle != self.mapsTrainingController.getSelectedVehicle(
        ) or g_currentPreviewVehicle.intCD != vehicle:
            self.mapsTrainingController.setSelectedVehicle(vehicle)
        selectedMapModel = model.selectedMapModel
        selectedMapModel.setSelectedScenario(self.__selectedScenario)
        selectedMapModel.setVehicleName(vehicleName)
        imageResource = R.images.gui.maps.icons.mapsTraining.minimap.scenarios.dyn(
            'c_{}_team{}_{}'.format(self.__selectedMap, scenario.team,
                                    scenario.vehicleType))
        selectedMapModel.setScenarioImage(
            imageResource() if imageResource.isValid() else R.invalid())
        points = selectedMapModel.getPoints()
        points.clear()
        teamData = mapConfig.teams[scenario.team]
        for teamId, teamForBaseData in mapConfig.teams.iteritems():
            teamPointModel = self.__createPointModel(
                'team{}'.format(teamId), [], teamForBaseData.isLeft,
                teamForBaseData.tooltipImage, teamForBaseData.position,
                MapsTrainingMinimapPoint.POINT_TYPE_BASE
                if teamId == scenario.team else
                MapsTrainingMinimapPoint.POINT_TYPE_ENEMY_BASE)
            points.addViewModel(teamPointModel)

        pointsData = teamData.scenarioPoints[scenario.vehicleType]
        for pointData in pointsData:
            pointModel = self.__createPointModel(
                pointData.id, pointData.textKeys, pointData.isLeft,
                pointData.tooltipImage, pointData.position,
                MapsTrainingMinimapPoint.POINT_TYPE_DEFAULT)
            points.addViewModel(pointModel)

        selectedMapModel.setIsShowCompleteAnimation(self.__ctxShowAnimation)
        self.__ctxShowAnimation = False

    @staticmethod
    def __createPointModel(pointId, textKeys, isLeft, tooltipImage, position,
                           pointType):
        pointModel = MapsTrainingMinimapPoint()
        pointModel.setId(pointId)
        textKeysModel = pointModel.getTextKeys()
        for textKey in textKeys:
            textKeysModel.addString(textKey)

        pointModel.setIsLeft(isLeft)
        if tooltipImage:
            pointModel.setIsShowTooltip(True)
            pointModel.setTooltipImage(
                R.images.gui.maps.icons.mapsTraining.minimap.tooltips.dyn(
                    tooltipImage)())
        pointModel.setPositionX(position.x)
        pointModel.setPositionY(position.y)
        pointModel.setType(pointType)
        return pointModel

    def __getVehicleForScenario(self, scenario):
        configuration = self.mapsTrainingController.getConfig()
        mapId = ArenaType.g_geometryNamesToIDs[self.__selectedMap]
        for vehCompDescr in configuration['vehicles'][mapId]:
            vehDescr = vehicles.VehicleDescr(
                typeID=vehicles.parseIntCompactDescr(vehCompDescr)[1:])
            vehicleData = self.itemsCache.items.getStockVehicle(vehCompDescr)
            if scenario.vehicleType == vehicleData.type:
                return (vehDescr.name, vehicleData.userName)

    def __getTargets(self, scenario):
        goals = self.__getScenarioConfig(scenario.vehicleType,
                                         scenario.team)['goals']
        for vehCls in VEHICLE_CLASSES_ORDER:
            for _ in xrange(goals[vehCls]):
                yield vehCls

    def __getScenarioConfig(self, vehType, team):
        mapId = ArenaType.g_geometryNamesToIDs[self.__selectedMap]
        config = self.mapsTrainingController.getConfig()
        return config.get('scenarios',
                          {}).get(mapId, {}).get(team, {}).get(vehType, {})

    def __filterChangeHandler(self, kwargs):
        incompleteFilter = kwargs.get('incompleteFilter', False)
        if incompleteFilter != self.__preferences.incompleteFilter:
            self.__preferences.incompleteFilter = incompleteFilter
            self.__preferences.save()
        titleFilter = kwargs.get('titleFilter', '')
        if titleFilter != self.__preferences.titleFilter:
            self.__preferences.titleFilter = titleFilter

    def __clickInfoHandler(self):
        from gui.shared.event_dispatcher import showBrowserOverlayView
        url = GUI_SETTINGS.infoPageMapsTraining
        showBrowserOverlayView(url, VIEW_ALIAS.BROWSER_OVERLAY)

    def __fillData(self):
        configuration = self.mapsTrainingController.getConfig()
        trainingMaps = configuration['maps']
        availableMaps = []
        mapIDs = self.lobbyContext.getServerSettings().getPreferredMapsConfig(
        )['mapIDs']
        for geometryID in mapIDs:
            if geometryID not in ArenaType.g_geometryCache:
                continue
            geometryType = ArenaType.g_geometryCache[geometryID]
            availableMaps.append(geometryType)

        with self.viewModel.transaction() as model:
            model.setIncompleteFilter(self.__preferences.incompleteFilter)
            model.setTitleFilter(self.__preferences.titleFilter)
            groupArray = model.getGroups()
            groupArray.clear()
            for groupId in range(self._MAX_MAP_DIFFICULTY):
                groupVM = MapsTrainingGroupModel()
                groupArray.addViewModel(groupVM)
                groupVM.setGroupId(groupId)
                groupVM.setGroupTitle(
                    backport.text(
                        R.strings.maps_training.mapSelection.groupTitle.num(
                            groupId)()))
                groupVM.setIsGroupDisabled(
                    groupId == self._DISABLED_MAP_GROUP_ID)

            mapsModel = model.getMaps()
            mapsModel.clear()
            for geometryType in availableMaps:
                slotModel = MapsTrainingMapModel()
                mapName = geometryType.geometryName
                mapId = geometryType.geometryID
                slotModel.setId(mapName)
                slotModel.setIsEnabled(mapId in trainingMaps)
                data = self.__account.mapsTraining.getGeometryData(mapId)
                slotModel.setIsCompleted(data['total'] >= self._SCENARIO_COUNT)
                slotModel.setGroupId(
                    trainingMaps.get(mapId, self._DEFAULT_MAP_DIFFICULTY) - 1)
                slotModel.setTitle(
                    R.strings.arenas.dyn('c_{}'.format(mapName)).name())
                slotModel.setImage(
                    R.images.gui.maps.icons.map.dyn('c_{}'.format(mapName))())
                mapsModel.addViewModel(slotModel)

            if self.__selectedMap:
                if g_currentPreviewVehicle.isPresent(
                ) and self.__tickCallback is None:
                    self.__onPreviewVehicleChanged()
                self.__updateAllSelections(model)
        self.__isDataLoaded = True
        return

    def __updateAllSelections(self, model):
        self.__selectScenario()
        self.__updateSelectedMap(model)
        self.__updateSelectedScenario(model)

    def __selectScenario(self):
        if not self.__selectedMap:
            return
        scenarios = self.__mapsConfig.getMapConfig(
            self.__selectedMap).scenarios
        if self.__ctxVehicleType and self.__ctxSide:
            self.__selectedScenario = next(
                (index for index, scenario in enumerate(scenarios)
                 if scenario.team == self.__ctxSide
                 and self.__ctxVehicleType == scenario.vehicleType), 0)
            self.__ctxVehicleType = ''
            self.__ctxSide = 0
        else:
            geometryID = ArenaType.g_geometryNamesToIDs[self.__selectedMap]
            data = self.__account.mapsTraining.getGeometryData(geometryID)
            self.__selectedScenario = next((
                index for index, scenario in enumerate(scenarios)
                if not data[scenario.vehicleType][scenario.team]['completed']),
                                           0)

    def __onBlurRectUpdated(self, args):
        viewX, viewY = self.getParentWindow().globalPosition
        blurRect = Math.Vector4(
            int(args.get('left')) + viewX,
            int(args.get('top')) + viewY,
            int(args.get('right')) + viewX,
            int(args.get('bottom')) + viewY)
        if not self.__blur.enabled:
            self.__blur.enable()
        if self.__blurRectId:
            self.__blur.changeRect(self.__blurRectId, blurRect)
        else:
            self.__blurRectId = self.__blur.addRect(blurRect)

    def __onPreviewVehicleChangeStarted(self):
        if self.__tickCallback is not None and not self.__finalizationInProgress:
            BigWorld.cancelCallback(self.__tickCallback)
            self.__tickCallback = None
        return

    def __onPreviewVehicleChanged(self):
        if self.__tickCallback is None and not self.__finalizationInProgress:
            self.__tickCallback = BigWorld.callback(self._UPDATE_TICK_RATE,
                                                    self.__tick)
        return

    def __onC11nVisibilityChanged(self, _):
        vehCompDescr = self.mapsTrainingController.getSelectedVehicle()
        if self.__selectedMap and vehCompDescr:
            g_currentPreviewVehicle.selectNoVehicle()
            g_currentPreviewVehicle.selectVehicle(vehCompDescr)

    def __updateMarkerPosition(self):
        if self.__selectedMap and self.viewModel.isBound(
        ) and self.hangarSpace.spaceInited:
            vehEntity = self.hangarSpace.space.getVehicleEntity()
            if not vehEntity or not vehEntity.model:
                return
            guiNode = vehEntity.model.node(TankNodeNames.GUI)
            mat = Math.Matrix(guiNode)
            markerWorldPos = mat.applyToOrigin()
            markerWorldPos.y += self.__markerPosOffset
            pos = self.worldToScreenPos(markerWorldPos)
            if pos:
                self.viewModel.vehicleMarker.setTop(pos.y)

    def worldToScreenPos(self, worldPos):
        screenWidth, screenHeight = self.getParentWindow().size
        viewProjMatrix = getViewProjectionMatrix()
        clipPos = viewProjMatrix.applyV4Point(
            Math.Vector4(worldPos.x, worldPos.y, worldPos.z, 1.0))
        if clipPos.w <= 0.0:
            return None
        else:
            ndcPos = Math.Vector2()
            ndcPos.x = clipPos.x / clipPos.w
            ndcPos.y = clipPos.y / clipPos.w
            if abs(ndcPos.x) > 1.0 or abs(ndcPos.y) > 1.0:
                return None
            halfScreenWidth = screenWidth / 2.0
            halfScreenHeight = screenHeight / 2.0
            screenPosX = halfScreenWidth * (ndcPos.x + 1.0)
            screenPosY = halfScreenHeight * (1.0 - ndcPos.y)
            return Math.Vector2(screenPosX, screenPosY)

    def __tick(self):
        self.__updateMarkerPosition()
        self.__tickCallback = BigWorld.callback(self._UPDATE_TICK_RATE,
                                                self.__tick)
class BCMessageWindow(BCMessageWindowMeta):
    _hangarSpace = dependency.descriptor(IHangarSpace)
    BC_NEW_MODULE_UNLOCK_SOUND_ID = 'bc_new_module_unlock'
    BC_RESOURCE_FLY_SOUND_ID = 'bc_resources_fly'
    BC_RESOURCE_GLOW_SOUND_ID = 'bc_resources_glow'
    BC_INFO_LINE_DISAPPEAR_SOUND_ID = 'bc_info_line_disappear'
    FLY_ANIMATIONS = ['gold', 'prem', 'credits', 'experience']
    RTPC_EXT_BC_ELEMENT_POSITION = 'RTPC_ext_bc_element_position'

    def __init__(self, content):
        super(BCMessageWindow, self).__init__(content)
        self.__blur = None
        return

    def needRTPCCorection(self, animation):
        return self.isFlyAnimation(animation)

    def isFlyAnimation(self, animation):
        return animation in self.FLY_ANIMATIONS

    def setParentWindow(self, window):
        super(BCMessageWindow, self).setParentWindow(window)
        self.__blur = CachedBlur(enabled=True,
                                 ownLayer=window.layer,
                                 blurAnimRepeatCount=1)

    def onMessageButtonClicked(self):
        self.onCustomButton(needStopEffect=True, needCloseWindow=False)

    def onTryClosing(self):
        return False

    @subtitleDecorator
    def onMessageAppear(self, type):
        pass

    def onMessageDisappear(self, type, animation):
        if type != BOOTCAMP_MESSAGE_ALIASES.RENDERER_INTRO and not self.isFlyAnimation(
                animation):
            SoundGroups.g_instance.playSound2D(
                self.BC_INFO_LINE_DISAPPEAR_SOUND_ID)

    def onMessageRemoved(self):
        callback = self._content.get('callback')
        if callback is not None:
            callback(False)
        self.submit()
        return

    def onMessageExecuted(self, renderedType):
        callback = self._content.get('callback')
        if callback is not None:
            callback(True)
        return

    def hideBlur(self):
        self.__blur.disable()

    def onMessageAnimationStopped(self, animation):
        if self.needRTPCCorection(animation):
            self.soundManager.setRTPC(self.RTPC_EXT_BC_ELEMENT_POSITION,
                                      SOUNDS.MIN_MISSIONS_ZOOM)

    def onMessageAnimationStarted(self, animation):
        if self.needRTPCCorection(animation):
            self.soundManager.playSound(self.BC_RESOURCE_FLY_SOUND_ID)
            self.soundManager.playSound(self.BC_RESOURCE_GLOW_SOUND_ID)
            self.soundManager.setRTPC(self.RTPC_EXT_BC_ELEMENT_POSITION,
                                      SOUNDS.MAX_MISSIONS_ZOOM)
        else:
            self.soundManager.playSound(self.BC_NEW_MODULE_UNLOCK_SOUND_ID)

    def _populate(self):
        super(BCMessageWindow, self)._populate()
        self.as_setMessageDataS(self._content['messages'])
        self.as_blurOtherWindowsS(WindowLayer.TOP_WINDOW)
        g_bootcampEvents.onRequestBootcampMessageWindowClose += self.onMessageRemoved
        if self._hangarSpace.spaceInited:
            self.__setCameraDisabled(True)
        else:
            self._hangarSpace.onSpaceCreate += self.__onSpaceCreated

    def _dispose(self):
        super(BCMessageWindow, self)._dispose()
        if self.__blur is not None:
            self.__blur.fini()
        g_bootcampEvents.onRequestBootcampMessageWindowClose -= self.onMessageRemoved
        self._hangarSpace.onSpaceCreate -= self.__onSpaceCreated
        self.__setCameraDisabled(False)
        return

    def _stop(self, needCloseWindow=True):
        self._content.clear()
        for _, effect in self._gui.effects.iterEffects():
            if effect.isStillRunning(self.uniqueName):
                effect.stop()

        if needCloseWindow:
            self.destroy()

    def __onSpaceCreated(self):
        BigWorld.callback(0.1, partial(self.__setCameraDisabled, True))

    def __setCameraDisabled(self, disabled):
        self.fireEvent(
            CameraRelatedEvents(
                CameraRelatedEvents.FORCE_DISABLE_IDLE_PARALAX_MOVEMENT,
                ctx={
                    'isDisable': disabled,
                    'setIdle': True,
                    'setParallax': True
                }), EVENT_BUS_SCOPE.LOBBY)
        self.fireEvent(
            CameraRelatedEvents(
                CameraRelatedEvents.FORCE_DISABLE_CAMERA_MOVEMENT,
                ctx={'disable': disabled}), EVENT_BUS_SCOPE.LOBBY)
class CustomizationStyleInfo(CustomizationStyleInfoMeta, CallbackDelayer):
    service = dependency.descriptor(ICustomizationService)
    itemsCache = dependency.descriptor(IItemsCache)

    @property
    def visible(self):
        return self.__visible

    def __init__(self):
        CustomizationStyleInfoMeta.__init__(self)
        CallbackDelayer.__init__(self)
        self.__ctx = None
        self.__blur = None
        self.__blurRectId = None
        self.__visible = False
        self.__prevStyle = None
        self.__selectedStyle = None
        self.__paramsDOF = None
        self.__blurParams = None
        return

    def _populate(self):
        self.__ctx = self.service.getCtx()
        self.__blur = CachedBlur()
        g_clientUpdateManager.addMoneyCallback(self.updateButton)
        g_currentVehicle.onChangeStarted += self.__onVehicleChangeStarted
        self.__ctx.events.onUpdateStyleInfoDOF += self.__onUpdateStyleInfoDOF
        self.service.onCustomizationHelperRecreated += self.__onCustomizationHelperRecreated
        self.__setBackgroundAlpha()

    def _dispose(self):
        g_clientUpdateManager.removeObjectCallbacks(self)
        g_currentVehicle.onChangeStarted -= self.__onVehicleChangeStarted
        self.__ctx.events.onUpdateStyleInfoDOF -= self.__onUpdateStyleInfoDOF
        self.service.onCustomizationHelperRecreated -= self.__onCustomizationHelperRecreated
        self.__ctx = None
        if self.__blur is not None:
            self.__blur.fini()
        return

    def show(self, style=None):
        self.__prevStyle = self.__ctx.mode.modifiedStyle
        self.__selectedStyle = style or self.__ctx.mode.modifiedStyle
        if self.__selectedStyle is None:
            return
        else:
            if self.__prevStyle is None or self.__selectedStyle != self.__prevStyle:
                self.__installStyle(self.__selectedStyle)
            styleInfoVO = self.__makeVO(self.__selectedStyle)
            self.as_setDataS(styleInfoVO)
            self.updateButton()
            self.as_showS()
            self.__visible = True
            self.delayCallback(STYLE_INFO_BLUR_DELAY, self.__enableBlur)
            self.__ctx.mode.unselectSlot()
            return

    def updateButton(self, *_):
        if self.__selectedStyle:
            buttonVO = self.__makeButtonVO(self.__selectedStyle)
            self.as_buttonUpdateS(buttonVO)

    def onClose(self):
        self.__ctx.events.onHideStyleInfo()
        self.disableBlur()
        self.__visible = False
        self.__selectedStyle = None
        if self.__prevStyle is None:
            slotId = C11nId(areaId=Area.MISC,
                            slotType=GUI_ITEM_TYPE.STYLE,
                            regionIdx=0)
            self.__ctx.mode.removeItem(slotId)
        elif self.__prevStyle != self.__ctx.mode.modifiedStyle:
            self.__installStyle(self.__prevStyle)
        self.__prevStyle = None
        return

    def onApply(self):
        self.__ctx.events.onHideStyleInfo(toBuyWindow=True)
        if self.__blurRectId:
            self.__blur.removeRect(self.__blurRectId)
            self.__blurRectId = None
        self.service.setDOFenabled(False)
        self.__visible = False
        return

    def hide(self):
        self.stopCallback(self.__enableBlur)
        self.stopCallback(self.service.setDOFenabled)
        self.disableBlur()
        self.as_hideS()
        self.__paramsDOF = None
        return

    def disableBlur(self):
        if self.__blurRectId:
            self.__blur.removeRect(self.__blurRectId)
            self.__blurRectId = None
        self.__blur.disable()
        self.__paramsDOF = None
        self.service.setDOFenabled(False)
        return

    def __makeVO(self, style):
        styleParams = self.__makeParamsVO(style)
        styleName = style.userName
        styleInfoText = style.longDescriptionSpecial
        styleInfo = text_styles.mainBig(
            styleInfoText % {
                'insertion_open': _INSERTION_OPEN_TAG,
                'insertion_close': _INSERTION_CLOSE_TAG
            })
        styleInfoBig = text_styles.mainBig(
            styleInfoText % {
                'insertion_open': _INSERTION_OPEN_TAG_BIG,
                'insertion_close': _INSERTION_CLOSE_TAG
            })
        suitableText = getSuitableText(style, g_currentVehicle.item)
        if suitableText:
            suitableBlock = text_styles.mainBig(
                backport.text(
                    R.strings.vehicle_customization.styleInfo.suitable()))
            suitableBlock += suitableText
        else:
            suitableBlock = text_styles.mainBig(
                backport.text(
                    R.strings.vehicle_customization.styleInfo.suitableAll()))
        return StyleInfoVO(styleName=styleName,
                           styleInfo=styleInfo,
                           styleInfoBig=styleInfoBig,
                           suitableBlock=suitableBlock,
                           styleParams=styleParams)._asdict()

    def __makeButtonVO(self, style):
        buttonVO = None
        if self.__ctx.isOutfitsModified():
            stylePrice = style.getBuyPrice().price
            moneyState = getPurchaseMoneyState(stylePrice)
            purchaseItem = first(self.__ctx.mode.getPurchaseItems())
            if purchaseItem is not None and purchaseItem.isFromInventory:
                label = backport.text(
                    R.strings.vehicle_customization.commit.apply())
                enabled = True
            else:
                label = backport.text(
                    R.strings.vehicle_customization.commit.buy())
                enabled = isTransactionValid(moneyState, stylePrice)
            buttonVO = ButtonVO(enabled=enabled,
                                label=label,
                                disabledTooltip=backport.text(
                                    R.strings.vehicle_customization.
                                    customization.buyDisabled.body()),
                                visible=True)._asdict()
        return buttonVO

    def __makeParamsVO(self, style):
        params = []
        vehicleCD = g_currentVehicle.item.descriptor.makeCompactDescr()
        for season in SeasonType.COMMON_SEASONS:
            outfit = style.getOutfit(season, vehicleCD=vehicleCD)
            if outfit:
                container = outfit.hull
                intCD = container.slotFor(GUI_ITEM_TYPE.CAMOUFLAGE).getItemCD()
                if not intCD:
                    continue
                camo = self.service.getItemByCD(intCD)
                if camo and camo.bonus:
                    bonus = camo.bonus.getFormattedValue(g_currentVehicle.item)
                    bonusIcon = backport.image(
                        R.images.gui.maps.icons.customization.style_info.bonus(
                        ))
                    formattedBonus = makeHtmlString(
                        'html_templates:lobby/customization',
                        'style_info_bonus',
                        ctx={'bonus': bonus})
                    bonusParam = ParamVO(bonusIcon, formattedBonus)
                    params.append(bonusParam._asdict())
                    break

        displayType = style.customizationDisplayType()
        if displayType == 0:
            historicIcon = backport.image(
                R.images.gui.maps.icons.customization.style_info.historical())
            historicString = backport.text(
                R.strings.vehicle_customization.styleInfo.historical())
        elif displayType == 1:
            historicIcon = backport.image(
                R.images.gui.maps.icons.customization.style_info.nonhistorical(
                ))
            historicString = backport.text(
                R.strings.vehicle_customization.styleInfo.nonhistorical())
        else:
            historicIcon = backport.image(
                R.images.gui.maps.icons.customization.style_info.fantastical())
            historicString = backport.text(
                R.strings.vehicle_customization.styleInfo.fantastical())
        historicParam = ParamVO(historicIcon, text_styles.main(historicString))
        params.append(historicParam._asdict())
        if style.isRentable:
            rentIcon = backport.image(
                R.images.gui.maps.icons.customization.style_info.rentable())
            rentString = backport.text(
                R.strings.vehicle_customization.styleInfo.rentable())
            rentParam = ParamVO(rentIcon, text_styles.main(rentString))
            params.append(rentParam._asdict())
        elif style.specialEventTag is not None:
            eventIcon = style.specialEventIcon
            eventName = style.specialEventName
            eventParam = ParamVO(eventIcon, text_styles.main(eventName))
            params.append(eventParam._asdict())
        return params

    def __enableBlur(self):
        self.__blur.enable()

    def __installStyle(self, style):
        slotId = C11nId(areaId=Area.MISC,
                        slotType=GUI_ITEM_TYPE.STYLE,
                        regionIdx=0)
        self.__ctx.mode.installItem(style.intCD, slotId)

    def __onUpdateStyleInfoDOF(self, paramsDOF):
        self.__paramsDOF = paramsDOF
        if self.__paramsDOF is not None and self.visible:
            self.service.setDOFparams(self.__paramsDOF)
            self.delayCallback(STYLE_INFO_BLUR_DELAY,
                               self.service.setDOFenabled,
                               enable=True)
        return

    def __onCustomizationHelperRecreated(self):
        if self.visible and self.__paramsDOF is not None:
            self.service.setDOFparams(self.__paramsDOF)
            self.service.setDOFenabled(True)
            self.service.suspendHighlighter()
        else:
            self.service.setDOFenabled(False)
        return

    def __onVehicleChangeStarted(self):
        self.__paramsDOF = None
        if self.visible:
            self.service.setDOFenabled(False)
        return

    def onWidthUpdated(self, x, width, height):
        if not self.visible:
            return
        blurRect = (round(x), 0, round(x + width), round(height))
        if self.__blurRectId:
            self.__blur.changeRect(self.__blurRectId, blurRect)
        else:
            self.__blurRectId = self.__blur.addRect(blurRect)

    def __setBackgroundAlpha(self):
        alpha = BACKGROUND_ALPHA_DEFERRED if isRendererPipelineDeferred(
        ) else BACKGROUND_ALPHA_FORWARD
        self.as_setBackgroundAlphaS(alpha)