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

overviewPanel.py (14329B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\neocom\wallet\panels\personal\overviewPanel.py
      2 import math
      3 from carbonui.util.various_unsorted import GetWindowAbove
      4 from carbon.common.script.util.format import FmtAmt
      5 from carbonui import uiconst
      6 from carbonui.control.radioButton import RadioButton
      7 from carbonui.control.scrollContainer import ScrollContainer
      8 from carbonui.primitives.container import Container
      9 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     10 from carbonui.primitives.fill import Fill
     11 from carbonui.primitives.transform import Transform
     12 from carbonui.uianimations import animations
     13 from carbonui.uicore import uicore
     14 from carbonui.util.color import Color
     15 from carbonui.control.button import Button
     16 from eve.client.script.ui.control.donutChart import DonutChart
     17 from eve.client.script.ui.control.eveLabel import Label, EveLabelMedium, EveCaptionLarge, EveLabelLarge, EveLabelMediumBold
     18 from eve.client.script.ui.control.eveWindowUnderlay import ListEntryUnderlay
     19 from eve.client.script.ui.shared.neocom.wallet.panels.personal import overviewPanelSignals
     20 from eve.client.script.ui.shared.neocom.wallet.transactionOverviewController import TransactionOverviewController
     21 from eve.common.lib import appConst
     22 from eve.common.script.util.eveFormat import FmtISK
     23 from localization import GetByLabel
     24 MIN_SEGMENT_SIZE = 0.02
     25 INCOME = 1
     26 EXPENSES = 2
     27 DONUT_RADIUS = 95
     28 DONUT_LINEWIDTH = 15.0
     29 DONUT_SHADOWWIDTH = 6
     30 DONUT_SHADOWOPACITY = 0.3
     31 COLOR_BY_REFGROUPID = {appConst.refGroupCorpAlliance: '#5c59d8',
     32  appConst.refGroupAgentsAndMissions: '#e68348',
     33  appConst.refGroupTrade: '#31c4a1',
     34  appConst.refGroupBounty: '#e53a3a',
     35  appConst.refGroupIndustry: '#3de53a',
     36  appConst.refGroupTransfer: '#e6e048',
     37  appConst.refGroupMisc: '#808080',
     38  appConst.refGroupHypernetRelay: '#3aa8e5'}
     39 
     40 class OverviewPanel(Container):
     41     default_name = 'OverviewPanel'
     42     isTabStop = True
     43 
     44     def ApplyAttributes(self, attributes):
     45         Container.ApplyAttributes(self, attributes)
     46         self.isInitialized = False
     47         self.selectedRefGroupID = None
     48         overviewPanelSignals.on_entry_selected.connect(self.OnEntrySelected)
     49         wnd = GetWindowAbove(self)
     50         if wnd:
     51             wnd.on_start_scale.connect(self.OnWindowStartScale)
     52             wnd.on_end_scale.connect(self.OnWindowEndScale)
     53             wnd.on_stacked_changed.connect(self.on_window_stack_changed)
     54             wnd.on_display_changed.connect(self.on_window_display_changed)
     55 
     56     def OnWindowEndScale(self, wnd):
     57         if not self.display:
     58             return
     59         animations.FadeTo(self.leftCont, self.leftCont.opacity, 1.0)
     60         self.ReconstructDonutChart()
     61         self.Update()
     62 
     63     def OnWindowStartScale(self, wnd):
     64         if not self.display:
     65             return
     66         animations.FadeTo(self.leftCont, self.leftCont.opacity, 0.0, duration=0.1)
     67 
     68     def OnEntrySelected(self, refGroupID):
     69         self.Update(refGroupID)
     70 
     71     def on_window_stack_changed(self, *args):
     72         self.ReconstructDonutChart()
     73         self.Update()
     74 
     75     def on_window_display_changed(self, *args):
     76         self.ReconstructDonutChart()
     77         self.Update()
     78 
     79     def OnTabSelect(self):
     80         if not self.isInitialized:
     81             self.ConstructLayout()
     82             self.isInitialized = True
     83         self.ReconstructDonutChart()
     84         self.Update()
     85 
     86     def ConstructLayout(self):
     87         self.rightCont = Container(name='rightCont', parent=self, align=uiconst.TORIGHT, width=200, padding=(32, 16, 0, 0))
     88         self.leftCont = Container(name='leftCont', parent=self, padLeft=16)
     89         self.backButton = Button(name='backButton', parent=self, func=self.OnBack, align=uiconst.BOTTOMRIGHT, hint=GetByLabel('UI/Commands/Back'), texturePath='res:/UI/Texture/Vgs/back.png', iconSize=16, iconPadding=8)
     90         self.ConstructRadioButtons()
     91         self.entriesCont = ScrollContainer(parent=self.rightCont, align=uiconst.TOALL, state=uiconst.UI_PICKCHILDREN, padTop=8)
     92 
     93     def ReconstructDonutChart(self):
     94         if self.destroyed or not self.isInitialized:
     95             return
     96         self.leftCont.Flush()
     97         radius = self.chart_radius
     98         self.donutTransform = Transform(name='donutTransform', parent=self.leftCont, align=uiconst.CENTER, pos=(0,
     99          0,
    100          radius * 2,
    101          radius * 2), alignMode=uiconst.TOPLEFT, scalingCenter=(0.5, 0.5))
    102         self.donutChart = DonutChart(parent=self.donutTransform, radius=radius, lineWidth=DONUT_LINEWIDTH, align=uiconst.CENTER, minSegmentSize=MIN_SEGMENT_SIZE)
    103         self.donutChart.on_segment_clicked.connect(self.OnSegmentClicked)
    104         self.donutChart.on_segment_mouse_enter.connect(self.OnSegmentMouseEnter)
    105         self.donutChart.on_segment_mouse_exit.connect(self.OnSegmentMouseExit)
    106         self.donutChart.GetSegmentColor = self.GetDonutChartSegmentColor
    107         radius = radius + DONUT_SHADOWWIDTH
    108         self.donutShadowTransform = Transform(name='donutShadowTransform', parent=self.leftCont, align=uiconst.CENTER, pos=(0,
    109          0,
    110          2 * radius,
    111          2 * radius), alignMode=uiconst.TOPLEFT, scalingCenter=(0.5, 0.5))
    112         self.donutChartShadow = DonutChart(parent=self.donutShadowTransform, radius=radius, lineWidth=DONUT_SHADOWWIDTH, align=uiconst.CENTER, state=uiconst.UI_DISABLED, minSegmentSize=MIN_SEGMENT_SIZE, opacity=0.0, outputMode=uiconst.OUTPUT_GLOW)
    113         self.donutChartShadow.GetSegmentColor = self.GetDonutChartSegmentColor
    114         self.ConstructDonutLabels()
    115 
    116     @property
    117     def chart_radius(self):
    118         wnd_width, wnd_height = GetWindowAbove(self).GetAbsoluteSize()
    119         w = wnd_width - self.rightCont.width
    120         h = wnd_height - 249
    121         radius = min(w, h) / 2.0 * 0.9
    122         return radius
    123 
    124     def ConstructDonutLabels(self):
    125         width, _ = self.leftCont.GetAbsoluteSize()
    126         self.donutLabelCont = ContainerAutoSize(name='donutLabelCont', parent=self.donutTransform, align=uiconst.CENTER, width=width - 120, opacity=0.0, idx=0)
    127         self.donutCenterCaption = EveCaptionLarge(parent=self.donutLabelCont, align=uiconst.TOTOP, color=Color.WHITE, padBottom=6, bold=False)
    128         self.donutCenterTitle = EveLabelMediumBold(parent=self.donutLabelCont, align=uiconst.TOTOP, padBottom=2)
    129         self.donutCenterSubCaption = EveLabelMedium(parent=self.donutLabelCont, align=uiconst.TOTOP, opacity=0.5)
    130 
    131     def OnSegmentMouseEnter(self, segmentID):
    132         pass
    133 
    134     def OnSegmentMouseExit(self, segmentID):
    135         pass
    136 
    137     def OnSegmentClicked(self, transactionGroup):
    138         if not transactionGroup.refTypeID:
    139             self.Update(transactionGroup.refGroupID)
    140 
    141     def GetDonutChartSegmentColor(self, transactionGroup, value):
    142         if not transactionGroup:
    143             return (1, 1, 1, 0.1)
    144         if transactionGroup.refGroupID in COLOR_BY_REFGROUPID:
    145             color = Color.HextoRGBA(COLOR_BY_REFGROUPID[transactionGroup.refGroupID])
    146         if not transactionGroup.refTypeID:
    147             return color
    148         transactionGroups = [ data.segmentID for data in self.donutChart.GetSegmentData() ]
    149         numSegments = len(transactionGroups)
    150         if numSegments <= 1:
    151             x = 1.0
    152         else:
    153             x = 0.3 + 0.7 * transactionGroups.index(transactionGroup) / float(numSegments - 1)
    154         color = Color(*color)
    155         brightness = color.GetBrightness()
    156         return color.SetBrightness(x * brightness).GetRGBA()
    157 
    158     def OnBack(self, *args):
    159         if self.selectedRefGroupID:
    160             self.Update()
    161 
    162     def ConstructRadioButtons(self):
    163         self.incomeRadioBtn = OverviewPanelRadioButton(name='incomeRadioBtn', parent=self.rightCont, text=GetByLabel('UI/Wallet/WalletWindow/Income'), groupname='incomeOrExpensesRadioGroup', retval=INCOME, callback=self.OnIncomeExpensesRadioButton, padBottom=6)
    164         self.incomeRadioBtn.SetChecked(True, report=False)
    165         self.expensesRadioBtn = OverviewPanelRadioButton(name='expensesRadioBtn', parent=self.rightCont, text=GetByLabel('UI/Wallet/WalletWindow/Expenses'), groupname='incomeOrExpensesRadioGroup', retval=EXPENSES, callback=self.OnIncomeExpensesRadioButton, padBottom=6)
    166 
    167     def OnIncomeExpensesRadioButton(self, *args):
    168         self.Update()
    169 
    170     def Update(self, refGroupID = None, animate = True):
    171         if self.destroyed or not self.isInitialized:
    172             return
    173         self.selectedRefGroupID = refGroupID
    174         self.controller = TransactionOverviewController(self.selectedRefGroupID)
    175         self.UpdateDonutChart()
    176         self.ConstructEntries()
    177         self.UpdateText()
    178         if not refGroupID:
    179             self.UpdateRadioButtons()
    180         self.UpdateBackButtonVisibility()
    181         uicore.registry.SetFocus(self)
    182         self.AnimEntry()
    183 
    184     def UpdateBackButtonVisibility(self):
    185         if self.selectedRefGroupID is None:
    186             self.backButton.Hide()
    187             self.backButton.OnMouseExit()
    188         else:
    189             self.backButton.Show()
    190 
    191     def AnimEntry(self):
    192         duration = 0.6
    193         if self.selectedRefGroupID:
    194             startScale = (0.9, 0.9)
    195         else:
    196             startScale = (1.1, 1.1)
    197         animations.Tr2DScaleTo(self.donutTransform, startScale, (1.0, 1.0), duration=duration)
    198         animations.FadeTo(self.donutTransform, 0.0, 1.0, duration=duration)
    199         animations.FadeTo(self.donutLabelCont, 0.0, 1.0, duration=duration, timeOffset=1.0)
    200         offset = 0.2
    201         animations.Tr2DScaleTo(self.donutShadowTransform, (0.9, 0.9), (1.0, 1.0), duration=duration - offset, timeOffset=duration + offset)
    202         animations.FadeTo(self.donutChartShadow, 0.0, DONUT_SHADOWOPACITY, duration=duration - offset, timeOffset=duration + offset)
    203 
    204     def UpdateText(self):
    205         totalIncome = self.controller.GetTotalIncome()
    206         totalExpenses = self.controller.GetTotalExpenses()
    207         totalAmount = totalIncome if self.IsIncomeSelected() else totalExpenses
    208         text = FmtAmt(totalAmount, fmt='sn')
    209         self.donutCenterCaption.SetText('<center>%s</center>' % text)
    210         if self.IsIncomeSelected():
    211             subCaption = GetByLabel('UI/Wallet/WalletWindow/Last30DaysIncome')
    212         else:
    213             subCaption = GetByLabel('UI/Wallet/WalletWindow/Last30DaysExpenses')
    214         self.donutCenterSubCaption.SetText('<center>%s</center>' % subCaption)
    215         title = self.controller.GetGroupName()
    216         if title:
    217             self.donutCenterTitle.Show()
    218             self.donutCenterTitle.SetText('<center>%s</center>' % title)
    219         else:
    220             self.donutCenterTitle.Hide()
    221 
    222     def UpdateRadioButtons(self):
    223         totalIncome = self.controller.GetTotalIncome()
    224         totalExpenses = self.controller.GetTotalExpenses()
    225         self.incomeRadioBtn.SetISKAmount(totalIncome)
    226         self.expensesRadioBtn.SetISKAmount(totalExpenses)
    227 
    228     def ConstructEntries(self):
    229         self.entriesCont.Flush()
    230         if self.IsIncomeSelected():
    231             transactionGroups = self.controller.GetIncomeTransactionGroups()
    232             total = self.controller.GetTotalIncome()
    233         else:
    234             transactionGroups = self.controller.GetExpenditureTransactionGroups()
    235             total = self.controller.GetTotalExpenses()
    236         if transactionGroups:
    237             for transactionGroup in transactionGroups:
    238                 ratio = transactionGroup.amount / total if total else 0.0
    239                 Entry(parent=self.entriesCont, align=uiconst.TOTOP, ratio=ratio, transactionGroup=transactionGroup, color=self.GetDonutChartSegmentColor(transactionGroup, ratio), padBottom=4)
    240 
    241         else:
    242             EveLabelMedium(parent=self.entriesCont, align=uiconst.TOTOP, text=GetByLabel('UI/Wallet/WalletWindow/HintNoTransactionsFound'), padLeft=17, opacity=0.75)
    243 
    244     def UpdateDonutChart(self):
    245         if self.IsIncomeSelected():
    246             groups = self.controller.GetIncomeTransactionGroups()
    247         else:
    248             groups = self.controller.GetExpenditureTransactionGroups()
    249         self.donutChart.Reset()
    250         self.donutChartShadow.Reset()
    251         if not groups:
    252             self.donutChart.AddSegment(value=1.0, segmentID=None)
    253             self.donutChart.Disable()
    254             self.donutChartShadow.AddSegment(value=1.0, segmentID=None)
    255         else:
    256             self.donutChart.Enable()
    257             for group in groups:
    258                 value = math.fabs(group.amount)
    259                 self.donutChart.AddSegment(value=value, segmentID=group, hint=group.GetHint())
    260                 self.donutChartShadow.AddSegment(value=value, segmentID=group)
    261 
    262         self.donutChart.Construct(animate=bool(groups))
    263         self.donutChartShadow.Construct(animate=False)
    264 
    265     def IsIncomeSelected(self):
    266         return self.expensesRadioBtn.GetGroupValue() == INCOME
    267 
    268 
    269 class Entry(Container):
    270     default_height = 18
    271     default_state = uiconst.UI_NORMAL
    272 
    273     def ApplyAttributes(self, attributes):
    274         super(Entry, self).ApplyAttributes(attributes)
    275         ratio = attributes.ratio
    276         color = attributes.color
    277         self.transactionGroup = attributes.transactionGroup
    278         self.label = Label(parent=self, align=uiconst.CENTERLEFT, text='%.1f%% %s' % (100 * ratio, self.transactionGroup.name), state=uiconst.UI_DISABLED, color=(1, 1, 1, 1), left=18)
    279         gauge = Fill(parent=self, align=uiconst.CENTERLEFT, state=uiconst.UI_DISABLED, color=color, pos=(2, 0, 10, 10))
    280         self.underlay = ListEntryUnderlay(bgParent=self)
    281 
    282     def UpdateAlignment(self, *args, **kwargs):
    283         alignment = super(Entry, self).UpdateAlignment(*args, **kwargs)
    284         return alignment
    285 
    286     def GetHint(self):
    287         return FmtISK(self.transactionGroup.amount)
    288 
    289     def OnClick(self, *args):
    290         if not self.transactionGroup.refTypeID:
    291             overviewPanelSignals.on_entry_selected(self.transactionGroup.refGroupID)
    292 
    293     def OnMouseEnter(self, *args):
    294         self.underlay.hovered = True
    295 
    296     def OnMouseExit(self, *args):
    297         self.underlay.hovered = False
    298 
    299 
    300 class OverviewPanelRadioButton(RadioButton):
    301 
    302     def ConstructLabel(self):
    303         super(OverviewPanelRadioButton, self).ConstructLabel()
    304         self.iskLabel = EveLabelLarge(parent=self, align=uiconst.TOPLEFT, left=self.label.left, top=20)
    305 
    306     def SetISKAmount(self, amount):
    307         text = FmtISK(amount)
    308         if amount >= 0:
    309             text = '+' + text
    310         self.iskLabel.SetText(text)