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

mining_scan_results_window.py (15438B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\inflight\mining_scan_results_window.py
      2 import sys
      3 import appConst
      4 import collections
      5 import eveicon
      6 import evelink.client
      7 import evetypes
      8 import localization
      9 import mining
     10 import utillib
     11 from carbon.common.script.sys.serviceManager import ServiceManager
     12 from carbon.common.script.util.format import FmtAmt, FmtDist
     13 from carbonui import uiconst, Align, PickState
     14 from carbonui.button.group import ButtonGroup
     15 from carbonui.control.button import Button
     16 from carbonui.control.contextMenu.menuData import MenuData
     17 from carbonui.control.window import Window
     18 from carbonui.loggers.buttonLogger import log_button_clicked
     19 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     20 from carbonui.primitives.warningContainer import WarningContainer
     21 from carbonui.uicore import uicore
     22 from carbonui.window.control.action import WindowMenuAction
     23 from carbonui.window.segment.underlay import WindowSegmentUnderlay
     24 from clientsettings.setting import CharSettingEnum
     25 from dogma import units
     26 from eve.client.script.parklife import states as state, states
     27 from eve.client.script.parklife.state import GetStateSvc
     28 from eve.client.script.remote.michelle import GetMichelle
     29 from eve.client.script.ui import eveColor
     30 from eve.client.script.ui.control import eveScroll
     31 from eve.client.script.ui.control.entries.generic import Generic
     32 from eve.client.script.ui.control.entries.util import GetFromClass
     33 from eve.client.script.ui.control.listgroup import ListGroup
     34 from eve.client.script.ui.inflight.bracketsAndTargets.targetIconCont import TargetIconCont
     35 from eve.common.script.util.eveFormat import FmtISKAndRound
     36 from eveservices.menu import GetMenuService
     37 from inventorycommon import typeHelpers
     38 from localization import GetByLabel
     39 from mining import MiningScan
     40 from mining.client import mining_signals, mining_util
     41 from mining.client.asteroid_scanning_service import AsteroidScanningService
     42 from mining.client.mining_overlay_controller import MiningOverlayController
     43 SCROLL_HEADERS_TIER_2 = (GetByLabel('UI/Common/Ore'),
     44  GetByLabel('UI/Common/Quantity'),
     45  GetByLabel('UI/Common/Volume'),
     46  GetByLabel('UI/Common/Value'),
     47  GetByLabel('UI/Common/Distance'))
     48 
     49 class SortGroupsBy():
     50     ALPHABETICALLY = 1
     51     VALUE = 2
     52     TYPE = 3
     53 
     54 
     55 sort_groups_by_setting = CharSettingEnum('miningScanSortGroupsBy', default_value=SortGroupsBy.ALPHABETICALLY)
     56 
     57 class MiningScanResultsWindow(Window):
     58     default_windowID = 'MiningScanResultsWindow2'
     59     default_isLightBackground = True
     60     default_scope = uiconst.SCOPE_INFLIGHT
     61     default_iconNum = eveicon.mining_overlay_toggle_default
     62     default_caption = GetByLabel('UI/Inflight/Scanner/MiningScanResults')
     63     default_width = 400
     64     default_height = 400
     65     analyticID = default_windowID
     66 
     67     def __init__(self, *args, **kwargs):
     68         super(MiningScanResultsWindow, self).__init__(*args, **kwargs)
     69         self.construct_layout()
     70         ServiceManager.Instance().RegisterForNotifyEvent(self, 'OnStateChange')
     71         ServiceManager.Instance().RegisterForNotifyEvent(self, 'OnSessionChanged')
     72         self.populate_scroll()
     73         self.connect_signals()
     74 
     75     def construct_layout(self):
     76         bottom_cont = ContainerAutoSize(parent=self.content, align=Align.TOBOTTOM, padTop=4)
     77         btn_group = ButtonGroup(parent=bottom_cont, align=Align.TOBOTTOM, padTop=4)
     78         pad_left, _, pad_right, pad_bottom = self.content_padding
     79         WindowSegmentUnderlay(bgParent=bottom_cont, padding=(-pad_left,
     80          0,
     81          -pad_right,
     82          -pad_bottom))
     83         tier = mining_util.get_current_ship_mining_scanner_upgrade_tier()
     84         if not tier or tier < MiningScan.TIER_2:
     85             WarningContainer(parent=bottom_cont, align=Align.TOBOTTOM, pickState=PickState.ON, textAlignment=Align.TOTOP, text=GetByLabel('UI/Mining/MiningScannerUpgradeRequired', module_name=evelink.type_link(appConst.typeSurveyScannerI, evetypes.GetName(appConst.typeSurveyScannerI))))
     86         self.scan_button = Button(parent=btn_group, label=GetByLabel('UI/Inflight/Scanner/Scan'), func=self.on_scan_button, analyticID='MiningScanButton')
     87         self.scroll = eveScroll.Scroll(parent=self.content)
     88         self.scroll.OnChar = lambda *_args: None
     89         self.scroll.sr.id = 'mining_scan_scroll'
     90 
     91     def on_scan_button(self, *args):
     92         MiningOverlayController.get_instance().perform_scan()
     93         log_button_clicked(self.scan_button)
     94 
     95     @classmethod
     96     def Open(cls, *args, **kwds):
     97         if not mining_util.has_current_ship_integrated_mining_scanner():
     98             return
     99         return super(MiningScanResultsWindow, cls).Open(*args, **kwds)
    100 
    101     def Close(self, setClosed = False, *args, **kwds):
    102         super(MiningScanResultsWindow, self).Close(setClosed, *args, **kwds)
    103         self.disconnect_signals()
    104 
    105     def GetCustomHeaderButtons(self):
    106         return [WindowMenuAction(window=self, icon=eveicon.bars_sort_ascending, label=GetByLabel('UI/Mining/SortGroupsBy'), callback=self.on_filter_button)]
    107 
    108     def on_filter_button(self, *args):
    109         m = MenuData()
    110         m.AddLabel(GetByLabel('UI/Mining/SortGroupsBy'))
    111         m.AddRadioButton(GetByLabel('UI/Mining/SortGroupsByAlphabetically'), SortGroupsBy.ALPHABETICALLY, sort_groups_by_setting)
    112         m.AddRadioButton(GetByLabel('UI/Mining/SortGroupsByValue'), SortGroupsBy.VALUE, sort_groups_by_setting)
    113         m.AddRadioButton(GetByLabel('UI/Mining/SortGroupsByType'), SortGroupsBy.TYPE, sort_groups_by_setting)
    114         return m
    115 
    116     def disconnect_signals(self):
    117         mining_signals.on_mining_scan_completed.disconnect(self.on_mining_scan_completed)
    118         mining_signals.on_mining_scan_effect_started.disconnect(self.on_mining_scan_effect_started)
    119         mining_signals.on_mining_scan_effect_completed.disconnect(self.on_mining_scan_effect_completed)
    120         sort_groups_by_setting.on_change.disconnect(self.on_sort_groups_by_setting)
    121 
    122     def connect_signals(self):
    123         mining_signals.on_mining_scan_completed.connect(self.on_mining_scan_completed)
    124         mining_signals.on_mining_scan_effect_started.connect(self.on_mining_scan_effect_started)
    125         mining_signals.on_mining_scan_effect_completed.connect(self.on_mining_scan_effect_completed)
    126         sort_groups_by_setting.on_change.connect(self.on_sort_groups_by_setting)
    127 
    128     def on_sort_groups_by_setting(self, *args):
    129         self.populate_scroll()
    130 
    131     def on_mining_scan_effect_started(self):
    132         self.scan_button.busy = True
    133 
    134     def on_mining_scan_effect_completed(self):
    135         self.scan_button.busy = False
    136 
    137     def on_mining_scan_completed(self):
    138         self.populate_scroll()
    139 
    140     def populate_scroll(self):
    141         asteroid_ids_and_quantities_by_type_id = self.get_asteroid_ids_and_quantities_by_type_ids()
    142         scan_tier = AsteroidScanningService.get_instance().get_current_scan_type()
    143         if scan_tier == MiningScan.TIER_2:
    144             scroll_list = self.get_tier_2_scan_scroll_list(asteroid_ids_and_quantities_by_type_id)
    145         else:
    146             scroll_list = self.get_tier_1_scan_entries(asteroid_ids_and_quantities_by_type_id)
    147         scroll_list = self.get_groups_sorted(scroll_list)
    148         self.scroll.Load(contentList=scroll_list, headers=SCROLL_HEADERS_TIER_2, noContentHint=GetByLabel('UI/Mining/NoScanResultsFound'))
    149 
    150     def get_groups_sorted(self, scroll_list):
    151         if sort_groups_by_setting.get() == SortGroupsBy.ALPHABETICALLY:
    152             scroll_list = localization.util.Sort(scroll_list, key=lambda x: x.label)
    153         elif sort_groups_by_setting.get() == SortGroupsBy.VALUE:
    154             scroll_list = sorted(scroll_list, key=lambda x: mining_util.get_volume_est_price(x['typeID']), reverse=True)
    155         elif sort_groups_by_setting.get() == SortGroupsBy.TYPE:
    156             scroll_list = sorted(scroll_list, key=lambda x: (evetypes.GetGroupID(x['typeID']), x['typeID']))
    157         return scroll_list
    158 
    159     def get_tier_1_scan_entries(self, asteroid_ids_and_quantities_by_type_id):
    160         scroll_list = []
    161         for type_id, asteroid_ids_and_quantities in asteroid_ids_and_quantities_by_type_id.items():
    162             scroll_list.append(GetFromClass(ListGroup, {'GetSubContent': self.get_entries_tier_1,
    163              'label': evetypes.GetName(type_id),
    164              'id': ('TypeSel', type_id),
    165              'groupItems': asteroid_ids_and_quantities,
    166              'typeID': type_id,
    167              'showlen': 1,
    168              'sublevel': 0,
    169              'state': 'locked',
    170              'currentTargetIDs': sm.GetService('target').GetTargets().keys(),
    171              'iconID': sm.GetService('bracket').GetBracketIcon(type_id),
    172              'posttext': self.get_list_group_post_text(type_id)}))
    173 
    174         return scroll_list
    175 
    176     def get_tier_2_scan_scroll_list(self, asteroid_ids_and_quantities_by_type_id):
    177         scroll_list = []
    178         for type_id, asteroid_ids_and_quantities in asteroid_ids_and_quantities_by_type_id.items():
    179             scroll_list.append(GetFromClass(ListGroup, {'GetSubContent': self.get_entries_tier_2,
    180              'label': evetypes.GetName(type_id),
    181              'id': ('TypeSel', type_id),
    182              'groupItems': asteroid_ids_and_quantities,
    183              'typeID': type_id,
    184              'showlen': 1,
    185              'sublevel': 0,
    186              'state': 'locked',
    187              'currentTargetIDs': sm.GetService('target').GetTargets().keys(),
    188              'iconID': sm.GetService('bracket').GetBracketIcon(type_id),
    189              'posttext': self.get_list_group_post_text(type_id)}))
    190 
    191         return scroll_list
    192 
    193     def get_list_group_post_text(self, type_id):
    194         volume_price = mining_util.get_volume_est_price(type_id)
    195         if not volume_price:
    196             return ''
    197         est_price = GetByLabel('UI/Shared/EstimatedPricePerSquareMeter', iskString=FmtISKAndRound(volume_price, False))
    198         return u"<color='{}'>{}</color>".format(eveColor.LED_GREY_HEX, est_price)
    199 
    200     def get_asteroid_ids_and_quantities_by_type_ids(self):
    201         quantity_by_asteroid_id = AsteroidScanningService.get_instance().get_quantities_by_asteroid_id()
    202         asteroid_ids_and_quantities_by_type_id = collections.defaultdict(list)
    203         ballpark = GetMichelle().GetBallpark()
    204         for asteroid_id, quantity in quantity_by_asteroid_id.items():
    205             ball = ballpark.GetBall(asteroid_id)
    206             type_id = mining.get_harvestable_type(ball.typeID)
    207             asteroid_ids_and_quantities_by_type_id[type_id].append((asteroid_id, quantity))
    208 
    209         return asteroid_ids_and_quantities_by_type_id
    210 
    211     def get_entries_tier_1(self, node, *args):
    212         scroll_list = []
    213         bp = GetMichelle().GetBallpark()
    214         for asteroid_id, _ in node.groupItems:
    215             try:
    216                 dist = bp.GetBall(asteroid_id).surfaceDist
    217             except AttributeError:
    218                 dist = 0
    219                 import traceback
    220                 traceback.print_exc()
    221                 sys.exc_clear()
    222 
    223             data = utillib.KeyVal()
    224             evetypes.GetVolume(node.typeID)
    225             rightLabelParts = ['-',
    226              '-',
    227              '-',
    228              FmtDist(dist)]
    229             data.label = '%s<t><right>%s' % (evetypes.GetName(node.typeID), '<t><right>'.join(rightLabelParts))
    230             data.itemID = asteroid_id
    231             data.typeID = node.typeID
    232             data.showinfo = 0
    233             data.isTarget = asteroid_id in node.currentTargetIDs
    234             data.sublevel = 1
    235             data.Set('sort_' + GetByLabel('UI/Common/Distance'), dist)
    236             entry = GetFromClass(MiningScanEntry, data)
    237             scroll_list.append(entry)
    238 
    239         return scroll_list
    240 
    241     def get_entries_tier_2(self, node, *args):
    242         scroll_list = []
    243         bp = sm.GetService('michelle').GetBallpark()
    244         for asteroid_id, qty in node.groupItems:
    245             try:
    246                 dist = bp.GetBall(asteroid_id).surfaceDist
    247             except AttributeError:
    248                 dist = 0
    249                 import traceback
    250                 traceback.print_exc()
    251                 sys.exc_clear()
    252 
    253             data = utillib.KeyVal()
    254             evetypes.GetVolume(node.typeID)
    255             volume = evetypes.GetVolume(node.typeID) * qty
    256             value = typeHelpers.GetAveragePrice(node.typeID)
    257             if value:
    258                 value = FmtISKAndRound(value * qty)
    259             else:
    260                 value = '-'
    261             volumeText = GetByLabel('UI/InfoWindow/ValueAndUnit', value=FmtAmt(volume, showFraction=0), unit=units.get_display_name(appConst.unitVolume))
    262             rightLabelParts = [FmtAmt(qty),
    263              volumeText,
    264              value,
    265              FmtDist(dist)]
    266             data.label = '%s<t><right>%s' % (evetypes.GetName(node.typeID), '<t><right>'.join(rightLabelParts))
    267             data.itemID = asteroid_id
    268             data.typeID = node.typeID
    269             data.showinfo = 0
    270             data.isTarget = asteroid_id in node.currentTargetIDs
    271             data.sublevel = 1
    272             data.Set('sort_' + GetByLabel('UI/Common/Quantity'), qty)
    273             data.Set('sort_' + GetByLabel('UI/Common/Volume'), volume)
    274             data.Set('sort_' + GetByLabel('UI/Common/Value'), value)
    275             data.Set('sort_' + GetByLabel('UI/Common/Distance'), dist)
    276             entry = GetFromClass(MiningScanEntry, data)
    277             scroll_list.append(entry)
    278 
    279         return scroll_list
    280 
    281     def OnStateChange(self, itemID, flag, newState, *args):
    282         if flag not in (state.targeting, state.targeted):
    283             return
    284         for node in self.scroll.GetNodes():
    285             if node.itemID == itemID and node.panel is not None:
    286                 node.panel.OnChangingState(flag, newState)
    287                 return
    288 
    289     def OnSessionChanged(self, isremote, session, change):
    290         if 'shipid' in change:
    291             self.Close()
    292 
    293 
    294 class MiningScanEntry(Generic):
    295 
    296     def ApplyAttributes(self, attributes):
    297         super(MiningScanEntry, self).ApplyAttributes(attributes)
    298         self.targetIconCont = TargetIconCont(parent=self, pos=(2, 0, 16, 16), iconSize=16, align=uiconst.CENTERLEFT)
    299 
    300     def Load(self, node):
    301         sublevelCorrection = self.sr.node.scroll.sr.get('sublevelCorrection', 0) if self.sr.node.scroll else 0
    302         node.sublevel += sublevelCorrection
    303         Generic.Load(self, node)
    304         targeting, targeted = sm.GetService('stateSvc').GetStates(node.itemID, [state.targeting, state.targeted])
    305         if targeting:
    306             self.targetIconCont.StartTargeting()
    307         elif targeted:
    308             self.targetIconCont.SetTargetedIcon()
    309 
    310     def OnChangingState(self, flag, newState):
    311         if flag == state.targeting:
    312             self.targetIconCont.HandleTargetingChanges(newState)
    313         elif flag == state.targeted:
    314             self.targetIconCont.HandleTargetedChanges(newState)
    315 
    316     def OnClick(self, *args):
    317         super(MiningScanEntry, self).OnClick(*args)
    318         uicore.cmd.ExecuteCombatCommand(self.sr.node.itemID, uiconst.UI_CLICK)
    319         GetStateSvc().SetState(self.sr.node.itemID, states.selected, True)
    320 
    321     def OnMouseEnter(self, *args):
    322         super(MiningScanEntry, self).OnMouseEnter(*args)
    323         GetStateSvc().SetState(self.sr.node.itemID, states.mouseOver, True)
    324 
    325     def OnMouseExit(self, *args):
    326         super(MiningScanEntry, self).OnMouseExit(*args)
    327         GetStateSvc().SetState(self.sr.node.itemID, states.mouseOver, False)
    328 
    329     def GetMenu(self, *args):
    330         return GetMenuService().CelestialMenu(self.sr.node.itemID)