NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

recommendationCont.py (20272B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\recommendation\recommendationCont.py
      2 import mathext
      3 import uthread2
      4 from carbon.client.script.environment.AudioUtil import PlaySound
      5 from carbonui import ButtonStyle, fontconst, uiconst
      6 from carbonui.control.button import Button
      7 from carbonui.primitives.container import Container
      8 from carbonui.primitives.containerAutoSize import ContainerAutoSize
      9 from carbonui.primitives.fill import Fill
     10 from carbonui.primitives.frame import Frame
     11 from carbonui.primitives.layoutGrid import LayoutGrid
     12 from carbonui.primitives.sprite import Sprite
     13 from carbonui.primitives.stretchspritehorizontal import StretchSpriteHorizontal
     14 from carbonui.uianimations import animations
     15 from carbonui.util.color import Color
     16 from eve.client.script.ui.control.moreIcon import DescriptionIcon
     17 from eve.client.script.ui.control.eveLabel import Label, EveLabelMedium
     18 from eve.client.script.ui.control.eveLoadingWheel import LoadingWheel
     19 from eve.client.script.ui.shared.agencyNew.ui.agencyWnd import AgencyWndNew
     20 from eve.client.script.ui.shared.recommendation.const import ANOTHER_ACTIVE, COMPLETED, CURRENT_ACTIVE, NO_ACTIVE, NUM_SLOTS, REJECTED, Sounds, UPDATE_TIMEOUT_SECONDS
     21 from eve.client.script.ui.shared.recommendation.uiConst import LIGHT_GREEN, LIGHT_YELLOW, MAIN_GREEN, MAIN_YELLOW
     22 from localization import GetByLabel
     23 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     24 ANIM_DURATION = 0.225
     25 DECO_OPACITY = 0.5
     26 ICON_FILL_OPACITY = 0.75
     27 
     28 class RecommendationsCont(Container):
     29     default_align = uiconst.CENTERTOP
     30     default_width = 935
     31     default_height = 415
     32 
     33     def __init__(self, **kwargs):
     34         super(RecommendationsCont, self).__init__(**kwargs)
     35         self.allCards = []
     36         self.recommendationSvc = sm.GetService('recommendationSvc')
     37         uthread2.StartTasklet(self.ConstructLayout)
     38 
     39     def ConstructLayout(self):
     40         labelCont = ContainerAutoSize(parent=self, minHeight=65, align=uiconst.TOTOP)
     41         Label(name='header', parent=labelCont, align=uiconst.TOTOP, text='<center>%s</center>' % GetByLabel('UI/recommendations/OpportunitiesHeader'), fontsize=18, top=12)
     42         Label(name='text', parent=labelCont, align=uiconst.TOTOP, text='<center>%s</center>' % GetByLabel('UI/recommendations/OpportunitiesDescription'), fontsize=13)
     43         treatmentsCont = Container(parent=self)
     44         mainGrid = LayoutGrid(columns=3, parent=treatmentsCont, align=uiconst.CENTERTOP, cellSpacing=20)
     45         shouldBlinkBtn = self.recommendationSvc.ShouldBtnsBlink()
     46         self.treatmentCard1 = RecommendationCard(parent=mainGrid, slotIdx=0, shouldBlinkBtn=shouldBlinkBtn)
     47         self.treatmentCard2 = RecommendationCard(parent=mainGrid, slotIdx=1, shouldBlinkBtn=shouldBlinkBtn)
     48         self.treatmentCard3 = RecommendationCard(parent=mainGrid, slotIdx=2, shouldBlinkBtn=shouldBlinkBtn)
     49         self.allCards = [self.treatmentCard1, self.treatmentCard2, self.treatmentCard3]
     50         self.LoadCards()
     51 
     52     def LoadCards(self):
     53         if not self.recommendationSvc.HasRecommendations():
     54             self.recommendationSvc.RequestRecommendations(NUM_SLOTS, allowOld=True)
     55         for slotIdx, card in enumerate(self.allCards):
     56             self.LoadCard(card, slotIdx)
     57 
     58     def LoadCard(self, card, slotIdx):
     59         recommendationController = self.recommendationSvc.GetRecommendationControllerForSlot(slotIdx)
     60         if not recommendationController:
     61             return
     62         card.recommendationController = recommendationController
     63         card.LoadCard()
     64 
     65 
     66 class RecommendationCard(Container):
     67     default_align = uiconst.CENTERLEFT
     68     default_height = 326
     69     default_width = 265
     70     __notifyevents__ = ['OnOperationDeactivatedUpdate', 'OnOperationCompleted']
     71 
     72     def __init__(self, **kwargs):
     73         super(RecommendationCard, self).__init__(**kwargs)
     74         self._recommendationController = None
     75         self.updateThread = None
     76 
     77     def ApplyAttributes(self, attributes):
     78         super(RecommendationCard, self).ApplyAttributes(attributes)
     79         self.slotIdx = attributes.slotIdx
     80         shouldBlinkBtn = attributes.shouldBlinkBtn
     81         self.ConstructLayout()
     82         if shouldBlinkBtn:
     83             uthread2.call_after_wallclocktime_delay(self.BlinkButton, 0.8)
     84         sm.RegisterNotify(self)
     85 
     86     def OnOperationDeactivatedUpdate(self):
     87         self.UpdateCard()
     88 
     89     def OnOperationCompleted(self, category_id, operation_id):
     90         if self.recommendationController and self.recommendationController.operationID == operation_id:
     91             self.UpdateCard()
     92 
     93     def ConstructLayout(self):
     94         self.mainContainer = Container(name='mainContainer', parent=self, align=uiconst.CENTER, width=self.default_width, height=self.default_height)
     95         Frame(bgParent=self.mainContainer, color=(1, 1, 1, 0.1))
     96         self.innerCard = Container(name='innerCard', parent=self.mainContainer, padding=1)
     97         self.backgroundTexture = Sprite(name='backgroundTexture', parent=self.mainContainer, align=uiconst.TOALL, padding=1, opacity=0.7)
     98         Fill(name='bgFill', parent=self.mainContainer, align=uiconst.TOALL, padding=1, color=(0, 0, 0, 1))
     99         self.topSection = TopSection(parent=self.innerCard)
    100         self.dismissButton = Button(name='dismissButton', parent=self.innerCard, align=uiconst.TOPRIGHT, texturePath='res:/UI/Texture/classes/Treatments/recycleIcon.png', iconSize=18, func=self.DismissRecommendation)
    101         Sprite(name='underlay', parent=self.innerCard, align=uiconst.TOPRIGHT, pos=(0, 0, 32, 32), texturePath='res:/UI/Texture/classes/Treatments/recycleButtonUnderlay.png', opacity=0.35 * DECO_OPACITY)
    102         self.actionBtn = Button(name='actionBtn', parent=self.innerCard, align=uiconst.CENTERBOTTOM, label=GetByLabel('UI/Agents/Dialogue/Buttons/AcceptMission'), top=8)
    103         self.textCont = TextCont(parent=self.innerCard, align=uiconst.TOBOTTOM)
    104         self.loadingWheel = LoadingWheel(name='loadingWheel', parent=self, align=uiconst.CENTER)
    105         self.loadingWheel.Hide()
    106         self.refreshButton = Button(name='refreshButton', parent=self, align=uiconst.CENTER, label=GetByLabel('UI/Commands/Refresh'), top=8, func=self.RequestRecommendation)
    107         self.refreshButton.Hide()
    108 
    109     def BlinkButton(self, numBlinks = 1):
    110         self.actionBtn.Blink(1, numBlinks)
    111 
    112     def QuitRecommendation(self, *args):
    113         if not self.recommendationController:
    114             return
    115         if not self.QuittingConfirmed():
    116             return
    117         self.AnimateClose()
    118         self.recommendationController.QuitRecommendation()
    119 
    120     @staticmethod
    121     def QuittingConfirmed():
    122         message = GetByLabel('UI/recommendations/QuitConfirmation')
    123         answer = prompt_player_fsd_dialog('AskAreYouSure', {'cons': message}, uiconst.YESNO)
    124         if answer == uiconst.ID_YES:
    125             return True
    126         return False
    127 
    128     def RequestRecommendation(self, *args):
    129         self.refreshButton.Hide()
    130         self.recommendationController.RequestRecommendations(1, allowOld=False)
    131         self.StartWaitingForUpdate()
    132 
    133     def DismissRecommendation(self, *args):
    134         if not self.recommendationController:
    135             return
    136         operationState = self.recommendationController.GetOperationState()
    137         if operationState == CURRENT_ACTIVE and not self.QuittingConfirmed():
    138             return
    139         self.AnimateClose()
    140         self.recommendationController.DismissRecommendation()
    141 
    142     def AnimateClose(self):
    143         animations.MorphScalar(self.mainContainer, 'opacity', startVal=self.opacity, endVal=0.0, duration=ANIM_DURATION, callback=self.StartWaitingForUpdate)
    144 
    145     def AnimateOpen(self):
    146         self.loadingWheel.Hide()
    147         animations.MorphScalar(self.mainContainer, 'opacity', startVal=self.mainContainer.opacity, endVal=1.0, duration=ANIM_DURATION, timeOffset=ANIM_DURATION, callback=self.mainContainer.Enable)
    148 
    149     def StartWaitingForUpdate(self):
    150         self.loadingWheel.Show()
    151         self.mainContainer.Disable()
    152         self.updateThread = uthread2.StartTasklet(self._WaitForUpdate)
    153 
    154     def _WaitForUpdate(self):
    155         secondsWaited = 0
    156         secondsToWait = UPDATE_TIMEOUT_SECONDS
    157         while secondsWaited < secondsToWait:
    158             uthread2.Sleep(1.0)
    159             secondsWaited += 1
    160 
    161         self.refreshButton.Show()
    162         self.loadingWheel.Hide()
    163 
    164     def OnNewRecommendationReceived(self):
    165         uthread2.StartTasklet(self.ProcessUpdatedData)
    166 
    167     def ProcessUpdatedData(self):
    168         if self.mainContainer.HasAnimation('opacity'):
    169             uthread2.Sleep(ANIM_DURATION)
    170         self.refreshButton.Hide()
    171         self.StopWaitingForData()
    172         self.LoadCard()
    173         self.AnimateOpen()
    174 
    175     def StopWaitingForData(self):
    176         if not self.updateThread:
    177             return
    178         self.updateThread.kill()
    179         self.updateThread = None
    180 
    181     def LoadCard(self):
    182         if not self.recommendationController or not self.recommendationController.operationID:
    183             self.AnimateClose()
    184             return
    185         self.topSection.LoadSection(self.recommendationController)
    186         backgroundTexturePath = self.recommendationController.GetBackgroundPath()
    187         self.backgroundTexture.texturePath = backgroundTexturePath
    188         self.textCont.LoadText(self.recommendationController)
    189         self.UpdateCard()
    190         self.recommendationController.RecommendationDisplayed()
    191 
    192     @property
    193     def recommendationController(self):
    194         return self._recommendationController
    195 
    196     @recommendationController.setter
    197     def recommendationController(self, newController):
    198         if self._recommendationController:
    199             return
    200         self._recommendationController = newController
    201         self.recommendationController.onNewRecommendation.clear()
    202         self._recommendationController.onNewRecommendation.connect(self.OnNewRecommendationReceived)
    203 
    204     def UpdateCard(self):
    205         if self.recommendationController.operationID is None:
    206             return
    207         operationState = self.recommendationController.GetOperationState()
    208         self.topSection.UpdateSection()
    209         self.UpdateButton(operationState)
    210         if operationState == COMPLETED:
    211             if self.recommendationController and self.recommendationController.IsCompletedAndUnseen():
    212                 self.BlinkButton(3)
    213                 uthread2.call_after_wallclocktime_delay(self.ClearSlot, 3.5, self.slotIdx, self.recommendationController.operationID)
    214                 self.recommendationController.MarkCompletionAnimationAsSeen()
    215                 sm.ScatterEvent('OnRecommendationsUpdated')
    216 
    217     def ClearSlot(self, slotIDx, operationID):
    218         if not self.recommendationController:
    219             return
    220         if slotIDx != self.recommendationController.slotIdx:
    221             return
    222         if operationID != self.recommendationController.operationID:
    223             return
    224         self.recommendationController.ResetController()
    225         self.AnimateClose()
    226         self.RequestRecommendation()
    227 
    228     def UpdateButton(self, operationState):
    229         self.actionBtn.hint = ''
    230         self.dismissButton.hint = GetByLabel('UI/recommendations/DismissConfirmation')
    231         if operationState == COMPLETED:
    232             self.actionBtn.SetLabel(GetByLabel('UI/Market/Orders/StatusCompleted'))
    233             self.actionBtn.Disable()
    234             self.actionBtn.func = None
    235             self.actionBtn.style = ButtonStyle.SUCCESS
    236             self.dismissButton.hint = GetByLabel('UI/recommendations/GetNewOpportunityHint')
    237         if operationState == CURRENT_ACTIVE:
    238             self.actionBtn.SetLabel(GetByLabel('UI/Commands/CmdQuit'))
    239             self.actionBtn.Enable()
    240             self.actionBtn.func = self.QuitRecommendation
    241             self.actionBtn.style = ButtonStyle.WARNING
    242         elif operationState == ANOTHER_ACTIVE:
    243             self.actionBtn.SetLabel(GetByLabel('UI/Agents/Dialogue/Buttons/AcceptMission'))
    244             self.actionBtn.hint = GetByLabel('UI/recommendations/AlreadyActive')
    245             self.actionBtn.Disable()
    246             self.actionBtn.func = None
    247             self.actionBtn.style = ButtonStyle.NORMAL
    248         elif operationState == NO_ACTIVE:
    249             self.actionBtn.SetLabel(GetByLabel('UI/Agents/Dialogue/Buttons/AcceptMission'))
    250             self.actionBtn.Enable()
    251             self.actionBtn.func = self.recommendationController.AcceptRecommendation
    252             self.actionBtn.style = ButtonStyle.NORMAL
    253         else:
    254             self.actionBtn.style = ButtonStyle.NORMAL
    255         self.dismissButton.Enable()
    256 
    257     def OnMouseEnter(self, *args):
    258         if self.innerCard.HasAnimation('opacity'):
    259             return
    260         PlaySound(Sounds.HOVER)
    261         animations.FadeTo(self.backgroundTexture, self.backgroundTexture.opacity, 1.0, 0.2, curveType=uiconst.ANIM_OVERSHOT)
    262 
    263     def OnMouseExit(self, *args):
    264         if self.innerCard.HasAnimation('opacity'):
    265             return
    266         animations.FadeTo(self.backgroundTexture, self.backgroundTexture.opacity, 0.7, 0.2)
    267 
    268 
    269 class TopSection(Container):
    270     default_align = uiconst.TOTOP
    271     default_height = 195
    272 
    273     def ApplyAttributes(self, attributes):
    274         self.treatmentController = None
    275         Container.ApplyAttributes(self, attributes)
    276         StretchSpriteHorizontal(name='contentCardTop', parent=self, align=uiconst.TOTOP_NOPUSH, texturePath='res:/UI/Texture/classes/Treatments/topBar.png', height=14, leftEdgeSize=94, opacity=DECO_OPACITY, padRight=34)
    277         self.statusLabel = EveLabelMedium(parent=self, align=uiconst.TOPLEFT, pos=(6, 6, 0, 0), text='')
    278         self.checkmark = Sprite(name='checkmark', parent=self, align=uiconst.TOPLEFT, pos=(24, 15, 32, 32), texturePath='res:/UI/Texture/classes/Treatments/completedIcon.png', color=LIGHT_GREEN)
    279         self.checkmark.display = False
    280         self.moreIcon = DescriptionIcon(parent=self, align=uiconst.BOTTOMRIGHT, top=20, left=6)
    281         iconCont = Container(name='iconCont', parent=self, align=uiconst.CENTERBOTTOM, pos=(0, 6, 122, 140))
    282         self.treatmentIcon = Sprite(name='treatmentIcon', parent=iconCont, align=uiconst.CENTER, pos=(0, 0, 120, 120))
    283         self.iconFrame = Sprite(name='iconFrame', parent=iconCont, align=uiconst.CENTER, pos=(0, 0, 122, 140), texturePath='res:/UI/Texture/classes/Treatments/iconFrame.png', opacity=DECO_OPACITY)
    284         self.iconFill = Sprite(name='iconFill', parent=iconCont, align=uiconst.CENTER, pos=(0, 0, 120, 140), texturePath='res:/UI/Texture/classes/Treatments/iconFrameFilled.png', opacity=0.0)
    285         Sprite(name='bottomBarLeft', parent=iconCont, align=uiconst.CENTERBOTTOM, pos=(-86, 10, 69, 14), texturePath='res:/UI/Texture/classes/Treatments/bottomBar.png', opacity=DECO_OPACITY)
    286         Sprite(name='bottomBarRight', parent=iconCont, align=uiconst.CENTERBOTTOM, pos=(86, 10, -69, 14), texturePath='res:/UI/Texture/classes/Treatments/bottomBar.png', opacity=DECO_OPACITY)
    287 
    288     def LoadSection(self, recommendationController):
    289         self.treatmentController = recommendationController
    290         self.treatmentIcon.texturePath = recommendationController.GetRecommendationIcon()
    291         self.moreIcon.LoadTooltipPanel = self.LoadMoreTooltipPanel
    292         self.UpdateSection()
    293 
    294     def UpdateSection(self):
    295         operationState = self.treatmentController.GetOperationState()
    296         self.statusLabel.SetRGBA(*self.statusLabel.default_color)
    297         self.iconFrame.opacity = DECO_OPACITY
    298         self.iconFill.opacity = 0.0
    299         solidIcon = False
    300         self.statusLabel.text = ''
    301         treatmentIconColor = Color.WHITE
    302         self.checkmark.display = False
    303         if operationState == REJECTED:
    304             self.statusLabel.text = GetByLabel('UI/Contracts/ContractsWindow/Rejected')
    305         elif operationState == CURRENT_ACTIVE:
    306             self.statusLabel.text = GetByLabel('Achievements/UI/active')
    307             self.statusLabel.SetRGBA(*MAIN_YELLOW)
    308             iconFillColor = self.GetColorWithOpacity(MAIN_YELLOW, ICON_FILL_OPACITY)
    309             self.iconFill.SetRGBA(*iconFillColor)
    310             solidIcon = True
    311             treatmentIconColor = LIGHT_YELLOW
    312             self.iconFrame.opacity = 0.0
    313         elif operationState == COMPLETED:
    314             iconFillColor = self.GetColorWithOpacity(MAIN_GREEN, ICON_FILL_OPACITY)
    315             self.iconFill.SetRGBA(*iconFillColor)
    316             solidIcon = True
    317             treatmentIconColor = LIGHT_GREEN
    318             self.iconFrame.opacity = 0.0
    319             self.checkmark.display = True
    320         self.treatmentIcon.texturePath = self.treatmentController.GetRecommendationIcon(solidIcon)
    321         self.treatmentIcon.SetRGBA(*treatmentIconColor)
    322 
    323     def GetColorWithOpacity(self, color, opacity):
    324         return color[:3] + (opacity,)
    325 
    326     def LoadMoreTooltipPanel(self, tooltipPanel, *args):
    327         hint = self.treatmentController.GetRecommendationHint()
    328         if hint:
    329             tooltipPanel.LoadGeneric1ColumnTemplate()
    330             tooltipPanel.AddLabelMedium(text=hint, wrapWidth=200)
    331         agencyContentGroupID = self.treatmentController.GetAgencyContentGroup()
    332         if agencyContentGroupID:
    333             if hint:
    334                 tooltipPanel.AddSpacer(height=6)
    335             tooltipPanel.SetState(uiconst.UI_NORMAL)
    336             self.showInAgencyBtn = Button(parent=tooltipPanel, align=uiconst.NOALIGN, label=GetByLabel('UI/Agency/ShowInAgency'), hint=GetByLabel('UI/Agency/ShowInAgencyHint'), texturePath='res:/UI/Texture/WindowIcons/theAgency.png', func=lambda *args: self.OpenInAgency(agencyContentGroupID))
    337 
    338     def OpenInAgency(self, agencyContentGroupID):
    339         AgencyWndNew.OpenAndShowContentGroup(agencyContentGroupID)
    340         sm.ScatterEvent('OnTreatmentWndOpenedOtherWnd', 'Agency')
    341 
    342 
    343 class TextCont(Container):
    344     default_name = 'treatmentContTextCont'
    345     default_bgColor = (0, 0, 0, 0.5)
    346     default_height = 130
    347 
    348     def ApplyAttributes(self, attributes):
    349         Container.ApplyAttributes(self, attributes)
    350         self.headerLabel = Label(name='header', parent=self, align=uiconst.TOTOP, fontsize=18, top=5, padding=(10, 0, 10, 0))
    351         self.textLabelScrollingCont = ScrollingTextCont(parent=self, height=self.height, fontsize=13, labelPadding=(10, 0, 10, 0))
    352 
    353     def LoadText(self, treatmentController):
    354         header = treatmentController.GetOperationName()
    355         text = treatmentController.GetOperationDescription()
    356         self.headerLabel.text = '<center>%s</center>' % header
    357         width = RecommendationCard.default_width - self.headerLabel.padLeft - self.headerLabel.padRight
    358         w, h = self.headerLabel.MeasureTextSize(header, width=width, fontsize=self.headerLabel.fontsize)
    359         scrollingHeight = self.height - h - self.headerLabel.top - 50
    360         self.textLabelScrollingCont.UpdateHeight(scrollingHeight)
    361         self.textLabelScrollingCont.SetText('<center>%s</center>' % text)
    362 
    363 
    364 SEC_PER_PIXEL = 0.07
    365 
    366 class ScrollingTextCont(Container):
    367     default_align = uiconst.TOTOP_NOPUSH
    368     default_state = uiconst.UI_NORMAL
    369     default_name = 'labelCont'
    370     default_clipChildren = True
    371     default_fontsize = fontconst.EVE_MEDIUM_FONTSIZE
    372     fadeHeight = 14
    373 
    374     def ApplyAttributes(self, attributes):
    375         Container.ApplyAttributes(self, attributes)
    376         text = attributes.text
    377         labelPadding = attributes.labelPadding or 0
    378         fontsize = attributes.fontsize or self.default_fontsize
    379         self.label = Label(name='scrollContLabel', parent=self, align=uiconst.TOTOP_NOPUSH, text='', fontsize=fontsize, padding=labelPadding)
    380         self.SetText(text)
    381 
    382     def SetText(self, text):
    383         self.label.text = text
    384         self.label.SetBottomAlphaFade(self.height, maxFadeHeight=self.fadeHeight)
    385 
    386     def UpdateHeight(self, newHeight):
    387         self.height = newHeight
    388 
    389     def OnMouseEnter(self, *args):
    390         diff = self.label.textheight - self.height
    391         if diff <= 2:
    392             return
    393         duration = mathext.clamp(SEC_PER_PIXEL * diff, 0, 2.0)
    394         animations.MorphScalar(self.label, 'padTop', self.label.padTop, -diff, duration=duration)
    395         fadeEndValue = (self.label.textheight, self.fadeHeight)
    396         self.label.SetBottomAlphaFade(*fadeEndValue)
    397 
    398     def OnMouseExit(self, *args):
    399         self.label.StopAnimations()
    400         self.label.padTop = 0
    401         self.label.SetBottomAlphaFade(self.height, self.fadeHeight)