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

underConstructionWnd.py (16196B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\underConstruction\underConstructionWnd.py
      2 import logging
      3 from collections import defaultdict
      4 from carbonui.button.const import ButtonVariant
      5 from carbon.common.script.sys.serviceConst import ROLE_PROGRAMMER
      6 from eve.client.script.ui.shared.underConstruction.util import GetBgTextureInfo, GetFactionBgTexturePath, FACTION_BG_HEIGHT, FACTION_BG_WIDTH
      7 from localization import GetByLabel
      8 from carbonui.window.settings import WindowMarginMode
      9 from carbonui.primitives.layoutGrid import LayoutGrid
     10 from carbonui.primitives.sprite import Sprite
     11 import evetypes
     12 import uthread2
     13 from eve.client.script.ui.shared.underConstruction.underConstructionInputItem import InputItemController, UnderConstructionInputScrollEntry
     14 from eve.client.script.ui.shared.underConstruction.underConstructionOutputCont import UnderConstructionOutputCont
     15 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     16 from threadutils import throttled
     17 from eve.client.script.environment.invControllers import ShipCargo
     18 import locks
     19 from spacecomponents.common.componentConst import UNDER_CONSTRUCTION
     20 from spacecomponents.common.data import get_space_component_for_type
     21 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     22 from carbonui.control.window import Window
     23 import carbonui.const as uiconst
     24 from carbonui.primitives.container import Container
     25 from carbonui.control.scrollContainer import ScrollContainer
     26 from eve.client.script.ui.control.eveLabel import EveLabelMedium
     27 from carbonui.control.button import Button
     28 from eve.common.script.util.eveFormat import FmtISK, FmtLP
     29 from spacecomponents.common.helper import HasUnderConstructionComponent
     30 from eve.common.lib import appConst
     31 logger = logging.getLogger(__name__)
     32 from eve.client.script.environment.invControllers import SpaceComponentInventory
     33 
     34 class UnderConstructionWnd(Window):
     35     __guid__ = 'UnderConstructionWnd'
     36     __notifyevents__ = ['OnSessionChanged']
     37     default_minSize = (930, 520)
     38     default_windowID = 'underConstructionWnd'
     39 
     40     def DebugReload(self, *args):
     41         self.Reload(self)
     42 
     43     def ApplyAttributes(self, attributes):
     44         Window.ApplyAttributes(self, attributes)
     45         self._itemID = attributes.itemID
     46         self._typeID = None
     47         self._depositingItems = False
     48         self._depositBtnDelay = False
     49         self._constructedTypeID = None
     50         self._inputRequiredByTypeID = {}
     51         self._qtyRequiredByTypeID = {}
     52         self.inputEntriesByTypeID = {}
     53         self.invCookie = sm.GetService('inv').Register(self)
     54         self.invController = SpaceComponentInventory(itemID=self._itemID)
     55         self._typeID = self.invController.GetTypeID()
     56         if not HasUnderConstructionComponent(self._typeID):
     57             self.Close()
     58             logger.exception('trying to open a under construction window for something without the component')
     59             return
     60         self.SetCaption(evetypes.GetName(self._typeID))
     61         underConstructionComp = get_space_component_for_type(self._typeID, UNDER_CONSTRUCTION)
     62         self._inputRequiredByTypeID = underConstructionComp.inputItems
     63         self._qtyRequiredByTypeID = {typeID:inputInfo.qtyRequired for typeID, inputInfo in self._inputRequiredByTypeID.iteritems()}
     64         self._constructedTypeID = underConstructionComp.constructedItem
     65         self.ConstructUI()
     66         self.LoadInputItems()
     67         self.Refresh()
     68         sm.RegisterNotify(self)
     69 
     70     def ConstructUI(self):
     71         self.bottomCont = ContainerAutoSize(parent=self.content, name='bottomCont', align=uiconst.TOBOTTOM, alignMode=uiconst.TOTOP)
     72         self.centerCont = Container(parent=self.content, name='centerCont', clipChildren=True)
     73         self.centerBgCont = Container(parent=self.content, name='centerBgCont', clipChildren=True)
     74         self.righSide = Container(parent=self.centerCont, name='righSide', align=uiconst.TORIGHT, width=400)
     75         self.leftSide = Container(parent=self.centerCont, name='leftSide')
     76         bgTexturePathInfo = GetBgTextureInfo(self._constructedTypeID)
     77         if bgTexturePathInfo:
     78             texturePath, tw, th = bgTexturePathInfo
     79             Sprite(parent=self.centerBgCont, pos=(0,
     80              0,
     81              tw,
     82              th), align=uiconst.CENTERRIGHT, texturePath=texturePath, state=uiconst.UI_DISABLED)
     83             showIcon = False
     84         else:
     85             showIcon = True
     86         factionBgTexturePath = GetFactionBgTexturePath(self._constructedTypeID)
     87         Sprite(parent=self.centerBgCont, pos=(0,
     88          0,
     89          FACTION_BG_WIDTH,
     90          FACTION_BG_HEIGHT), align=uiconst.CENTERRIGHT, texturePath=factionBgTexturePath, state=uiconst.UI_DISABLED)
     91         self.ConstructLeftSide()
     92         self.ConstructRightSide(showIcon=showIcon)
     93         self.ConstructBottom()
     94 
     95     def ConstructLeftSide(self):
     96         self.inputScroll = ScrollContainer(name='inputScroll', parent=self.leftSide, padRight=20)
     97 
     98     def ConstructBottom(self):
     99         padding = self._GetPaddingValue()
    100         depositBtnCont = ContainerAutoSize(parent=self.bottomCont, name='depositBtnCont', align=uiconst.TORIGHT)
    101         text = GetByLabel('UI/Inflight/SpaceComponents/UnderConstruction/DepositItems')
    102         self.depositItemsBtn = Button(parent=depositBtnCont, label=text, func=self.DepositItems, align=uiconst.CENTER)
    103         selectionBtnCont = ContainerAutoSize(parent=self.bottomCont, name='selectionBtnCont', align=uiconst.TORIGHT, left=padding)
    104         text = GetByLabel('UI/Inflight/SpaceComponents/UnderConstruction/DeselectAllItems')
    105         self.changeSelectionBtn = Button(parent=selectionBtnCont, label=text, func=self.ChangeSelection, align=uiconst.CENTER, variant=ButtonVariant.GHOST)
    106         self.bottomCont.minHeight = self.depositItemsBtn.height + 2 * padding
    107         gridParent = ContainerAutoSize(parent=self.bottomCont, name='gridParent', align=uiconst.CENTERLEFT)
    108         grid = LayoutGrid(parent=gridParent, align=uiconst.TOPLEFT, columns=2, cellSpacing=(24, 0))
    109         hasLpRewards = bool(any((x.lpRewards for x in self._inputRequiredByTypeID.itervalues())))
    110         lpRewardsText = GetByLabel('UI/Inflight/SpaceComponents/UnderConstruction/TotalLpPayout') if hasLpRewards else ''
    111         EveLabelMedium(parent=grid, text=lpRewardsText)
    112         hasIskRewards = bool(any((x.iskRewards for x in self._inputRequiredByTypeID.itervalues())))
    113         iskRewardsText = GetByLabel('UI/Inflight/SpaceComponents/UnderConstruction/TotalIskPayout') if hasIskRewards else ''
    114         EveLabelMedium(parent=grid, text=iskRewardsText)
    115         self.lpLabel = EveLabelMedium(parent=grid, state=uiconst.UI_NORMAL)
    116         self.iskLabel = EveLabelMedium(parent=grid)
    117         self.lpLabel.display = hasLpRewards
    118         self.iskLabel.display = hasIskRewards
    119 
    120     def _GetPaddingValue(self):
    121         padding = 8 if self.margin_mode == WindowMarginMode.COMPACT else 16
    122         return padding
    123 
    124     def ConstructRightSide(self, showIcon):
    125         self.outputCont = UnderConstructionOutputCont(parent=self.righSide, align=uiconst.CENTERRIGHT, constructedTypeID=self._constructedTypeID, showIcon=showIcon)
    126 
    127     def LoadInputItems(self):
    128         self.inputScroll.Flush()
    129         inputItemsList = self._inputRequiredByTypeID.items()
    130         inputItemsList.sort()
    131         cargoQtyByTypeID = self.GetQtyByTypeID_Cargo()
    132         paddingValue = self._GetPaddingValue()
    133         for input in inputItemsList:
    134             typeID, inputInfo = input
    135             qtyInCargo = cargoQtyByTypeID.get(typeID, 0)
    136             itemController = InputItemController(typeID, inputInfo.qtyRequired, inputInfo.iskRewards, inputInfo.lpRewards, isSelected=bool(qtyInCargo))
    137             inputEntry = UnderConstructionInputScrollEntry(parent=self.inputScroll, align=uiconst.TOTOP, itemController=itemController, inputChangedCallback=self.OnInputChanged, qtyInCargo=qtyInCargo, paddingValue=paddingValue, padBottom=1)
    138             self.inputEntriesByTypeID[typeID] = inputEntry
    139 
    140     def DepositItems(self, *args):
    141         with locks.TempLock('UnderConstructionWnd_DepositItems_%s' % self._itemID):
    142             sucessfulDeposit = False
    143             try:
    144                 self._depositingItems = True
    145                 self._depositBtnDelay = True
    146                 self.depositItemsBtn.Disable()
    147                 qtyByTypeID = self.GetTypeIDsAndQtyFromInputEntries()
    148                 if self.DepositConfirmed(qtyByTypeID):
    149                     failedToMove = self._DoDepositItems(qtyByTypeID)
    150                     sucessfulDeposit = not failedToMove
    151             finally:
    152                 self._depositingItems = False
    153                 if sucessfulDeposit:
    154                     self.Close()
    155                 else:
    156                     uthread2.call_after_wallclocktime_delay(self.EnableBtnAfterDeposit, 1.0)
    157                 self.Refresh()
    158 
    159     def ChangeSelection(self, *args):
    160         numItemsSelected = sum((qty for qty in self.GetTypeIDsAndQtyFromInputEntries().itervalues()))
    161         deselectAll = bool(numItemsSelected)
    162         if deselectAll:
    163             for typeID, inputEntry in self.inputEntriesByTypeID.iteritems():
    164                 inputEntry.SetEntryDeselected()
    165 
    166         else:
    167             for typeID, inputEntry in self.inputEntriesByTypeID.iteritems():
    168                 inputEntry.SelectNonSelectedEntry()
    169                 maxValue = inputEntry.inputItemController.maxToAdd
    170                 inputEntry.inputCont.inputEdit.SetValue(maxValue, False)
    171 
    172         self.Refresh()
    173 
    174     def EnableBtnAfterDeposit(self):
    175         self._depositBtnDelay = False
    176         self.UpdateBtn()
    177 
    178     def DepositConfirmed(self, qtyByTypeID):
    179         depositTextList = [ u'\u2022 %s' % GetByLabel('UI/Common/QuantityAndItem', quantity=qty, item=typeID) for typeID, qty in qtyByTypeID.iteritems() if qty ]
    180         depositText = '<br>'.join(depositTextList)
    181         rewardTextList = []
    182         totalIsk, totalLP, _ = self.GetRewardsFromTypeIDAndQty()
    183         if totalIsk or totalLP:
    184             if totalIsk:
    185                 rewardTextList += [FmtISK(totalIsk)]
    186             if totalLP:
    187                 rewardTextList += [FmtLP(totalLP)]
    188         rewardText = ''
    189         if rewardTextList:
    190             rewardText += '<br><br>%s<br>' % GetByLabel('UI/Inflight/SpaceComponents/UnderConstruction/RewardsTextInConfirmation')
    191             rewardText += '<br>'.join(rewardTextList)
    192         if prompt_player_fsd_dialog('ConfirmUnderConstructionDeposit', {'itemList': depositText,
    193          'rewardText': rewardText}, uiconst.YESNO, suppress=uiconst.ID_YES) == uiconst.ID_YES:
    194             return True
    195         return False
    196 
    197     def GetTypeIDsAndQtyFromInputEntries(self):
    198         qtyByTypeID = {}
    199         for typeID, inputEntry in self.inputEntriesByTypeID.iteritems():
    200             inputQty = inputEntry.GetInputQty()
    201             qtyByTypeID[typeID] = inputQty
    202 
    203         return qtyByTypeID
    204 
    205     def _DoDepositItems(self, qtyByTypeID):
    206         ballpark = sm.GetService('michelle').GetBallpark()
    207         underConstructionComp = ballpark.componentRegistry.GetComponentForItem(self._itemID, UNDER_CONSTRUCTION)
    208         failedToMove = underConstructionComp.DepositItemsFromShip(qtyByTypeID)
    209         if failedToMove:
    210             failedTextList = [ u'\u2022 %s' % GetByLabel('UI/Common/QuantityAndItem', quantity=qty, item=typeID) for typeID, qty in failedToMove.iteritems() if qty > 0 ]
    211             failedText = '<br>'.join(failedTextList)
    212             prompt_player_fsd_dialog('FailedUnderConstructionDeposit', {'itemList': failedText})
    213         return failedToMove
    214 
    215     def OnInputChanged(self, *args):
    216         self.Refresh()
    217 
    218     def Refresh(self):
    219         self._RefreshThrottled()
    220 
    221     @throttled(0.5)
    222     def _RefreshThrottled(self):
    223         if self._depositingItems:
    224             return
    225         self.UpdateInputEntries()
    226         self.UpdateRewards()
    227         self.UpdateBtn()
    228 
    229     def UpdateInputEntries(self):
    230         underConstructionQtyByTypeID = self.GetQtyByTypeID_UnderConstruction()
    231         cargoQtyByTypeID = self.GetQtyByTypeID_Cargo()
    232         qtyByTypeIdInWnd = {}
    233         qtyByTypeIdInContainer = {}
    234         for typeID, inputEntry in self.inputEntriesByTypeID.iteritems():
    235             unitsInContainer = underConstructionQtyByTypeID.get(typeID, 0)
    236             qtyInCargo = cargoQtyByTypeID.get(typeID, 0)
    237             inputEntry.UpdateEntry(unitsInContainer, qtyInCargo)
    238             if unitsInContainer:
    239                 qtyByTypeIdInContainer[typeID] = unitsInContainer
    240             if inputEntry.GetInputQty():
    241                 qtyByTypeIdInWnd[typeID] = inputEntry.GetInputQty()
    242 
    243         self.outputCont.UpdateProgress(qtyByTypeIdInContainer, qtyByTypeIdInWnd, self._qtyRequiredByTypeID)
    244 
    245     def GetQtyByTypeID_UnderConstruction(self):
    246         underConstructionQtyByTypeID = defaultdict(int)
    247         for item in self.invController.GetItems():
    248             underConstructionQtyByTypeID[item.typeID] += item.stacksize
    249 
    250         return underConstructionQtyByTypeID
    251 
    252     def GetQtyByTypeID_Cargo(self):
    253         cargoInvController = ShipCargo()
    254         cargoQtyByTypeID = defaultdict(int)
    255         for item in cargoInvController.GetItems():
    256             cargoQtyByTypeID[item.typeID] += item.stacksize
    257 
    258         return cargoQtyByTypeID
    259 
    260     def UpdateRewards(self):
    261         totalIsk, totalLP, lpByCorp = self.GetRewardsFromTypeIDAndQty()
    262         self.iskLabel.SetText(FmtISK(totalIsk))
    263         self.lpLabel.SetText(FmtLP(totalLP))
    264         if lpByCorp:
    265             corpsAndLp = sorted(lpByCorp.items())
    266             textList = []
    267             for corpID, lp in corpsAndLp:
    268                 t = GetByLabel('UI/Inflight/SpaceComponents/UnderConstruction/NumLpFromCorp', numLP=lp, corpName=cfg.eveowners.Get(corpID).name)
    269                 textList.append(t)
    270 
    271             self.lpLabel.hint = '<br>'.join(textList)
    272         else:
    273             self.lpLabel.hint = ''
    274 
    275     def GetRewardsFromTypeIDAndQty(self):
    276         totalIsk = 0
    277         totalLP = 0
    278         qtyByTypeID = self.GetTypeIDsAndQtyFromInputEntries()
    279         lpByCorp = defaultdict(int)
    280         for typeID, inputQty in qtyByTypeID.iteritems():
    281             inputInfo = self._inputRequiredByTypeID.get(typeID, None)
    282             if inputInfo:
    283                 totalIsk += inputQty * inputInfo.iskRewards
    284                 lpForType = 0
    285                 for corpID, lp in inputInfo.lpRewards.iteritems():
    286                     numLpFromCorp = inputQty * lp
    287                     lpForType += numLpFromCorp
    288                     lpByCorp[corpID] += numLpFromCorp
    289 
    290                 totalLP += lpForType
    291 
    292         return (totalIsk, totalLP, lpByCorp)
    293 
    294     def UpdateBtn(self):
    295         if self._depositBtnDelay:
    296             return
    297         numItems = sum((qty for qty in self.GetTypeIDsAndQtyFromInputEntries().itervalues()))
    298         totalMaxValue = sum((inputEntry.inputItemController.maxToAdd for inputEntry in self.inputEntriesByTypeID.itervalues()))
    299         if numItems > 0:
    300             self.depositItemsBtn.Enable()
    301             self.changeSelectionBtn.SetLabel(GetByLabel('UI/Inflight/SpaceComponents/UnderConstruction/DeselectAllItems'))
    302             self.changeSelectionBtn.hint = ''
    303         else:
    304             self.depositItemsBtn.Disable()
    305             self.changeSelectionBtn.SetLabel(GetByLabel('UI/Inflight/SpaceComponents/UnderConstruction/AutoSelect'))
    306             self.changeSelectionBtn.hint = GetByLabel('UI/Inflight/SpaceComponents/UnderConstruction/AutoSelectHint')
    307         if totalMaxValue:
    308             self.changeSelectionBtn.Enable()
    309         else:
    310             self.changeSelectionBtn.Disable()
    311 
    312     def OnInvChangeAny(self, item, change):
    313         if self._AreWeInterestedInChange(item, change):
    314             self.Refresh()
    315 
    316     def _AreWeInterestedInChange(self, itemID, change):
    317         if itemID.locationID in (session.shipid, self._itemID):
    318             return True
    319         if appConst.ixLocationID in change and change[appConst.ixLocationID] == session.shipid:
    320             return True
    321         return False
    322 
    323     def OnSessionChanged(self, isRemote, sess, change):
    324         if 'shipid' in change:
    325             self.Refresh()
    326 
    327     def Close(self, *args, **kwargs):
    328         super(UnderConstructionWnd, self).Close(*args, **kwargs)
    329         sm.GetService('inv').Unregister(self.invCookie)