multiFitWnd.py (28876B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\fitting\multiFitWnd.py 2 from collections import defaultdict 3 import evetypes 4 import uthread 5 from carbon.common.script.sys.serviceConst import ROLE_GML, ROLE_WORLDMOD 6 from carbon.common.script.util.commonutils import StripTags 7 from carbon.common.script.util.linkUtil import GetShowInfoLink 8 from carbon.common.script.util.timerstuff import AutoTimer 9 from carbonui.control.combo import Combo 10 from carbonui.control.comboEntryData import ComboEntryData 11 from carbonui.control.singlelineedits.singleLineEditInteger import SingleLineEditInteger 12 from carbonui.control.singlelineedits.singleLineEditText import SingleLineEditText 13 from carbonui.primitives.container import Container 14 from carbonui.primitives.containerAutoSize import ContainerAutoSize 15 from carbonui.primitives.flowcontainer import FlowContainer 16 from carbonui.primitives.layoutGrid import LayoutGrid 17 from carbonui.primitives.sprite import Sprite 18 from carbonui.primitives.transform import Transform 19 from carbonui.util.sortUtil import SortListOfTuples 20 from carbonui.control.button import Button 21 from carbonui.control.checkbox import Checkbox 22 from eve.client.script.ui.control.eveIcon import Icon 23 from eve.client.script.ui.control.eveLabel import EveLabelMedium, EveLabelLarge, EveCaptionSmall, EveCaptionMedium, EveLabelSmall 24 from carbonui.control.window import Window 25 import carbonui.const as uiconst 26 from eve.client.script.ui.util import uix 27 from eve.client.script.ui.control.infoIcon import MoreExtraInfoInTooltip 28 from carbonui.control.progressBar import ProgressBar 29 from eve.client.script.ui.shared.dockedUI.controllers.stationController import StationController 30 from eve.client.script.ui.shared.dockedUI.controllers.structureController import StructureController 31 from eve.client.script.ui.shared.dockedUI.lobbyWnd import CheckCanAccessService 32 from eve.common.script.sys.eveCfg import IsDocked, InStructure 33 from globalConfig.getFunctions import GetMaxShipsToFit 34 from inventorycommon.util import IsModularShip 35 from localization import GetByLabel 36 from player_messaging.client.ui_message import prompt_player_fsd_dialog 37 from shipfitting import Fitting 38 from shipfitting.multiBuyUtil import BuyMultipleTypesWithQty 39 from threadutils import throttled 40 from utillib import KeyVal 41 from carbonui.control.buttonIcon import ButtonIcon 42 from carbonui.uicore import uicore 43 NORMAL_COLOR = (1, 44 1, 45 1, 46 0.75) 47 WARNING_COLOR = (1, 48 0, 49 0, 50 0.75) 51 MAX_TOOLTIP_ENTRIES = 10 52 REFRESH_TEXTUREPATH = 'res:/UI/Texture/Icons/105_32_22.png' 53 MAX_TEXT_WIDTH = 300 54 LEFT_EDGE = 10 55 56 class MultiFitWnd(Window): 57 __notifyevents__ = ['OnSessionChanged', 'OnMultipleItemChange'] 58 default_windowID = 'multiFitWnd' 59 default_captionLabelPath = 'UI/Fitting/FittingWindow/FittingManagement/MultiFitHeader' 60 default_iconNum = 'res:/ui/Texture/WindowIcons/fittingManagement.png' 61 layoutColumns = 3 62 63 def ApplyAttributes(self, attributes): 64 Window.ApplyAttributes(self, attributes) 65 self.fitting = None 66 self.isFitting = False 67 self.MakeUnstackable() 68 self.canFitNum = 0 69 self.tryingToFitNum = 1 70 self.currentProgress = 0 71 self.ConstructUI() 72 fitting = attributes.fitting 73 self.tryingToFitNum = attributes.get('qty', 1) 74 self.LoadWindow(fitting, self.tryingToFitNum) 75 self.SetInventoryStatus() 76 sm.RegisterNotify(self) 77 78 def ConstructUI(self): 79 self.BuildTopParentUI() 80 self.AddButtons() 81 numColumns = 2 82 self.sr.main.clipChildren = True 83 self.layoutGrid = layoutGrid = LayoutGrid(parent=ContainerAutoSize(parent=self.GetMainArea(), align=uiconst.TOTOP), align=uiconst.TOPLEFT, columns=numColumns, cellSpacing=(4, 10)) 84 spacer = Container(pos=(0, 0, 50, 0), align=uiconst.TOPLEFT) 85 layoutGrid.AddCell(cellObject=spacer, colSpan=1) 86 layoutGrid.FillRow() 87 self.BuildNumToFitUI() 88 self.BuildWarningUI() 89 self.BuildRefreshInventory() 90 self.missingLayoutGrid = LayoutGrid(parent=self.layoutGrid, columns=2, cellSpacing=(4, 10)) 91 self.BuildAvailableShipsUI() 92 self.BuildEquipmentUI() 93 self.BuildProgressUI() 94 self.MakeRigCbUI() 95 96 def BuildTopParentUI(self): 97 self.topParent = Container(parent=self.GetMainArea(), name='topParent', align=uiconst.TOTOP, height=100, clipChildren=True) 98 self.shipIcon = Icon(name='shipIcon', parent=self.topParent, state=uiconst.UI_NORMAL, size=64, ignoreSize=True) 99 self.shipIcon.GetDragData = self.GetFittingDragData 100 self.shipIcon.OnClick = self.OpenFitting 101 self.shipIcon.hint = GetByLabel('UI/Fitting/ShowFitting') 102 self.techSprite = Sprite(name='techIcon', parent=self.topParent, align=uiconst.RELATIVE, width=16, height=16, idx=0) 103 self.fitNameEdit = SingleLineEditText(name='fitNameEdit', parent=self.topParent, left=72, width=150, maxLength=20, hint=GetByLabel('UI/Common/ShipName')) 104 top = self.fitNameEdit.top + self.fitNameEdit.height + 5 105 self.shipNameLabel = EveLabelMedium(name='shipNameLabel', parent=self.topParent, left=77, top=top, state=uiconst.UI_NORMAL) 106 top = self.shipNameLabel.top + 20 107 equipmentText = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/EquipmentLocation') 108 equipCont = Container(name='equipCont', parent=self.topParent, align=uiconst.TOTOP, top=top, padLeft=77) 109 equipLabel = EveLabelSmall(text=equipmentText, parent=equipCont, name='equipLabel', align=uiconst.CENTERLEFT) 110 self.equipmentLocationCombo = Combo(parent=equipCont, options=[], name='equipmentLocationCombo', pos=(equipLabel.left + equipLabel.textwidth + 6, 111 0, 112 0, 113 0), callback=self.OnEquipLocationChanged, hint=GetByLabel('UI/Fitting/FittingWindow/FittingManagement/EquipmentLocationHint')) 114 equipCont.height = max(equipLabel.height, self.equipmentLocationCombo.height) 115 116 def LoadEquipCombo(self): 117 fittingSvc = sm.GetService('fittingSvc') 118 personalContainers = fittingSvc.FindPersonalContainers() 119 options = [] 120 if personalContainers: 121 cfg.evelocations.Prime({x.itemID for x in personalContainers}) 122 for eachContainer in personalContainers: 123 itemID = eachContainer.itemID 124 containerName = cfg.evelocations.Get(itemID).name or evetypes.GetName(eachContainer.typeID) 125 options.append((containerName.lower(), ComboEntryData(containerName, itemID))) 126 127 options = SortListOfTuples(options) 128 options.insert(0, ComboEntryData(GetByLabel('UI/Inventory/ItemHangar'), None)) 129 if [ (x.label, x.returnValue) for x in self.equipmentLocationCombo.entries ] != [ (x.label, x.returnValue) for x in options ]: 130 self.equipmentLocationCombo.LoadOptions(options) 131 132 def AddButtons(self): 133 btnCont = FlowContainer(name='buttonParent', parent=self.sr.main, align=uiconst.TOBOTTOM, padding=6, autoHeight=True, centerContent=True, contentSpacing=uiconst.BUTTONGROUPMARGIN, idx=0) 134 text = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/FitShips', numToFit=1) 135 self.fitBtn = Button(parent=btnCont, label=text, func=self.DoFitShips, align=uiconst.NOALIGN) 136 self.cancelBtn = Button(parent=btnCont, label=GetByLabel('UI/Common/Close'), func=self.Cancel, align=uiconst.NOALIGN) 137 if sm.GetService('publicQaToolsClient').CanGiveItemForMultifit(): 138 self.spawnFitBtn = Button(parent=btnCont, label='Create Missing', func=self.GiveAllPlayer, align=uiconst.NOALIGN) 139 140 def BuildNumToFitUI(self): 141 maxShipsAllowed = GetMaxShipsToFit(sm.GetService('machoNet')) 142 numCont = Container(name='numCont', align=uiconst.TOTOP, height=30, padLeft=LEFT_EDGE) 143 text = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/NumShipsToFit') 144 self.numToFitLabel = EveLabelLarge(name='numToFitLabel', parent=numCont, text=text, width=250, autoFitToText=True) 145 left = self.numToFitLabel.left + self.numToFitLabel.textwidth + 10 146 self.numToFitEdit = SingleLineEditInteger(name='numToFitEdit', parent=numCont, minValue=1, maxValue=maxShipsAllowed, OnChange=self.OnNumChanged, left=left, align=uiconst.CENTERLEFT) 147 numCont.height = max(self.numToFitLabel.textheight, self.numToFitEdit.height) 148 self.layoutGrid.AddCell(cellObject=numCont, colSpan=self.layoutGrid.columns) 149 150 def BuildWarningUI(self): 151 self.numWarningLabel = EveCaptionSmall(name='numWarningLabel', state=uiconst.UI_NORMAL, align=uiconst.CENTERTOP, width=MAX_TEXT_WIDTH, autoFitToText=True, text=GetByLabel('UI/Fitting/FittingWindow/FittingManagement/MissingShipEquipment')) 152 self.numWarningLabel.SetRGBA(*WARNING_COLOR) 153 self.PulseLabel(self.numWarningLabel) 154 self.numWarningLabel.LoadTooltipPanel = self.LoadMissingTooltip 155 self.layoutGrid.AddCell(cellObject=self.numWarningLabel, colSpan=self.layoutGrid.columns) 156 self.moreInfoIcon = MoreExtraInfoInTooltip(parent=self.numWarningLabel.parent, align=uiconst.CENTER) 157 self.t3Warning = EveCaptionSmall(name='t3Warning', state=uiconst.UI_NORMAL, align=uiconst.CENTERTOP, width=MAX_TEXT_WIDTH, autoFitToText=True, text=GetByLabel('UI/Fitting/FittingWindow/FittingManagement/InvalidT3Fit')) 158 self.t3Warning.SetRGBA(*WARNING_COLOR) 159 self.layoutGrid.AddCell(cellObject=self.t3Warning, colSpan=self.layoutGrid.columns) 160 self.HideT3Warning() 161 self.moreInfoIcon.display = False 162 self.moreInfoIcon.LoadTooltipPanel = self.LoadMissingTooltip 163 self.layoutGrid.FillRow() 164 165 def BuildRefreshInventory(self): 166 self.refreshCont = Transform(parent=self.layoutGrid, pos=(0, 0, 32, 32), align=uiconst.CENTER) 167 self.refreshIcon = ButtonIcon(name='refreshSprite', parent=self.refreshCont, width=32, height=32, align=uiconst.CENTER, texturePath=REFRESH_TEXTUREPATH, iconSize=32, func=self.OnRefreshClicked) 168 self.refreshIcon.hint = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/RefreshInventoryStatusHint') 169 170 def OnRefreshClicked(self, *args): 171 uthread.new(self.refreshCont.StartRotationCycle, cycles=1) 172 self.RefreshInventory() 173 174 def RefreshInventory(self): 175 self.LoadEquipCombo() 176 self.SetEquipmentText() 177 self.SetInventoryStatus() 178 179 def OnEquipLocationChanged(self, combo, key, val): 180 self.RefreshInventory() 181 182 def BuildAvailableShipsUI(self): 183 self.shipCounter = EveCaptionMedium(name='shipCounter', parent=self.missingLayoutGrid, state=uiconst.UI_NORMAL, align=uiconst.CENTERRIGHT, left=4, text='000') 184 self.shipCounter.LoadTooltipPanel = self.LoadShipCounterTooltipPanel 185 self.shipCounter.missingDict = {} 186 shipText = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/PackagedShipsInHangar') 187 self.availableShipsLabel = EveLabelLarge(name='availableShipsLabel', parent=self.missingLayoutGrid, state=uiconst.UI_NORMAL, text=shipText, align=uiconst.CENTERLEFT, width=MAX_TEXT_WIDTH, autoFitToText=True) 188 self.availableShipsLabel.hint = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/PackagedShipsInHangarHint') 189 self.layoutGrid.FillRow() 190 191 def BuildEquipmentUI(self): 192 self.equipmentCounter = EveCaptionMedium(name='equipmentCounter', parent=self.missingLayoutGrid, state=uiconst.UI_NORMAL, align=uiconst.CENTERRIGHT, left=4, text='000') 193 self.equipmentCounter.LoadTooltipPanel = self.LoadEqCounterTooltipPanel 194 self.equipmentCounter.missingDict = {} 195 self.availableEquipmentLabel = EveLabelLarge(name='availableEquipmentLabel', parent=self.missingLayoutGrid, state=uiconst.UI_NORMAL, text='', align=uiconst.CENTERLEFT, width=MAX_TEXT_WIDTH, autoFitToText=True) 196 self.SetEquipmentText() 197 self.layoutGrid.FillRow() 198 199 def SetEquipmentText(self): 200 locationID = self.equipmentLocationCombo.GetValue() 201 if locationID is None: 202 locationName = GetByLabel('UI/Inventory/ItemHangar') 203 else: 204 locationName = cfg.evelocations.Get(locationID).name or self.equipmentLocationCombo.GetKey() 205 eqText = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/RoundsOfFittingsInLocation', locationName=locationName) 206 self.availableEquipmentLabel.text = eqText 207 208 def BuildProgressUI(self): 209 self.progressCont = Container(parent=self.sr.main, height=36, align=uiconst.TOBOTTOM, padding=(10, 0, 10, 10)) 210 self.progressCounter = EveCaptionMedium(name='progressCounter', parent=self.progressCont, state=uiconst.UI_NORMAL, align=uiconst.CENTERTOP) 211 self.progressBar = ProgressBar(parent=self.progressCont, height=10, align=uiconst.TOBOTTOM) 212 self.progressCont.display = False 213 214 def MakeRigCbUI(self): 215 checked = settings.user.ui.Get('fitting_rigCB', True) 216 text = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/FitRigs') 217 self.rigCB = Checkbox(name='rigCB', text=text, OnChange=self.OnCbChanged, left=LEFT_EDGE, checked=checked, settingsPath=('user', 'ui'), settingsKey='fitting_rigCB') 218 self.rigCB.hint = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/FitRigsHint') 219 self.layoutGrid.AddCell(cellObject=self.rigCB, colSpan=self.layoutGrid.columns) 220 221 def OnNumChanged(self, *args): 222 self.onNumChangedTimer = AutoTimer(100, self.SetInventoryStatus) 223 224 def OnCbChanged(self, *args): 225 self.SetInventoryStatus() 226 227 def OpenFitting(self, *args): 228 sm.GetService('fittingSvc').DisplayFitting(self.fitting) 229 230 def LoadWindow(self, fitting, qty = 1): 231 self.fitting = fitting 232 self.shipCounter.missingDict = {} 233 self.equipmentCounter.missingDict = {} 234 shipTypeID = fitting.shipTypeID 235 self.shipIcon.LoadIconByTypeID(shipTypeID) 236 uix.GetTechLevelIcon(self.techSprite, typeID=shipTypeID) 237 self.numToFitEdit.SetValue(qty) 238 self.fitNameEdit.SetValue(fitting.name) 239 self.shipNameLabel.text = GetShowInfoLink(shipTypeID, evetypes.GetName(shipTypeID)) 240 self.VerifyT3Fit() 241 self.RefreshInventory() 242 self._ApplyFixedWindowSize() 243 self.RegisterPositionAndSize() 244 self.Maximize() 245 246 def _ApplyFixedWindowSize(self): 247 self.missingLayoutGrid.RefreshGridLayout() 248 self.layoutGrid.RefreshGridLayout() 249 layoutWidth, layoutHeight = self.layoutGrid.GetSize() 250 newHeight = layoutHeight + self.fitBtn.height + self.progressCont.height + self.topParent.height 251 height = max(newHeight, self.default_height) 252 width = max(layoutWidth, self.default_width) 253 width, height = self.GetWindowSizeForContentSize(width, height) 254 self.SetFixedWidth(width) 255 self.SetFixedHeight(height) 256 257 def SetInventoryStatus(self): 258 self.onNumChangedTimer = None 259 fitting = self.fitting 260 shipTypeID = fitting.shipTypeID 261 fittingSvc = sm.GetService('fittingSvc') 262 fittingObj = Fitting(fitting.fitData, None) 263 itemTypes = fittingObj.GetQuantityByType() 264 modulesByFlag = fittingObj.GetModulesByFlag() 265 rigsByFlags = fittingObj.GetRigsByFlag() 266 rigsToFit = bool(rigsByFlags) 267 if rigsToFit: 268 self.rigCB.display = True 269 else: 270 self.rigCB.display = False 271 numToFit = self.numToFitEdit.GetValue() 272 self.tryingToFitNum = numToFit 273 maxAvailableFitting, missingForFullFit = self._GetMaxAvailabeAndMissingForFullFit(itemTypes, modulesByFlag, numToFit) 274 nonSingletonShipsNumDict = fittingSvc.GetQtyInLocationByTypeIDs([shipTypeID], onlyGetNonSingletons=True) 275 packagedShipsNum = nonSingletonShipsNumDict.get(shipTypeID, 0) 276 canFitNum = min(packagedShipsNum, numToFit) 277 if maxAvailableFitting is not None: 278 canFitNum = min(canFitNum, maxAvailableFitting) 279 self.canFitNum = canFitNum 280 btnText = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/FitShips', numToFit=self.canFitNum) 281 self.fitBtn.SetLabel(btnText) 282 self.UpdateFitBtnState() 283 missingNumShips = max(0, numToFit - packagedShipsNum) 284 if missingNumShips: 285 missingDict = {shipTypeID: missingNumShips} 286 else: 287 missingDict = {} 288 self.shipCounter.missingDict = missingDict 289 if missingForFullFit: 290 missingDict = missingForFullFit 291 else: 292 missingDict = {} 293 self.equipmentCounter.missingDict = missingDict 294 if missingForFullFit or missingNumShips: 295 missingText = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/MissingShipEquipment') 296 self.numWarningLabel.text = missingText 297 self.moreInfoIcon.display = True 298 self.moreInfoIcon.left = self.numWarningLabel.textwidth / 2 + 10 299 if sm.GetService('publicQaToolsClient').CanGiveItemForMultifit(): 300 self.spawnFitBtn.Enable() 301 else: 302 self.numWarningLabel.text = '' 303 self.numWarningLabel.height = 0 304 self.moreInfoIcon.display = False 305 if sm.GetService('publicQaToolsClient').CanGiveItemForMultifit(): 306 self.spawnFitBtn.Disable() 307 self.SetAvailabilityShipOrEq(self.shipCounter, packagedShipsNum, numToFit) 308 self.SetAvailabilityShipOrEq(self.equipmentCounter, maxAvailableFitting, numToFit) 309 310 def UpdateFitBtnState(self): 311 if self.canFitNum < 1 or self.IsInvalidT3Fit(): 312 self.fitBtn.Disable() 313 else: 314 self.fitBtn.Enable() 315 316 def _GetMaxAvailabeAndMissingForFullFit(self, itemTypes, modulesByFlag, numToFit): 317 locationID = self.equipmentLocationCombo.GetValue() 318 fittingSvc = sm.GetService('fittingSvc') 319 qtyByTypeID = fittingSvc.GetQtyInLocationByTypeIDs(itemTypes, locationID=locationID) 320 rigTypeIDs = {t for f, t in modulesByFlag.iteritems() if f in const.rigSlotFlags} 321 maxAvailableFitting, missingForFullFit = fittingSvc.GetMaxAvailabeAndMissingForFullFit(True, itemTypes, numToFit, qtyByTypeID, rigTypeIDs) 322 return (maxAvailableFitting, missingForFullFit) 323 324 def SetAvailabilityShipOrEq(self, label, available, numToFit): 325 if available is None: 326 label.text = '-' 327 label.SetRGBA(*NORMAL_COLOR) 328 return 329 label.text = available 330 if available < numToFit: 331 label.SetRGBA(*WARNING_COLOR) 332 else: 333 label.SetRGBA(*NORMAL_COLOR) 334 335 def DoFitShips(self, *args): 336 fitting = self.fitting 337 fitRigs = self.rigCB.GetValue() 338 numToActuallyFit = self.canFitNum 339 fittingName = self.fitNameEdit.GetValue() 340 if fittingName is None or fittingName.strip() == '': 341 fittingName = fitting.name or evetypes.GetName(fitting.shipTypeID) 342 fittingName = StripTags(fittingName) 343 fittingSvc = sm.GetService('fittingSvc') 344 fittingObj = Fitting(fitting.fitData, None) 345 rigsToFit = fittingObj.GetRigsByFlag() 346 rigsToFit = bool(rigsToFit) 347 if fitRigs or not rigsToFit: 348 cargoItemsByType = {} 349 else: 350 cargoItemsByType = defaultdict(int) 351 for flagID, typeID in fittingObj.GetModulesByFlag().iteritems(): 352 if flagID in const.rigSlotFlags: 353 cargoItemsByType[typeID] += 1 354 355 cargoItemsByType = dict(cargoItemsByType) 356 if session.stationid: 357 stationController = StationController(itemID=session.stationid) 358 elif InStructure(): 359 stationController = StructureController(itemID=session.structureid) 360 else: 361 return 362 CheckCanAccessService('fitting', stationController) 363 equipmentLocationID = self.equipmentLocationCombo.GetValue() 364 _, missingForFullFit = self._GetMaxAvailabeAndMissingForFullFit(fittingObj.GetQuantityByType(), fittingObj.GetModulesByFlag(), numToActuallyFit) 365 if missingForFullFit: 366 self.SetInventoryStatus() 367 prompt_player_fsd_dialog('uiwarning03') 368 return 369 try: 370 fitInfo = fittingObj.GetKeyValForApplyingFit() 371 self.PrepareForMultiFitCall() 372 fittingSvc.DoFitManyShips(fitting.shipTypeID, fitInfo, cargoItemsByType, fitRigs, fittingName, numToActuallyFit, itemContainerID=equipmentLocationID) 373 finally: 374 uthread.new(self.ResetUIAfterFitting) 375 376 def PrepareForMultiFitCall(self): 377 self.fitBtn.Disable() 378 self.cancelBtn.Disable() 379 self.isFitting = True 380 self.currentProgress = 0 381 self.progressCounter.text = self.currentProgress 382 self.progressCont.display = True 383 self.layoutGrid.Disable() 384 self.layoutGrid.opacity = 0.2 385 sm.RegisterForNotifyEvent(self, 'OnItemChange') 386 387 def ResetUIAfterFitting(self): 388 sm.UnregisterForNotifyEvent(self, 'OnItemChange') 389 self.isFitting = False 390 self.currentProgress = 0 391 uicore.animations.BlinkOut(self.progressCont, startVal=0.0, endVal=1.0, duration=0.5, loops=3, sleep=True) 392 self.progressCont.display = False 393 self.progressCounter.text = self.currentProgress 394 self.cancelBtn.Enable() 395 self.layoutGrid.Enable() 396 self.layoutGrid.opacity = 1.0 397 self.SetInventoryStatus() 398 399 def Cancel(self, *args): 400 self.CloseByUser() 401 402 def GetFittingDragData(self): 403 entry = KeyVal() 404 entry.fitting = self.fitting 405 entry.label = self.fitting.name 406 entry.displayText = self.fitting.name 407 entry.__guid__ = 'listentry.FittingEntry' 408 return [entry] 409 410 def LoadMissingTooltip(self, tooltipPanel, *args): 411 text = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/MissingItems', numToFit=self.tryingToFitNum, fittingName=self.fitting.name) 412 tooltipPanel.AddLabelLarge(text=text, padBottom=8) 413 self.LoadShipCounterTooltipPanel(tooltipPanel, singleGroupShowing=False) 414 self.LoadEqCounterTooltipPanel(tooltipPanel, singleGroupShowing=False) 415 missingDict = {} 416 missingDict.update(self.shipCounter.missingDict) 417 missingDict.update(self.equipmentCounter.missingDict) 418 self.AddBuyAllBtn(tooltipPanel, missingDict) 419 420 def LoadShipCounterTooltipPanel(self, tooltipPanel, *args, **kwargs): 421 missingDict = self.shipCounter.missingDict 422 if not missingDict: 423 return 424 singleGroupShowing = kwargs.get('singleGroupShowing', True) 425 text = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/MissingShips', numToFit=self.tryingToFitNum, fittingName=self.fitting.name) 426 return self.LoadCounterTooltip(tooltipPanel, missingDict, text, singleGroupShowing) 427 428 def LoadEqCounterTooltipPanel(self, tooltipPanel, *args, **kwargs): 429 missingDict = self.equipmentCounter.missingDict 430 if not missingDict: 431 return 432 singleGroupShowing = kwargs.get('singleGroupShowing', True) 433 text = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/MissingEquipment', numToFit=self.tryingToFitNum, fittingName=self.fitting.name) 434 self.LoadCounterTooltip(tooltipPanel, missingDict, text, singleGroupShowing) 435 436 def LoadCounterTooltip(self, tooltipPanel, missingDict, text, singleGroupShowing = True): 437 tooltipPanel.LoadGeneric1ColumnTemplate() 438 tooltipPanel.state = uiconst.UI_NORMAL 439 if singleGroupShowing: 440 tooltipPanel.AddLabelLarge(text=text, padBottom=8) 441 typeList = [] 442 for eachTypeID, eachQty in missingDict.iteritems(): 443 typeName = evetypes.GetName(eachTypeID) 444 typeList.append((typeName.lower(), (eachTypeID, eachQty))) 445 446 typeList = SortListOfTuples(typeList) 447 for eachTypeID, eachQty in typeList[:MAX_TOOLTIP_ENTRIES]: 448 typeCont = TooltipEntry(parent=tooltipPanel, typeID=eachTypeID, qty=eachQty) 449 450 if len(typeList) > MAX_TOOLTIP_ENTRIES: 451 numItemsNotDisplayed = len(typeList) - MAX_TOOLTIP_ENTRIES 452 text = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/MoreItemTypesMissing', numMoreItems=numItemsNotDisplayed) 453 tooltipPanel.AddLabelMedium(text=text, align=uiconst.CENTERLEFT) 454 if singleGroupShowing: 455 self.AddBuyAllBtn(tooltipPanel, missingDict) 456 457 def AddBuyAllBtn(self, tooltipPanel, missingDict): 458 459 def BuyAll(*args): 460 BuyMultipleTypesWithQty(missingDict) 461 462 Button(parent=tooltipPanel, label=GetByLabel('UI/Market/MarketQuote/BuyAll'), func=BuyAll, align=uiconst.CENTER) 463 if session.role & ROLE_WORLDMOD == ROLE_WORLDMOD: 464 Button(parent=tooltipPanel, label='GM: Give all', func=self.GiveAllGM, align=uiconst.CENTERRIGHT, args=(missingDict,)) 465 if session.role & ROLE_GML == ROLE_GML: 466 Button(parent=tooltipPanel, label='GM: Load me all', func=self.LoadAllGM, align=uiconst.CENTERRIGHT, args=(missingDict,)) 467 468 def GiveAllGM(self, missingDict): 469 from eve.client.script.ui.shared.fittingScreen.missingItemsPopup import GiveAllGM 470 GiveAllGM(missingDict) 471 472 def LoadAllGM(self, missingDict): 473 from eve.client.script.ui.shared.fittingScreen.missingItemsPopup import LoadAllGM 474 LoadAllGM(missingDict) 475 476 def GiveAllPlayer(self, *args): 477 self.SetInventoryStatus() 478 missingDict = {} 479 missingDict.update(self.shipCounter.missingDict) 480 missingDict.update(self.equipmentCounter.missingDict) 481 commandString = '' 482 for typeID, qty in missingDict.iteritems(): 483 commandString += '{typeID}|{qty},'.format(typeID=typeID, qty=qty) 484 485 commandString = commandString[:-1] 486 sm.GetService('publicQaToolsClient').SlashCmd('/giveitem {}'.format(commandString)) 487 488 def OnItemChange(self, item, change, location): 489 if item.typeID != self.fitting.shipTypeID: 490 return 491 if const.ixSingleton in change: 492 self.currentProgress += 1 493 self.progressCounter.text = '%s / %s' % (self.currentProgress, self.canFitNum) 494 495 def OnSessionChanged(self, isRemote, sess, change): 496 if not IsDocked(): 497 self.CloseByUser() 498 499 def PulseLabel(self, label): 500 uicore.animations.FadeTo(label, startVal=0.65, endVal=0.9, duration=1.0, loops=uiconst.ANIM_REPEAT, curveType=uiconst.ANIM_WAVE) 501 502 def OnMultipleItemChange(self, *args): 503 if self.isFitting: 504 return 505 self.RefreshOnItemChanged_throttled() 506 507 @throttled(0.5) 508 def RefreshOnItemChanged_throttled(self): 509 self.RefreshInventory() 510 511 def VerifyT3Fit(self): 512 isInvalidT3Fit = self.IsInvalidT3Fit() 513 if isInvalidT3Fit: 514 self.t3Warning.text = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/InvalidT3Fit') 515 else: 516 self.HideT3Warning() 517 518 def IsInvalidT3Fit(self): 519 fitting = self.fitting 520 if not fitting: 521 self.HideT3Warning() 522 return False 523 shipTypeID = fitting.shipTypeID 524 if not IsModularShip(shipTypeID): 525 return False 526 clientDogmaStaticSvc = sm.GetService('clientDogmaStaticSvc') 527 subsystemSlotFlagsMissing = const.subsystemSlotFlags[:] 528 for typeID, flagID, qty in fitting.fitData: 529 if flagID in subsystemSlotFlagsMissing: 530 isObsolete = bool(clientDogmaStaticSvc.GetTypeAttribute(typeID, const.attributeModuleIsObsolete)) 531 if not isObsolete: 532 subsystemSlotFlagsMissing.remove(flagID) 533 if clientDogmaStaticSvc.GetTypeAttribute2(typeID, const.attributeFitsToShipType) != shipTypeID: 534 return True 535 536 return bool(subsystemSlotFlagsMissing) 537 538 def HideT3Warning(self): 539 self.t3Warning.text = '' 540 self.t3Warning.height = 0 541 542 543 class TooltipEntry(Container): 544 default_height = 32 545 default_align = uiconst.TOPLEFT 546 547 def ApplyAttributes(self, attributes): 548 Container.ApplyAttributes(self, attributes) 549 typeID = attributes.typeID 550 qty = attributes.qty 551 iconPadding = 1 * const.defaultPadding 552 typeIcon = Icon(name='typeIcon', parent=self, state=uiconst.UI_NORMAL, size=32, left=iconPadding, ignoreSize=True, typeID=typeID) 553 techIcon = uix.GetTechLevelIcon(typeID=typeID) 554 if techIcon: 555 techIcon.left = iconPadding 556 techIcon.SetParent(self, idx=0) 557 typeName = evetypes.GetName(typeID) 558 link = '<url="showinfo:%s">%s</url>' % (typeID, typeName) 559 text = '%sx %s' % (qty, link) 560 left = iconPadding * 2 + typeIcon.width + 10 561 label = EveLabelMedium(parent=self, left=left, text=text, state=uiconst.UI_NORMAL, align=uiconst.CENTERLEFT) 562 self.width = label.left + label.textwidth + 10