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

BasePinContainer.py (42526B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\planet\pinContainers\BasePinContainer.py
      2 import carbonui.const as uiconst
      3 import dogma.const
      4 import dogma.data
      5 import eve.common.script.util.planetCommon as planetCommon
      6 import evetypes
      7 import inventorycommon.const as invconst
      8 import localization
      9 import utillib
     10 from carbon.common.script.util.format import FmtDist, FmtAmt
     11 from carbon.common.script.util.timerstuff import AutoTimer
     12 from carbonui import Density, fontconst, TextColor
     13 from carbonui.control.button import Button
     14 from carbonui.button.const import HEIGHT_COMPACT
     15 from carbonui.control.singlelineedits.singleLineEditInteger import SingleLineEditInteger
     16 from carbonui.decorative.panelUnderlay import PanelUnderlay
     17 from carbonui.primitives.container import Container
     18 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     19 from carbonui.primitives.frame import Frame
     20 from carbonui.primitives.gridcontainer import GridContainer
     21 from clientsettings.setting import CharSettingNumeric
     22 from carbonui.uianimations import animations
     23 from carbonui.uicore import uicore
     24 from carbonui.util.various_unsorted import SortListOfTuples
     25 from dogma.attributes.format import GetFormatAndValue, FormatUnit
     26 from carbonui.button.group import ButtonGroup
     27 from carbonui.control.buttonIcon import ButtonIcon
     28 from eve.client.script.ui.control.entries.generic import Generic
     29 from eve.client.script.ui.control.entries.item import Item
     30 from eve.client.script.ui.control.entries.util import GetFromClass
     31 from eve.client.script.ui.control.eveIcon import Icon
     32 from eve.client.script.ui.control.eveLabel import EveLabelSmall, Label
     33 from eve.client.script.ui.control.eveScroll import Scroll
     34 from carbonui.control.window import Window
     35 from eve.client.script.ui.shared.planet import planetCommon as planetCommonUI
     36 from eve.client.script.ui.shared.planet.planetConst import GetPinNameShort
     37 from eve.client.script.ui.shared.planet.planetItemEntry import PlanetItemEntry
     38 from eveexceptions import UserError
     39 from localization import GetByLabel
     40 HEIGHT_SETTING_KEY = 'PiActionContainerHeight_%s'
     41 
     42 class BasePinContainer(Window):
     43     __notifyevents__ = ['OnRefreshPins', 'ProcessColonyDataSet']
     44     default_width = 600
     45     default_minSize = (300, 185)
     46     default_state = uiconst.UI_NORMAL
     47     default_opacity = 0.0
     48     default_isCollapseable = False
     49     default_isLightBackground = True
     50     default_isStackable = False
     51     default_isMinimizable = False
     52     default_isOverlayable = False
     53     default_windowID = 'PlanetPinWindow'
     54     INFO_CONT_HEIGHT = 70
     55     panelIDs = [planetCommonUI.PANEL_STATS,
     56      planetCommonUI.PANEL_LINKS,
     57      planetCommonUI.PANEL_ROUTES,
     58      planetCommonUI.PANEL_DECOMMISSION]
     59     createRouteBtn = None
     60 
     61     def GetBaseHeight(self):
     62         _, content_height = self.main.GetAbsoluteSize()
     63         _, height = self.GetWindowSizeForContentSize(height=content_height)
     64         return height
     65 
     66     def ApplyAttributes(self, attributes):
     67         Window.ApplyAttributes(self, attributes)
     68         panelID = attributes.panelID
     69         self.planetUISvc = sm.GetService('planetUI')
     70         self.planetSvc = sm.GetService('planetSvc')
     71         self.pin = attributes.Get('pin', None)
     72         self.showingActionContainer = False
     73         self.currentRoute = None
     74         self.showNext = None
     75         self.panelID = None
     76         self.commodityToRoute = None
     77         self.buttonTextValue = ''
     78         self.panelFuncsByID = self._GetPanelFuncsByID()
     79         self.buttonsByID = {}
     80         self.main = ContainerAutoSize(parent=self.sr.main, name='main', padding=3, state=uiconst.UI_PICKCHILDREN, align=uiconst.TOTOP, alignMode=uiconst.TOTOP, callback=self._on_main_size_changed, only_use_callback_when_size_changes=True)
     81         infoCont = Container(parent=self.main, name='infoCont', padding=5, align=uiconst.TOTOP, height=self.INFO_CONT_HEIGHT * fontconst.fontSizeFactor)
     82         self.infoContLeft = Container(name='leftCol', parent=infoCont, align=uiconst.TOLEFT_PROP, width=0.5, padRight=6)
     83         self.infoContRight = Container(name='rightCol', parent=infoCont, align=uiconst.TOLEFT_PROP, width=0.5)
     84         self._GetInfoCont()
     85         self._UpdateInfoCont()
     86         self.buttonCont = GridContainer(parent=self.main, name='buttonCont', height=40, align=uiconst.TOTOP, padding=(-1, 0, -1, 0))
     87         PanelUnderlay(bgParent=self.buttonCont)
     88         self.buttonCont.lines = 1
     89         self.buttonCont.columns = 6
     90         self.buttonTextCont = self._DrawAlignTopCont(22, 'buttonTextCont')
     91         self.buttonText = EveLabelSmall(parent=self.buttonTextCont, align=uiconst.CENTER, color=(1.0, 1.0, 1.0, 1.0), state=uiconst.UI_NORMAL)
     92         self.buttonTextCont.height = max(22, self.buttonText.textheight)
     93         self.actionCont = Container(parent=self.sr.main, name='actionCont', padding=(6, 0, 6, 6))
     94         self.SetCaption(self._GetPinName())
     95         self.LoadActionButtons()
     96         uicore.animations.FadeTo(self, 0.0, 1.0, duration=0.3)
     97         self.updateInfoContTimer = AutoTimer(100, self._UpdateInfoCont)
     98         sm.GetService('audio').SendUIEvent('msg_pi_pininteraction_open_play')
     99         self.UpdateWindowHeight(animate=False)
    100         if panelID and panelID in self.panelIDs:
    101             self.ShowPanel(panelID)
    102 
    103     def GetID(self):
    104         return self.pin.id
    105 
    106     def ShowDefaultPanel(self):
    107         if hasattr(self, 'defaultPanelID'):
    108             self.ShowPanel(self.defaultPanelID)
    109 
    110     def _GetPinName(self):
    111         return planetCommon.GetGenericPinName(self.pin.typeID, self.pin.id)
    112 
    113     def _GetInfoCont(self):
    114         pass
    115 
    116     def _GetPanelFuncsByID(self):
    117         return {planetCommonUI.PANEL_STATS: self.PanelShowStats,
    118          planetCommonUI.PANEL_LINKS: self.PanelShowLinks,
    119          planetCommonUI.PANEL_ROUTES: self.PanelShowRoutes,
    120          planetCommonUI.PANEL_DECOMMISSION: self.PanelDecommissionPin,
    121          planetCommonUI.PANEL_UPGRADE: self.PanelUpgrade,
    122          planetCommonUI.PANEL_LAUNCH: self.PanelLaunch,
    123          planetCommonUI.PANEL_STORAGE: self.PanelShowStorage,
    124          planetCommonUI.PANEL_PRODUCTS: self.PanelShowProducts,
    125          planetCommonUI.PANEL_SCHEMATICS: self.PanelShowSchematics,
    126          planetCommonUI.PANEL_SURVEYFORDEPOSITS: self.OpenSurveyWindow,
    127          planetCommonUI.PANEL_UPGRADELINK: self.PanelUpgrade,
    128          planetCommonUI.PANEL_TRANSFER: self.PanelSelectTransferDest,
    129          planetCommonUI.PANEL_CREATEROUTE: self.PanelCreateRoute}
    130 
    131     def OpenSurveyWindow(self):
    132         pass
    133 
    134     def PanelShowSchematics(self):
    135         pass
    136 
    137     def PanelLaunch(self):
    138         pass
    139 
    140     def PanelUpgrade(self):
    141         pass
    142 
    143     def ShowPanel(self, panelID, *args):
    144         self._UpdateSelectedButton(panelID)
    145         _, label = planetCommonUI.PANELDATA[panelID]
    146         name = localization.GetByLabel(label)
    147         self.buttonText.text = name
    148         self.buttonTextValue = name
    149         if self.showingActionContainer:
    150             self.showNext = panelID
    151             return
    152         self.showNext = None
    153         self.showingActionContainer = True
    154         self.actionCont.Flush()
    155         if self.panelID != panelID:
    156             func = self.panelFuncsByID[panelID]
    157             if args:
    158                 cont = func(*args)
    159             else:
    160                 cont = func()
    161             if cont:
    162                 cont.state = uiconst.UI_HIDDEN
    163                 self.panelID = panelID
    164                 cont.opacity = 0.0
    165                 self.ResizeActionCont(panelID)
    166                 cont.state = uiconst.UI_PICKCHILDREN
    167                 animations.FadeIn(cont, duration=0.25)
    168                 uicore.registry.SetFocus(cont)
    169         else:
    170             self.HideCurrentPanel()
    171         self.showingActionContainer = False
    172         if self.showNext:
    173             self.ShowPanel(self.showNext)
    174 
    175     def _UpdateSelectedButton(self, panelID):
    176         oldBtn = self.buttonsByID.get(self.panelID, None)
    177         if oldBtn:
    178             oldBtn.SetDeselected()
    179         btn = self.buttonsByID.get(panelID, None)
    180         if btn:
    181             btn.SetSelected()
    182 
    183     def HideCurrentPanel(self):
    184         self.actionCont.Flush()
    185         self.UpdateWindowHeight()
    186         self._UpdateSelectedButton(None)
    187         self.panelID = None
    188         self.buttonTextValue = ''
    189 
    190     def _DrawAlignTopCont(self, height, name, padding = (0, 0, 0, 0), state = uiconst.UI_PICKCHILDREN):
    191         return Container(parent=self.main, name=name, pos=(0,
    192          0,
    193          0,
    194          height), padding=padding, state=state, align=uiconst.TOTOP)
    195 
    196     def OnIconButtonMouseEnter(self, iconButton, *args):
    197         ButtonIcon.OnMouseEnter(iconButton, *args)
    198         self.buttonText.text = iconButton.name
    199 
    200     def OnIconButtonMouseExit(self, iconButton, *args):
    201         ButtonIcon.OnMouseExit(iconButton, *args)
    202         self.buttonText.text = self.buttonTextValue
    203 
    204     def LoadActionButtons(self):
    205         iconSize = 32
    206         w = self.width - 6
    207         maxIcons = 7.0
    208         numButtons = len(self.panelIDs)
    209         n = float(numButtons)
    210         pad = 5 + 1 * iconSize * (1.0 - n / maxIcons)
    211         w -= 2 * pad
    212         self.buttonCont.columns = numButtons
    213         for i, panelID in enumerate(self.panelIDs):
    214             iconPath, cerberusPath = planetCommonUI.PANELDATA[panelID]
    215             panelName = localization.GetByLabel(cerberusPath)
    216             if i == 0:
    217                 self.defaultPanel = self.panelFuncsByID[panelID]
    218                 self.defaultPanelID = panelID
    219             cont = Container(name=panelName, parent=self.buttonCont)
    220             btn = ButtonIcon(texturePath=iconPath, parent=cont, align=uiconst.CENTER, name=panelName, width=iconSize, height=iconSize, iconSize=iconSize, func=self._OnIconButtonClicked, args=(panelID,))
    221             btn.OnMouseEnter = (self.OnIconButtonMouseEnter, btn)
    222             btn.OnMouseExit = (self.OnIconButtonMouseExit, btn)
    223             self.buttonsByID[panelID] = btn
    224 
    225     def _OnIconButtonClicked(self, panelID, *args):
    226         self.ShowPanel(panelID)
    227 
    228     def CloseByUser(self, *args):
    229         self.planetUISvc.eventManager.DeselectCurrentlySelected()
    230 
    231     def PanelShowLinks(self):
    232         cont = Container(parent=self.actionCont, state=uiconst.UI_HIDDEN)
    233         self.linkScroll = Scroll(parent=cont, name='linksScroll', align=uiconst.TOALL)
    234         self.linkScroll.sr.id = 'planetBasePinLinkScroll'
    235         self.LoadLinkScroll()
    236         btns = [[localization.GetByLabel('UI/PI/Common/CreateNew'), self._CreateNewLink, None], [localization.GetByLabel('UI/PI/Common/DeleteLink'), self._DeleteLink, None]]
    237         ButtonGroup(btns=btns, idx=0, parent=cont)
    238         return cont
    239 
    240     def LoadLinkScroll(self):
    241         scrolllist = []
    242         planet = sm.GetService('planetUI').GetCurrentPlanet()
    243         colony = planet.GetColony(session.charid)
    244         links = colony.colonyData.GetLinksForPin(self.pin.id)
    245         for linkedPinID in links:
    246             link = colony.GetLink(self.pin.id, linkedPinID)
    247             linkedPin = colony.GetPin(linkedPinID)
    248             distance = link.GetDistance()
    249             bandwidthUsed = link.GetBandwidthUsage()
    250             percentageUsed = 100 * (bandwidthUsed / link.GetTotalBandwidth())
    251             data = utillib.KeyVal()
    252             data.label = '%s<t>%s<t>%s' % (planetCommon.GetGenericPinName(linkedPin.typeID, linkedPin.id), FmtDist(distance), localization.GetByLabel('UI/Common/Percentage', percentage=percentageUsed))
    253             data.Set('sort_%s' % localization.GetByLabel('UI/PI/Common/CapacityUsed'), percentageUsed)
    254             data.hint = ''
    255             data.OnMouseEnter = self.OnLinkEntryHover
    256             data.OnMouseExit = self.OnLinkEntryExit
    257             data.OnDblClick = self.OnLinkListentryDblClicked
    258             data.id = (link.endpoint1.id, link.endpoint2.id)
    259             sortBy = linkedPinID
    260             scrolllist.append((sortBy, GetFromClass(Generic, data)))
    261 
    262         scrolllist = SortListOfTuples(scrolllist)
    263         self.linkScroll.Load(contentList=scrolllist, noContentHint=localization.GetByLabel('UI/PI/Common/NoLinksPresent'), headers=[localization.GetByLabel('UI/PI/Common/Destination'), localization.GetByLabel('UI/Common/Distance'), localization.GetByLabel('UI/PI/Common/CapacityUsed')])
    264 
    265     def IsSomeProductUnrouted(self):
    266         colonyData = self._GetColonyData()
    267         if colonyData:
    268             return colonyData.IsSomeProductUnrouted(self.pin.id)
    269 
    270     def IsSomeConsumableUnfulfilled(self):
    271         colonyData = self._GetColonyData()
    272         if colonyData:
    273             return colonyData.IsSomeConsumableUnfulfilled(self.pin.id)
    274 
    275     def _GetColonyData(self):
    276         colony = sm.GetService('planetUI').planet.GetColony(session.charid)
    277         if colony:
    278             return colony.colonyData
    279 
    280     def OnLinkListentryDblClicked(self, entry):
    281         myPinManager = sm.GetService('planetUI').myPinManager
    282         linkID = entry.sr.node.id
    283         link = myPinManager.linksByPinIDs[linkID]
    284         for node in self.linkScroll.GetNodes():
    285             myPinManager.RemoveHighlightLink(node.id)
    286 
    287         sm.GetService('planetUI').eventManager.SelectLink(link.linkGraphicID1)
    288 
    289     def OnLinkEntryHover(self, entry):
    290         node = entry.sr.node
    291         self.planetUISvc.myPinManager.HighlightLink(self.pin.id, node.id)
    292 
    293     def OnLinkEntryExit(self, entry):
    294         node = entry.sr.node
    295         self.planetUISvc.myPinManager.RemoveHighlightLink(node.id)
    296 
    297     def _CreateNewLink(self, *args):
    298         self.planetUISvc.myPinManager.SetLinkParent(self.pin.id)
    299         self.CloseByUser()
    300 
    301     def _DeleteLink(self, *args):
    302         selected = self.linkScroll.GetSelected()
    303         if len(selected) > 0:
    304             self.planetUISvc.myPinManager.RemoveLink(selected[0].id)
    305             self.LoadLinkScroll()
    306 
    307     def ResizeActionCont(self, panelID = None):
    308         if panelID:
    309             minHeight, maxHeight = planetCommonUI.PANEL_MIN_MAX_HEIGHT[panelID]
    310             if maxHeight:
    311                 height = (minHeight + maxHeight) / 2
    312             else:
    313                 heightSetting = CharSettingNumeric(HEIGHT_SETTING_KEY % panelID, minHeight, minHeight, 1000)
    314                 height = heightSetting.get()
    315         else:
    316             height = minHeight = maxHeight = 0
    317         self.UpdateWindowHeight(height, minHeight, maxHeight)
    318 
    319     def _on_main_size_changed(self):
    320         self.ResizeActionCont(self.panelID)
    321 
    322     def OnEndScale_(self, *etc):
    323         if self.panelID is None:
    324             return
    325         minHeight, maxHeight = planetCommonUI.PANEL_MIN_MAX_HEIGHT[self.panelID]
    326         if maxHeight:
    327             return
    328         newHeight = self.height - self.GetBaseHeight()
    329         heightSetting = CharSettingNumeric(HEIGHT_SETTING_KEY % self.panelID, minHeight, minHeight, 1000)
    330         heightSetting.set(newHeight)
    331 
    332     def UpdateWindowHeight(self, height = 0, minHeight = 0, maxHeight = 0, animate = True):
    333         baseHeight = self.GetBaseHeight()
    334         newHeight = height + baseHeight
    335         if animate:
    336             uicore.animations.MorphScalar(self, 'height', self.height, newHeight, duration=0.3)
    337         else:
    338             self.height = newHeight
    339         self.SetMinSize((self.default_minSize[0] * fontconst.fontSizeFactor, baseHeight + minHeight))
    340         if minHeight == maxHeight:
    341             self.SetFixedHeight(baseHeight + minHeight)
    342         elif maxHeight:
    343             self.SetFixedHeight(None)
    344             self.SetMaxSize((self.default_maxSize[0], baseHeight + maxHeight))
    345         else:
    346             self.SetFixedHeight(None)
    347             self.SetMaxSize((self.default_maxSize[0], None))
    348 
    349     def _UpdateInfoCont(self):
    350         pass
    351 
    352     def PanelShowStorage(self):
    353         cont = Container(parent=self.actionCont, state=uiconst.UI_HIDDEN)
    354         self.storageContentScroll = Scroll(parent=cont, name='storageContentsScroll', id='planetStorageContentsScroll')
    355         self.storageContentScroll.sr.fixedColumns = {'': 28}
    356         self.LoadStorageContentScroll()
    357         btns = [[localization.GetByLabel('UI/PI/Common/CreateRoute'), self._CreateRoute, 'storageContentScroll'], [localization.GetByLabel('UI/PI/Common/ExpeditedTransfer'), self._CreateTransfer, None]]
    358         self.createRouteButton = ButtonGroup(btns=btns, parent=cont, idx=0)
    359         return cont
    360 
    361     def LoadStorageContentScroll(self):
    362         scrolllist = []
    363         for typeID, amount in self.pin.contents.iteritems():
    364             volume = evetypes.GetVolume(typeID) * amount
    365             volume = GetByLabel('UI/InfoWindow/ValueAndUnit', value=volume, unit=FormatUnit(dogma.const.unitVolume))
    366             sortBy = amount
    367             scrolllist.append((sortBy, GetFromClass(PlanetItemEntry, {'label': '<t>%s<t><right>%s<t><right>%s' % (evetypes.GetName(typeID), FmtAmt(amount), volume),
    368               'amount': amount,
    369               'typeID': typeID,
    370               'itemID': None,
    371               'getIcon': True,
    372               'OnDblClick': self.OnStorageEntryDblClicked})))
    373 
    374         scrolllist = SortListOfTuples(scrolllist)
    375         self.storageContentScroll.Load(contentList=scrolllist, noContentHint=localization.GetByLabel('UI/PI/Common/NoContentsPresent'), headers=['',
    376          localization.GetByLabel('UI/PI/Common/Type'),
    377          localization.GetByLabel('UI/Common/Amount'),
    378          localization.GetByLabel('UI/Common/Volume')])
    379 
    380     def OnStorageEntryDblClicked(self, entry):
    381         self._CreateRoute('storageContentScroll')
    382 
    383     def PanelShowProducts(self):
    384         cont = Container(parent=self.actionCont, state=uiconst.UI_HIDDEN)
    385         self.productScroll = Scroll(parent=cont, name='productsScroll')
    386         self.productScroll.sr.id = 'planetBasePinProductScroll'
    387         self.LoadProductScroll()
    388         btns = [[localization.GetByLabel('UI/PI/Common/CreateRoute'), self._CreateRoute, 'productScroll']]
    389         self.createRouteButton = ButtonGroup(btns=btns, parent=cont, idx=0)
    390         btns = [[localization.GetByLabel('UI/PI/Common/DeleteRoute'), self._DeleteRoute, ()]]
    391         self.deleteRouteButton = ButtonGroup(btns=btns, parent=cont, idx=0)
    392         self.createRouteButton.state = uiconst.UI_HIDDEN
    393         self.deleteRouteButton.state = uiconst.UI_HIDDEN
    394         return cont
    395 
    396     def LoadProductScroll(self):
    397         routesByTypeID = self._GetRoutesByTypeID()
    398         scrolllist = []
    399         for typeID, amount in self.pin.GetProductMaxOutput().iteritems():
    400             typeName = evetypes.GetName(typeID)
    401             for route in routesByTypeID.get(typeID, []):
    402                 qty = route.GetQuantity()
    403                 amount -= qty
    404                 scrolllist.append(GetFromClass(Item, {'label': '%s<t>%s<t>%s<t>%s' % ('',
    405                            qty,
    406                            typeName,
    407                            localization.GetByLabel('UI/PI/Common/Routed')),
    408                  'typeID': typeID,
    409                  'itemID': None,
    410                  'getIcon': True,
    411                  'routeID': route.routeID,
    412                  'OnMouseEnter': self.OnRouteEntryHover,
    413                  'OnMouseExit': self.OnRouteEntryExit,
    414                  'OnClick': self.OnProductEntryClicked,
    415                  'OnDblClick': self.OnProductEntryDblClicked}))
    416 
    417             if amount > 0:
    418                 scrolllist.append(GetFromClass(Item, {'label': '%s<t>%s<t>%s<t><color=red>%s</color>' % ('',
    419                            amount,
    420                            evetypes.GetName(typeID),
    421                            localization.GetByLabel('UI/PI/Common/NotRouted')),
    422                  'typeID': typeID,
    423                  'amount': amount,
    424                  'itemID': None,
    425                  'getIcon': True,
    426                  'OnClick': self.OnProductEntryClicked,
    427                  'OnDblClick': self.OnProductEntryDblClicked}))
    428 
    429         self.productScroll.Load(contentList=scrolllist, noContentHint=localization.GetByLabel('UI/PI/Common/NoProductsPresent'), headers=['',
    430          localization.GetByLabel('UI/Common/Amount'),
    431          localization.GetByLabel('UI/PI/Common/Type'),
    432          localization.GetByLabel('UI/Generic/Status')])
    433 
    434     def _GetRoutesByTypeID(self):
    435         colony = self.planetUISvc.planet.GetColony(session.charid)
    436         if colony is None or colony.colonyData is None:
    437             raise RuntimeError('Cannot load product scroll for pin on a planet that has no colony')
    438         sourcedRoutes = colony.colonyData.GetSourceRoutesForPin(self.pin.id)
    439         routesByTypeID = {}
    440         for route in sourcedRoutes:
    441             typeID = route.GetType()
    442             if typeID not in routesByTypeID:
    443                 routesByTypeID[typeID] = []
    444             routesByTypeID[typeID].append(route)
    445 
    446         return routesByTypeID
    447 
    448     def OnProductEntryClicked(self, entry):
    449         node = entry.sr.node
    450         if node.Get('routeID', None) is None:
    451             self.createRouteButton.state = uiconst.UI_NORMAL
    452             self.deleteRouteButton.state = uiconst.UI_HIDDEN
    453         else:
    454             self.createRouteButton.state = uiconst.UI_HIDDEN
    455             self.deleteRouteButton.state = uiconst.UI_NORMAL
    456 
    457     def OnProductEntryDblClicked(self, entry):
    458         node = entry.sr.node
    459         if node.Get('routeID', None) is None:
    460             self._CreateRoute('productScroll')
    461 
    462     def _CreateRoute(self, scroll):
    463         selected = getattr(self, scroll).GetSelected()
    464         if len(selected) > 0:
    465             entry = selected[0]
    466             self.ShowPanel(planetCommonUI.PANEL_CREATEROUTE, entry.typeID, entry.amount)
    467 
    468     def SubmitRoute(self, *args):
    469         if not getattr(self, 'routeAmountEdit', None):
    470             return
    471         sm.GetService('planetUI').myPinManager.CreateRoute(self.routeAmountEdit.GetValue())
    472         self.HideCurrentPanel()
    473         self.commodityToRoute = None
    474 
    475     def _DeleteRoute(self):
    476         selected = self.productScroll.GetSelected()
    477         if len(selected) > 0:
    478             entry = selected[0]
    479             if entry.routeID:
    480                 self.planetUISvc.myPinManager.RemoveRoute(entry.routeID)
    481                 self.LoadProductScroll()
    482                 self.createRouteButton.state = uiconst.UI_HIDDEN
    483                 self.deleteRouteButton.state = uiconst.UI_HIDDEN
    484 
    485     def _DeleteRouteFromEntry(self):
    486         if not hasattr(self, 'routeScroll'):
    487             return
    488         selected = self.routeScroll.GetSelected()
    489         if len(selected) > 0:
    490             entry = selected[0]
    491             if entry.routeID:
    492                 self.planetUISvc.myPinManager.RemoveRoute(entry.routeID)
    493                 self.LoadRouteScroll()
    494                 animations.FadeOut(self.routeInfo, duration=0.125, sleep=True)
    495 
    496     def _CreateTransfer(self, *args):
    497         if sm.GetService('planetUI').GetCurrentPlanet().IsInEditMode():
    498             raise UserError('CannotTransferInEditMode')
    499         self.planetUISvc.myPinManager.EnterRouteMode(self.pin.id, None, oneoff=True)
    500         self.ShowPanel(planetCommonUI.PANEL_TRANSFER)
    501 
    502     def PanelDecommissionPin(self):
    503         typeName = evetypes.GetName(self.pin.typeID)
    504         if evetypes.GetGroupID(self.pin.typeID) == invconst.groupCommandPins:
    505             text = localization.GetByLabel('UI/PI/Common/DecommissionCommandPin', typeName=typeName)
    506         else:
    507             text = localization.GetByLabel('UI/PI/Common/DecommissionLink', typeName=typeName)
    508         cont = Container(parent=self.actionCont, state=uiconst.UI_HIDDEN)
    509         Label(parent=cont, text=text, align=uiconst.TOTOP)
    510         btns = [[localization.GetByLabel('UI/PI/Common/Proceed'), self._DecommissionSelf, None]]
    511         ButtonGroup(btns=btns, idx=0, parent=cont)
    512         return cont
    513 
    514     def _DecommissionSelf(self, *args):
    515         sm.GetService('audio').SendUIEvent('msg_pi_build_decommission_play')
    516         self.planetUISvc.myPinManager.RemovePin(self.pin.id)
    517 
    518     def OnRouteEntryHover(self, entry):
    519         self.planetUISvc.myPinManager.ShowRoute(entry.sr.node.routeID)
    520 
    521     def OnRouteEntryExit(self, entry):
    522         self.planetUISvc.myPinManager.StopShowingRoute(entry.sr.node.routeID)
    523 
    524     def OnRefreshPins(self, pinIDs):
    525         if self.panelID == planetCommonUI.PANEL_STORAGE:
    526             self.LoadStorageContentScroll()
    527 
    528     def GetPanelID(self):
    529         return self.panelID
    530 
    531     def ProcessColonyDataSet(self, planetID):
    532         if self.planetUISvc.planetID != planetID:
    533             return
    534         self.pin = sm.GetService('planetSvc').GetPlanet(planetID).GetPin(self.pin.id)
    535 
    536     def PanelShowStats(self, *args):
    537         cont = Container(parent=self.actionCont, align=uiconst.TOALL, state=uiconst.UI_HIDDEN)
    538         self.statsScroll = scroll = Scroll(parent=cont, name='StatsScroll')
    539         scrolllist = self.GetStatsEntries()
    540         scroll.Load(contentList=scrolllist, headers=[localization.GetByLabel('UI/PI/Common/Attribute'), localization.GetByLabel('UI/Common/Value')])
    541         return cont
    542 
    543     def GetStatsEntries(self):
    544         scrolllist = []
    545         if self.pin.GetCpuUsage() > 0:
    546             scrolllist.append(GetFromClass(Generic, {'label': '%s<t>%s' % (localization.GetByLabel('UI/PI/Common/CpuUsage'), localization.GetByLabel('UI/PI/Common/TeraFlopsAmount', amount=self.pin.GetCpuUsage()))}))
    547         if self.pin.GetCpuOutput() > 0:
    548             scrolllist.append(GetFromClass(Generic, {'label': '%s<t>%s' % (localization.GetByLabel('UI/PI/Common/CpuOutput'), localization.GetByLabel('UI/PI/Common/TeraFlopsAmount', amount=self.pin.GetCpuOutput()))}))
    549         if self.pin.GetPowerUsage() > 0:
    550             scrolllist.append(GetFromClass(Generic, {'label': '%s<t>%s' % (localization.GetByLabel('UI/PI/Common/PowerUsage'), localization.GetByLabel('UI/PI/Common/MegaWattsAmount', amount=self.pin.GetPowerUsage()))}))
    551         if self.pin.GetPowerOutput() > 0:
    552             scrolllist.append(GetFromClass(Generic, {'label': '%s<t>%s' % (localization.GetByLabel('UI/PI/Common/PowerOutput'), localization.GetByLabel('UI/PI/Common/MegaWattsAmount', amount=self.pin.GetPowerOutput()))}))
    553         return scrolllist
    554 
    555     def OnPlanetRouteWaypointAdded(self, currentRoute):
    556         self.currentRoute = currentRoute
    557         self.UpdatePanelCreateRoute()
    558 
    559     def PanelCreateRoute(self, typeID, amount):
    560         self.planetUISvc.myPinManager.EnterRouteMode(self.pin.id, typeID)
    561         cont = Container(parent=self.actionCont, state=uiconst.UI_HIDDEN)
    562         cont._OnClose = self.OnPanelCreateRouteClosed
    563         w = self.width - 5
    564         self.sourceMaxAmount = amount
    565         self.routeMaxAmount = amount
    566         self.commodityToRoute = typeID
    567         self.commoditySourceMaxAmount = amount
    568         self.currRouteCycleTime = self.pin.GetCycleTime()
    569         resourceTxt = localization.GetByLabel('UI/PI/Common/ItemAmount', itemName=evetypes.GetName(typeID), amount=int(self.routeMaxAmount))
    570         CaptionAndSubtext(parent=cont, caption=localization.GetByLabel('UI/PI/Common/CommodityToRoute'), subtext=resourceTxt, iconTypeID=typeID, align=uiconst.TOTOP)
    571         CaptionAndSubtext(parent=cont, caption=localization.GetByLabel('UI/PI/Common/QtyAmount'), align=uiconst.TOTOP, state=uiconst.UI_DISABLED, padBottom=0)
    572         amountCont = Container(name='amountCont', parent=cont, align=uiconst.TOTOP, height=HEIGHT_COMPACT, padBottom=4)
    573         self.routeAmountEdit = SingleLineEditInteger(name='routeAmountEdit', parent=amountCont, setvalue=self.routeMaxAmount, width=100, align=uiconst.TOPLEFT, maxValue=self.routeMaxAmount, OnChange=self.OnRouteAmountEditChanged, density=Density.COMPACT)
    574         self.routeAmountText = EveLabelSmall(parent=amountCont, left=108, state=uiconst.UI_NORMAL, align=uiconst.CENTERLEFT)
    575         self.routeDestText = CaptionAndSubtext(parent=cont, caption=localization.GetByLabel('UI/Common/Destination'), align=uiconst.TOTOP)
    576         btnGroup = ButtonGroup(parent=cont, line=False, idx=0)
    577         self.createRouteButton = btnGroup.AddButton(localization.GetByLabel('UI/PI/Common/CreateRoute'), self.SubmitRoute)
    578         self.UpdatePanelCreateRoute()
    579         return cont
    580 
    581     def OnPanelCreateRouteClosed(self, *args):
    582         if not self.destroyed:
    583             sm.GetService('planetUI').eventManager.SetStateNormal()
    584 
    585     def OnRouteAmountEditChanged(self, newVal):
    586         try:
    587             routeAmount = int(newVal)
    588         except ValueError:
    589             return
    590 
    591         if not self.currRouteCycleTime:
    592             return
    593         routeAmount = min(routeAmount, self.routeMaxAmount)
    594         routeAmount = max(routeAmount, 0.0)
    595         volume = planetCommon.GetCommodityTotalVolume({self.commodityToRoute: routeAmount})
    596         volumePerHour = planetCommon.GetBandwidth(volume, self.currRouteCycleTime)
    597         sm.GetService('planetUI').myPinManager.OnRouteVolumeChanged(volumePerHour)
    598 
    599     def UpdatePanelCreateRoute(self):
    600         if not self.currentRoute or len(self.currentRoute) < 2:
    601             destName = localization.GetByLabel('UI/PI/Common/NoDestinationSelected')
    602             self.routeMaxAmount = self.sourceMaxAmount
    603             self.currRouteCycleTime = self.pin.GetCycleTime()
    604             self.createRouteButton.Disable()
    605             self.createRouteButton.hint = localization.GetByLabel('UI/PI/Common/NoDestinationSelected')
    606         else:
    607             self.routeDestPin = sm.GetService('planetUI').GetCurrentPlanet().GetColony(session.charid).GetPin(self.currentRoute[-1])
    608             isValid, invalidTxt, self.currRouteCycleTime = planetCommon.GetRouteValidationInfo(self.pin, self.routeDestPin, self.commodityToRoute)
    609             destName = planetCommon.GetGenericPinName(self.routeDestPin.typeID, self.routeDestPin.id)
    610             if not isValid:
    611                 destName = localization.GetByLabel('UI/PI/Common/InvalidDestination', destName=destName, reason=invalidTxt)
    612             if not isValid:
    613                 self.routeMaxAmount = 0
    614             elif self.routeDestPin.IsProcessor() and self.commodityToRoute in self.routeDestPin.GetConsumables():
    615                 destMaxAmount = self.routeDestPin.GetConsumables().get(self.commodityToRoute)
    616                 if self.pin.IsStorage():
    617                     self.routeMaxAmount = destMaxAmount
    618                 else:
    619                     self.routeMaxAmount = min(destMaxAmount, self.commoditySourceMaxAmount)
    620             else:
    621                 self.routeMaxAmount = self.commoditySourceMaxAmount
    622             if isValid:
    623                 self.createRouteButton.Enable()
    624                 self.createRouteButton.hint = ''
    625             else:
    626                 self.createRouteButton.Disable()
    627                 self.createRouteButton.hint = localization.GetByLabel('UI/PI/Common/NoDestinationSelected')
    628         self.routeAmountEdit.SetText(self.routeMaxAmount)
    629         self.routeAmountEdit.SetMaxValue(self.routeMaxAmount)
    630         self.routeAmountText.text = localization.GetByLabel('UI/PI/Common/RoutedPortion', maxAmount=self.routeMaxAmount)
    631         self.OnRouteAmountEditChanged(self.routeMaxAmount)
    632         self.routeDestText.SetSubtext(destName)
    633 
    634     def PanelSelectTransferDest(self, *args):
    635         cont = Container(parent=self.actionCont, pos=(0, 0, 0, 15), align=uiconst.TOTOP, state=uiconst.UI_HIDDEN)
    636         cont._OnClose = self.OnPanelSelectTransferDestClosed
    637         Label(parent=cont, text=localization.GetByLabel('UI/PI/Common/SelectTransferDestination'), align=uiconst.TOTOP)
    638         return cont
    639 
    640     def OnPanelSelectTransferDestClosed(self, *args):
    641         sm.GetService('planetUI').eventManager.SetStateNormal()
    642 
    643     def SetPin(self, pin):
    644         self.pin = pin
    645 
    646     def PanelShowRoutes(self, *args):
    647         self.showRoutesCont = cont = Container(parent=self.actionCont, state=uiconst.UI_HIDDEN)
    648         self.routeScroll = Scroll(parent=cont, name='routeScroll')
    649         self.routeScroll.multiSelect = False
    650         self.routeScroll.sr.id = 'planetBaseShowRoutesScroll'
    651         self.routeInfo = ContainerAutoSize(parent=cont, align=uiconst.TOBOTTOM, state=uiconst.UI_HIDDEN, idx=0, padTop=4)
    652         content_width, _ = self.content.GetAbsoluteSize()
    653         w = content_width / 2 - 10
    654         info_cont = ContainerAutoSize(parent=self.routeInfo, align=uiconst.TOTOP)
    655         self.routeInfoSource = CaptionAndSubtext(parent=info_cont, caption=localization.GetByLabel('UI/PI/Common/Origin'), width=w)
    656         self.routeInfoDest = CaptionAndSubtext(parent=info_cont, caption=localization.GetByLabel('UI/PI/Common/Destination'), width=w, top=42)
    657         self.routeInfoType = CaptionAndSubtext(parent=info_cont, caption=localization.GetByLabel('UI/Common/Commodity'), width=w, left=w)
    658         self.routeInfoBandwidth = CaptionAndSubtext(parent=info_cont, caption=localization.GetByLabel('UI/PI/Common/CapacityUsed'), width=w, left=w, top=42)
    659         self.routeInfoBtns = ButtonGroup(parent=self.routeInfo, align=uiconst.TOTOP, top=16)
    660         if self.pin.IsStorage() and hasattr(self, '_CreateRoute'):
    661             self.createRouteBtn = Button(parent=self.routeInfoBtns, label=localization.GetByLabel('UI/PI/Common/CreateRoute'), func=self._CreateRoute, args='routeScroll')
    662         Button(parent=self.routeInfoBtns, label=localization.GetByLabel('UI/PI/Common/DeleteRoute'), func=self._DeleteRouteFromEntry, args=())
    663         self.LoadRouteScroll()
    664         return cont
    665 
    666     def GetRouteTypeLabel(self, route, pin):
    667         if not route or not pin:
    668             return localization.GetByLabel('UI/Common/Unknown')
    669         elif route.GetSourcePinID() == pin.id:
    670             return localization.GetByLabel('UI/PI/Common/Outgoing')
    671         elif route.GetDestinationPinID() == pin.id:
    672             return localization.GetByLabel('UI/PI/Common/Incoming')
    673         else:
    674             return localization.GetByLabel('UI/PI/Common/Transiting')
    675 
    676     def IsTransit(self, route, pin):
    677         if not route or not pin:
    678             return False
    679         if route.GetSourcePinID() == pin.id or route.GetDestinationPinID() == pin.id:
    680             return False
    681         return True
    682 
    683     def LoadRouteScroll(self):
    684         scrolllist = []
    685         routesShown = []
    686         colony = self.planetUISvc.GetCurrentPlanet().GetColony(self.pin.ownerID)
    687         if colony is None or colony.colonyData is None:
    688             raise RuntimeError('Unable to load route scroll without active colony on planet')
    689         planetUISvc = sm.GetService('planetUI')
    690         links = colony.colonyData.GetLinksForPin(self.pin.id)
    691         for linkedPinID in links:
    692             link = colony.GetLink(self.pin.id, linkedPinID)
    693             for routeID in link.routesTransiting:
    694                 if routeID in routesShown:
    695                     continue
    696                 route = colony.GetRoute(routeID)
    697                 typeID = route.GetType()
    698                 qty = route.GetQuantity()
    699                 typeName = evetypes.GetName(typeID)
    700                 if route.GetSourcePinID() == self.pin.id:
    701                     sourceText = localization.GetByLabel('UI/PI/Common/ThisStructure')
    702                 else:
    703                     sourcePin = planetUISvc.planet.GetPin(route.GetSourcePinID())
    704                     sourceText = GetPinNameShort(sourcePin.typeID, sourcePin.id)
    705                 if route.GetDestinationPinID() == self.pin.id:
    706                     destText = localization.GetByLabel('UI/PI/Common/ThisStructure')
    707                 else:
    708                     destPin = planetUISvc.planet.GetPin(route.GetDestinationPinID())
    709                     destText = GetPinNameShort(destPin.typeID, destPin.id)
    710                 if self.IsTransit(route, self.pin):
    711                     textColor = '<font color=%s>' % TextColor.SECONDARY.hex_argb
    712                 else:
    713                     textColor = ''
    714                 scrolllist.append(GetFromClass(Item, {'label': '<t>%s%s<t>%s<t>%s<t>%s<t>%s' % (textColor,
    715                            typeName,
    716                            qty,
    717                            self.GetRouteTypeLabel(route, self.pin),
    718                            sourceText,
    719                            destText),
    720                  'typeID': typeID,
    721                  'itemID': None,
    722                  'getIcon': True,
    723                  'OnMouseEnter': self.OnRouteEntryHover,
    724                  'OnMouseExit': self.OnRouteEntryExit,
    725                  'routeID': route.routeID,
    726                  'OnClick': self.OnRouteEntryClick,
    727                  'amount': qty}))
    728                 routesShown.append(route.routeID)
    729 
    730         self.routeScroll.Load(contentList=scrolllist, noContentHint=localization.GetByLabel('UI/PI/Common/NoIncomingOrOutgoingRoutes'), headers=['',
    731          localization.GetByLabel('UI/Common/Commodity'),
    732          localization.GetByLabel('UI/Common/Quantity'),
    733          localization.GetByLabel('UI/PI/Common/Type'),
    734          localization.GetByLabel('UI/PI/Common/Origin'),
    735          localization.GetByLabel('UI/PI/Common/Destination')])
    736 
    737     def OnRouteEntryClick(self, *args):
    738         selectedRoutes = self.routeScroll.GetSelected()
    739         if len(selectedRoutes) < 1:
    740             self.routeInfo.state = uiconst.UI_HIDDEN
    741             return
    742         selectedRouteData = selectedRoutes[0]
    743         selectedRoute = None
    744         colony = self.planetUISvc.GetCurrentPlanet().GetColony(session.charid)
    745         links = colony.colonyData.GetLinksForPin(self.pin.id)
    746         for linkedPinID in links:
    747             link = colony.GetLink(self.pin.id, linkedPinID)
    748             for routeID in link.routesTransiting:
    749                 if routeID == selectedRouteData.routeID:
    750                     selectedRoute = route = colony.GetRoute(routeID)
    751                     break
    752 
    753         if selectedRoute is None or not evetypes.Exists(selectedRoute.GetType()):
    754             return
    755         if selectedRoute.GetSourcePinID() == self.pin.id:
    756             self.routeInfoSource.SetSubtext(localization.GetByLabel('UI/PI/Common/ThisStructure'))
    757         else:
    758             sourcePin = sm.GetService('planetUI').planet.GetPin(selectedRoute.GetSourcePinID())
    759             self.routeInfoSource.SetSubtext(planetCommon.GetGenericPinName(sourcePin.typeID, sourcePin.id))
    760         if selectedRoute.GetDestinationPinID() == self.pin.id:
    761             self.routeInfoDest.SetSubtext(localization.GetByLabel('UI/PI/Common/ThisStructure'))
    762         else:
    763             destPin = sm.GetService('planetUI').planet.GetPin(selectedRoute.GetDestinationPinID())
    764             self.routeInfoDest.SetSubtext(planetCommon.GetGenericPinName(destPin.typeID, destPin.id))
    765         routeTypeID = route.GetType()
    766         routeQty = route.GetQuantity()
    767         self.routeInfoType.SetSubtext(localization.GetByLabel('UI/PI/Common/ItemAmount', itemName=evetypes.GetName(routeTypeID), amount=int(routeQty)))
    768         bandwidthAttr = dogma.data.get_attribute(dogma.const.attributeLogisticalCapacity)
    769         self.routeInfoBandwidth.SetSubtext(GetFormatAndValue(bandwidthAttr, selectedRoute.GetBandwidthUsage()))
    770         if self.createRouteBtn:
    771             if selectedRoute.GetDestinationPinID() == self.pin.id:
    772                 self.createRouteBtn.state = uiconst.UI_NORMAL
    773             else:
    774                 self.createRouteBtn.state = uiconst.UI_HIDDEN
    775         self.routeInfo.opacity = 0.0
    776         self.routeInfo.state = uiconst.UI_PICKCHILDREN
    777         animations.FadeIn(self.routeInfo, duration=0.125, sleep=True)
    778 
    779 
    780 class IconButton(Container):
    781     default_color = (1.0, 1.0, 1.0, 1.0)
    782     default_size = 32
    783     default_state = uiconst.UI_NORMAL
    784     default_align = uiconst.RELATIVE
    785 
    786     def ApplyAttributes(self, attributes):
    787         Container.ApplyAttributes(self, attributes)
    788         size = attributes.get('size', self.default_size)
    789         color = attributes.get('color', self.default_color)
    790         self.isSelected = attributes.get('isSelected', False)
    791         self.icon = Icon(icon=attributes.icon, typeID=attributes.typeID, parent=self, pos=(0,
    792          0,
    793          size,
    794          size), state=uiconst.UI_DISABLED, size=size, ignoreSize=True, color=color)
    795         self.selectedFrame = Frame(parent=self, color=(1.0, 1.0, 1.0, 0.5), state=uiconst.UI_HIDDEN)
    796         self.frame = Frame(parent=self, color=(1.0, 1.0, 1.0, 0.8), state=uiconst.UI_HIDDEN)
    797         if self.isSelected:
    798             self.SetSelected(True)
    799 
    800     def OnMouseEnter(self, *args):
    801         self.ShowFrame()
    802 
    803     def OnMouseExit(self, *args):
    804         if not self.isSelected:
    805             self.HideFrame()
    806 
    807     def SetSelected(self):
    808         self.isSelected = True
    809         self.ShowFrame()
    810 
    811     def SetDeselected(self):
    812         self.isSelected = False
    813         self.HideFrame()
    814 
    815     def ShowFrame(self):
    816         self.frame.state = uiconst.UI_DISABLED
    817         self.opacity = 1.0
    818 
    819     def HideFrame(self):
    820         self.frame.state = uiconst.UI_HIDDEN
    821         self.opacity = 0.3
    822 
    823 
    824 class CaptionAndSubtext(ContainerAutoSize):
    825     default_state = uiconst.UI_NORMAL
    826     default_name = 'CaptionAndSubtext'
    827     default_align = uiconst.TOPLEFT
    828     default_alignMode = uiconst.TOTOP
    829     default_width = 180
    830     default_padBottom = 4
    831 
    832     def ApplyAttributes(self, attributes):
    833         super(CaptionAndSubtext, self).ApplyAttributes(attributes)
    834         self.captionTxt = attributes.Get('caption', '')
    835         self.subtextTxt = attributes.Get('subtext', '')
    836         self.iconTypeID = attributes.Get('iconTypeID', None)
    837         self.height = attributes.Get('height', self.default_height)
    838         self.width = attributes.Get('width', self.default_width)
    839         self.iconSize = 28
    840         self.icon = None
    841         self.CreateLayout()
    842 
    843     def CreateLayout(self):
    844         if self.iconTypeID:
    845             padLeft = self.iconSize
    846         else:
    847             padLeft = 0
    848         self.caption = CaptionLabel(parent=self, text=self.captionTxt, padding=(padLeft,
    849          0,
    850          4,
    851          0), align=uiconst.TOTOP)
    852         self.subtext = EveLabelSmall(parent=self, text=self.subtextTxt, align=uiconst.TOTOP, padding=(padLeft,
    853          0,
    854          4,
    855          0), lineSpacing=-0.1)
    856         if self.iconTypeID:
    857             self.icon = Icon(parent=self, pos=(-5,
    858              0,
    859              self.iconSize,
    860              self.iconSize), state=uiconst.UI_DISABLED, typeID=self.iconTypeID, size=self.iconSize, ignoreSize=True)
    861 
    862     def SetSubtext(self, subtext):
    863         self.subtextTxt = subtext
    864         self.subtext.text = self.subtextTxt
    865 
    866     def SetCaption(self, caption):
    867         self.captionTxt = caption
    868         self.caption.text = self.captionTxt
    869 
    870     def SetIcon(self, typeID):
    871         if typeID == self.iconTypeID:
    872             return
    873         self.iconTypeID = typeID
    874         self.Flush()
    875         self.CreateLayout()
    876 
    877     def GetMenu(self):
    878         if self.iconTypeID:
    879             return sm.GetService('menu').GetMenuFromItemIDTypeID(None, self.iconTypeID, includeMarketDetails=True)
    880 
    881     def LoadTooltipPanel(self, tooltipPanel, *args):
    882         if self.iconTypeID:
    883             planetCommonUI.LoadProductTooltipPanel(tooltipPanel, self.iconTypeID)
    884 
    885 
    886 class CaptionLabel(EveLabelSmall):
    887     default_state = uiconst.UI_DISABLED
    888     default_color = (1.0, 1.0, 1.0, 0.95)