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

fleet.py (51234B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\fleet\fleet.py
      2 import eveicon
      3 from carbonui.control.animatedsprite import AnimSprite
      4 from carbonui.control.contextMenu.menuEntryData import MenuEntryData
      5 from carbonui.primitives.container import Container
      6 from carbonui.primitives.fill import Fill
      7 from carbonui.primitives.sprite import Sprite
      8 from carbonui.util.various_unsorted import ParanoidDecoMethod, SortListOfTuples
      9 from eve.client.script.parklife import states as state
     10 from eve.client.script.ui.control.entries.generic import Generic
     11 from eve.client.script.ui.control.entries.util import GetFromClass
     12 from eve.client.script.ui.control.glowSprite import GlowSprite
     13 from eve.client.script.ui.control.listgroup import ListGroup as Group
     14 from eve.client.script.ui.inflight.baseTacticalEntry import BaseTacticalEntry
     15 from eve.client.script.ui.services.menuAction import Action
     16 from eve.client.script.ui.shared.fleet.fleetConst import FLEET_VIEW_FLAT_LIST_SETTING
     17 from eve.client.script.ui.shared.fleet.fleetUtil import GetFleetMemberMenuOptions
     18 from eve.client.script.ui.shared.radialMenu.radialMenu import RadialMenuSpaceCharacter
     19 import weakref
     20 from eve.client.script.ui.util import uix
     21 from eve.client.script.util.bubble import SlimItemFromCharID
     22 import uthread
     23 from eve.client.script.ui.control import eveIcon, eveLabel, eveScroll
     24 import blue
     25 import carbonui.const as uiconst
     26 import log
     27 import localization
     28 from collections import defaultdict
     29 import evefleet.client
     30 from evefleet import fleetActivityNames, ACTIVITY_MISC
     31 from utillib import KeyVal
     32 from carbonui.uicore import uicore
     33 from eveservices.menu import GetMenuService
     34 from menu import MenuLabel, MenuList
     35 CONNOT_BE_MOVED_INCOMPATIBLE = -1
     36 CANNOT_BE_MOVED = 0
     37 CAN_BE_COMMANDER = 1
     38 CAN_ONLY_BE_MEMBER = 2
     39 COLOR_CANNOT_BE_MOVED = (1,
     40  0,
     41  0,
     42  0.15)
     43 COLOR_CAN_BE_COMMANDER = (1,
     44  1,
     45  1,
     46  0.2)
     47 COLOR_CAN_ONLY_BE_MEMBER = (1,
     48  1,
     49  1,
     50  0.07)
     51 EDIT_MODE_CONFIG = 'fleet_watchlistcolor_editMode'
     52 WATCHLIST_COLORS_CONFIG = 'fleet_watchlistcolors'
     53 
     54 def CommanderName(group):
     55     cmdr = group['commander']
     56     if cmdr:
     57         return cfg.eveowners.Get(cmdr).name
     58     else:
     59         return '<color=0x%%(alpha)xffffff>%s</color>' % localization.GetByLabel('UI/Fleet/FleetWindow/NoCommander')
     60 
     61 
     62 def SquadronName(fleet, squadID):
     63     squadron = fleet['squads'][squadID]
     64     squadronName = squadron['name']
     65     if squadronName == '':
     66         squadno = GroupNumber(fleet, 'squad', squadID)
     67         squadronName = localization.GetByLabel('UI/Fleet/DefaultSquadName', squadNumber=squadno)
     68     return squadronName
     69 
     70 
     71 def WingName(fleet, wingID):
     72     wing = fleet['wings'][wingID]
     73     wingName = wing['name']
     74     if wingName == '':
     75         wingno = GroupNumber(fleet, 'wing', wingID)
     76         wingName = localization.GetByLabel('UI/Fleet/DefaultWingName', wingNumber=wingno)
     77     return wingName
     78 
     79 
     80 def GroupNumber(fleet, groupType, groupID):
     81     ids = fleet['%ss' % groupType].keys()
     82     ids.sort()
     83     return ids.index(groupID) + 1
     84 
     85 
     86 def GetSquadMenu(squadID):
     87     m = MenuList()
     88     fleetSvc = sm.GetService('fleet')
     89     if fleetSvc.IsCommanderOrBoss():
     90         m = MenuList([(MenuLabel('UI/Fleet/FleetWindow/ChangeName'), lambda : fleetSvc.ChangeSquadName(squadID)), (MenuLabel('UI/Fleet/FleetWindow/DeleteSquad'), lambda : fleetSvc.DeleteSquad(squadID))])
     91         if squadID == fleetSvc.GetAutoJoinSquadID():
     92             m.append((MenuLabel('UI/Fleet/FleetWindow/RemoveSquadAsAutoJoin'), lambda : fleetSvc.SetAutoJoinSquadID(None)))
     93         else:
     94             m.append((MenuLabel('UI/Fleet/FleetWindow/SetSquadAsAutoJoin'), lambda : fleetSvc.SetAutoJoinSquadID(squadID)))
     95     m.append((MenuLabel('UI/Fleet/FleetWindow/AddSquadMembersToWatchlist'), lambda : fleetSvc.AddFavoriteSquad(squadID)))
     96     return m
     97 
     98 
     99 class MyFleetPanel(Container):
    100     __guid__ = 'form.FleetView'
    101     __notifyevents__ = ['OnFleetMemberChanging',
    102      'OnManyFleetMembersChanging',
    103      'OnCollapsed',
    104      'OnExpanded',
    105      'OnFleetJoin_Local',
    106      'OnFleetLeave_Local',
    107      'OnFleetWingAdded_Local',
    108      'OnFleetWingDeleted_Local',
    109      'OnFleetSquadAdded_Local',
    110      'OnFleetSquadDeleted_Local',
    111      'OnFleetMemberChanged_Local',
    112      'OnFleetWingNameChanged_Local',
    113      'OnFleetSquadNameChanged_Local',
    114      'OnFleetOptionsChanged_Local']
    115 
    116     def PostStartup(self):
    117         sm.RegisterNotify(self)
    118         header = self
    119         header.baseHeight = 30
    120         self.sr.topEntry = FleetRoleCont(parent=header, align=uiconst.TOTOP, height=16, padBottom=8)
    121         self.sr.scroll = eveScroll.Scroll(parent=self)
    122         self.sr.scroll.sr.content.OnDropData = self.OnDropData
    123         self.members = {}
    124         self.myGroups = {}
    125         self.pending_RefreshFromRec = []
    126         self.scrollToProportion = 0
    127         self.fleet = None
    128         self.HandleFleetChanged()
    129         FLEET_VIEW_FLAT_LIST_SETTING.on_change.connect(self.HandleFleetChanged)
    130 
    131     def LoadPanel(self):
    132         if not self.sr.Get('inited', 0):
    133             setattr(self.sr, 'inited', 1)
    134             self.PostStartup()
    135         if session.fleetid is not None:
    136             if getattr(self.sr, 'scroll', None):
    137                 self.sr.scroll._OnResize()
    138 
    139     def OnFleetMemberChanging(self, charID):
    140         rec = self.members.get(charID)
    141         if rec is not None:
    142             rec.changing = True
    143             self.RefreshFromRec(rec)
    144 
    145     def OnManyFleetMembersChanging(self, charIDs):
    146         squadMembersByWingID = defaultdict(list)
    147         otherMembers = []
    148         for eachCharID in charIDs:
    149             rec = self.members.get(eachCharID)
    150             if rec is None:
    151                 continue
    152             if not FLEET_VIEW_FLAT_LIST_SETTING.is_enabled() and rec.squadID not in (None, -1) and rec.wingID not in (None, -1):
    153                 rec.changing = True
    154                 squadMembersByWingID[rec.wingID].append(rec)
    155             else:
    156                 otherMembers.append(eachCharID)
    157 
    158         for charsInWing in squadMembersByWingID.itervalues():
    159             recForFirstChar = charsInWing[0]
    160             if recForFirstChar:
    161                 self.RefreshFromRec(recForFirstChar)
    162 
    163         for charID in otherMembers:
    164             self.OnFleetMemberChanging(charID)
    165 
    166     def UpdateHeader(self):
    167         from eve.client.script.ui.shared.fleet.fleetwindow import FleetWindow
    168         wnd = FleetWindow.GetIfOpen()
    169         if wnd:
    170             wnd.UpdateHeader()
    171 
    172     def CheckHint(self):
    173         if not self.sr.scroll.GetNodes():
    174             self.sr.scroll.ShowHint(localization.GetByLabel('UI/Fleet/NoFleet'))
    175         else:
    176             self.sr.scroll.ShowHint()
    177         self.UpdateHeader()
    178 
    179     def OnFleetWingAdded_Local(self, *args):
    180         self.HandleFleetChanged()
    181 
    182     def OnFleetWingDeleted_Local(self, *args):
    183         self.HandleFleetChanged()
    184 
    185     def OnFleetSquadAdded_Local(self, *args):
    186         self.HandleFleetChanged()
    187 
    188     def OnFleetSquadDeleted_Local(self, *args):
    189         self.HandleFleetChanged()
    190 
    191     def OnFleetSquadNameChanged_Local(self, squadID, name):
    192         self.fleet['squads'][squadID]['name'] = name
    193         headerNode = self.HeaderNodeFromGroupTypeAndID('squad', squadID)
    194         if headerNode:
    195             numMembers = len(sm.GetService('fleet').GetMembersInSquad(squadID))
    196             if numMembers == 0:
    197                 headerNode.label = localization.GetByLabel('UI/Fleet/FleetWindow/UnitHeaderEmpty', unitName=name)
    198             else:
    199                 headerNode.groupInfo = localization.GetByLabel('UI/Fleet/FleetWindow/UnitHeaderWithCount', unitName=name, memberCount=numMembers)
    200             if headerNode.panel:
    201                 headerNode.panel.Load(headerNode)
    202 
    203     def OnFleetOptionsChanged_Local(self, oldOptions, newOptions):
    204         oldSquadID = oldOptions.autoJoinSquadID
    205         newSquadID = newOptions.autoJoinSquadID
    206         if oldSquadID == newSquadID:
    207             return
    208         if not FleetSvc().IsCommanderOrBoss():
    209             return
    210         oldHeaderNode = self.HeaderNodeFromGroupTypeAndID('squad', oldSquadID)
    211         newHeaderNode = self.HeaderNodeFromGroupTypeAndID('squad', newSquadID)
    212         for eachHeaderNode in (oldHeaderNode, newHeaderNode):
    213             if eachHeaderNode and eachHeaderNode.panel:
    214                 eachHeaderNode.showAsAutoJoinSquad = eachHeaderNode.groupID == newSquadID
    215                 eachHeaderNode.panel.Load(eachHeaderNode)
    216 
    217     def OnFleetWingNameChanged_Local(self, wingID, name):
    218         self.fleet['wings'][wingID]['name'] = name
    219         headerNode = self.HeaderNodeFromGroupTypeAndID('wing', wingID)
    220         if headerNode:
    221             numMembers = len(sm.GetService('fleet').GetMembersInWing(wingID))
    222             if numMembers == 0:
    223                 headerNode.groupInfo = localization.GetByLabel('UI/Fleet/FleetWindow/UnitHeaderEmpty', unitName=name)
    224             else:
    225                 headerNode.groupInfo = localization.GetByLabel('UI/Fleet/FleetWindow/UnitHeaderWithCount', unitName=name, memberCount=numMembers)
    226             if headerNode.panel:
    227                 headerNode.panel.Load(headerNode)
    228 
    229     def OnFleetJoin_Local(self, rec):
    230         if not self or self.destroyed:
    231             return
    232         if rec.charID == session.charid:
    233             self.HandleFleetChanged()
    234         else:
    235             self.AddChar(rec)
    236 
    237     def AddChar(self, rec):
    238         if self.fleet is None:
    239             return
    240         self.members[rec.charID] = rec
    241         FleetSvc().AddToFleet(self.fleet, rec)
    242         if not FLEET_VIEW_FLAT_LIST_SETTING.is_enabled():
    243             self.HandleFleetChanged()
    244         self.RefreshFromRec(rec)
    245 
    246     def OnFleetLeave_Local(self, rec):
    247         if rec.charID == session.charid:
    248             return
    249         self.RemoveChar(rec.charID)
    250         if rec.role == evefleet.fleetRoleSquadCmdr:
    251             self.FlashHeader('squad', rec.squadID)
    252         elif rec.role == evefleet.fleetRoleWingCmdr:
    253             self.FlashHeader('wing', rec.wingID)
    254         elif rec.role == evefleet.fleetRoleLeader:
    255             self.FlashHeader('fleet', session.fleetid)
    256 
    257     def RemoveChar(self, charID):
    258         rec = self.members.pop(charID, None)
    259         if rec is None or self.fleet is None:
    260             return
    261         if None not in (rec.squadID, rec.wingID):
    262             self.RemoveFromFleet(self.fleet, rec)
    263             if FLEET_VIEW_FLAT_LIST_SETTING.is_enabled():
    264                 self.RemoveCharFromScroll(charID)
    265             else:
    266                 self.HandleFleetChanged()
    267             self.RefreshFromRec(rec, removing=1)
    268 
    269     def OnFleetMemberChanged_Local(self, charID, fleetID, oldWingID, oldSquadID, oldRole, oldJob, oldMemberOptOuts, newWingID, newSquadID, newRole, newJob, newMemberOptOuts):
    270         rec = self.members[charID]
    271 
    272         def UpdateRec():
    273             rec.changing = False
    274             rec.role, rec.job = newRole, newJob
    275             rec.wingID, rec.squadID = newWingID, newSquadID
    276             rec.memberOptOuts = newMemberOptOuts
    277 
    278         if (oldWingID, oldSquadID) != (newWingID, newSquadID):
    279             if FLEET_VIEW_FLAT_LIST_SETTING.is_enabled():
    280                 UpdateRec()
    281                 self.RefreshFromRec(rec)
    282             else:
    283                 if evefleet.fleetRoleLeader in (oldRole, newRole):
    284                     self.HandleFleetChanged()
    285                 else:
    286                     self.RemoveChar(charID)
    287                     UpdateRec()
    288                     self.AddChar(rec)
    289                 self.UpdateHeader()
    290         else:
    291             UpdateRec()
    292             if oldRole == evefleet.fleetRoleSquadCmdr != newRole:
    293                 self.fleet['squads'][rec.squadID]['commander'] = None
    294             elif oldRole == evefleet.fleetRoleMember != newRole:
    295                 self.fleet['squads'][rec.squadID]['commander'] = rec.charID
    296             self.RefreshFromRec(rec)
    297         if oldRole == evefleet.fleetRoleSquadCmdr and (newRole != evefleet.fleetRoleSquadCmdr or newSquadID != oldSquadID):
    298             self.FlashHeader('squad', oldSquadID)
    299         elif oldRole == evefleet.fleetRoleWingCmdr and (newRole != evefleet.fleetRoleWingCmdr or newWingID != oldWingID):
    300             self.FlashHeader('wing', oldWingID)
    301         elif oldRole == evefleet.fleetRoleLeader != newRole:
    302             self.FlashHeader('fleet', session.fleetid)
    303 
    304     def FlashHeader(self, groupType, groupID):
    305         uthread.new(self.FlashHeader_thread, groupType, groupID)
    306 
    307     def FlashHeader_thread(self, groupType, groupID):
    308         headerNode = self.HeaderNodeFromGroupTypeAndID(groupType, groupID)
    309         if headerNode and headerNode.panel:
    310             if hasattr(headerNode.panel, 'Flash'):
    311                 headerNode.panel.Flash()
    312 
    313     def RemoveFromFleet(self, fleet, rec):
    314 
    315         def Name(charID):
    316             return charID and cfg.eveowners.Get(charID).name
    317 
    318         def RemoveCommander(group, charID):
    319             if group['commander'] == charID:
    320                 group['commander'] = None
    321             else:
    322                 log.LogError('Commander is', Name(group['commander']), 'not', Name(charID))
    323 
    324         if rec.squadID != -1:
    325             squad = fleet['squads'][rec.squadID]
    326             if rec.role == evefleet.fleetRoleSquadCmdr:
    327                 RemoveCommander(squad, rec.charID)
    328             try:
    329                 squad['members'].remove(rec.charID)
    330             except ValueError:
    331                 log.LogError(Name(rec.charID), 'not in squad.')
    332 
    333         elif rec.wingID != -1:
    334             RemoveCommander(fleet['wings'][rec.wingID], rec.charID)
    335         else:
    336             RemoveCommander(fleet, rec.charID)
    337 
    338     def RefreshFromRec(self, rec, removing = 0):
    339         self.scrollToProportion = self.sr.scroll.GetScrollProportion()
    340         if getattr(self, 'loading_RefreshFromRec', 0):
    341             self.pending_RefreshFromRec.append(rec)
    342             return
    343         setattr(self, 'loading_RefreshFromRec', 1)
    344         try:
    345             if FLEET_VIEW_FLAT_LIST_SETTING.is_enabled():
    346                 if not removing:
    347                     self.AddOrUpdateScrollEntry(rec.charID)
    348             elif rec.wingID not in (None, -1):
    349                 self.RefreshRecMemberInWing(rec.wingID, rec.squadID)
    350             else:
    351                 self.HandleFleetChanged()
    352             self.UpdateHeader()
    353             self.loading_RefreshFromRec = 0
    354             if self.pending_RefreshFromRec:
    355                 recToRefresh = self.pending_RefreshFromRec.pop(0)
    356                 self.RefreshFromRec(recToRefresh)
    357         finally:
    358             self.sr.scroll.ScrollToProportion(self.scrollToProportion)
    359             setattr(self, 'loading_RefreshFromRec', 0)
    360 
    361     def RefreshRecMemberInWing(self, wingID, squadID):
    362         inSquad = squadID not in (None, -1)
    363         if inSquad:
    364             loadingVariable = 'refreshing_squadMembers_wingID_%s' % wingID
    365             pendingVariable = 'pendingRefresing_squadMembers_wingID_%s' % wingID
    366         else:
    367             loadingVariable = 'refreshing_non_squadMembers_wingID_%s' % wingID
    368             pendingVariable = 'pending_non_refreshingWingID_%s' % wingID
    369         if getattr(self, loadingVariable, False):
    370             setattr(self, pendingVariable, True)
    371             return
    372         setattr(self, loadingVariable, True)
    373         wingHeaderNode = self.HeaderNodeFromGroupTypeAndID('wing', wingID)
    374         try:
    375             if inSquad:
    376                 if wingHeaderNode:
    377                     self.ReloadScrollEntry(wingHeaderNode)
    378             else:
    379                 fleetHeaderNode = self.HeaderNodeFromGroupTypeAndID('fleet', session.fleetid)
    380                 if fleetHeaderNode:
    381                     self.ReloadScrollEntry(fleetHeaderNode)
    382         finally:
    383             setattr(self, loadingVariable, False)
    384             if getattr(self, pendingVariable, False):
    385                 setattr(self, pendingVariable, False)
    386                 self.RefreshRecMemberInWingCaller_thread(wingID, squadID)
    387 
    388     def RefreshRecMemberInWingCaller_thread(self, wingID, squadID):
    389         blue.pyos.synchro.SleepWallclock(0)
    390         self.RefreshRecMemberInWing(wingID, squadID)
    391 
    392     def ReloadScrollEntry(self, headerNode):
    393         if headerNode:
    394             scroll = getattr(headerNode, 'scroll', None)
    395             if scroll:
    396                 scroll.PrepareSubContent(headerNode)
    397 
    398     def HeaderNodeFromGroupTypeAndID(self, groupType, groupID):
    399         for entry in self.sr.scroll.GetNodes():
    400             if entry.groupType == groupType and entry.groupID == groupID:
    401                 return entry
    402 
    403     def HandleFleetChanged(self, *args):
    404         uthread.pool('FleetView::HandleFleetChanged', self.DoHandleFleetChanged)
    405 
    406     def DoHandleFleetChanged(self):
    407         if not self or self.destroyed:
    408             return
    409         if getattr(self, 'loading_HandleFleetChanged', 0):
    410             setattr(self, 'pending_HandleFleetChanged', 1)
    411             return
    412         setattr(self, 'loading_HandleFleetChanged', 1)
    413         blue.pyos.synchro.SleepWallclock(1000)
    414         setattr(self, 'pending_HandleFleetChanged', 0)
    415         try:
    416             try:
    417                 self.members = FleetSvc().GetMembers().copy()
    418                 if session.charid in self.members:
    419                     self.sr.scroll.Load(contentList=[])
    420                     self.LoadFleet()
    421                     self.CheckHint()
    422                 setattr(self, 'loading_HandleFleetChanged', 0)
    423                 if getattr(self, 'pending_HandleFleetChanged', 0):
    424                     setattr(self, 'pending_HandleFleetChanged', 0)
    425                     self.HandleFleetChanged()
    426             finally:
    427                 setattr(self, 'loading_HandleFleetChanged', 0)
    428 
    429         except:
    430             pass
    431 
    432     def EmptyGroupEntry(self, label, indent, groupType, groupID):
    433         return GetFromClass(EmptyGroup, {'label': label,
    434          'indent': indent,
    435          'groupType': groupType,
    436          'groupID': groupID})
    437 
    438     def MakeCharEntry(self, charID, sublevel = 0, isLast = False):
    439         data = self.GetMemberData(charID, sublevel=sublevel)
    440         data.isLast = isLast
    441         data.groupType = 'fleetMember'
    442         return GetFromClass(FleetMember, data)
    443 
    444     def MakeSquadEntry(self, squadID, sublevel = 0):
    445         headerdata = self.GetHeaderData('squad', squadID, sublevel)
    446         if headerdata.numMembers == 0:
    447             return GetFromClass(EmptyGroup, {'squadID': squadID,
    448              'groupType': 'squad',
    449              'groupID': squadID,
    450              'label': localization.GetByLabel('UI/Fleet/FleetWindow/UnitHeaderEmpty', unitName=SquadronName(self.fleet, squadID)),
    451              'GetMenu': self.EmptySquadMenu,
    452              'indent': 2,
    453              'showAsAutoJoinSquad': headerdata.showAsAutoJoinSquad})
    454         else:
    455             return GetFromClass(FleetHeader, headerdata)
    456 
    457     def EmptySquadMenu(self, entry):
    458         return GetSquadMenu(entry.sr.node.squadID)
    459 
    460     def MakeWingEntry(self, wingID, sublevel = 0):
    461         headerdata = self.GetHeaderData('wing', wingID, sublevel)
    462         return GetFromClass(FleetHeader, headerdata)
    463 
    464     def MakeFleetEntry(self):
    465         headerdata = self.GetHeaderData('fleet', session.fleetid, 0)
    466         return GetFromClass(FleetHeader, headerdata)
    467 
    468     def AddToScroll(self, *entries):
    469         self.sr.scroll.AddEntries(-1, entries)
    470 
    471     def RemoveCharFromScroll(self, charID):
    472         for entry in self.sr.scroll.GetNodes():
    473             if entry.charID == charID:
    474                 self.sr.scroll.RemoveEntries([entry])
    475                 return
    476 
    477     def LoadFleet(self):
    478         fleetMembers = {}
    479         for charID, member in self.members.iteritems():
    480             if None not in (member.squadID, member.wingID):
    481                 fleetMembers[charID] = member
    482             if charID == session.charid:
    483                 self.myGroups['squad'] = member.squadID
    484                 self.myGroups['wing'] = member.wingID
    485 
    486         self.fleet = FleetSvc().GetFleetHierarchy(fleetMembers)
    487         if FLEET_VIEW_FLAT_LIST_SETTING.is_enabled():
    488             scrollList = []
    489             for charID in self.members.keys():
    490                 entry = self.MakeCharEntry(charID, sublevel=1, isLast=True)
    491                 scrollList.append((cfg.eveowners.Get(charID).name.lower(), entry))
    492 
    493             scrollList = SortListOfTuples(scrollList)
    494             self.sr.scroll.Load(contentList=scrollList)
    495         else:
    496             self.AddToScroll(self.MakeFleetEntry())
    497             self.sr.scroll.ScrollToProportion(self.scrollToProportion)
    498 
    499     def GetMemberData(self, charID, slimItem = None, member = None, sublevel = 0):
    500         if slimItem is None:
    501             slimItem = SlimItemFromCharID(charID)
    502         data = KeyVal()
    503         data.charRec = cfg.eveowners.Get(charID)
    504         data.itemID = data.id = data.charID = charID
    505         data.typeID = data.charRec.typeID
    506         data.squadID = None
    507         data.wingID = None
    508         data.displayName = data.charRec.name
    509         data.roleIcons = []
    510         member = member or self.members.get(charID)
    511         if member:
    512             data.squadID = member.squadID
    513             data.wingID = member.wingID
    514             data.role = member.role
    515             if member.job & evefleet.fleetJobCreator:
    516                 data.roleIcons.append({'id': '73_20',
    517                  'hint': localization.GetByLabel('UI/Fleet/Ranks/Boss')})
    518             if member.role == evefleet.fleetRoleLeader:
    519                 data.roleIcons.append({'id': '73_17',
    520                  'hint': localization.GetByLabel('UI/Fleet/Ranks/FleetCommander')})
    521             elif member.role == evefleet.fleetRoleWingCmdr:
    522                 data.roleIcons.append({'id': '73_18',
    523                  'hint': localization.GetByLabel('UI/Fleet/Ranks/WingCommander')})
    524             elif member.role == evefleet.fleetRoleSquadCmdr:
    525                 data.roleIcons.append({'id': '73_19',
    526                  'hint': localization.GetByLabel('UI/Fleet/Ranks/SquadCommander')})
    527             if False in (member.memberOptOuts.acceptsFleetWarp, member.memberOptOuts.acceptsConduitJumps, member.memberOptOuts.acceptsFleetRegroups):
    528                 hintList = []
    529                 if not member.memberOptOuts.acceptsFleetWarp:
    530                     hintList.append(localization.GetByLabel('UI/Fleet/FleetWindow/DoesNotTakeFleetWarp'))
    531                 if not member.memberOptOuts.acceptsConduitJumps:
    532                     hintList.append(localization.GetByLabel('UI/Fleet/FleetWindow/DoesNotAcceptConduitJumps'))
    533                 if not member.memberOptOuts.acceptsFleetRegroups:
    534                     hintList.append(localization.GetByLabel('UI/Fleet/FleetWindow/DoesNotAcceptFleetRegroup'))
    535                 hint = '<br>'.join(hintList)
    536                 data.roleIcons.append({'id': '73_47',
    537                  'hint': hint})
    538         data.label = data.displayName
    539         data.isSub = 0
    540         data.sort_name = data.displayName
    541         data.sublevel = sublevel
    542         data.member = member
    543         if slimItem:
    544             data.slimItem = weakref.ref(slimItem)
    545         else:
    546             data.slimItem = None
    547         data.changing = getattr(member, 'changing', False)
    548         return data
    549 
    550     def GetHeaderData(self, gtype, gid, sublevel):
    551         data = KeyVal()
    552         data.id = ('fleet', '%s_%s' % (gtype, gid))
    553         data.groupType = gtype
    554         data.groupID = gid
    555         data.rawText = ''
    556         data.displayName = data.label = ''
    557         data.sublevel = sublevel
    558         data.expanded = True
    559         data.showicon = 'hide'
    560         data.hideFill = True
    561         data.hideTopLine = True
    562         data.hideExpanderLine = True
    563         data.showlen = False
    564         data.BlockOpenWindow = 1
    565         data.labelstyle = {'uppercase': True,
    566          'fontsize': 9,
    567          'letterspacing': 2}
    568         data.myGroups = self.myGroups
    569         group = self.GetGroup(gtype, gid)
    570         data.commanderName = CommanderName(group) % {'alpha': 119}
    571         data.commanderData = None
    572         fleetSvc = sm.GetService('fleet')
    573         if gtype == 'squad':
    574             data.GetSubContent = self.SquadContentGetter(gid, sublevel)
    575             num = len(fleetSvc.GetMembersInSquad(gid))
    576             if num == 0:
    577                 data.groupInfo = localization.GetByLabel('UI/Fleet/FleetWindow/UnitHeaderEmpty', unitName=SquadronName(self.fleet, gid))
    578             else:
    579                 data.groupInfo = localization.GetByLabel('UI/Fleet/FleetWindow/UnitHeaderWithCount', unitName=SquadronName(self.fleet, gid), memberCount=num)
    580             if fleetSvc.options.autoJoinSquadID == gid and FleetSvc().IsCommanderOrBoss():
    581                 data.showAsAutoJoinSquad = True
    582             else:
    583                 data.showAsAutoJoinSquad = False
    584         elif gtype == 'wing':
    585             data.GetSubContent = self.WingContentGetter(gid, sublevel)
    586             num = len(fleetSvc.GetMembersInWing(gid))
    587             data.groupInfo = localization.GetByLabel('UI/Fleet/FleetWindow/UnitHeaderWithCount', unitName=WingName(self.fleet, gid), memberCount=num)
    588         elif gtype == 'fleet':
    589             data.GetSubContent = self.FleetContentGetter(gid, sublevel)
    590             num = len(self.members)
    591             data.groupInfo = localization.GetByLabel('UI/Fleet/FleetWindow/UnitHeaderWithCount', unitName=localization.GetByLabel('UI/Fleet/Fleet'), memberCount=num)
    592             data.scroll = self.sr.scroll
    593         else:
    594             raise NotImplementedError
    595         data.numMembers = num
    596         if group['commander']:
    597             commanderData = self.GetMemberData(group['commander'])
    598             data.commanderData = commanderData
    599         data.openByDefault = data.open = True
    600         return data
    601 
    602     def AddOrUpdateScrollEntry(self, charID):
    603         newEntry = self.MakeCharEntry(charID)
    604         newEntry.sublevel = 1
    605         newEntry.isLast = 1
    606         for i, data in enumerate(self.sr.scroll.GetNodes()):
    607             if data.Get('id', None) == charID:
    608                 newEntry.panel = data.Get('panel', None)
    609                 scroll = data.Get('scroll', None)
    610                 if scroll is not None:
    611                     newEntry.scroll = scroll
    612                 newEntry.idx = i
    613                 self.sr.scroll.GetNodes()[i] = newEntry
    614                 if newEntry.panel is not None:
    615                     newEntry.panel.Load(newEntry)
    616                 return
    617 
    618         self.sr.scroll.AddEntries(-1, [newEntry])
    619         self.sr.scroll.Sort(by='name')
    620 
    621     def SquadContentGetter(self, squadID, sublevel):
    622 
    623         def GetContent(*blah):
    624             squad = self.fleet['squads'][squadID]
    625             ret = []
    626             if squad['members']:
    627                 sortedMembers = SortListOfTuples([ ((charID != squad['commander'], self.members[charID].job != evefleet.fleetJobCreator, cfg.eveowners.Get(charID).name.lower()), charID) for charID in squad['members'] ])
    628                 if squad['commander'] is not None:
    629                     sortedMembers.remove(squad['commander'])
    630                 for i in range(len(sortedMembers)):
    631                     charID = sortedMembers[i]
    632                     ret.append(self.MakeCharEntry(charID, sublevel=sublevel + 1, isLast=i == len(sortedMembers) - 1))
    633 
    634             if not ret:
    635                 emptyGroupEntry = self.EmptyGroupEntry(localization.GetByLabel('UI/Fleet/FleetWindow/SquadEmpty'), sublevel + 1, 'squad', squadID)
    636                 ret = [emptyGroupEntry]
    637             return ret
    638 
    639         return GetContent
    640 
    641     def WingContentGetter(self, wingID, sublevel):
    642 
    643         def GetContent(*blah):
    644             wing = self.fleet['wings'][wingID]
    645             ret = []
    646             squads = wing['squads'][:]
    647             squads.sort()
    648             for squadID in squads:
    649                 ret.append(self.MakeSquadEntry(squadID, sublevel + 1))
    650 
    651             if not ret:
    652                 emptyGroupEntery = self.EmptyGroupEntry(localization.GetByLabel('UI/Fleet/FleetWindow/WingEmpty'), sublevel + 1, 'wing', wingID)
    653                 ret = [emptyGroupEntery]
    654             return ret
    655 
    656         return GetContent
    657 
    658     def FleetContentGetter(self, fleetID, sublevel):
    659 
    660         def GetContent(*blah):
    661             ret = []
    662             wings = self.fleet['wings'].keys()
    663             wings.sort()
    664             for wingID in wings:
    665                 ret.append(self.MakeWingEntry(wingID, sublevel + 1))
    666 
    667             return ret
    668 
    669         return GetContent
    670 
    671     def GetGroup(self, groupType, groupID):
    672         if groupType == 'fleet':
    673             return self.fleet
    674         if groupType == 'wing':
    675             return self.fleet['wings'][groupID]
    676         if groupType == 'squad':
    677             return self.fleet['squads'][groupID]
    678         raise NotImplementedError
    679 
    680     def GetMemberEntry(self, charID):
    681         for entry in self.sr.scroll.GetNodes():
    682             if entry.charID == charID:
    683                 return entry
    684 
    685     def OnExpanded(self, wnd, *args):
    686         pass
    687 
    688     def OnDropData(self, dragObject, droppedGuys, *args):
    689         if not sm.GetService('fleet').IsCommanderOrBoss():
    690             return
    691         sm.GetService('fleet').DropOnFleetCommander(droppedGuys, CAN_ONLY_BE_MEMBER)
    692 
    693 
    694 class FleetHeader(Group):
    695     __guid__ = 'listentry.FleetHeader'
    696     isDragObject = True
    697 
    698     def Startup(self, *args, **kw):
    699         Group.Startup(self, *args, **kw)
    700         text_gaugepar = Container(name='text_gaugepar', parent=self, idx=0, align=uiconst.TOALL, pos=(0, 0, 0, 0))
    701         text_gaugepar.width = 0
    702         self.sr.text_gaugepar = text_gaugepar
    703         self.sr.label.parent.width = 0
    704         self.sr.label.parent.SetParent(text_gaugepar)
    705         Container(name='toppush', parent=self.sr.label.parent, align=uiconst.TOTOP, height=14)
    706         roleIconsContainer = Container(name='roleIconsContainer', parent=self.sr.label.parent, width=0, align=uiconst.TORIGHT)
    707         self.roleIconsContainer = roleIconsContainer
    708         self.sr.topLabel = eveLabel.EveLabelMedium(text='', parent=self.sr.label.parent, left=0, top=0, state=uiconst.UI_DISABLED, color=None, idx=0)
    709         self.sr.bottomLabel = eveLabel.EveLabelMedium(text='', parent=self.sr.label.parent, left=0, top=12, state=uiconst.UI_DISABLED, color=None, idx=0)
    710         changing = AnimSprite(icons=[ 'ui_38_16_%s' % (210 + i) for i in xrange(8) ], align=uiconst.TOPRIGHT, parent=self, pos=(0, 13, 16, 16))
    711         self.sr.changing = changing
    712         changing.state = uiconst.UI_NORMAL
    713         self.sr.myGroupSelection = Fill(name='myGroupSelection', bgParent=self, padding=(0, 1, 0, 1), color=(0.0, 0.5, 0.0, 0.1))
    714         self.sr.myGroupSelection.display = False
    715         self.movingHilite = Fill(bgParent=self, name='movingHilite', color=(1, 0, 0, 0.25))
    716         self.movingHilite.display = False
    717 
    718     def Load(self, node, *args, **kw):
    719         sublevel = node.Get('sublevel', 0)
    720         if node.groupType != 'fleet':
    721             node.hasArrow = True
    722         Group.Load(self, node, *args, **kw)
    723         self.sr.label.left += 2
    724         self.sr.topLabel.left = self.sr.label.left
    725         self.sr.bottomLabel.left = self.sr.label.left
    726         if node.commanderData and node.commanderData.itemID == session.charid:
    727             self.sr.myGroupSelection.display = True
    728         else:
    729             isMyGroup = node.myGroups.get(node.groupType, None) == node.groupID or node.groupType == 'fleet'
    730             if isMyGroup:
    731                 self.sr.expander.icon.ignoreColorBlindMode = False
    732                 self.sr.expander.SetRGBA(0.0, 0.5, 0.0, 0.8)
    733         label = self.GetTopLabelText(node)
    734         self.sr.topLabel.text = label
    735         self.sr.bottomLabel.top = max(12, self.sr.topLabel.top + self.sr.topLabel.textheight)
    736         bottomLabelText = self.GetBottomLabelText(node)
    737         self.sr.bottomLabel.text = bottomLabelText
    738         icons = getattr(node.commanderData, 'roleIcons', [])
    739         UpdateRoleIcons(self.roleIconsContainer, icons)
    740         if node.commanderData and node.commanderData.changing:
    741             self.sr.changing.state = uiconst.UI_DISABLED
    742             self.hint = localization.GetByLabel('UI/Fleet/FleetWindow/MemberChanging')
    743             self.sr.changing.Play()
    744         else:
    745             self.hint = None
    746             self.sr.changing.Stop()
    747             self.sr.changing.state = uiconst.UI_HIDDEN
    748         autoJoinIcon = getattr(self, 'autoJoinIcon', None)
    749         if node.showAsAutoJoinSquad:
    750             left = self.sr.topLabel.left + self.sr.topLabel.textwidth + 4
    751             if autoJoinIcon is None or autoJoinIcon.destroyed:
    752                 self.autoJoinIcon = Sprite(parent=self, texturePath='res:/UI/Texture/classes/fleet/defaultSquad.png', hint=localization.GetByLabel('UI/Fleet/FleetWindow/DefaultSquadHint'), align=uiconst.TOPLEFT, pos=(left,
    753                  0,
    754                  16,
    755                  16))
    756             self.autoJoinIcon.display = True
    757             self.autoJoinIcon.left = left
    758         elif autoJoinIcon:
    759             autoJoinIcon.display = False
    760 
    761     def OnDropData(self, dragObject, droppedGuys, *args):
    762         try:
    763             sm.GetService('fleet').OnDropCommanderDropData(dragObject, droppedGuys, self.sr.node)
    764         finally:
    765             self.movingHilite.display = False
    766 
    767     def OnDragEnter(self, dragObj, nodes):
    768         draggedGuy = nodes[0]
    769         if hasattr(draggedGuy, 'charID'):
    770             if self.sr.node.commanderData and self.sr.node.commanderData.itemID == draggedGuy.charID:
    771                 return
    772         groupType = self.sr.node.groupType
    773         groupID = self.sr.node.groupID
    774         isMultiMove = len(nodes) > 1
    775         canMove = sm.GetService('fleet').CanMoveToThisEntry(draggedGuy, self.sr.node, groupType, groupID=groupID, isMultiMove=isMultiMove)
    776         if canMove == CONNOT_BE_MOVED_INCOMPATIBLE:
    777             return
    778         if canMove == CANNOT_BE_MOVED:
    779             self.movingHilite.SetRGBA(*COLOR_CANNOT_BE_MOVED)
    780         elif canMove == CAN_BE_COMMANDER:
    781             self.movingHilite.SetRGBA(*COLOR_CAN_BE_COMMANDER)
    782         else:
    783             self.movingHilite.SetRGBA(*COLOR_CAN_ONLY_BE_MEMBER)
    784         self.movingHilite.display = True
    785 
    786     def OnDragExit(self, dragObj, nodes):
    787         self.movingHilite.display = False
    788 
    789     def GetHeight(self, *args):
    790         node, width = args
    791         topLabelHeight = uix.GetTextHeight('<b>' + node.groupInfo + '</b>', maxLines=1)
    792         bottomLabelHeight = uix.GetTextHeight(node.commanderName, maxLines=1)
    793         node.height = max(12, topLabelHeight) + bottomLabelHeight + 2
    794         return node.height
    795 
    796     def ToggleAllSquads(self, node, isOpen = True):
    797         toggleThread = uthread.new(self.ToggleAllSquads_thread, node, isOpen)
    798         toggleThread.context = 'FleetHeader::ToggleAllSquads'
    799 
    800     def ToggleAllSquads_thread(self, node, isOpen = True):
    801         if isOpen:
    802             self.DoToggleFleetHeader(node, isOpen, groupType='fleet')
    803             self.DoToggleFleetHeader(node, isOpen, groupType='wing')
    804         self.DoToggleFleetHeader(node, isOpen, groupType='squad')
    805 
    806     def ToggleAllWings(self, node, isOpen = True):
    807         toggleThread = uthread.new(self.ToggleAllWings_thread, node, isOpen)
    808         toggleThread.context = 'FleetHeader::ToggleAllWings'
    809 
    810     def ToggleAllWings_thread(self, node, isOpen = True):
    811         if isOpen:
    812             self.DoToggleFleetHeader(node, isOpen, groupType='fleet')
    813         self.DoToggleFleetHeader(node, isOpen, groupType='wing')
    814 
    815     def DoToggleFleetHeader(self, node, isOpen, groupType):
    816         scroll = node.scroll
    817         for entry in scroll.GetNodes():
    818             if entry.__guid__ != 'listentry.FleetHeader':
    819                 continue
    820             if entry.groupType == groupType:
    821                 if entry.panel:
    822                     self.ShowOpenState(isOpen)
    823                     self.UpdateLabel()
    824                     uicore.registry.SetListGroupOpenState(entry.id, isOpen)
    825                     scroll.PrepareSubContent(entry)
    826                 else:
    827                     uicore.registry.SetListGroupOpenState(entry.id, isOpen)
    828                     entry.scroll.PrepareSubContent(entry)
    829 
    830     def OnMouseDown(self, *args):
    831         commanderData = self.sr.node.commanderData
    832         if commanderData is None:
    833             return
    834         GetMenuService().TryExpandActionMenu(itemID=commanderData.charID, clickedObject=self, radialMenuClass=RadialMenuSpaceCharacter)
    835 
    836     def GetMenu(self):
    837         m = MenuList()
    838         commanderData = self.sr.node.commanderData
    839         if commanderData:
    840             m += GetMenuService().FleetMenu(commanderData.charID, unparsed=False)
    841             m += [None]
    842             m.append(MenuEntryData(MenuLabel('UI/Common/Pilot', {'character': commanderData.charID}), subMenuData=lambda : self._GetPilotSubMenuData(commanderData.charID), texturePath=eveicon.person))
    843         m += [None]
    844         if self.sr.node.groupType == 'squad':
    845             return m + GetSquadMenu(self.sr.node.groupID)
    846         if self.sr.node.groupType == 'wing':
    847             return m + self.GetWingMenu(self.sr.node.groupID)
    848         if self.sr.node.groupType == 'fleet':
    849             m += self.GetFleetMenu()
    850             m += [None]
    851             m += [(MenuLabel('UI/Fleet/FleetWindow/OpenAllWings'), self.ToggleAllWings, (self.sr.node, True)),
    852              (MenuLabel('UI/Fleet/FleetWindow/CloseAllWings'), self.ToggleAllWings, (self.sr.node, False)),
    853              (MenuLabel('UI/Fleet/FleetWindow/OpenAllSquads'), self.ToggleAllSquads, (self.sr.node, True)),
    854              (MenuLabel('UI/Fleet/FleetWindow/CloseAllSquads'), self.ToggleAllSquads, (self.sr.node, False))]
    855             return m
    856         raise NotImplementedError
    857 
    858     def _GetPilotSubMenuData(self, charID):
    859         subMenuData = GetMenuService().CharacterMenu(charID)
    860         return MenuList(subMenuData).filter(['UI/Fleet/Fleet', 'UI/Commands/ShowInfo'])
    861 
    862     def GetFleetMenu(self):
    863         ret = MenuList()
    864         if session.fleetrole != evefleet.fleetRoleLeader:
    865             ret += [(MenuLabel('UI/Fleet/LeaveMyFleet'), FleetSvc().LeaveFleet)]
    866         if FleetSvc().IsBoss() or session.fleetrole == evefleet.fleetRoleLeader:
    867             ret.extend([None, (MenuLabel('UI/Fleet/FleetWindow/CreateNewWing'), lambda : FleetSvc().CreateWing())])
    868         else:
    869             ret.append(None)
    870         if session.fleetrole in evefleet.fleetCmdrRoles:
    871             ret.append((MenuLabel('UI/Fleet/FleetWindow/Regroup'), lambda : FleetSvc().Regroup()))
    872         if FleetSvc().HasActiveBeacon(session.charid):
    873             ret.append((MenuLabel('UI/Fleet/FleetBroadcast/Commands/JumpBeacon'), lambda : FleetSvc().SendBroadcast_JumpBeacon()))
    874         ret.append((MenuLabel('UI/Fleet/FleetBroadcast/Commands/Location'), lambda : FleetSvc().SendBroadcast_Location()))
    875         return ret
    876 
    877     def GetWingMenu(self, wingID):
    878         if FleetSvc().IsBoss() or session.fleetrole in (evefleet.fleetRoleLeader, evefleet.fleetRoleWingCmdr):
    879             return MenuList([(MenuLabel('UI/Fleet/FleetWindow/DeleteWing'), lambda : sm.GetService('fleet').DeleteWing(wingID)), (MenuLabel('UI/Fleet/FleetWindow/ChangeName'), lambda : sm.GetService('fleet').ChangeWingName(wingID)), (MenuLabel('UI/Fleet/FleetWindow/CreateNewSquad'), lambda : sm.GetService('fleet').CreateSquad(wingID))])
    880         else:
    881             return MenuList()
    882 
    883     def Flash(self):
    884         sm.GetService('ui').BlinkSpriteA(self.sr.topLabel, 1.0, 400, 8, passColor=0)
    885         sm.GetService('ui').BlinkSpriteA(self.sr.bottomLabel, 1.0, 400, 8, passColor=0)
    886 
    887     def GetDragData(self, *args):
    888         commanderData = self.sr.node.commanderData
    889         if commanderData:
    890             info = cfg.eveowners.Get(commanderData.charID)
    891             fakeNode = self.sr.node
    892             fakeNode.info = info
    893             fakeNode.charID = commanderData.charID
    894             fakeNode.itemID = commanderData.charID
    895             return [fakeNode]
    896         else:
    897             return []
    898 
    899     @classmethod
    900     def GetTopLabelText(cls, node, *args):
    901         label = localization.GetByLabel('UI/Fleet/FleetWindow/UnitHeader', unitTitle=node.groupInfo)
    902         if node.numMembers == 0:
    903             label = '<color=0x88ffffff>%s</color>' % label
    904         return label
    905 
    906     @classmethod
    907     def GetBottomLabelText(cls, node, *args):
    908         label = node.commanderName
    909         return label
    910 
    911     @classmethod
    912     def GetCopyData(cls, node):
    913         sublevel = node.Get('sublevel', 0)
    914         indent = ' ' * sublevel * 4
    915         topLabel = cls.GetTopLabelText(node)
    916         bottomLabel = cls.GetBottomLabelText(node)
    917         text = indent + '-' + topLabel + '\n ' + indent + bottomLabel
    918         return text
    919 
    920 
    921 def UpdateRoleIcons(parent, icons):
    922     parent.Flush()
    923     left = 0
    924     if icons is not None and len(icons):
    925         parent.width = len(icons) * 20
    926         for icon in icons:
    927             iconpath = icon['id']
    928             eveIcon.Icon(icon=iconpath, parent=parent, pos=(left,
    929              0,
    930              16,
    931              16), align=uiconst.TOPLEFT, hint=icon['hint'])
    932             left += 20
    933 
    934 
    935 def FleetSvc():
    936     return sm.GetService('fleet')
    937 
    938 
    939 def GetFleetMenu():
    940     ret = MenuList([(localization.GetByLabel('UI/Fleet/LeaveMyFleet'), FleetSvc().LeaveFleet)])
    941     if FleetSvc().IsBoss() or session.fleetrole == evefleet.fleetRoleLeader:
    942         ret.extend([None, (localization.GetByLabel('UI/Fleet/FleetWindow/Regroup'), lambda : FleetSvc().Regroup())])
    943     else:
    944         ret.append(None)
    945     if FleetSvc().HasActiveBeacon(session.charid):
    946         ret.append((localization.GetByLabel('UI/Fleet/FleetBroadcast/Commands/JumpBeacon'), lambda : FleetSvc().SendBroadcast_JumpBeacon()))
    947     ret.append((localization.GetByLabel('UI/Fleet/FleetBroadcast/Commands/Location'), lambda : FleetSvc().SendBroadcast_Location()))
    948     return ret
    949 
    950 
    951 class EmptyGroup(Generic):
    952     __guid__ = 'listentry.EmptyGroup'
    953 
    954     def Load(self, data):
    955         Generic.Load(self, data)
    956         self.sr.label.left = 20 + 16 * data.indent
    957         self.sr.label.opacity = 0.7
    958         self.sr.label.Update()
    959         self.movingHilite = Fill(bgParent=self, name='movingHilite', color=(1, 0, 0, 0.25))
    960         self.movingHilite.display = False
    961         autoJoinIcon = getattr(self, 'autoJoinIcon', None)
    962         if data.showAsAutoJoinSquad:
    963             left = self.sr.label.left + self.sr.label.textwidth + 4
    964             if autoJoinIcon is None or autoJoinIcon.destroyed:
    965                 self.autoJoinIcon = Sprite(parent=self, texturePath='res:/UI/Texture/classes/fleet/defaultSquad.png', hint=localization.GetByLabel('UI/Fleet/FleetWindow/DefaultSquadHint'), align=uiconst.CENTERLEFT, pos=(left,
    966                  0,
    967                  16,
    968                  16))
    969             self.autoJoinIcon.display = True
    970             self.autoJoinIcon.left = left
    971         elif autoJoinIcon:
    972             autoJoinIcon.display = False
    973 
    974     def OnDropData(self, dragObject, droppedGuys, *args):
    975         try:
    976             sm.GetService('fleet').OnDropCommanderDropData(dragObject, droppedGuys, self.sr.node)
    977         finally:
    978             self.movingHilite.display = False
    979 
    980     def OnDragEnter(self, dragObj, nodes):
    981         draggedGuy = nodes[0]
    982         groupType = self.sr.node.groupType
    983         groupID = self.sr.node.groupID
    984         isMultiMove = len(nodes) > 1
    985         canMove = sm.GetService('fleet').CanMoveToThisEntry(draggedGuy, self.sr.node, groupType, groupID=groupID, isMultiMove=isMultiMove)
    986         if canMove == CONNOT_BE_MOVED_INCOMPATIBLE:
    987             return
    988         if canMove == CANNOT_BE_MOVED:
    989             self.movingHilite.SetRGBA(*COLOR_CANNOT_BE_MOVED)
    990         elif canMove == CAN_BE_COMMANDER:
    991             self.movingHilite.SetRGBA(*COLOR_CAN_BE_COMMANDER)
    992         else:
    993             self.movingHilite.SetRGBA(*COLOR_CAN_ONLY_BE_MEMBER)
    994         self.movingHilite.display = True
    995 
    996     def OnDragExit(self, dragObj, nodes):
    997         self.movingHilite.display = False
    998 
    999     @classmethod
   1000     def GetCopyData(cls, node):
   1001         sublevel = node.Get('isSub', 0)
   1002         indent = ' ' * sublevel * 4
   1003         return indent + node.label
   1004 
   1005 
   1006 class FleetMember(BaseTacticalEntry):
   1007     __guid__ = 'listentry.FleetMember'
   1008     isDragObject = True
   1009 
   1010     def Startup(self, *args, **kw):
   1011         BaseTacticalEntry.Startup(self, *args, **kw)
   1012         idx = self.sr.label.parent.children.index(self.sr.label)
   1013         text_gaugepar = Container(name='text_gaugepar', parent=self, idx=idx, align=uiconst.TOALL, pos=(0, 0, 0, 0))
   1014         text_gaugepar.width = 0
   1015         textpar = Container(name='textpar', parent=text_gaugepar, idx=idx, align=uiconst.TOALL, pos=(0, 0, 0, 0), clipChildren=True)
   1016         self.sr.text_gaugepar = text_gaugepar
   1017         self.children.remove(self.sr.label)
   1018         textpar.children.append(self.sr.label)
   1019         Container(name='toppush', parent=textpar, align=uiconst.TOTOP, height=2)
   1020         roleIconsContainer = Container(name='roleIconsContainer', parent=textpar, width=0, align=uiconst.TORIGHT)
   1021         self.roleIconsContainer = roleIconsContainer
   1022         changing = AnimSprite(icons=[ 'ui_38_16_%s' % (210 + i) for i in xrange(8) ], align=uiconst.TOPRIGHT, parent=self, pos=(0, 0, 16, 16))
   1023         self.sr.changing = changing
   1024         changing.state = uiconst.UI_HIDDEN
   1025         self.sr.myGroupSelection = Fill(name='myGroupSelection', bgParent=self, padding=(0, 1, 0, 1), color=(0.0, 0.5, 0.0, 0.15))
   1026         self.sr.myGroupSelection.display = False
   1027         self.movingHilite = Fill(bgParent=self, name='movingHilite', color=(1, 0, 0, 0.25))
   1028         self.movingHilite.display = False
   1029 
   1030     def Load(self, node):
   1031         Generic.Load(self, node)
   1032         data = node
   1033         if settings.user.ui.Get('flatFleetView', False):
   1034             left = 0
   1035         else:
   1036             left = 20
   1037             if node.itemID == session.charid:
   1038                 self.sr.myGroupSelection.display = True
   1039         indent = left + node.sublevel * 16
   1040         self.sr.label.left = indent
   1041         selected, = sm.GetService('stateSvc').GetStates(data.itemID, [state.selected])
   1042         if selected:
   1043             self.Select()
   1044         icons = node.Get('roleIcons', None)
   1045         UpdateRoleIcons(self.roleIconsContainer, icons)
   1046         if node.changing:
   1047             self.sr.changing.state = uiconst.UI_DISABLED
   1048             self.hint = localization.GetByLabel('UI/Fleet/FleetWindow/MemberChanging')
   1049             self.sr.changing.Play()
   1050         else:
   1051             self.hint = None
   1052             self.sr.changing.Stop()
   1053             self.sr.changing.state = uiconst.UI_HIDDEN
   1054         self.sr.label.Update()
   1055 
   1056     def GetHeight(_self, *args):
   1057         node, width = args
   1058         node.height = uix.GetTextHeight(node.label, maxLines=1) + 4
   1059         return node.height
   1060 
   1061     def GetDragData(self, *args):
   1062         selectedNodes = self.sr.node.scroll.GetSelectedNodes(self.sr.node)
   1063         for eachNode in selectedNodes:
   1064             info = cfg.eveowners.Get(eachNode.itemID)
   1065             eachNode.info = info
   1066 
   1067         return selectedNodes
   1068 
   1069     def OnDropData(self, dragObject, droppedGuys, *args):
   1070         if FLEET_VIEW_FLAT_LIST_SETTING.is_enabled():
   1071             self.movingHilite.display = False
   1072             return
   1073         try:
   1074             sm.GetService('fleet').OnDropCommanderDropData(dragObject, droppedGuys, self.sr.node)
   1075         finally:
   1076             self.movingHilite.display = False
   1077 
   1078     def OnDragEnter(self, dragObj, nodes):
   1079         draggedGuy = nodes[0]
   1080         if hasattr(draggedGuy, 'charID'):
   1081             if self.sr.node.itemID == draggedGuy.charID:
   1082                 return
   1083         isMultiMove = len(nodes) > 1
   1084         canMove = sm.GetService('fleet').CanMoveToThisEntry(draggedGuy, self.sr.node, 'fleetMember', groupID=None, isMultiMove=isMultiMove)
   1085         if canMove == CONNOT_BE_MOVED_INCOMPATIBLE:
   1086             return
   1087         if canMove == CANNOT_BE_MOVED:
   1088             self.movingHilite.SetRGBA(*COLOR_CANNOT_BE_MOVED)
   1089         else:
   1090             self.movingHilite.SetRGBA(*COLOR_CAN_ONLY_BE_MEMBER)
   1091         self.movingHilite.display = True
   1092 
   1093     def OnDragExit(self, dragObj, nodes):
   1094         self.movingHilite.display = False
   1095 
   1096     def GetMenu(self):
   1097         return GetFleetMemberMenuOptions(self.sr.node.charID)
   1098 
   1099     def OnMouseDown(self, *args):
   1100         GetMenuService().TryExpandActionMenu(itemID=self.sr.node.charID, clickedObject=self, radialMenuClass=RadialMenuSpaceCharacter)
   1101 
   1102     @classmethod
   1103     def GetCopyData(cls, node):
   1104         sublevel = node.Get('isSub', 0)
   1105         indent = ' ' * sublevel * 4
   1106         return indent + node.label
   1107 
   1108     GetMenu = ParanoidDecoMethod(GetMenu, ('sr', 'node'))
   1109 
   1110 
   1111 class FleetAction(Action):
   1112 
   1113     def ApplyAttributes(self, attributes):
   1114         super(FleetAction, self).ApplyAttributes(attributes)
   1115         self.broadcastID = attributes.broadcastID
   1116         texturePath = attributes.texturePath
   1117         self.func = attributes.func
   1118         self.sr.icon = self.icon = GlowSprite(texturePath=texturePath, parent=self, align=uiconst.CENTER, pos=(1, 0, 16, 16), state=uiconst.UI_DISABLED)
   1119         self.sr.fill = Fill(parent=self, state=uiconst.UI_HIDDEN, width=self.width, height=self.height, align=uiconst.RELATIVE, color=(1, 1, 1, 0.5))
   1120 
   1121     def Prepare_(self, icon = None):
   1122         pass
   1123 
   1124     def OnMouseMove(self, *args):
   1125         pass
   1126 
   1127     def OnClick(self, *args):
   1128         self.func()
   1129 
   1130     def LoadTooltipPanel(self, tooltipPanel, *args):
   1131         if not self.broadcastID:
   1132             return
   1133         cmdName = 'CmdFleetBroadcast_%s' % self.broadcastID
   1134         cmd = uicore.cmd.commandMap.GetCommandByName(cmdName)
   1135         shortcutStr = cmd.GetShortcutAsString()
   1136         tooltipPanel.LoadGeneric3ColumnTemplate()
   1137         tooltipPanel.AddLabelMedium(text=self.hint, cellPadding=(0, 0, 7, 0), colSpan=tooltipPanel.columns - 1, width=200, autoFitToText=True)
   1138         if shortcutStr:
   1139             tooltipPanel.AddShortcutCell(shortcutStr)
   1140         else:
   1141             tooltipPanel.AddCell()
   1142 
   1143 
   1144 class FleetRoleCont(Container):
   1145     __guid__ = 'xtriui.FleetRoleCont'
   1146     __notifyevents__ = ['OnMyFleetInfoChanged', 'OnSessionChanged']
   1147     __dependencies__ = ['fleet']
   1148     default_height = 16
   1149     default_name = 'fleetRoleCont'
   1150 
   1151     def ApplyAttributes(self, attributes):
   1152         Container.ApplyAttributes(self, attributes)
   1153         sm.RegisterNotify(self)
   1154         self.buttons = {}
   1155         self.roleIconsContainer = Container(name='roleIconsContainer', parent=self, align=uiconst.TOLEFT)
   1156         self.UpdateRoleIcons()
   1157 
   1158     def UpdateRoleIcons(self):
   1159         info = sm.GetService('fleet').GetMemberInfo(session.charid)
   1160         if info is None:
   1161             return
   1162         icons = []
   1163         if info.role == evefleet.fleetRoleLeader:
   1164             icons.append({'id': 'ui_73_16_17',
   1165              'hint': localization.GetByLabel('UI/Fleet/Ranks/FleetCommander')})
   1166         elif info.role == evefleet.fleetRoleWingCmdr:
   1167             icons.append({'id': 'ui_73_16_18',
   1168              'hint': localization.GetByLabel('UI/Fleet/Ranks/WingCommander')})
   1169         elif info.role == evefleet.fleetRoleSquadCmdr:
   1170             icons.append({'id': 'ui_73_16_19',
   1171              'hint': localization.GetByLabel('UI/Fleet/Ranks/SquadCommander')})
   1172         if info.job & evefleet.fleetJobCreator:
   1173             icons.append({'id': 'ui_73_16_20',
   1174              'hint': localization.GetByLabel('UI/Fleet/Ranks/Boss')})
   1175         self.display = bool(icons)
   1176         UpdateRoleIcons(self.roleIconsContainer, icons)
   1177 
   1178     def OnMyFleetInfoChanged(self):
   1179         self.UpdateRoleIcons()
   1180 
   1181     def OnSessionChanged(self, isRemote, sess, change):
   1182         if not self.destroyed:
   1183             self.UpdateRoleIcons()
   1184 
   1185 
   1186 def GetAllFleetActivities():
   1187     return {k:localization.GetByLabel(v) for k, v in fleetActivityNames.iteritems()}
   1188 
   1189 
   1190 def GetFleetActivityName(activityID):
   1191     if activityID not in fleetActivityNames:
   1192         activityID = ACTIVITY_MISC
   1193     labelPath = fleetActivityNames.get(activityID, 'UI/Agency/Fleetup/UnknownActivity')
   1194     return localization.GetByLabel(labelPath)