fittingCenter.py (14805B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\fittingScreen\fittingCenter.py 2 import blue 3 import math 4 import uthread 5 from carbonui import const as uiconst 6 from carbonui.primitives.container import Container 7 from carbonui.uicore import uicore 8 from eve.client.script.ui.control.scenecontainer import SceneContainerBaseNavigation, STENCIL_MAP_DEFAULT 9 from eve.client.script.ui.inflight.shipHud.groupAllIcon import GroupAllButton 10 from eve.client.script.ui.shared.fitting.fittingUtil import GetScaleFactor, EatSignalChangingErrors 11 from eve.client.script.ui.shared.fitting.shipSceneContainer import ShipSceneContainer 12 from eve.client.script.ui.shared.fitting.slotAdder import SlotAdder 13 from eve.client.script.ui.shared.fittingScreen.feedbackLabelCont import FeedbackLabelCont 14 from eve.client.script.ui.shared.fittingScreen.fittingLayout import FittingLayout 15 from eve.client.script.ui.shared.fittingScreen.fittingRadialMenu import RadialMenuIcon 16 from eve.client.script.ui.shared.fittingScreen.slot import FittingSlot 17 from eve.client.script.ui.station.fitting.stanceSlot import StanceSlots 18 from eve.common.script.sys.eveCfg import IsControllingStructure 19 from eveservices.menu import GetMenuService 20 from eveui.decorators import lock_and_set_pending 21 from inventorycommon import const as invconst 22 from localization import GetByLabel 23 from menu import MenuLabel, MenuList 24 from signals.signalUtil import ChangeSignalConnect 25 26 class FittingCenter(FittingLayout): 27 default_align = uiconst.CENTER 28 default_state = uiconst.UI_PICKCHILDREN 29 30 def ApplyAttributes(self, attributes): 31 FittingLayout.ApplyAttributes(self, attributes) 32 self.controller = attributes.controller 33 self.ChangeSignalConnection(connect=True) 34 self.slots = {} 35 self.slotList = [] 36 self.menuSlots = {} 37 self.AddSlots() 38 self.AddFeedbackLabel() 39 self.AddSceneContainer() 40 uthread.new(self.AnimateSlots) 41 self.UpdateGauges() 42 self.SetShipStance() 43 self.UpdateRadialMenuAndGroupAllDisplay() 44 45 def ChangeSignalConnection(self, connect = True): 46 signalAndCallback = [(self.controller.on_stats_changed, self.UpdateGaugesOnSignal), 47 (self.controller.on_gauge_preview_changed, self.UpdatePreviewGauges), 48 (self.controller.on_new_itemID, self.OnNewItem), 49 (self.controller.on_slots_with_menu_changed, self.OnSlotsWithMenuChanged), 50 (self.controller.on_simulation_state_changed, self.OnSimulationStateChanged), 51 (self.controller.on_slots_updated, self.CheckGroupAllButton)] 52 ChangeSignalConnect(signalAndCallback, connect) 53 54 def OnNewItem(self, *args): 55 self.UpdateGauges() 56 self.SetShipStance() 57 58 def GetSlots(self): 59 return self.slots 60 61 def AddToSlotsWithMenu(self, slot): 62 self.menuSlots[slot] = 1 63 64 def ClearSlotsWithMenu(self): 65 for slot in self.menuSlots.iterkeys(): 66 slot.HideUtilButtons() 67 68 self.menuSlots = {} 69 70 def AddSceneContainer(self): 71 size = 550 * GetScaleFactor() 72 self.sceneContainerParent = ShipSceneParent(parent=self, align=uiconst.CENTER, width=size, height=size, controller=self.controller) 73 self.sceneContainer = self.sceneContainerParent.sceneContainer 74 self.sceneNavigation = self.sceneContainerParent.sceneNavigation 75 76 def AddFeedbackLabel(self): 77 FeedbackLabelCont(parent=self, idx=0, align=uiconst.CENTERBOTTOM, top=150) 78 79 def AddSlots(self): 80 self.slotCont = Container(parent=self, name='slotCont', align=uiconst.TOALL, state=uiconst.UI_PICKCHILDREN, idx=0) 81 self.slotList = [] 82 slotAdder = SlotAdder(self.controller, FittingSlot) 83 for groupIdx, group in self.controller.GetSlotsByGroups().iteritems(): 84 if groupIdx < 0: 85 continue 86 arcStart, arcLength = self.controller.SLOTGROUP_LAYOUT_ARCS[groupIdx] 87 slotAdder.StartGroup(arcStart, arcLength, len(group)) 88 for slotIdx, slotController in enumerate(group): 89 slot = slotAdder.AddSlot(self.slotCont, slotController.flagID) 90 self.slotList.append(slot) 91 self.slots[slotController.flagID] = slot 92 93 self.stances = StanceSlots(parent=self.slotCont, shipID=self.controller.GetItemID(), angleToPos=lambda angle: slotAdder.GetPositionNumbers(angle), typeID=self.controller.GetTypeID(), controller=self.controller) 94 self.slotList.extend(self.stances.GetStanceContainers()) 95 self.AddRadialMenuIcons() 96 97 def AddRadialMenuIcons(self): 98 rad = int(243 * self.scaleFactor) 99 cX = cY = self.baseShapeSize / 2 100 size = int(22 * GetScaleFactor()) 101 102 def GetLocation(angle, size): 103 cos = math.cos(angle * math.pi / 180.0) 104 sin = math.sin(angle * math.pi / 180.0) 105 left = int(round(rad * cos + cX - size / 2)) 106 top = int(round(rad * sin + cY - size / 2)) 107 return (left, top) 108 109 left, top = GetLocation(227, size) 110 self.allHiSlotsIcon = RadialMenuIcon(name='hiSlotRadial', parent=self.slotCont, texturePath='res:/ui/Texture/classes/RadialMenu/fitting/high.png', pos=(left, 111 top, 112 size, 113 size), mouseDownFunc=self.TryOpenRadialMenu, flags=invconst.hiSlotFlags, iconSize=size, hint=GetByLabel('UI/Fitting/FittingWindow/RadialMenu/RadialMenuHighSlots')) 114 left, top = GetLocation(315, size) 115 self.allMedSlotsIcon = RadialMenuIcon(name='medSlotRadial', parent=self.slotCont, texturePath='res:/ui/Texture/classes/RadialMenu/fitting/med.png', pos=(left, 116 top, 117 size, 118 size), mouseDownFunc=self.TryOpenRadialMenu, flags=invconst.medSlotFlags, iconSize=size, hint=GetByLabel('UI/Fitting/FittingWindow/RadialMenu/RadialMenuMedSlots')) 119 left, top = GetLocation(45, size) 120 texturePath = 'res:/ui/Texture/classes/RadialMenu/fitting/low.png' 121 self.allLoSlotsIcon = RadialMenuIcon(name='loSlotRadial', parent=self.slotCont, texturePath=texturePath, pos=(left, 122 top, 123 size, 124 size), mouseDownFunc=self.TryOpenRadialMenu, flags=invconst.loSlotFlags, iconSize=size, hint=GetByLabel('UI/Fitting/FittingWindow/RadialMenu/RadialMenuLowSlots')) 125 left, top = GetLocation(227, size) 126 self.groupAllButton = GroupAllButton(parent=self, idx=0, pos=(left, 127 top, 128 size, 129 size)) 130 131 def CheckGroupAllButton(self): 132 if self.groupAllButton is not None and not self.groupAllButton.destroyed: 133 self.groupAllButton.CheckGroupAllButton() 134 135 def TryOpenRadialMenu(self, icon, slotList, mouseButton, *args): 136 if mouseButton != uiconst.MOUSELEFT: 137 return 138 uthread.new(self.ExpandRadialMenu, icon, slotList) 139 140 def ExpandRadialMenu(self, anchorObject, slotList, *args): 141 from eve.client.script.ui.shared.fittingScreen.fittingRadialMenu import RadialMenuFitting 142 radialMenu = RadialMenuFitting(name='radialMenuFitting', parent=uicore.layer.menu, state=uiconst.UI_NORMAL, align=uiconst.TOPLEFT, anchorObject=anchorObject, slotList=slotList, isStructure=self.controller.ControllerForCategory() == const.categoryStructure) 143 uicore.layer.menu.radialMenu = radialMenu 144 uicore.uilib.SetMouseCapture(radialMenu) 145 146 def ChangeRadialMenuIconDisplay(self, displayState): 147 for element in [self.allHiSlotsIcon, self.allMedSlotsIcon, self.allLoSlotsIcon]: 148 element.display = displayState 149 150 def AnimateSlots(self): 151 uthread.new(self.EntryAnimation, self.slotList) 152 153 def EntryAnimation(self, toAnimate): 154 for obj in toAnimate: 155 obj.opacity = 0.0 156 157 for i, obj in enumerate(toAnimate): 158 if obj.state == uiconst.UI_DISABLED: 159 endOpacity = 0.05 160 else: 161 endOpacity = 1.0 162 sm.GetService('audio').SendUIEvent('msg_fittingSlotHi_play') 163 uicore.animations.FadeTo(obj, 0.0, endOpacity, duration=0.3) 164 blue.synchro.SleepWallclock(5) 165 166 def UpdatePreviewGauges(self, cpuLoad, powerLoad, calibrationLoad, *args): 167 if self.controller is None or not self.controller.CurrentShipIsLoaded(): 168 return 169 if self.controller.IsGodmaPrimingInterfering(): 170 return 171 cpuOutput = self.controller.GetCPUOutput() 172 portion = self.GetPortion(cpuLoad, cpuOutput.value) 173 self.cpuGaugePreview.SetValue(portion, animate=False) 174 powerOutput = self.controller.GetPowerOutput() 175 portion = self.GetPortion(powerLoad, powerOutput.value) 176 self.powerGaugePreview.SetValue(portion, animate=False) 177 calibrationOutput = self.controller.GetCalibrationOutput() 178 if calibrationLoad and calibrationOutput.value > 0: 179 portion = calibrationLoad / calibrationOutput.value 180 else: 181 portion = 0.0 182 self.calibrationGaugePreview.SetValue(portion, animate=False) 183 184 def UpdateGaugesOnSignal(self): 185 uthread.new(self.UpdateGauges) 186 187 @lock_and_set_pending() 188 def UpdateGauges(self): 189 if self.controller is None or not self.controller.CurrentShipIsLoaded(): 190 return 191 self.UpdatePowerGauge() 192 self.UpdateCPUGauge() 193 self.UpdateCalibrationGauge() 194 195 def UpdatePowerGauge(self): 196 powerLoad = self.controller.GetPowerLoad() 197 powerOutput = self.controller.GetPowerOutput() 198 portion = self.GetPortion(powerLoad.value, powerOutput.value) 199 self.powerGauge.SetValue(portion) 200 201 def UpdateCPUGauge(self): 202 cpuLoad = self.controller.GetCPULoad() 203 cpuOutput = self.controller.GetCPUOutput() 204 portion = self.GetPortion(cpuLoad.value, cpuOutput.value) 205 self.cpuGauge.SetValue(portion) 206 207 def GetPortion(self, loadValue, outputValue): 208 portion = 0.0 209 if loadValue: 210 if outputValue == 0.0: 211 portion = 1.0 212 else: 213 portion = loadValue / outputValue 214 return portion 215 216 def UpdateCalibrationGauge(self): 217 calibrationLoad = self.controller.GetCalibrationLoad() 218 calibrationOutput = self.controller.GetCalibrationOutput() 219 if calibrationLoad.value and calibrationOutput.value > 0: 220 portion = calibrationLoad.value / calibrationOutput.value 221 else: 222 portion = 0.0 223 self.calibrationGauge.SetValue(portion) 224 self.calibrationGauge.SetCalibrationNumbers(calibrationLoad.value, calibrationOutput.value) 225 226 def SetShipStance(self): 227 if self.controller.HasStance(): 228 self.ShowStanceButtons() 229 else: 230 self.HideStanceButtons() 231 232 def ShowStanceButtons(self): 233 self.stances.display = True 234 self.stances.ShowStances(self.controller.GetItemID(), self.controller.GetTypeID()) 235 236 def HideStanceButtons(self): 237 self.stances.display = False 238 239 def GetTooltipPosition(self): 240 return (uicore.uilib.x - 5, 241 uicore.uilib.y - 5, 242 10, 243 10) 244 245 def OnSlotsWithMenuChanged(self, oldFlagID, newFlagID): 246 slot = self.slots.get(oldFlagID, None) 247 if slot is not None: 248 slot.HideUtilButtons() 249 250 def OnSimulationStateChanged(self): 251 self.UpdateRadialMenuAndGroupAllDisplay() 252 253 def UpdateRadialMenuAndGroupAllDisplay(self): 254 isSimulated = self.controller.IsSimulated() 255 if isSimulated: 256 displayState = True 257 else: 258 displayState = False 259 self.ChangeRadialMenuIconDisplay(displayState=displayState) 260 self.groupAllButton.display = not isSimulated 261 262 def Close(self): 263 with EatSignalChangingErrors(errorMsg='fitting center'): 264 self.ChangeSignalConnection(connect=False) 265 FittingLayout.Close(self) 266 267 268 class ShipSceneParent(Container): 269 270 def ApplyAttributes(self, attributes): 271 Container.ApplyAttributes(self, attributes) 272 self.controller = attributes.controller 273 self.stencilMask = attributes.Get('stencilMask', STENCIL_MAP_DEFAULT) 274 self.ChangeSignalConnection(connect=True) 275 self.sceneContainer = ShipSceneContainer(align=uiconst.TOALL, parent=self, state=uiconst.UI_DISABLED, controller=self.controller) 276 self.SetScene() 277 self.sceneContainer.LoadShipModel() 278 scaleFactor = GetScaleFactor() 279 self.sceneNavigation = SceneContainerBaseNavigation(parent=self, align=uiconst.TOALL, pos=(0, 0, 0, 0), idx=0, state=uiconst.UI_NORMAL, pickRadius=225 * scaleFactor) 280 self.sceneNavigation.Startup(self.sceneContainer) 281 self.sceneNavigation.OnDropData = self.OnDropData 282 self.sceneNavigation.GetMenu = self.GetShipMenu 283 284 def ChangeSignalConnection(self, connect = True): 285 signalAndCallback = [(self.controller.on_new_itemID, self.OnNewShipLoaded)] 286 ChangeSignalConnect(signalAndCallback, connect) 287 288 def SetScene(self): 289 scenePath = self.controller.scenePath 290 self.sceneContainer.PrepareSpaceScene(scenePath=scenePath) 291 self.sceneContainer.SetStencilMap(self.stencilMask) 292 293 def OnNewShipLoaded(self, *_args): 294 self.ReloadShipModel() 295 296 def OnDropData(self, dragObj, nodes): 297 if hasattr(self.controller, 'OnDropData'): 298 self.controller.OnDropData(dragObj, nodes) 299 300 def ReloadShipModel(self): 301 self.SetScene() 302 self.sceneContainer.ReloadShipModel(animate=False) 303 304 def GetShipMenu(self, *args): 305 itemID = self.controller.itemID 306 if itemID is None: 307 return MenuList() 308 m = MenuList() 309 if self.controller.IsSimulated(): 310 typeID = self.controller.GetTypeID() 311 m += GetMenuService().GetMenuFromItemIDTypeID(None, typeID=typeID, includeMarketDetails=True) 312 m += [[MenuLabel('UI/Inventory/ItemActions/StripFitting'), self.controller.StripFitting, []]] 313 return m.filter(['UI/Fitting/FittingWindow/SimulateShip']) 314 if IsControllingStructure(): 315 m += GetMenuService().CelestialMenu(session.structureid) 316 elif session.stationid or session.structureid: 317 hangarInv = sm.GetService('invCache').GetInventory(const.containerHangar) 318 hangarItems = [hangarInv.GetItem()] + hangarInv.List(const.flagHangar) 319 for each in hangarItems: 320 if each and each.itemID == self.controller.itemID: 321 m += GetMenuService().InvItemMenu(each) 322 323 elif session.solarsystemid: 324 m += GetMenuService().CelestialMenu(session.shipid) 325 return m 326 327 def Close(self): 328 with EatSignalChangingErrors(errorMsg='ShipSceneParent'): 329 self.ChangeSignalConnection(connect=False) 330 Container.Close(self)