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)