surveyUI.py (32990B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\planet\surveyUI.py 2 import math 3 import blue 4 import evetypes 5 import geo2 6 import localization 7 import uthread 8 from carbonui import fontconst, uiconst 9 from carbonui.control.slider import Slider 10 from carbonui.control.window import Window 11 from carbonui.primitives.container import Container 12 from carbonui.primitives.containerAutoSize import ContainerAutoSize 13 from carbonui.primitives.fill import Fill 14 from carbonui.uianimations import animations 15 from carbonui.uicore import uicore 16 from carbonui.util.color import Color 17 from eve.client.script.ui.control import eveIcon, eveLabel 18 from eve.client.script.ui.control.bargraph import BarGraph 19 from carbonui.control.buttonIcon import ButtonIcon 20 from carbonui.control.button import Button 21 from eve.client.script.ui.control.eveLabel import EveLabelSmall 22 from eve.client.script.ui.control.gauge import Gauge 23 from eve.client.script.ui.control.infoIcon import MoreInfoIcon 24 from eve.client.script.ui.shared.planet import planetCommon as planetCommonUI 25 from eve.client.script.ui.shared.planet.pinContainers.BasePinContainer import CaptionLabel, IconButton 26 from eve.common.lib import appConst 27 from eve.common.lib.PlanetResources import builder 28 from eve.common.script.util import planetCommon 29 from localization import GetByLabel 30 from localization.formatters.timeIntervalFormatters import FormatTimeIntervalShortWritten 31 BTNSIZE = 16 32 33 class SurveyWindow(Window): 34 __notifyevents__ = ['OnPlanetViewChanged', 'OnEditModeChanged', 'OnEditModeBuiltOrDestroyed'] 35 default_fixedWidth = 730 36 default_fixedHeight = 320 37 default_windowID = 'PlanetSurvey' 38 39 def ApplyAttributes(self, attributes): 40 self.default_fixedHeight *= fontconst.fontSizeFactor 41 super(SurveyWindow, self).ApplyAttributes(attributes) 42 self.ecuPinID = attributes.get('ecuPinID') 43 self.barGraphUpdating = False 44 self.planetUISvc = sm.GetService('planetUI') 45 self.planet = self.planetUISvc.planet 46 self.pin = self.planet.GetPin(self.ecuPinID) 47 self.extractionHeadValues = {} 48 self.resourceTypeIDs = self.planet.remoteHandler.GetPlanetResourceInfo().keys() 49 self.currResourceTypeID = self.pin.programType 50 self.outputVals = [] 51 self.programCycleTime = None 52 self.dragThread = None 53 self.currCycleTime = None 54 self.UpdateCurrentRadius() 55 self.sh = None 56 if self.currResourceTypeID is not None: 57 inRange, self.sh = self.planetUISvc.planet.GetResourceData(self.currResourceTypeID) 58 self.revertToResource = self.planetUISvc.selectedResourceTypeID 59 self.currentResource = None 60 self.editsEnabled = self.pin.GetExtractionType() is None or self.pin.GetTimeToExpiry() <= 0 61 if self.editsEnabled: 62 self.planetUISvc.myPinManager.UnlockHeads(self.pin.id) 63 self.barTimeIndicatorThread = None 64 self.overlapValues = {} 65 self.stateColor = None 66 self.pinData = None 67 if self.pin.IsInEditMode(): 68 self.pinData = self.pin.Serialize() 69 self.MakeUnResizeable() 70 captionTxt = localization.GetByLabel('UI/PI/Common/SurveyingProgram', pinName=planetCommon.GetGenericPinName(self.pin.typeID, self.pin.id)) 71 self.SetCaption(captionTxt) 72 Container(parent=self.sr.main, align=uiconst.TOTOP, height=10) 73 self.leftCont = Container(name='leftCont', parent=self.sr.main, align=uiconst.TOLEFT, width=130, padding=(8, 0, 3, 6)) 74 self.rightCont = Container(name='rightCont', parent=self.sr.main, align=uiconst.TORIGHT, width=160, padding=(10, 0, 6, 6)) 75 self.centerCont = Container(name='centerCont', parent=self.sr.main, align=uiconst.TOALL) 76 self._ConstructLeftContainer() 77 self._ConstructCenterContainer() 78 self._ConstructRightContainer() 79 self.SetCurrentResource(self.currResourceTypeID) 80 self.UpdateSubmitButton() 81 82 def _ConstructLeftContainer(self): 83 CaptionLabel(parent=self.leftCont, text=localization.GetByLabel('UI/PI/Common/ExtractorHeadUnits'), align=uiconst.TOTOP) 84 self.ConstructExtractorHeadBtns() 85 self.noExtractorsLabel = CaptionLabel(name='noExtractorsLabel', parent=self.leftCont, text=localization.GetByLabel('UI/PI/Common/NoExtractorsInstalled'), align=uiconst.TOTOP, padTop=4, color=Color.RED, state=uiconst.UI_HIDDEN) 86 self.UpdateNoExtractorsLabel() 87 MoreInfoIcon(parent=self.leftCont, align=uiconst.BOTTOMLEFT, hint=GetByLabel('UI/PI/Common/ECUHelpText')) 88 89 def UpdateNoExtractorsLabel(self): 90 if not self.pin.GetNumHeads(): 91 self.noExtractorsLabel.Show() 92 else: 93 self.noExtractorsLabel.Hide() 94 95 def UpdateCurrentRadius(self): 96 self.currentRadius = max(min(self.pin.headRadius, planetCommon.RADIUS_DRILLAREAMAX), planetCommon.RADIUS_DRILLAREAMIN) 97 98 def ConstructExtractorHeadBtns(self): 99 self.headButtons = [] 100 headEntryCont = Container(parent=self.leftCont, name='headEntryCont', align=uiconst.TOTOP, height=140, padTop=4) 101 headEntryContLeft = Container(parent=headEntryCont, name='headEntryContLeft', align=uiconst.TOLEFT, width=self.leftCont.width / 2) 102 headEntryContRight = Container(parent=headEntryCont, name='headEntryContRight', align=uiconst.TOLEFT, width=self.leftCont.width / 2) 103 for i in xrange(planetCommon.ECU_MAX_HEADS): 104 value = self.GetResourceLayerValueForHead(i) 105 state = uiconst.UI_NORMAL if self.editsEnabled else uiconst.UI_DISABLED 106 parent = headEntryContLeft if i < 5 else headEntryContRight 107 btn = ExtractionHeadEntry(parent=parent, headID=i, ecuID=self.pin.id, align=uiconst.TOTOP, height=20, state=state, value=value, pin=self.pin) 108 btn.OnClick = (self.OnHeadBtnClicked, i) 109 self.headButtons.append(btn) 110 111 def ConstructAreaSliderAndButtons(self): 112 sliderParCont = ContainerAutoSize(name='sliderParCont', parent=self.rightCont, align=uiconst.TOTOP, padTop=10) 113 CaptionLabel(parent=sliderParCont, text=localization.GetByLabel('UI/PI/Common/ProgramDuration'), align=uiconst.TOTOP, padBottom=2) 114 sliderCont = ContainerAutoSize(parent=sliderParCont, name='sliderCont', align=uiconst.TOTOP, alignMode=uiconst.TOTOP) 115 subtrBtn = ButtonIcon(parent=sliderCont, name='subtractBtn', align=uiconst.CENTERLEFT, texturePath='res:/UI/Texture/Icons/minus.png', iconSize=12, func=self.DecreaseDrillAreaSize, width=BTNSIZE) 116 addBtn = ButtonIcon(parent=sliderCont, name='addBtn', align=uiconst.CENTERRIGHT, texturePath='res:/UI/Texture/Icons/plus.png', iconSize=12, func=self.IncreaseDrillAreaSize, width=BTNSIZE) 117 sliderValue = math.sqrt((self.currentRadius - planetCommon.RADIUS_DRILLAREAMIN) / planetCommon.RADIUS_DRILLAREADIFF) 118 self.programDurationSlider = Slider(parent=sliderCont, name='programDurationSlider', align=uiconst.TOTOP, minValue=0.0, maxValue=1.0, value=sliderValue, hint=localization.GetByLabel('UI/PI/Common/ExtractionAreaSize'), callback=self.OnProgramDurationSliderReleased, on_dragging=self.OnProgramDurationSliderMoved, padding=(BTNSIZE + 4, 119 0, 120 BTNSIZE + 4, 121 0)) 122 self.programDurationSlider.barCont.OnMouseWheel = self.OnProgramDurationSliderMouseWheel 123 if not self.editsEnabled: 124 self.programDurationSlider.Disable() 125 subtrBtn.Disable() 126 addBtn.Disable() 127 self.programDurationLabel = EveLabelSmall(name='programDurationLabel', parent=sliderParCont, align=uiconst.TOTOP, padTop=2) 128 self.UpdateProgramDurationLabel() 129 130 def UpdateProgramDurationLabel(self): 131 self.programDurationLabel.text = self.GetProgramDurationText() 132 133 def DecreaseDrillAreaSize(self, *args): 134 self.ChangeDrillAreaSize(numSteps=-1) 135 136 def IncreaseDrillAreaSize(self, *args): 137 self.ChangeDrillAreaSize(numSteps=1) 138 139 def ChangeDrillAreaSize(self, numSteps): 140 newSliderValue = self._GetNextSliderValue(numSteps) 141 self.programDurationSlider.SetValue(newSliderValue) 142 self.UpdateProgramDuration() 143 self.UpdateDurationLabels() 144 145 def _GetNextSliderValue(self, numSteps): 146 oldNumCycles = None 147 sliderVal = self.programDurationSlider.value 148 maxCount = 1000 149 count = 0 150 while count < maxCount: 151 count += 1 152 cycleTime, numCycles = self._GetCycleTimeAndNumCyclesFromSliderVal(sliderVal) 153 if not oldNumCycles: 154 oldNumCycles = numCycles 155 if oldNumCycles != numCycles: 156 break 157 sliderVal += 0.001 * numSteps 158 159 return sliderVal 160 161 def _GetCycleTimeAndNumCyclesFromSliderVal(self, sliderVal): 162 radius = self._GetRadiusFromSliderVal(sliderVal) 163 programLength = planetCommon.GetProgramLengthFromHeadRadius(radius) 164 cycleTime = planetCommon.GetCycleTimeFromProgramLength(programLength) 165 numCycles = int(programLength / cycleTime) 166 return (cycleTime, numCycles) 167 168 def _GetRadiusFromSliderVal(self, sliderVal): 169 return sliderVal ** 2 * planetCommon.RADIUS_DRILLAREADIFF + planetCommon.RADIUS_DRILLAREAMIN 170 171 def OnProgramDurationSliderReleased(self, slider): 172 self.UpdateProgramDuration() 173 self.UpdateDurationLabels() 174 175 def UpdateProgramDuration(self, updateBargraph = True): 176 radius = self.programDurationSlider.value ** 2 * planetCommon.RADIUS_DRILLAREADIFF + planetCommon.RADIUS_DRILLAREAMIN 177 self.planetUISvc.myPinManager.SetExtractionHeadRadius(self.pin.id, radius) 178 self.currentRadius = radius 179 self.UpdateProgram(updateBargraph=updateBargraph) 180 181 def OnProgramDurationSliderMoved(self, slider): 182 self.UpdateDurationLabels() 183 self.UpdateProgramDuration(updateBargraph=False) 184 185 def UpdateDurationLabels(self): 186 text = self.GetProgramDurationText() 187 self.barGraph.SetXLabels((localization.GetByLabel('UI/PI/Common/SurveyProgramStart'), text)) 188 self.programDurationLabel.text = text 189 190 def GetProgramDurationText(self): 191 cycleTime, numCycles = self._GetCycleTimeAndNumCyclesFromSliderVal(self.programDurationSlider.value) 192 cycleTime = int(cycleTime * const.HOUR) 193 text = self._GetProgramDurationText(cycleTime, numCycles) 194 return text 195 196 def _GetProgramDurationText(self, cycleTime, numCycles): 197 return FormatTimeIntervalShortWritten(cycleTime * numCycles, showTo='minute') 198 199 def OnProgramDurationSliderMouseWheel(self, dz, *args): 200 self.ChangeDrillAreaSize(int(dz / 120)) 201 202 def _ConstructCenterContainer(self): 203 self.barGraph = BarGraph(parent=self.centerCont, align=uiconst.TOALL, barUpdateDelayMs=1, barHintFunc=self.GetBarHint, padding=(0, 2, 0, 10)) 204 uthread.new(self.UpdateProgram) 205 206 def GetBarHint(self, numBar, value, maxValue): 207 accOutput = sum(self.outputVals[:numBar]) 208 accTime = self.currCycleTime * numBar 209 accPerHour = appConst.HOUR * accOutput / accTime 210 return localization.GetByLabel('UI/PI/Common/SurveyBarHint', numBar=numBar, value=value, accOutput=accOutput, accTime=accTime, accPerHour=accPerHour) 211 212 def UpdateProgram(self, replaceHeadID = None, point = None, updateBargraph = True): 213 if self.currentResource is None: 214 return 215 cycleTime, maxValue, numCycles = self.GetProgramParameters(point, replaceHeadID) 216 self.currCycleTime = cycleTime 217 self.programCycleTime = cycleTime 218 self.outputVals = self.pin.GetProgramOutputPrediction(maxValue, cycleTime, numCycles) 219 self._UpdateOutputPerHourLabel(numCycles) 220 if updateBargraph: 221 self._UpdateBargraph(numCycles) 222 223 def GetProgramParameters(self, point, replaceHeadID): 224 if self.editsEnabled: 225 heads = self.pin.heads[:] 226 if replaceHeadID is not None: 227 for each in self.pin.heads: 228 if each[0] == replaceHeadID: 229 heads.remove(each) 230 heads.append((replaceHeadID, point.phi, point.theta)) 231 break 232 233 colony = self.GetColony() 234 maxValue, cycleTime, numCycles, self.overlapValues = colony.CreateProgram(self.currentResource, self.pin.id, self.currResourceTypeID, points=heads, headRadius=self.currentRadius) 235 self.UpdateOverlapValues() 236 self.planetUISvc.myPinManager.SetEcuOverlapValues(self.pin.id, self.overlapValues) 237 else: 238 maxValue, cycleTime, numCycles = self.pin.GetProgramParameters() 239 return (cycleTime, maxValue, numCycles) 240 241 def _UpdateBargraph(self, numCycles): 242 self.barGraph.SetValues(self.outputVals) 243 xLabels = (localization.GetByLabel('UI/PI/Common/SurveyProgramStart'), self._GetProgramDurationText(self.programCycleTime, numCycles)) 244 self.barGraph.SetXLabels(xLabels) 245 self.UpdateBarTimeIndicator() 246 247 def UpdateOverlapValues(self): 248 for id, headButton in enumerate(self.headButtons): 249 headButton.SetOverlapValue(self.overlapValues.get(id, None)) 250 251 def _UpdateOutputPerHourLabel(self, numCycles): 252 totalOutput = sum(self.outputVals) 253 perHourOutput = float(totalOutput) * appConst.HOUR / (numCycles * self.programCycleTime) 254 if self.currResourceTypeID: 255 self.outputPerHourTxt.Show() 256 self.outputPerHourTxt.SetText(localization.GetByLabel('UI/PI/Common/SurveyPerHourOutput', perHourOutput=perHourOutput)) 257 self.outputTotalTxt.SetText(localization.GetByLabel('UI/PI/Common/SurveyTotalOutput', totalOutput=totalOutput)) 258 else: 259 self.outputPerHourTxt.Hide() 260 261 def UpdateBarTimeIndicator(self): 262 if self.pin.IsActive() and not self.pin.IsInEditMode(): 263 if self.barTimeIndicatorThread is None: 264 self.barTimeIndicatorThread = uthread.new(self._UpdateBarTimeIndicator) 265 else: 266 self.barGraph.HideTimeIndicator() 267 if self.barTimeIndicatorThread is not None: 268 self.barTimeIndicatorThread.kill() 269 self.barTimeIndicatorThread = None 270 271 def _UpdateBarTimeIndicator(self): 272 while self and not self.destroyed: 273 indicatorValue = float(blue.os.GetWallclockTime() - self.pin.installTime) / (self.pin.expiryTime - self.pin.installTime) 274 if indicatorValue > 0.0 and indicatorValue < 1.0: 275 self.barGraph.ShowTimeIndicator(indicatorValue) 276 blue.pyos.synchro.SleepWallclock(10000) 277 278 def OnHeadEntryMouseEnter(self, headID): 279 if not uicore.uilib.leftbtn: 280 self.headButtons[headID].ShowFill() 281 282 def OnHeadEntryMouseExit(self, headID): 283 self.headButtons[headID].HideFill() 284 285 def _ConstructRightContainer(self): 286 self.ConstructResourceSelectionIcons() 287 if self.pin.IsActive(): 288 self.ConstructCurrCycleGauge() 289 else: 290 self.ConstructAreaSliderAndButtons() 291 self.ConstructOutputLabels() 292 self.ConstructSubmitButton() 293 self.ConstructStateIndicatorCont() 294 295 def ConstructCurrCycleGauge(self): 296 self.currCycleGauge = Gauge(parent=self.rightCont, align=uiconst.TOTOP, value=0.0, color=planetCommonUI.PLANET_COLOR_CYCLE, label=localization.GetByLabel('UI/PI/Common/CurrentCycle'), padTop=10) 297 uthread.new(self._UpdateCurrCycleGauge) 298 299 def ConstructOutputLabels(self): 300 self.outputTxtCont = ContainerAutoSize(parent=self.rightCont, align=uiconst.TOTOP, height=40, padTop=10) 301 CaptionLabel(parent=self.outputTxtCont, text=localization.GetByLabel('UI/PI/Common/Output'), align=uiconst.TOTOP) 302 self.outputPerHourTxt = EveLabelSmall(parent=self.outputTxtCont, text=localization.GetByLabel('UI/Common/None'), align=uiconst.TOTOP) 303 self.outputTotalTxt = EveLabelSmall(parent=self.outputTxtCont, align=uiconst.TOTOP) 304 self.UpdateOutputTextCont() 305 306 def UpdateOutputTextCont(self): 307 if self.currResourceTypeID: 308 self.outputTxtCont.Show() 309 else: 310 self.outputTxtCont.Hide() 311 312 def ConstructStateIndicatorCont(self): 313 stateParent = ContainerAutoSize(parent=self.rightCont, align=uiconst.TOBOTTOM, padBottom=2) 314 self.stateTxt = eveLabel.EveLabelSmall(parent=stateParent, align=uiconst.CENTERTOP, color=Color.WHITE, state=uiconst.UI_NORMAL, padding=(0, 2, 0, 2), width=self.leftCont.width - 10) 315 self.stateColorFill = Fill(bgParent=stateParent) 316 self.UpdateStateInfoCont() 317 318 def ConstructResourceSelectionIcons(self): 319 CaptionLabel(parent=self.rightCont, text=localization.GetByLabel('UI/PI/Common/SelectedResource'), align=uiconst.TOTOP) 320 self.resourceIconButtons = {} 321 numIcons = len(self.resourceTypeIDs) 322 ICONSIZE = 25 323 PAD = 4 324 if self.editsEnabled: 325 state = uiconst.UI_PICKCHILDREN 326 else: 327 state = uiconst.UI_DISABLED 328 iconCont = Container(parent=self.rightCont, align=uiconst.TOTOP, pos=(0, 329 0, 330 numIcons * (ICONSIZE + PAD), 331 ICONSIZE), state=state, padding=(0, 2, 0, 2)) 332 resourceTypes = [ (evetypes.GetName(typeID), typeID) for typeID in self.resourceTypeIDs ] 333 resourceTypes.sort() 334 for i, (typeName, typeID) in enumerate(resourceTypes): 335 ib = IconButton(parent=iconCont, pos=(i * (ICONSIZE + PAD), 336 0, 337 ICONSIZE, 338 ICONSIZE), size=ICONSIZE, typeID=typeID, ignoreSize=True) 339 self.resourceIconButtons[typeID] = ib 340 ib.OnClick = (self.OnResourceBtnClicked, typeID) 341 ib.OnMouseEnter = (self.OnResourceBtnMouseEnter, ib, typeID) 342 ib.OnMouseExit = (self.OnResourceBtnMouseExit, ib) 343 344 self.selectedResourceTxt = EveLabelSmall(parent=self.rightCont, text='', align=uiconst.TOTOP) 345 self.SetCurrentResourceText(self.currResourceTypeID) 346 347 def _UpdateCurrCycleGauge(self): 348 while not self.destroyed: 349 if self.pin.IsActive(): 350 self.currCycleGauge.Show() 351 txt, cycleProportion = planetCommonUI.GetPinCycleInfo(self.pin, self.programCycleTime) 352 self.currCycleGauge.SetValueInstantly(cycleProportion) 353 self.currCycleGauge.SetSubText(txt) 354 else: 355 self.currCycleGauge.Hide() 356 blue.pyos.synchro.SleepWallclock(1000) 357 358 def UpdateStateInfoCont(self): 359 if self.pin.IsInEditMode(): 360 color = Color.WHITE 361 text = localization.GetByLabel('UI/PI/Common/EditsPending') 362 animations.FadeTo(self.stateColorFill, 0.0, 0.5, duration=2.0, curveType=uiconst.ANIM_WAVE, loops=uiconst.ANIM_REPEAT) 363 elif self.pin.IsActive(): 364 color = Color('GREEN').SetAlpha(0.4).GetRGBA() 365 text = localization.GetByLabel('UI/PI/Common/SurveyProgramRunning') 366 animations.FadeTo(self.stateColorFill, 0.2, 0.5, duration=3.0, curveType=uiconst.ANIM_WAVE, loops=uiconst.ANIM_REPEAT) 367 else: 368 color = Color.WHITE 369 text = localization.GetByLabel('UI/Common/Idle') 370 animations.FadeTo(self.stateColorFill, 0.0, 0.5, duration=2.0, curveType=uiconst.ANIM_WAVE, loops=uiconst.ANIM_REPEAT) 371 self.stateColorFill.SetRGBA(*color) 372 self.stateTxt.SetText('<center>' + text) 373 374 def ConstructSubmitButton(self): 375 if self.editsEnabled: 376 btnName = localization.GetByLabel('UI/PI/Common/SurveyInstallProgram') 377 func = self._ApplyProgram 378 else: 379 btnName = localization.GetByLabel('UI/PI/Common/SurveyStopProgram') 380 func = self._StopProgram 381 self.submitButton = Button(parent=self.rightCont, label=btnName, func=func, align=uiconst.TOBOTTOM, idx=0, fixedheight=20) 382 383 def UpdateSubmitButton(self): 384 nextEditTime = self.pin.GetNextEditTime() 385 if nextEditTime is not None and nextEditTime > blue.os.GetWallclockTime() and not self.pin.IsInEditMode(): 386 self.submitButton.Disable() 387 uthread.new(self._UnlockStopButtonThread).context = '_SetSubmitButtonState' 388 elif self.currentResource is None or not self.pin.GetNumHeads(): 389 self.submitButton.Disable() 390 self.submitButton.SetHint('') 391 else: 392 self.submitButton.Enable() 393 self.submitButton.SetHint('') 394 395 def _UnlockStopButtonThread(self): 396 nextEditTime = self.pin.GetNextEditTime() 397 while nextEditTime > blue.os.GetWallclockTime(): 398 self.submitButton.SetHint(localization.GetByLabel('UI/PI/Common/SurveyEditsAvailableIn', time=nextEditTime - blue.os.GetWallclockTime())) 399 blue.pyos.synchro.SleepWallclock(200) 400 if not self or self.destroyed: 401 return 402 403 self.UpdateSubmitButton() 404 405 def OnHeadBtnClicked(self, headID): 406 head = self.pin.FindHead(headID) 407 if not head: 408 self.PlaceProbeAtDefaultPosition(headID) 409 else: 410 self.planetUISvc.myPinManager.RemoveExtractionHead(self.pin.id, headID) 411 if headID in self.extractionHeadValues: 412 self.extractionHeadValues.pop(headID) 413 self.headButtons[headID].SetValue(None) 414 self.UpdateProgram() 415 self.UpdateNoExtractorsLabel() 416 self.UpdateSubmitButton() 417 418 def OnBeginDragExtractionHead(self, headID, surfacePoint): 419 sm.GetService('audio').SendUIEvent('msg_pi_extractor_play') 420 sm.GetService('audio').SendUIEvent('msg_pi_extractor_distorted_play') 421 if self.currResourceTypeID is not None: 422 self.dragThread = uthread.new(self._WhileExtractionHeadDraggedThread, headID, surfacePoint) 423 else: 424 self.headButtons[headID].SetValue(0.0) 425 426 def OnEndDragExtractionHead(self): 427 sm.GetService('audio').SendUIEvent('msg_pi_extractor_stop') 428 sm.GetService('audio').SendUIEvent('msg_pi_extractor_distorted_stop') 429 if self.dragThread is not None: 430 self.dragThread.kill() 431 self.dragThread = None 432 433 def OnExtractionHeadMoved(self, headID, surfacePoint): 434 self.UpdateHeadPosition(headID, surfacePoint) 435 436 def OnExtractionHeadAdded(self, headID, surfacePoint): 437 self.UpdateProgram() 438 self.UpdateNoExtractorsLabel() 439 self._UpdateExtractorValues() 440 441 def _UpdateExtractorValues(self): 442 for i in xrange(planetCommon.ECU_MAX_HEADS): 443 value = self.GetResourceLayerValueForHead(i) 444 self.headButtons[i].SetValue(value) 445 446 def OnExtractionHeadRemoved(self, headID): 447 self.UpdateProgram() 448 self.UpdateNoExtractorsLabel() 449 self._UpdateExtractorValues() 450 451 def _WhileExtractionHeadDraggedThread(self, headID, surfacePoint): 452 while not self.destroyed: 453 if self.currentResource is not None: 454 self.UpdateProgram(replaceHeadID=headID, point=surfacePoint) 455 blue.pyos.synchro.SleepWallclock(200) 456 457 def UpdateHeadPosition(self, headID, surfacePoint): 458 heads = self.pin.heads 459 headRadius = self.pin.headRadius 460 if self.currentResource is not None: 461 value = self.GetResourceLayerValueForHead(headID, surfacePoint) 462 overlapValue = self.overlapValues.get(headID, None) 463 self.headButtons[headID].SetValue(value=value, overlapValue=overlapValue) 464 if value is not None: 465 sm.GetService('audio').SetGlobalRTPC('pitch_extractor_quality', 100 * value / 250) 466 if overlapValue is not None: 467 sm.GetService('audio').SetGlobalRTPC('volume_extractor_interference', 10 * overlapValue) 468 else: 469 self.headButtons[headID].SetValue(value=0.0) 470 471 def UpdateHeadButtonValues(self): 472 for headButton in self.headButtons: 473 value = self.GetResourceLayerValueForHead(headButton.headID) 474 self.extractionHeadValues[headButton.headID] = value 475 headButton.SetValue(value) 476 477 def GetResourceLayerValueForHead(self, headID, surfacePoint = None): 478 if self.currResourceTypeID: 479 head = self.pin.FindHead(headID) 480 if head: 481 headID, phi, theta = head 482 if surfacePoint: 483 theta = 2.0 * math.pi - surfacePoint.theta 484 phi = surfacePoint.phi 485 else: 486 theta = 2.0 * math.pi - theta 487 phi = phi 488 return max(0.0, builder.GetValueAt(self.sh, theta, phi)) 489 else: 490 if self.pin.FindHead(headID) is not None: 491 return 0.0 492 return 493 494 def PlaceProbeAtDefaultPosition(self, headID): 495 OFFSET = 0.08 496 VEC_X = (-1, 0, 0) 497 rotAngle = float(headID) / planetCommon.ECU_MAX_HEADS * 2 * math.pi 498 ecuVector = self.planetUISvc.myPinManager.pinsByID[self.pin.id].surfacePoint.GetAsXYZTuple() 499 normal = geo2.Vec3Cross(ecuVector, VEC_X) 500 normal = geo2.Vector(*normal) * OFFSET 501 posVec = geo2.Vec3Subtract(ecuVector, normal) 502 posVec = geo2.Vec3Normalize(posVec) 503 rotMat = geo2.MatrixRotationAxis(ecuVector, rotAngle) 504 posVec = geo2.Multiply(rotMat, posVec) 505 surfacePoint = planetCommon.SurfacePoint(*posVec) 506 self.planetUISvc.myPinManager.PlaceExtractionHead(self.pin.id, surfacePoint, headID) 507 self.UpdateHeadPosition(headID, surfacePoint) 508 509 def _ApplyProgram(self, *args): 510 if self.currResourceTypeID is not None: 511 self.planet.InstallProgram(self.pin.id, self.currResourceTypeID, self.currentRadius) 512 self.planetUISvc.myPinManager.ReRenderPin(self.pin) 513 self.planetUISvc.eventManager.SelectPin(self.pin.id) 514 self.Close() 515 516 def _Cancel(self, *args): 517 self.planetUISvc.CancelInstallProgram(self.pin.id, self.pinData) 518 self.Close() 519 520 def _StopProgram(self, *args): 521 self.editsEnabled = True 522 self.pin.inEditMode = True 523 self.leftCont.Flush() 524 self.rightCont.Flush() 525 self.planetUISvc.myPinManager.UnlockHeads(self.pin.id) 526 self.planetUISvc.GetCurrentPlanet().InstallProgram(self.pin.id, None, self.currentRadius) 527 self._ConstructLeftContainer() 528 self._ConstructRightContainer() 529 self.SetCurrentResource(self.currResourceTypeID) 530 self.UpdateSubmitButton() 531 532 def OnResourceBtnClicked(self, typeID, *args): 533 self.SetCurrentResource(typeID) 534 535 def OnResourceBtnMouseEnter(self, btn, typeID, *args): 536 self.SetCurrentResourceText(typeID) 537 IconButton.OnMouseEnter(btn) 538 539 def OnResourceBtnMouseExit(self, btn, *args): 540 self.SetCurrentResourceText(self.currResourceTypeID) 541 IconButton.OnMouseExit(btn) 542 543 def SetCurrentResource(self, typeID = None): 544 self.currResourceTypeID = typeID 545 self.currentResource = None if typeID is None else self.planet.GetResourceHarmonic(typeID) 546 self.UpdateSelectedResourceIconBtns(typeID) 547 self.UpdateSubmitButton() 548 if typeID is None: 549 self.sh = None 550 else: 551 inRange, self.sh = self.planetUISvc.planet.GetResourceData(self.currResourceTypeID) 552 self.SetCurrentResourceText(typeID) 553 self.UpdateHeadButtonValues() 554 self.UpdateProgram() 555 self.planetUISvc.ShowResource(typeID) 556 self.UpdateOutputTextCont() 557 558 def UpdateSelectedResourceIconBtns(self, typeID): 559 for ibTypeID, ib in self.resourceIconButtons.iteritems(): 560 if self.currResourceTypeID: 561 ib.SetDeselected() 562 if not self.editsEnabled and ibTypeID != typeID: 563 ib.Disable() 564 565 if typeID: 566 ib = self.resourceIconButtons[typeID] 567 ib.SetSelected() 568 569 def SetCurrentResourceText(self, typeID): 570 if typeID: 571 text = evetypes.GetName(typeID) 572 else: 573 text = '<color=red>%s</color>' % localization.GetByLabel('UI/PI/Common/NoResourceSelected') 574 self.selectedResourceTxt.text = text 575 576 def OnPlanetViewChanged(self, newPlanet, oldPlanet): 577 self.Close() 578 579 def OnEditModeBuiltOrDestroyed(self, planetID): 580 if not self or self.destroyed: 581 return 582 if self.planet.planetID != planetID: 583 return 584 if self.planet.GetPin(self.pin.id) is None: 585 self.Close() 586 587 def OnEditModeChanged(self, isEdit): 588 if not self or self.destroyed: 589 return 590 if not isEdit: 591 self.Close() 592 593 def CloseByUser(self, *args): 594 self.planetUISvc.CancelInstallProgram(self.pin.id, self.pinData) 595 Window.CloseByUser(self, *args) 596 597 def _OnClose(self, *args): 598 if hasattr(self, 'revertToResource'): 599 self.planetUISvc.ShowResource(self.revertToResource) 600 self.planetUISvc.ExitSurveyMode() 601 602 def GetColony(self): 603 return self.planetUISvc.GetCurrentPlanet().GetColony(session.charid) 604 605 606 class ExtractionHeadEntry(Container): 607 __guid__ = 'uicls.ExtractionHeadEntry' 608 default_name = 'ExtractionHeadEntry' 609 default_height = 20 610 default_state = uiconst.UI_NORMAL 611 default_padBottom = 9 612 613 def ApplyAttributes(self, attributes): 614 Container.ApplyAttributes(self, attributes) 615 self.headID = attributes.headID 616 self.ecuID = attributes.ecuID 617 self.value = attributes.get('value', None) 618 self.pin = attributes.pin 619 self.overlapValue = None 620 self.fill = Fill(parent=self, align=uiconst.TOTOP, height=self.default_height, color=Color(*Color.WHITE).SetAlpha(0.1).GetRGBA(), state=uiconst.UI_HIDDEN, idx=0) 621 self.icon = eveIcon.Icon(parent=self, icon='ui_77_32_38', size=self.default_height, ignoreSize=True, state=uiconst.UI_DISABLED, left=-2) 622 self.label = EveLabelSmall(parent=self, text='', left=self.default_height, top=4) 623 self.SetValue(self.value) 624 625 def SetValue(self, value = None, overlapValue = None): 626 self.value = value 627 self.overlapValue = overlapValue 628 if value is None: 629 txt = localization.GetByLabel('UI/PI/Common/SurveyDashSign') 630 self.opacity = 0.5 631 else: 632 if overlapValue: 633 txt = localization.GetByLabel('UI/PI/Common/SurveyHeadValueDisturbed', value=value, percentage=int(math.ceil(100 * overlapValue))) 634 else: 635 txt = localization.GetByLabel('UI/PI/Common/SurveyHeadValue', value=value) 636 self.opacity = 1.0 637 self.label.text = txt 638 639 def GetHint(self, *args): 640 if self.value is None: 641 return localization.GetByLabel('UI/PI/Common/SurveyInstallHeadHint', power=self.pin.GetExtractorHeadPowerUsage(), cpu=self.pin.GetExtractorHeadCpuUsage()) 642 if self.overlapValue: 643 disturbanceText = localization.GetByLabel('UI/PI/Common/SurveyExtractorHeadDisturbanceHint', percentage=int(math.ceil(100 * self.overlapValue))) 644 else: 645 disturbanceText = '' 646 hint = localization.GetByLabel('UI/PI/Common/SurveyExtractorHeadHint', headID=self.headID + 1, value=self.value, disturbanceText=disturbanceText) 647 return hint 648 649 def LoadTooltipPanel(self, tooltipPanel, *args): 650 tooltipPanel.LoadGeneric2ColumnTemplate() 651 tooltipPanel.AddLabelMedium(text=self.GetHint(), colSpan=2, cellPadding=(0, 0, 0, 10), wrapWidth=200) 652 tooltipPanel.AddLabelShortcut(GetByLabel('UI/PI/Common/InstallExtractor'), GetByLabel('UI/PI/Common/InstallExtractorShortcut')) 653 tooltipPanel.AddSpacer(height=1) 654 tooltipPanel.AddLabelShortcut(GetByLabel('UI/PI/Common/MoveExtractor'), GetByLabel('UI/PI/Common/MoveExtractorShortcut')) 655 656 def GetTooltipPointer(self): 657 if self.headID < 5: 658 return uiconst.POINT_RIGHT_2 659 else: 660 return uiconst.POINT_LEFT_2 661 662 def SetOverlapValue(self, overlapValue): 663 self.SetValue(self.value, overlapValue) 664 665 def OnMouseEnter(self, *args): 666 if not self or self.destroyed: 667 return 668 self.ShowFill() 669 if self.value is None: 670 self.label.text = localization.GetByLabel('UI/PI/Common/SurveyInstall') 671 self.opacity = 1.0 672 sm.GetService('planetUI').myPinManager.OnExtractionHeadMouseEnter(self.ecuID, self.headID) 673 674 def OnMouseExit(self, *args): 675 if not self or self.destroyed: 676 return 677 self.HideFill() 678 if self.value is None: 679 self.label.text = localization.GetByLabel('UI/PI/Common/SurveyDashSign') 680 self.opacity = 0.5 681 sm.GetService('planetUI').myPinManager.OnExtractionHeadMouseExit(self.ecuID, self.headID) 682 683 def ShowFill(self): 684 if self.overlapValue: 685 self.fill.height = 28 686 else: 687 self.fill.height = self.default_height 688 self.fill.state = uiconst.UI_DISABLED 689 690 def HideFill(self): 691 self.fill.state = uiconst.UI_HIDDEN