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

blueprintCenter.py (21073B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\industry\views\blueprintCenter.py
      2 from math import pi
      3 from carbon.client.script.environment.AudioUtil import PlaySound
      4 from carbonui.control.singlelineedits.singleLineEditInteger import SingleLineEditInteger
      5 from carbonui.primitives.frame import Frame
      6 from carbonui.primitives.transform import Transform
      7 from eve.client.script.ui.control.themeColored import FrameThemeColored
      8 from eve.client.script.ui.shared.industry import industryUIConst
      9 from eve.client.script.ui.shared.industry.views.errorFrame import ErrorFrame
     10 import industry
     11 import localization
     12 import uthread
     13 import blue
     14 import carbonui.const as uiconst
     15 from carbonui.primitives.container import Container
     16 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     17 from carbonui.primitives.sprite import Sprite
     18 from carbonui.util.color import Color
     19 from localization import GetByLabel
     20 from carbon.common.script.sys.service import ROLE_PROGRAMMER
     21 from eve.client.script.ui.control.itemIcon import ItemIcon
     22 from eve.client.script.ui.control.eveLabel import EveLabelMedium
     23 from eve.client.script.ui.control.gaugeCircular import GaugeCircular
     24 from eve.client.script.ui.shared.industry.industryUIConst import GetJobColor, COLOR_FRAME
     25 from eve.client.script.ui.shared.industry.views.containersMETE import ContainerME, ContainerTE
     26 from eve.client.script.ui.shared.industry.views.industryCaptionLabel import IndustryCaptionLabel
     27 from eve.client.script.ui.shared.industry.views.skillIcon import SkillIcon
     28 from carbonui.uicore import uicore
     29 from eveservices.menu import GetMenuService
     30 WEDGE_TRAVEL = 15
     31 
     32 class BlueprintCenter(Container):
     33     __notifyevents__ = ('OnIndustryWndMouseWheel', 'OnIndustryWndClick', 'OnBlueprintBrowserNumericInput')
     34 
     35     def ApplyAttributes(self, attributes):
     36         Container.ApplyAttributes(self, attributes)
     37         sm.RegisterNotify(self)
     38         self.jobData = attributes.jobData
     39         self.newNumRuns = None
     40         self.setJobRunsThread = None
     41         self.oldJobData = None
     42         self.numericInputTimer = None
     43         self.iconCont = BlueprintItemIcon(parent=self, align=uiconst.CENTER, state=uiconst.UI_NORMAL, pos=(0, 0, 64, 64), opacity=0.0, jobData=self.jobData)
     44         self.errorFrame = ErrorFrame(parent=self, align=uiconst.CENTER, state=uiconst.UI_DISABLED, width=80, height=80)
     45         self.ConstructBackground()
     46         self.ConstructRunsCont()
     47         self.gauge = None
     48         self.skillSprite = SkillIcon(parent=self, align=uiconst.CENTERBOTTOM, top=5, jobData=self.jobData)
     49         self.containerME = ContainerME(parent=self, align=uiconst.CENTER, pos=(113, -25, 79, 30), jobData=self.jobData, opacity=0.0)
     50         self.containerTE = ContainerTE(parent=self, align=uiconst.CENTER, pos=(113, 25, 79, 30), jobData=self.jobData, opacity=0.0)
     51         self.runsRemainingCont = ContainerAutoSize(name='bpCopyCont', parent=self, align=uiconst.CENTERTOP, state=uiconst.UI_NORMAL, top=90)
     52         self.runsRemainingCont.OnClick = self.OnRunsRemainingContClicked
     53         self.runsRemainingCaption = IndustryCaptionLabel(parent=self.runsRemainingCont, align=uiconst.CENTERTOP)
     54         self.runsRemainingLabel = EveLabelMedium(name='runsRemainingLabel', parent=self.runsRemainingCont, align=uiconst.CENTERTOP, top=14)
     55         self.UpdateState()
     56         self.AnimEntry()
     57 
     58     def ConstructRunsCont(self):
     59         self.runsCont = ContainerAutoSize(parent=self, align=uiconst.CENTER, top=100, width=76)
     60         labelCont = ContainerAutoSize(parent=self.runsCont, align=uiconst.TOTOP)
     61         self.runsCaption = IndustryCaptionLabel(name='runsCaption', parent=labelCont, align=uiconst.CENTER, text=GetByLabel('UI/Industry/JobRuns'))
     62         self.runsEdit = BlueprintSingleLineEdit(parent=self.runsCont, align=uiconst.TOTOP, OnChange=self.OnRunsEdit, autoselect=True)
     63         self.runsPerCopyCont = ContainerAutoSize(name='runsPerCopyCont', parent=self.runsCont, align=uiconst.TOTOP, padTop=8, state=uiconst.UI_HIDDEN)
     64         labelCont = ContainerAutoSize(parent=self.runsPerCopyCont, align=uiconst.TOTOP)
     65         IndustryCaptionLabel(name='runsPerCopyCaption', parent=labelCont, align=uiconst.CENTER, text=GetByLabel('UI/Industry/RunsPerCopy'))
     66         self.runsPerCopyEdit = BlueprintSingleLineEdit(parent=self.runsPerCopyCont, align=uiconst.TOTOP, OnChange=self.OnRunsPerCopyEdit, autoselect=True)
     67 
     68     def OnRunsRemainingContClicked(self, *args):
     69         if self.runsEdit.state == uiconst.UI_NORMAL:
     70             self.runsEdit.SetValue(self.jobData.maxRuns)
     71 
     72     def OnBlueprintBrowserNumericInput(self, key, flag):
     73         if not self.numericInputTimer:
     74             self.runsEdit.SelectAll()
     75         else:
     76             self.numericInputTimer.kill()
     77         self.numericInputTimer = uthread.new(self.NumericInputTimer)
     78         self.runsEdit.OnChar(key, flag)
     79 
     80     def NumericInputTimer(self):
     81         blue.synchro.SleepWallclock(1000)
     82         self.numericInputTimer = None
     83 
     84     def OnJobUpdated(self, job):
     85         if self.jobData and self.jobData == job:
     86             self.UpdateStateJob()
     87 
     88     def UpdateStateJob(self):
     89         self.iconCont.Show()
     90         typeID = self.jobData.blueprint.blueprintTypeID
     91         self.iconCont.SetTypeID(typeID=typeID, bpData=self.jobData.blueprint)
     92         self.UpdateGaugeValue()
     93         self.UpdateStateRunsEdit()
     94         self.UpdateStateRunsPerCopyEdit()
     95         self.skillSprite.Show()
     96         self.UpdateRunsRemainingLabel()
     97         self.containerME.SetValue(self.jobData.blueprint.materialEfficiency)
     98         self.containerTE.SetValue(self.jobData.blueprint.timeEfficiency)
     99         self.jobData.on_updated.connect(self.OnJobUpdated)
    100         activity = self.jobData.GetCurrentActivity()
    101         if activity and activity.IsOmegaActivity():
    102             self.iconCont.ShowOmegaOverlay()
    103         else:
    104             self.iconCont.HideOmegaOverlay()
    105         sm.ScatterEvent('OnSelectedIndustryJobChanged', jobData=self.jobData)
    106 
    107     def UpdateRunsRemainingLabel(self):
    108         if not self.jobData:
    109             return
    110         if self.jobData.IsInstalled():
    111             self.runsRemainingCont.Hide()
    112         else:
    113             runsText = self.jobData.GetRunsRemainingLabel()
    114             if runsText:
    115                 self.runsRemainingCont.Show()
    116                 self.runsRemainingLabel.text = runsText
    117                 self.runsRemainingCaption.text = self.jobData.GetRunsRemainingCaption()
    118             else:
    119                 self.runsRemainingCont.Hide()
    120 
    121     def SetNumRuns(self, numRuns):
    122         if not self.jobData.IsInstalled():
    123             self.runsEdit.SetValue(numRuns)
    124 
    125     def UpdateStateRunsEdit(self):
    126         if self.jobData.IsInstalled():
    127             self.runsEdit.SetMinValue(self.jobData.runs)
    128             self.runsEdit.SetMaxValue(self.jobData.runs)
    129             self.runsEdit.Show()
    130             self.runsCaption.Show()
    131             self.runsEdit.Disable()
    132         else:
    133             self.runsEdit.SetMinValue(1)
    134             self.runsEdit.SetMaxValue(self.jobData.maxRuns)
    135             self.runsEdit.Enable()
    136             self.runsEdit.Show()
    137             self.runsCaption.Show()
    138         self.runsEdit.SetValue(self.jobData.runs)
    139 
    140     def UpdateStateRunsPerCopyEdit(self):
    141         if self.jobData.activityID == industry.COPYING:
    142             if self.jobData.IsInstalled():
    143                 self.runsPerCopyEdit.SetMinValue(self.jobData.licensedRuns)
    144                 self.runsPerCopyEdit.SetMaxValue(self.jobData.licensedRuns)
    145                 self.runsPerCopyEdit.Disable()
    146             else:
    147                 self.runsPerCopyEdit.SetMinValue(1)
    148                 self.runsPerCopyEdit.SetMaxValue(self.jobData.maxLicensedRuns)
    149                 self.runsPerCopyEdit.Enable()
    150             self.runsPerCopyEdit.SetValue(self.jobData.licensedRuns)
    151             self.runsPerCopyCont.Show()
    152         else:
    153             self.runsPerCopyCont.Hide()
    154 
    155     def UpdateState(self):
    156         if self.jobData:
    157             self.UpdateStateJob()
    158         else:
    159             self.iconCont.Hide()
    160             self.runsEdit.Hide()
    161             self.runsPerCopyCont.Hide()
    162             self.runsCaption.Hide()
    163             self.skillSprite.Hide()
    164             self.runsRemainingCont.Hide()
    165             self.containerME.SetValue(0.0)
    166             self.containerTE.SetValue(0.0)
    167 
    168     def ReconstructGauge(self):
    169         if self.gauge:
    170             self.gauge.Close()
    171             self.gauge = None
    172         if not self.jobData:
    173             return
    174         color = GetJobColor(self.jobData)
    175         h, s, b = Color(*color).GetHSB()
    176         colorEnd = Color(*color).SetBrightness(b * 0.5).GetRGBA()
    177         self.gauge = BlueprintGaugeCircular(name='gauge', parent=self, align=uiconst.CENTER, radius=64, lineWidth=4, colorStart=color, colorEnd=colorEnd, jobData=self.jobData)
    178 
    179     def AnimWedges(self, startVal, endVal, duration, curveType = None):
    180         uicore.animations.MorphScalar(self.topWedge, 'top', startVal, endVal, duration=duration, curveType=curveType)
    181         uicore.animations.MorphScalar(self.bottomWedge, 'top', startVal, endVal, duration=duration, curveType=curveType)
    182         uicore.animations.MorphScalar(self.leftWedge, 'left', startVal, endVal, duration=duration, curveType=curveType)
    183         uicore.animations.MorphScalar(self.rightWedge, 'left', startVal, endVal, duration=duration, curveType=curveType)
    184 
    185     def AnimEntry(self):
    186         duration = 0.7
    187         if self.jobData:
    188             self.HideDashes()
    189             if self.topWedge.top < WEDGE_TRAVEL:
    190                 self.AnimWedges(0, WEDGE_TRAVEL, duration)
    191             else:
    192                 self.AnimWedges(WEDGE_TRAVEL, 18, 0.5, curveType=uiconst.ANIM_WAVE)
    193             if not self.IsSameBlueprint():
    194                 uicore.animations.FadeTo(self.iconCont, 0.0, 1.0, duration=0.5)
    195             for obj in (self.containerME, self.containerTE):
    196                 obj.Enable()
    197                 uicore.animations.FadeIn(obj, duration=duration)
    198 
    199         else:
    200             self.AnimWedges(self.topWedge.top, 0.0, duration)
    201             for obj in (self.containerME, self.containerTE):
    202                 obj.Disable()
    203                 uicore.animations.FadeOut(obj, duration=duration)
    204 
    205             self.ShowDashes()
    206         if self.jobData and self.jobData.IsPreview():
    207             uicore.animations.FadeTo(self.iconCont, 0.0, 0.65, duration=0.5)
    208             self.errorFrame.Show()
    209             wedgeColor = industryUIConst.COLOR_NOTREADY
    210         else:
    211             self.errorFrame.Hide()
    212             wedgeColor = Color.WHITE
    213         for dots in self.wedgeDots:
    214             dots.SetRGBA(*wedgeColor)
    215 
    216         if self.gauge:
    217             uicore.animations.BlinkIn(self.gauge, 0.0, 1.0, timeOffset=0.98)
    218         for dots in self.wedgeDots:
    219             uicore.animations.BlinkIn(dots, 0.0, 0.85, timeOffset=0.78)
    220 
    221         for pattern in self.wedgeBg:
    222             if self.jobData and self.jobData.IsPreview():
    223                 color = industryUIConst.COLOR_NOTREADY
    224             else:
    225                 color = GetJobColor(self.jobData)
    226             uicore.animations.SpColorMorphTo(pattern, pattern.GetRGBA(), color, duration=0.3)
    227 
    228     def IsSameBlueprint(self):
    229         if not self.oldJobData or not self.jobData:
    230             return False
    231         if self.jobData:
    232             return self.jobData.blueprint.IsSameBlueprint(self.oldJobData.blueprint)
    233         return False
    234 
    235     def UpdateGaugeValue(self):
    236         if not self.gauge or not self.jobData:
    237             return
    238         self.gauge.SetValue(self.jobData.GetGaugeValue())
    239 
    240     def SetJobRuns(self, value):
    241         if not self.jobData:
    242             return
    243         if self.jobData.runs == value:
    244             if self.newNumRuns is None or self.newNumRuns == value:
    245                 return
    246         self.newNumRuns = value
    247         if self.setJobRunsThread is None:
    248             self.setJobRunsThread = uthread.new(self._SetJobRuns)
    249 
    250     def _SetJobRuns(self):
    251         while self.jobData and self.newNumRuns is not None and not self.destroyed:
    252             if self.newNumRuns != self.jobData.runs:
    253                 newNumRuns = self.newNumRuns
    254                 self.newNumRuns = None
    255                 self.jobData.runs = newNumRuns
    256             blue.synchro.SleepWallclock(100)
    257 
    258         if self.jobData:
    259             self.jobData.on_facility(self.jobData)
    260         self.setJobRunsThread = None
    261 
    262     def OnRunsEdit(self, value):
    263         try:
    264             value = int(value)
    265         except ValueError:
    266             return
    267 
    268         if self.jobData and not self.jobData.IsInstalled():
    269             self.SetJobRuns(value)
    270 
    271     def OnRunsChanged(self):
    272         self.UpdateGaugeValue()
    273         self.UpdateRunsRemainingLabel()
    274 
    275     def OnRunsPerCopyEdit(self, value):
    276         try:
    277             value = int(value)
    278         except ValueError:
    279             return
    280 
    281         self.jobData.licensedRuns = value
    282 
    283     def ConstructBackground(self):
    284         Frame(name='bgFrame', parent=self, align=uiconst.CENTER, state=uiconst.UI_DISABLED, width=75, height=75, opacity=0.1)
    285         blueprintBg = FrameThemeColored(name='blueprintBgFill', parent=self, align=uiconst.CENTER, state=uiconst.UI_DISABLED, texturePath='res:/UI/Texture/classes/Industry/Center/bgFrame.png', width=90, height=90)
    286         self.dashesCont = Container(name='dashesCont', parent=self, state=uiconst.UI_DISABLED, pos=(75, 0, 150, 150), align=uiconst.CENTER)
    287         self.bgCont = Container(name='bgCont', parent=self, state=uiconst.UI_DISABLED, width=150, height=150, align=uiconst.CENTER)
    288         self.topWedge = Container(name='topWedge', parent=self.bgCont, align=uiconst.CENTERTOP, pos=(0, 0, 84, 60))
    289         topLines = Sprite(bgParent=self.topWedge, texturePath='res:/UI/Texture/classes/Industry/Center/wedgeTopBottom.png')
    290         topDots = Sprite(bgParent=self.topWedge, texturePath='res:/UI/Texture/classes/Industry/Center/dotsTopBottom.png')
    291         topBg = Sprite(bgParent=self.topWedge, texturePath='res:/UI/Texture/classes/Industry/Center/bgTop.png', color=COLOR_FRAME)
    292         self.bottomWedge = Container(name='bottomWedge', parent=self.bgCont, align=uiconst.CENTERBOTTOM, pos=(0, 0, 84, 60))
    293         bottomLines = Sprite(bgParent=self.bottomWedge, texturePath='res:/UI/Texture/classes/Industry/Center/wedgeTopBottom.png', rotation=pi)
    294         bottomDots = Sprite(bgParent=self.bottomWedge, texturePath='res:/UI/Texture/classes/Industry/Center/dotsTopBottom.png', rotation=pi)
    295         bottomBg = Sprite(bgParent=self.bottomWedge, texturePath='res:/UI/Texture/classes/Industry/Center/bgBottom.png', color=COLOR_FRAME)
    296         self.leftWedge = Container(name='leftWedge', parent=self.bgCont, align=uiconst.CENTERLEFT, pos=(0, 0, 60, 84))
    297         leftLines = Sprite(bgParent=self.leftWedge, texturePath='res:/UI/Texture/classes/Industry/Center/wedgeLeftRight.png')
    298         leftDots = Sprite(bgParent=self.leftWedge, texturePath='res:/UI/Texture/classes/Industry/Center/dotsLeftRight.png')
    299         leftBg = Sprite(bgParent=self.leftWedge, texturePath='res:/UI/Texture/classes/Industry/Center/bgLeft.png', color=COLOR_FRAME)
    300         self.rightWedge = Container(name='rightWedge', parent=self.bgCont, align=uiconst.CENTERRIGHT, pos=(0, 0, 60, 84))
    301         rightLines = Sprite(bgParent=self.rightWedge, texturePath='res:/UI/Texture/classes/Industry/Center/wedgeLeftRight.png', rotation=pi)
    302         rightDots = Sprite(bgParent=self.rightWedge, texturePath='res:/UI/Texture/classes/Industry/Center/dotsLeftRight.png', rotation=pi)
    303         rightBg = Sprite(bgParent=self.rightWedge, texturePath='res:/UI/Texture/classes/Industry/Center/bgRight.png', color=COLOR_FRAME)
    304         self.wedgeLines = [topLines,
    305          bottomLines,
    306          leftLines,
    307          rightLines]
    308         self.wedgeDots = [topDots,
    309          bottomDots,
    310          leftDots,
    311          rightDots]
    312         self.wedgeBg = [topBg,
    313          bottomBg,
    314          leftBg,
    315          rightBg]
    316 
    317     def ShowDashes(self):
    318         for rotation in (0,
    319          pi / 2,
    320          pi,
    321          3 * pi / 2):
    322             BlueDash(parent=self.dashesCont, align=uiconst.CENTERLEFT, rotation=pi / 4 + rotation, rotationCenter=(0.0, 0.5))
    323 
    324     def HideDashes(self):
    325         self.dashesCont.Flush()
    326 
    327     def OnNewJobData(self, jobData):
    328         self.oldJobData = self.jobData
    329         self.jobData = jobData
    330         self.skillSprite.OnNewJobData(jobData)
    331         self.containerME.OnNewJobData(jobData)
    332         self.containerTE.OnNewJobData(jobData)
    333         self.iconCont.OnNewJobData(jobData)
    334         self.ReconstructGauge()
    335         if self.gauge:
    336             self.gauge.OnNewJobData(jobData)
    337         self.UpdateState()
    338         self.AnimEntry()
    339         self.numericInputTimer = None
    340 
    341     def OnIndustryWndMouseWheel(self, *args):
    342         if not self.jobData:
    343             return
    344         self.runsEdit.OnMouseWheel()
    345         if uicore.registry.GetFocus() != self.runsEdit:
    346             uicore.registry.SetFocus(self.runsEdit)
    347 
    348     def OnIndustryWndClick(self):
    349         if not self.jobData:
    350             return
    351         uicore.registry.SetFocus(self.runsEdit)
    352 
    353 
    354 class BlueprintGaugeCircular(GaugeCircular):
    355     default_opacity = 0.0
    356 
    357     def ApplyAttributes(self, attributes):
    358         GaugeCircular.ApplyAttributes(self, attributes)
    359         self.jobData = attributes.jobData
    360 
    361     def OnNewJobData(self, jobData):
    362         self.jobData = jobData
    363 
    364     def OnMouseEnter(self, *args):
    365         GaugeCircular.OnMouseEnter(self, *args)
    366         sm.GetService('audio').SendUIEvent('ind_circleMouseEnter')
    367 
    368     def SetValue(self, value, *args):
    369         GaugeCircular.SetValue(self, value, *args)
    370         sm.GetService('audio').SetGlobalRTPC('ind_circleValue', 100 * value)
    371 
    372     def OnMouseExit(self, *args):
    373         GaugeCircular.OnMouseExit(self, *args)
    374         sm.GetService('audio').SendUIEvent('ind_circleMouseExit')
    375 
    376     def OnDropData(self, dragSource, dragData):
    377         sm.ScatterEvent('OnIndustryDropData', dragSource, dragData)
    378 
    379     def GetTooltipPosition(self, *args):
    380         l, t, w, h = self.GetAbsolute()
    381         offset = 43
    382         return (l,
    383          t - offset,
    384          w,
    385          h + 2 * offset)
    386 
    387     def GetTooltipPointer(self):
    388         return uiconst.POINT_BOTTOM_2
    389 
    390 
    391 class BlueDash(Transform):
    392     default_width = 100
    393     default_height = 6
    394 
    395     def ApplyAttributes(self, attributes):
    396         Transform.ApplyAttributes(self, attributes)
    397         self.sprite1 = Sprite(parent=self, align=uiconst.CENTERLEFT, pos=(0, 0, 49, 6), texturePath='res:/UI/Texture/classes/Industry/Center/blueDash.png')
    398         self.sprite2 = Sprite(parent=self, align=uiconst.CENTERLEFT, pos=(0, 0, 49, 6), texturePath='res:/UI/Texture/classes/Industry/Center/blueDash.png')
    399         self.sprite3 = Sprite(parent=self, align=uiconst.CENTERLEFT, pos=(0, 0, 49, 6), texturePath='res:/UI/Texture/classes/Industry/Center/blueDash.png')
    400         uthread.new(self.Animate)
    401 
    402     def Animate(self):
    403         x0 = self.default_width
    404         x1 = 0
    405         k = 0.22
    406         while not self.destroyed:
    407             for i in xrange(2):
    408                 for j, obj in enumerate((self.sprite1, self.sprite2, self.sprite3)):
    409                     uicore.animations.MorphScalar(obj, 'left', x0, x1, duration=k * (j + 1))
    410                     uicore.animations.FadeTo(obj, 0.0, 1.5, duration=2 * k, curveType=uiconst.ANIM_WAVE)
    411 
    412                 blue.synchro.SleepWallclock(4 * k * 1000)
    413 
    414             blue.synchro.SleepWallclock(1000)
    415 
    416 
    417 class BlueprintSingleLineEdit(SingleLineEditInteger):
    418 
    419     def Disable(self):
    420         super(BlueprintSingleLineEdit, self).Disable()
    421         self.textLabel.left = 0
    422         self.textLabel.align = uiconst.CENTER
    423         self.SetReadOnly(True)
    424 
    425     def Enable(self):
    426         super(BlueprintSingleLineEdit, self).Enable()
    427         self.textLabel.left = self.textLeftMargin
    428         self.textLabel.align = uiconst.CENTERLEFT
    429         self.SetReadOnly(False)
    430 
    431 
    432 class BlueprintItemIcon(ItemIcon):
    433 
    434     def ApplyAttributes(self, attributes):
    435         ItemIcon.ApplyAttributes(self, attributes)
    436         self.jobData = attributes.jobData
    437 
    438     def GetMenu(self):
    439         bpData = self.jobData.blueprint
    440         m = GetMenuService().GetMenuFromItemIDTypeID(self.jobData.blueprintID, bpData.blueprintTypeID, includeMarketDetails=True).filter(['UI/Industry/ViewInIndustry'])
    441         m.append((localization.GetByLabel('UI/Industry/RemoveBlueprint'), self.RemoveBlueprint))
    442         if session.role & ROLE_PROGRAMMER:
    443             m.insert(0, ('GM: Give me these materials', self._GiveMeMaterials))
    444         return m
    445 
    446     def _GiveMeMaterials(self):
    447         materials = [ (material.typeID, material.quantity) for material in self.jobData.materials ]
    448         sm.GetService('info').DoCreateMaterials(materials)
    449 
    450     def RemoveBlueprint(self):
    451         sm.ScatterEvent('OnIndustryRemoveBlueprint')
    452 
    453     def OnNewJobData(self, jobData):
    454         self.jobData = jobData
    455 
    456     def OnMouseEnter(self, *args):
    457         ItemIcon.OnMouseEnter(self, *args)
    458         PlaySound(uiconst.SOUND_BUTTON_HOVER)
    459 
    460     def OnDropData(self, dragSource, dragData):
    461         sm.ScatterEvent('OnIndustryDropData', dragSource, dragData)
    462 
    463     def GetHint(self):
    464         hint = ItemIcon.GetHint(self)
    465         if hint:
    466             return hint.strip()