expeditedTransferUI.py (19500B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\planet\expeditedTransferUI.py 2 import math 3 import blue 4 import carbonui.const as uiconst 5 import eve.common.script.util.planetCommon as planetCommon 6 import evetypes 7 import localization 8 from carbon.common.script.util import timerstuff 9 from carbonui.button.const import HEIGHT_NORMAL 10 from carbonui.primitives.container import Container 11 from carbonui.primitives.containerAutoSize import ContainerAutoSize 12 from carbonui.uicore import uicore 13 from eve.client.script.ui.control import eveLabel, eveScroll 14 from carbonui.button.group import ButtonGroup 15 from eve.client.script.ui.control.entries.item import Item 16 from eve.client.script.ui.control.entries.status_bar import StatusBar 17 from eve.client.script.ui.control.entries.util import GetFromClass 18 from carbonui.control.window import Window 19 from eve.client.script.ui.control.gauge import Gauge 20 from eve.client.script.ui.shared.planet import planetCommon as planetCommonUI 21 from eve.client.script.ui.util import uix 22 from eveexceptions import UserError 23 from fsdBuiltData.common.planet import get_schematic_name 24 from player_messaging.client.ui_message import prompt_player_fsd_dialog 25 26 class ExpeditedTransferManagementWindow(Window): 27 __guid__ = 'form.ExpeditedTransferManagementWindow' 28 default_windowID = 'createTransfer' 29 default_iconNum = 'res:/ui/Texture/WindowIcons/items.png' 30 default_minSize = (500, 400) 31 default_width = 800 32 default_height = 500 33 default_isStackable = False 34 35 def ApplyAttributes(self, attributes): 36 Window.ApplyAttributes(self, attributes) 37 self.planet = attributes.planet 38 self.path = attributes.path 39 if not self.path or len(self.path) < 2: 40 raise UserError('CreateRouteTooShort') 41 colony = self.planet.GetColony(session.charid) 42 self.sourcePin = colony.GetPin(self.path[0]) 43 self.destinationPin = None 44 minBandwidth = None 45 prevID = None 46 for pinID in self.path: 47 pin = colony.GetPin(pinID) 48 if not pin: 49 raise UserError('RouteFailedValidationPinDoesNotExist') 50 if prevID is None: 51 prevID = pinID 52 continue 53 link = colony.GetLink(pin.id, prevID) 54 if link is None: 55 raise UserError('RouteFailedValidationLinkDoesNotExist') 56 if minBandwidth is None or minBandwidth > link.GetTotalBandwidth(): 57 minBandwidth = link.GetTotalBandwidth() 58 prevID = pinID 59 60 self.availableBandwidth = minBandwidth 61 sourceName = planetCommon.GetGenericPinName(self.sourcePin.typeID, self.sourcePin.id) 62 self.SetCaption(localization.GetByLabel('UI/PI/Common/ExpeditedTransferFrom', sourceName=sourceName)) 63 self.ConstructLayout() 64 self.SetSourcePinGaugeInfo() 65 self.scope = uiconst.SCOPE_INGAME 66 self.ResetPinContents() 67 self.SetDestination(colony.GetPin(self.path[-1])) 68 self.OnResizeUpdate() 69 self.updateTimer = timerstuff.AutoTimer(100, self.SetNextTransferText) 70 71 def ConstructLayout(self): 72 self.bottomCont = Container(name='bottomCont', parent=self.sr.main, align=uiconst.TOBOTTOM, height=HEIGHT_NORMAL, padding=(0, 8, 0, 0)) 73 self.leftCont = Container(name='leftCont', parent=self.sr.main, align=uiconst.TOLEFT_PROP, width=0.33, clipChildren=True) 74 self.middleCont = Container(name='middleCont', parent=self.sr.main, align=uiconst.TOLEFT_PROP, width=0.33, padding=(16, 0, 0, 0), clipChildren=True) 75 self.rightCont = Container(name='rightCont', parent=self.sr.main, align=uiconst.TOALL, padding=(16, 0, 0, 0), clipChildren=True) 76 colTopHeight = 80 77 self.sourcePinHeader = Container(name='pinHeader', parent=self.leftCont, align=uiconst.TOTOP, height=colTopHeight) 78 self.sourcePinList = Container(name='pinList', parent=self.leftCont, align=uiconst.TOALL, state=uiconst.UI_PICKCHILDREN) 79 self.transferHeader = ContainerAutoSize(name='transferHeader', parent=self.middleCont, align=uiconst.TOTOP, height=colTopHeight) 80 eveLabel.EveHeaderLarge(text=localization.GetByLabel('UI/PI/Common/ToBeTransferred'), parent=self.transferHeader, align=uiconst.TOTOP, state=uiconst.UI_NORMAL) 81 self.volumeText = eveLabel.EveLabelSmall(parent=self.transferHeader, align=uiconst.TOTOP, state=uiconst.UI_NORMAL, padTop=8) 82 self.timeText = eveLabel.EveLabelSmall(parent=self.transferHeader, align=uiconst.TOTOP, state=uiconst.UI_NORMAL, hint=localization.GetByLabel('UI/PI/Common/ExpeditedTransferProcessingHint')) 83 self.cooldownTimeText = eveLabel.EveLabelSmall(parent=self.transferHeader, align=uiconst.TOTOP, hint=localization.GetByLabel('UI/PI/Common/CoolDownTimeHint')) 84 self.transferListScroll = eveScroll.Scroll(parent=self.middleCont, name='transferList') 85 self.transferListScroll.sr.id = 'transferListScroll' 86 content = self.transferListScroll.sr.content 87 content.OnDropData = self.OnTransferScrollDropData 88 self.destPinHeader = Container(name='destPinHeader', parent=self.rightCont, align=uiconst.TOTOP, height=colTopHeight) 89 self.destPinList = Container(name='destPinList', parent=self.rightCont, align=uiconst.TOALL, state=uiconst.UI_PICKCHILDREN) 90 self.footerLeft = Container(name='footerLeft', parent=self.bottomCont, align=uiconst.TOLEFT_PROP, width=0.66) 91 self.footerRight = Container(name='footerRight', parent=self.bottomCont, align=uiconst.TOALL) 92 btns = [(localization.GetByLabel('UI/PI/Common/ExecuteTransfer'), 93 self.GoForTransfer, 94 (), 95 None)] 96 ButtonGroup(btns=btns, parent=self.footerRight) 97 hint = localization.GetByLabel('UI/PI/Common/ExpeditedTransferSplitHint') 98 btns = [(localization.GetByLabel('UI/PI/Common/Add'), 99 self.AddBtnClicked, 100 (), 101 None, 102 False, 103 False, 104 False, 105 hint), (localization.GetByLabel('UI/PI/Common/Remove'), 106 self.RemoveBtnClicked, 107 (), 108 None, 109 False, 110 False, 111 False, 112 hint)] 113 ButtonGroup(btns=btns, parent=self.footerLeft) 114 self.OnResizeUpdate() 115 eveLabel.EveHeaderLarge(text=planetCommon.GetGenericPinName(self.sourcePin.typeID, self.sourcePin.id), parent=self.sourcePinHeader, align=uiconst.TOTOP, maxLines=1, state=uiconst.UI_NORMAL) 116 self.sourcePinSubGauge = Gauge(parent=self.sourcePinHeader, value=0.0, color=planetCommonUI.PLANET_COLOR_STORAGE, label=localization.GetByLabel('UI/PI/Common/Capacity'), left=0, align=uiconst.TOTOP, state=uiconst.UI_NORMAL, padTop=8) 117 self.sourcePinListScroll = eveScroll.Scroll(parent=self.sourcePinList, name='pinList') 118 self.sourcePinListScroll.sr.id = 'sourcePinListScroll' 119 content = self.sourcePinListScroll.sr.content 120 content.OnDropData = self.OnSourceScrollDropData 121 self.destPinText = eveLabel.EveHeaderLarge(text='', parent=self.destPinHeader, align=uiconst.TOTOP, state=uiconst.UI_NORMAL, maxLines=1, padBottom=8) 122 self.destPinSubText = eveLabel.EveLabelLarge(text='', parent=self.destPinHeader, align=uiconst.TOTOP, top=5, state=uiconst.UI_HIDDEN) 123 self.destPinSubGauge = Gauge(parent=self.destPinHeader, value=0.0, color=planetCommonUI.PLANET_COLOR_STORAGE, label=localization.GetByLabel('UI/PI/Common/Capacity'), align=uiconst.TOTOP, state=uiconst.UI_HIDDEN, padTop=2) 124 self.destPinListScroll = eveScroll.Scroll(parent=self.destPinList) 125 self.destPinListScroll.sr.id = 'destPinListScroll' 126 127 def OnTransferScrollDropData(self, dragObj, nodes, *args): 128 if nodes[0].scroll.name == 'pinList': 129 self.AddCommodity(nodes) 130 131 def OnSourceScrollDropData(self, dragObj, nodes, *args): 132 if nodes[0].scroll.name == 'transferList': 133 self.RemoveCommodity(nodes) 134 135 def AddBtnClicked(self, *args): 136 selected = self.sourcePinListScroll.GetSelected() 137 self.AddCommodity(selected) 138 139 def RemoveBtnClicked(self, *args): 140 selected = self.transferListScroll.GetSelected() 141 self.RemoveCommodity(selected) 142 143 def AddCommodity(self, selected): 144 toMove = {} 145 if len(selected) == 1 and uicore.uilib.Key(uiconst.VK_SHIFT): 146 typeID = selected[0].typeID 147 typeName = planetCommonUI.GetProductNameAndTier(typeID) 148 ret = uix.QtyPopup(self.pinContents[typeID], 1, 1, None, localization.GetByLabel('UI/PI/Common/QuantityToTransfer', typeName=typeName)) 149 if ret and 'qty' in ret: 150 toMove[typeID] = min(self.pinContents[typeID], max(1, ret['qty'])) 151 else: 152 for entry in selected: 153 toMove[entry.typeID] = self.pinContents[entry.typeID] 154 155 if self.destPin.IsConsumer(): 156 toMove = self._ApplyConsumerFilter(toMove) 157 if not toMove: 158 raise UserError('ConsumerCantAcceptCommodities') 159 elif self.destPin.IsStorage(): 160 toMove = self._ApplyMaxAmountFilter(toMove) 161 for typeID, qty in toMove.iteritems(): 162 self.pinContents[typeID] -= qty 163 if self.pinContents[typeID] <= 0: 164 del self.pinContents[typeID] 165 if typeID not in self.transferContents: 166 self.transferContents[typeID] = 0 167 self.transferContents[typeID] += qty 168 169 self.RefreshLists() 170 171 def _ApplyConsumerFilter(self, toMove): 172 newToMove = {} 173 for typeID, qty in toMove.iteritems(): 174 remainingSpace = self.destPin.CanAccept(typeID, -1) 175 alreadyInTransfer = self.transferContents.get(typeID, 0) 176 if remainingSpace: 177 amount = min(remainingSpace - alreadyInTransfer, qty) 178 if amount > 0: 179 newToMove[typeID] = amount 180 181 return newToMove 182 183 def _ApplyMaxAmountFilter(self, toMove): 184 availableVolume = self.destPin.GetCapacity() - self.destPin.capacityUsed 185 availableVolume -= planetCommon.GetCommodityTotalVolume(self.transferContents) 186 transferVolume = planetCommon.GetCommodityTotalVolume(toMove) 187 if transferVolume >= availableVolume: 188 newToMove = {} 189 if len(toMove) == 1: 190 for typeID, quantity in toMove.iteritems(): 191 commodityVolume = evetypes.GetVolume(typeID) 192 maxAmount = int(math.floor(availableVolume / commodityVolume)) 193 newToMove[typeID] = maxAmount 194 195 prompt_player_fsd_dialog('ExpeditedTransferNotEnoughSpace') 196 return newToMove 197 else: 198 return toMove 199 200 def RemoveCommodity(self, selected): 201 toMove = {} 202 if len(selected) == 1 and uicore.uilib.Key(uiconst.VK_SHIFT): 203 typeID = selected[0].typeID 204 typeName = planetCommonUI.GetProductNameAndTier(typeID) 205 ret = uix.QtyPopup(self.transferContents[typeID], 1, 1, None, localization.GetByLabel('UI/PI/Common/QuantityToRemove', typeName=typeName)) 206 if ret and 'qty' in ret: 207 toMove[typeID] = min(self.transferContents[typeID], max(1, ret['qty'])) 208 else: 209 for entry in selected: 210 toMove[entry.typeID] = self.transferContents[entry.typeID] 211 212 for typeID, qty in toMove.iteritems(): 213 self.transferContents[typeID] -= qty 214 if self.transferContents[typeID] <= 0: 215 del self.transferContents[typeID] 216 if typeID not in self.pinContents: 217 self.pinContents[typeID] = 0 218 self.pinContents[typeID] += qty 219 220 self.RefreshLists() 221 222 def GoForTransfer(self, *args): 223 if len(self.transferContents) < 1: 224 raise UserError('PleaseSelectCommoditiesToTransfer') 225 for typeID, quantity in self.transferContents.iteritems(): 226 if typeID not in self.sourcePin.contents: 227 raise UserError('RouteFailedValidationExpeditedSourceLacksCommodity', {'typeName': evetypes.GetName(typeID)}) 228 if quantity > self.sourcePin.contents[typeID]: 229 raise UserError('RouteFailedValidationExpeditedSourceLacksCommodityQty', {'typeName': evetypes.GetName(typeID), 230 'qty': quantity}) 231 232 if not self.sourcePin.CanTransfer(self.transferContents): 233 raise UserError('RouteFailedValidationExpeditedSourceNotReady') 234 if len(self.transferContents) > 0: 235 self.ShowLoad() 236 try: 237 self.planet.TransferCommodities(self.path, self.transferContents) 238 finally: 239 self.ResetPinContents() 240 self.HideLoad() 241 242 self.CloseByUser() 243 244 def ResetPinContents(self, *args): 245 self.pinContents = self.sourcePin.contents.copy() 246 self.transferContents = {} 247 self.RefreshLists() 248 249 def RefreshLists(self, *args): 250 pinListItems = [] 251 for typeID, qty in self.pinContents.iteritems(): 252 pinListItems.append(GetFromClass(ExpeditedDraggableItem, {'itemID': None, 253 'typeID': typeID, 254 'label': '<t>%d<t>%s' % (qty, planetCommonUI.GetProductNameAndTier(typeID)), 255 'getIcon': 1, 256 'quantity': qty, 257 'OnDropData': self.OnSourceScrollDropData})) 258 259 transferListItems = [] 260 for typeID, qty in self.transferContents.iteritems(): 261 transferListItems.append(GetFromClass(ExpeditedDraggableItem, {'itemID': None, 262 'typeID': typeID, 263 'label': '<t>%d<t>%s' % (qty, planetCommonUI.GetProductNameAndTier(typeID)), 264 'getIcon': 1, 265 'quantity': qty, 266 'OnDropData': self.OnTransferScrollDropData})) 267 268 self.sourcePinListScroll.Load(contentList=pinListItems, noContentHint=localization.GetByLabel('UI/PI/Common/StorehouseIsEmpty'), headers=[localization.GetByLabel('UI/Common/Type'), localization.GetByLabel('UI/Common/Quantity'), localization.GetByLabel('UI/Common/Name')]) 269 self.transferListScroll.Load(contentList=transferListItems, noContentHint=localization.GetByLabel('UI/PI/Common/NoItemsFound'), headers=[localization.GetByLabel('UI/Common/Type'), localization.GetByLabel('UI/Common/Quantity'), localization.GetByLabel('UI/Common/Name')]) 270 transferVolume = planetCommon.GetCommodityTotalVolume(self.transferContents) 271 self.volumeText.text = localization.GetByLabel('UI/PI/Common/VolumeAmount', amount=transferVolume) 272 self.SetNextTransferText() 273 self.SetCooldownTimeText() 274 275 def SetNextTransferText(self): 276 if self.sourcePin.lastRunTime is None or self.sourcePin.lastRunTime <= blue.os.GetWallclockTime(): 277 self.timeText.text = localization.GetByLabel('UI/PI/Common/NextTransferNow') 278 else: 279 self.timeText.text = localization.GetByLabel('UI/PI/Common/NextTransferTime', time=self.sourcePin.lastRunTime - blue.os.GetWallclockTime()) 280 281 def SetCooldownTimeText(self): 282 time = planetCommon.GetExpeditedTransferTime(self.availableBandwidth, self.transferContents) 283 self.cooldownTimeText.text = localization.GetByLabel('UI/PI/Common/CooldownTime', time=time) 284 285 def SetSourcePinGaugeInfo(self): 286 self.sourcePinSubGauge.state = uiconst.UI_DISABLED 287 self.sourcePinSubGauge.SetText(localization.GetByLabel('UI/PI/Common/Capacity')) 288 usageRatio = self.sourcePin.capacityUsed / self.sourcePin.GetCapacity() 289 self.sourcePinSubGauge.SetSubText(localization.GetByLabel('UI/PI/Common/CapacityProportionUsed', capacityUsed=self.sourcePin.capacityUsed, capacityMax=self.sourcePin.GetCapacity(), percentage=usageRatio * 100.0)) 290 self.sourcePinSubGauge.SetValue(usageRatio) 291 292 def RefreshDestinationPinInfo(self): 293 self.destPinSubText.state = uiconst.UI_HIDDEN 294 self.destPinSubGauge.state = uiconst.UI_HIDDEN 295 if not self.destPin: 296 self.destPinText.text = localization.GetByLabel('UI/PI/Common/NoOriginSelected') 297 self.destPinSubText.text = '' 298 self.destPinSubText.state = uiconst.UI_DISABLED 299 self.destPinListScroll.Load(contentList=[], noContentHint=localization.GetByLabel('UI/PI/Common/NoOriginSelected')) 300 return 301 self.destPinText.text = localization.GetByLabel('UI/PI/Common/TransferDestinationName', typeName=planetCommon.GetGenericPinName(self.destPin.typeID, self.destPin.id)) 302 scrollHeaders = [] 303 scrollContents = [] 304 scrollNoContentText = '' 305 if self.destPin.IsConsumer(): 306 self.destPinSubText.state = uiconst.UI_DISABLED 307 if self.destPin.schematicID is None: 308 self.destPinSubText.text = localization.GetByLabel('UI/PI/Common/NoSchematicInstalled') 309 scrollNoContentText = localization.GetByLabel('UI/PI/Common/NoSchematicInstalled') 310 else: 311 self.destPinSubText.text = localization.GetByLabel('UI/PI/Common/SchematicName', schematicName=get_schematic_name(self.destPin.schematicID)) 312 scrollHeaders = [] 313 demands = self.destPin.GetConsumables() 314 for typeID, qty in demands.iteritems(): 315 remainingSpace = self.destPin.CanAccept(typeID, -1) 316 load = qty - remainingSpace 317 fraction = load / float(qty) 318 entry = GetFromClass(StatusBar, {'label': planetCommonUI.GetProductNameAndTier(typeID), 319 'text': localization.GetByLabel('UI/PI/Common/UnitQuantityAndDemand', quantity=load, demand=qty), 320 'value': fraction, 321 'iconID': evetypes.GetIconID(typeID)}) 322 scrollContents.append(entry) 323 324 elif self.destPin.IsStorage(): 325 self.destPinSubGauge.state = uiconst.UI_DISABLED 326 self.destPinSubGauge.SetText(localization.GetByLabel('UI/PI/Common/Capacity')) 327 usageRatio = self.destPin.capacityUsed / self.destPin.GetCapacity() 328 self.destPinSubGauge.SetSubText(localization.GetByLabel('UI/PI/Common/CapacityProportionUsed', capacityUsed=self.destPin.capacityUsed, capacityMax=self.destPin.GetCapacity(), percentage=usageRatio * 100.0)) 329 self.destPinSubGauge.SetValue(usageRatio) 330 scrollHeaders = [localization.GetByLabel('UI/Common/Type'), localization.GetByLabel('UI/Common/Quantity'), localization.GetByLabel('UI/Common/Name')] 331 contents = self.destPin.GetContents() 332 for typeID, qty in contents.iteritems(): 333 lbl = '<t>%d<t>%s' % (qty, planetCommonUI.GetProductNameAndTier(typeID)) 334 scrollContents.append(GetFromClass(ExpeditedDraggableItem, {'itemID': None, 335 'typeID': typeID, 336 'label': lbl, 337 'getIcon': 1, 338 'quantity': qty})) 339 340 scrollNoContentText = localization.GetByLabel('UI/PI/Common/StorehouseIsEmpty') 341 self.destPinListScroll.Load(contentList=scrollContents, headers=scrollHeaders, noContentHint=scrollNoContentText) 342 343 def SetDestination(self, destinationPin): 344 self.destPin = destinationPin 345 self.RefreshDestinationPinInfo() 346 347 348 class ExpeditedDraggableItem(Item): 349 __guid__ = 'listentry.CustomsItem' 350 351 def LoadTooltipPanel(self, tooltipPanel, *args): 352 planetCommonUI.LoadProductTooltipPanel(tooltipPanel, self.sr.node.typeID)