class MultiFitWnd(Window): __guid__ = 'form.MultiFitWnd' __notifyevents__ = ['OnSessionChanged'] default_topParentHeight = 70 default_height = 400 default_width = 320 default_windowID = 'multiFitWnd' default_captionLabelPath = 'UI/Fitting/FittingWindow/FittingManagement/MultiFitHeader' layoutColumns = 3 def ApplyAttributes(self, attributes): Window.ApplyAttributes(self, attributes) self.fitting = None self.MakeUnResizeable() self.MakeUnstackable() self.canFitNum = 0 self.tryingToFitNum = 1 self.currentProgress = 0 self.ConstructUI() fitting = attributes.fitting self.tryingToFitNum = attributes.get('qty', 1) self.LoadWindow(fitting, self.tryingToFitNum) self.SetInventoryStatus() sm.RegisterNotify(self) def ConstructUI(self): self.BuildTopParentUI() self.AddButtons() numColumns = 2 self.layoutGrid = layoutGrid = LayoutGrid(parent=self.sr.main, columns=numColumns, cellSpacing=(4, 10)) spacer = Container(pos=(0, 0, 50, 0), align=uiconst.TOPLEFT) layoutGrid.AddCell(cellObject=spacer, colSpan=1) layoutGrid.FillRow() self.BuildNumToFitUI() self.BuildWarningUI() self.BuildRefreshInventory() self.missingLayoutGrid = LayoutGrid(parent=self.layoutGrid, columns=2, cellSpacing=(4, 10)) self.BuildAvailableShipsUI() self.BuildEquipmentUI() self.BuildProgressUI() self.MakeRigCbUI() def BuildTopParentUI(self): self.sr.topParent.padding = (2 * const.defaultPadding, 0, 2 * const.defaultPadding, 0) self.shipIcon = Icon(name='shipIcon', parent=self.sr.topParent, state=uiconst.UI_NORMAL, size=64, ignoreSize=True) self.shipIcon.GetDragData = self.GetFittingDragData self.shipIcon.OnClick = self.OpenFitting self.shipIcon.hint = GetByLabel('UI/Fitting/ShowFitting') self.techSprite = Sprite(name='techIcon', parent=self.sr.topParent, align=uiconst.RELATIVE, width=16, height=16, idx=0) self.fitNameEdit = SinglelineEdit( name='fitNameEdit', parent=self.sr.topParent, left=72, width=150, maxLength=20, hint=GetByLabel('UI/Common/ShipName')) top = self.fitNameEdit.top + self.fitNameEdit.height + 5 self.shipNameLabel = EveLabelMedium(name='shipNameLabel', parent=self.sr.topParent, left=77, top=top, state=uiconst.UI_NORMAL) def AddButtons(self): btnCont = FlowContainer(name='buttonParent', parent=self.sr.main, align=uiconst.TOBOTTOM, padding=6, autoHeight=True, centerContent=True, contentSpacing=uiconst.BUTTONGROUPMARGIN, idx=0) text = GetByLabel( 'UI/Fitting/FittingWindow/FittingManagement/FitShips', numToFit=1) self.fitBtn = Button(parent=btnCont, label=text, func=self.DoFitShips, align=uiconst.NOALIGN) self.cancelBtn = Button(parent=btnCont, label=GetByLabel('UI/Commands/Cancel'), func=self.Cancel, align=uiconst.NOALIGN) def BuildNumToFitUI(self): maxShipsAllowed = int( sm.GetService('machoNet').GetGlobalConfig().get( 'bulkFit_maxShips', 30)) numCont = Container(name='numCont', align=uiconst.TOTOP, height=30, padLeft=LEFT_EDGE) text = GetByLabel( 'UI/Fitting/FittingWindow/FittingManagement/NumShipsToFit') self.numToFitLabel = EveLabelLarge(name='numToFitLabel', parent=numCont, text=text, width=250, autoFitToText=True) left = self.numToFitLabel.left + self.numToFitLabel.textwidth + 10 self.numToFitEdit = SinglelineEdit(name='numToFitEdit', parent=numCont, ints=[1, maxShipsAllowed], OnChange=self.OnNumChanged, left=left, align=uiconst.CENTERLEFT) numCont.height = max(self.numToFitLabel.textheight, self.numToFitEdit.height) self.layoutGrid.AddCell(cellObject=numCont, colSpan=self.layoutGrid.columns) def BuildWarningUI(self): self.numWarningLabel = EveCaptionSmall(name='numWarningLabel', state=uiconst.UI_NORMAL, align=uiconst.CENTERTOP, width=MAX_TEXT_WIDTH, autoFitToText=True) self.numWarningLabel.SetRGBA(*WARNING_COLOR) self.numWarningLabel.LoadTooltipPanel = self.LoadMissingTooltip self.layoutGrid.AddCell(cellObject=self.numWarningLabel, colSpan=self.layoutGrid.columns) self.layoutGrid.FillRow() def BuildRefreshInventory(self): self.refreshCont = Transform(parent=self.layoutGrid, pos=(0, 0, 32, 32), align=uiconst.CENTER) self.refreshIcon = ButtonIcon(name='refreshSprite', parent=self.refreshCont, width=32, height=32, align=uiconst.CENTER, texturePath=REFRESH_TEXTUREPATH, iconSize=32, func=self.OnRefreshClicked) self.refreshIcon.hint = GetByLabel( 'UI/Fitting/FittingWindow/FittingManagement/RefreshInventoryStatusHint' ) def OnRefreshClicked(self, *args): uthread.new(self.refreshCont.StartRotationCycle, cycles=1) self.SetInventoryStatus() def BuildAvailableShipsUI(self): self.shipCounter = EveCaptionMedium(name='shipCounter', parent=self.missingLayoutGrid, state=uiconst.UI_NORMAL, align=uiconst.CENTERRIGHT, left=4) self.shipCounter.LoadTooltipPanel = self.LoadShipCounterTooltipPanel self.shipCounter.missingDict = {} shipText = GetByLabel( 'UI/Fitting/FittingWindow/FittingManagement/PackagedShipsInHangar') self.availableShipsLabel = EveLabelLarge(name='availableShipsLabel', parent=self.missingLayoutGrid, state=uiconst.UI_NORMAL, text=shipText, align=uiconst.CENTERLEFT, width=MAX_TEXT_WIDTH, autoFitToText=True) self.availableShipsLabel.hint = GetByLabel( 'UI/Fitting/FittingWindow/FittingManagement/PackagedShipsInHangarHint' ) self.layoutGrid.FillRow() def BuildEquipmentUI(self): self.equipmentCounter = EveCaptionMedium(name='equipmentCounter', parent=self.missingLayoutGrid, state=uiconst.UI_NORMAL, align=uiconst.CENTERRIGHT, left=4) self.equipmentCounter.LoadTooltipPanel = self.LoadEqCounterTooltipPanel self.equipmentCounter.missingDict = {} eqText = GetByLabel( 'UI/Fitting/FittingWindow/FittingManagement/RoundsOfFittingsInHangar' ) self.availableEquipmentLabel = EveLabelLarge( name='availableEquipmentLabel', parent=self.missingLayoutGrid, state=uiconst.UI_NORMAL, text=eqText, align=uiconst.CENTERLEFT, width=MAX_TEXT_WIDTH, autoFitToText=True) self.layoutGrid.FillRow() def BuildProgressUI(self): self.progressCont = Container(parent=self.sr.main, height=36, align=uiconst.TOBOTTOM, padding=(10, 0, 10, 10)) self.progressCounter = EveCaptionMedium(name='progressCounter', parent=self.progressCont, state=uiconst.UI_NORMAL, align=uiconst.CENTERTOP) self.progressBar = ProgressBar(parent=self.progressCont, height=10, align=uiconst.TOBOTTOM) self.progressCont.display = False def MakeRigCbUI(self): checked = settings.user.ui.Get('fitting_rigCB', True) text = GetByLabel('UI/Fitting/FittingWindow/FittingManagement/FitRigs') self.rigCB = Checkbox(name='rigCB', text=text, OnChange=self.OnCbChanged, left=LEFT_EDGE, checked=checked, prefstype=('user', 'ui'), configName='fitting_rigCB') self.rigCB.hint = GetByLabel( 'UI/Fitting/FittingWindow/FittingManagement/FitRigsHint') self.layoutGrid.AddCell(cellObject=self.rigCB, colSpan=self.layoutGrid.columns) def OnNumChanged(self, *args): self.onNumChangedTimer = AutoTimer(100, self.SetInventoryStatus) def OnCbChanged(self, *args): self.SetInventoryStatus() def OpenFitting(self, *args): sm.GetService('fittingSvc').DisplayFitting(self.fitting) def LoadWindow(self, fitting, qty=1): self.fitting = fitting self.shipCounter.missingDict = {} self.equipmentCounter.missingDict = {} shipTypeID = fitting.shipTypeID self.shipIcon.LoadIconByTypeID(shipTypeID) uix.GetTechLevelIcon(self.techSprite, typeID=shipTypeID) self.numToFitEdit.text = qty self.fitNameEdit.SetValue(fitting.name) self.shipNameLabel.text = GetShowInfoLink(shipTypeID, evetypes.GetName(shipTypeID)) self.SetInventoryStatus() self.missingLayoutGrid.RefreshGridLayout() self.layoutGrid.RefreshGridLayout() layoutWidth, layoutHeight = self.layoutGrid.GetSize() newHeight = layoutHeight + self.fitBtn.height + self.progressCont.height + self.sr.topParent.height + 20 self.height = max(newHeight, self.default_height) self.width = max(layoutWidth + 20, self.default_width) def SetInventoryStatus(self): self.onNumChangedTimer = None fitting = self.fitting shipTypeID = fitting.shipTypeID fittingSvc = sm.GetService('fittingSvc') chargesByType, dronesByType, fightersByTypeID, iceByType, itemTypes, modulesByFlag, rigsToFit, subsystems = fittingSvc.GetTypesToFit( fitting, None) if rigsToFit: self.rigCB.display = True else: self.rigCB.display = False numToFit = self.numToFitEdit.GetValue() self.tryingToFitNum = numToFit maxAvailableFitting, missingForFullFit = self._GetMaxAvailabeAndMissingForFullFit( itemTypes, modulesByFlag, numToFit) nonSingletonShipsNumDict = fittingSvc.GetQt0yInHangarByTypeIDs( [shipTypeID], onlyGetNonSingletons=True) packagedShipsNum = nonSingletonShipsNumDict.get(shipTypeID, 0) self.canFitNum = min(packagedShipsNum, maxAvailableFitting, numToFit) btnText = GetByLabel( 'UI/Fitting/FittingWindow/FittingManagement/FitShips', numToFit=self.canFitNum) self.fitBtn.SetLabel(btnText) if self.canFitNum < 1: self.fitBtn.Disable() else: self.fitBtn.Enable() missingNumShips = max(0, numToFit - packagedShipsNum) if missingNumShips: missingDict = {shipTypeID: missingNumShips} else: missingDict = {} self.shipCounter.missingDict = missingDict if missingForFullFit: missingDict = missingForFullFit else: missingDict = {} self.equipmentCounter.missingDict = missingDict if missingForFullFit or missingNumShips: missingText = GetByLabel( 'UI/Fitting/FittingWindow/FittingManagement/MissingShipEquipment' ) self.numWarningLabel.text = missingText else: self.numWarningLabel.text = '' self.numWarningLabel.height = 0 self.SetAvailabilityShipOrEq(self.shipCounter, packagedShipsNum, numToFit) self.SetAvailabilityShipOrEq(self.equipmentCounter, maxAvailableFitting, numToFit) def _GetMaxAvailabeAndMissingForFullFit(self, itemTypes, modulesByFlag, numToFit): fittingSvc = sm.GetService('fittingSvc') qtyByTypeID = fittingSvc.GetQt0yInHangarByTypeIDs(itemTypes) rigTypeIDs = { t for f, t in modulesByFlag.iteritems() if f in const.rigSlotFlags } maxAvailableFitting, missingForFullFit = fittingSvc.GetMaxAvailabeAndMissingForFullFit( True, itemTypes, numToFit, qtyByTypeID, rigTypeIDs) return (maxAvailableFitting, missingForFullFit) def SetAvailabilityShipOrEq(self, label, available, numToFit): label.text = available if available < numToFit: label.SetRGB(*WARNING_COLOR) else: label.SetRGB(*NORMAL_COLOR) def DoFitShips(self, *args): fitting = self.fitting fitRigs = self.rigCB.GetValue() toActuallyFit = self.canFitNum fittingName = self.fitNameEdit.GetValue() fittingSvc = sm.GetService('fittingSvc') chargesByType, dronesByType, fightersByTypeID, iceByType, itemTypes, modulesByFlag, rigsToFit, subsystems = fittingSvc.GetTypesToFit( fitting, None) if fitRigs or not rigsToFit: cargoItemsByType = {} else: cargoItemsByType = defaultdict(int) for flagID, typeID in modulesByFlag.iteritems(): if flagID in const.rigSlotFlags: cargoItemsByType[typeID] += 1 cargoItemsByType = dict(cargoItemsByType) lobby = GetLobbyClass().GetIfOpen() if lobby is None: return lobby.CheckCanAccessService('fitting') maxAvailableFitting, missingForFullFit = self._GetMaxAvailabeAndMissingForFullFit( itemTypes, modulesByFlag, toActuallyFit) if missingForFullFit: self.SetInventoryStatus() eve.Message('uiwarning03') return try: self.PrepareForMultiFitCall() fittingSvc.DoFitManyShips(chargesByType, dronesByType, fightersByTypeID, fitRigs, fitting, iceByType, cargoItemsByType, toActuallyFit, modulesByFlag, fittingName) finally: uthread.new(self.ResetUIAfterFitting) def PrepareForMultiFitCall(self): self.fitBtn.Disable() self.cancelBtn.Disable() self.currentProgress = 0 self.progressCounter.text = self.currentProgress self.progressCont.display = True self.layoutGrid.Disable() self.layoutGrid.opacity = 0.2 sm.RegisterForNotifyEvent(self, 'OnItemChange') def ResetUIAfterFitting(self): sm.UnregisterForNotifyEvent(self, 'OnItemChange') self.currentProgress = 0 uicore.animations.BlinkOut(self.progressCont, startVal=0.0, endVal=1.0, duration=0.5, loops=3, sleep=True) self.progressCont.display = False self.progressCounter.text = self.currentProgress self.cancelBtn.Enable() self.layoutGrid.Enable() self.layoutGrid.opacity = 1.0 self.SetInventoryStatus() def Cancel(self, *args): self.CloseByUser() def GetFittingDragData(self): entry = KeyVal() entry.fitting = self.fitting entry.label = self.fitting.name entry.displayText = self.fitting.name entry.__guid__ = 'listentry.FittingEntry' return [entry] def LoadMissingTooltip(self, tooltipPanel, *args): text = GetByLabel( 'UI/Fitting/FittingWindow/FittingManagement/MissingItems', numToFit=self.tryingToFitNum, fittingName=self.fitting.name) tooltipPanel.AddLabelLarge(text=text, padBottom=8) self.LoadShipCounterTooltipPanel(tooltipPanel, singleGroupShowing=False) self.LoadEqCounterTooltipPanel(tooltipPanel, singleGroupShowing=False) missingDict = {} missingDict.update(self.shipCounter.missingDict) missingDict.update(self.equipmentCounter.missingDict) self.AddBuyAllBtn(tooltipPanel, missingDict) def LoadShipCounterTooltipPanel(self, tooltipPanel, *args, **kwargs): missingDict = self.shipCounter.missingDict if not missingDict: return singleGroupShowing = kwargs.get('singleGroupShowing', True) text = GetByLabel( 'UI/Fitting/FittingWindow/FittingManagement/MissingShips', numToFit=self.tryingToFitNum, fittingName=self.fitting.name) return self.LoadCounterTooltip(tooltipPanel, missingDict, text, singleGroupShowing) def LoadEqCounterTooltipPanel(self, tooltipPanel, *args, **kwargs): missingDict = self.equipmentCounter.missingDict if not missingDict: return singleGroupShowing = kwargs.get('singleGroupShowing', True) text = GetByLabel( 'UI/Fitting/FittingWindow/FittingManagement/MissingEquipment', numToFit=self.tryingToFitNum, fittingName=self.fitting.name) self.LoadCounterTooltip(tooltipPanel, missingDict, text, singleGroupShowing) def LoadCounterTooltip(self, tooltipPanel, missingDict, text, singleGroupShowing=True): tooltipPanel.LoadGeneric1ColumnTemplate() tooltipPanel.state = uiconst.UI_NORMAL if singleGroupShowing: tooltipPanel.AddLabelLarge(text=text, padBottom=8) typeList = [] for eachTypeID, eachQty in missingDict.iteritems(): typeName = evetypes.GetName(eachTypeID) typeList.append((typeName.lower(), (eachTypeID, eachQty))) typeList = SortListOfTuples(typeList) for eachTypeID, eachQty in typeList[:MAX_TOOLTIP_ENTRIES]: typeCont = TooltipEntry(parent=tooltipPanel, typeID=eachTypeID, qty=eachQty) if len(typeList) > MAX_TOOLTIP_ENTRIES: numItemsNotDisplayed = len(typeList) - MAX_TOOLTIP_ENTRIES text = GetByLabel( 'UI/Fitting/FittingWindow/FittingManagement/MoreItemTypesMissing', numMoreItems=numItemsNotDisplayed) tooltipPanel.AddLabelMedium(text=text, align=uiconst.CENTERLEFT) if singleGroupShowing: self.AddBuyAllBtn(tooltipPanel, missingDict) def AddBuyAllBtn(self, tooltipPanel, missingDict): def BuyAll(*args): BuyMultipleTypesWithQty(missingDict) Button(parent=tooltipPanel, label=GetByLabel('UI/Market/MarketQuote/BuyAll'), func=BuyAll, align=uiconst.CENTER) if session.role & ROLE_GMH == ROLE_GMH: Button(parent=tooltipPanel, label='GM: Give all', func=self.GiveAllGM, align=uiconst.CENTERRIGHT, args=(missingDict, )) def GiveAllGM(self, missingDict): numToCountTo = len(missingDict) + 1 header = 'GM Item Gift' sm.GetService('loading').ProgressWnd(header, '', 1, numToCountTo) counter = 1 for typeID, qty in missingDict.iteritems(): counter += 1 sm.GetService('loading').ProgressWnd(header, '', counter, numToCountTo) sm.RemoteSvc('slash').SlashCmd('/create %s %s' % (typeID, qty)) sm.GetService('loading').ProgressWnd('Done', '', numToCountTo, numToCountTo) def OnItemChange(self, item, change): if item.typeID != self.fitting.shipTypeID: return if const.ixSingleton in change: self.currentProgress += 1 self.progressCounter.text = '%s / %s' % (self.currentProgress, self.canFitNum) def OnSessionChanged(self, isRemote, sess, change): if not IsDocked(): self.CloseByUser()
class MultiTrainingOverlay(Container): SUPPRESS_KEY = 'suppress.MultiplePilotTrainingPromotion' CONTENT_LEFT = 140 CHARACTERS_LEFT = -180 default_align = uiconst.TOALL default_clipChildren = True default_state = uiconst.UI_HIDDEN def ApplyAttributes(self, attributes): super(MultiTrainingOverlay, self).ApplyAttributes(attributes) self.Layout() def Layout(self): self.compactMode = False Frame(bgParent=self, texturePath='res:/UI/Texture/classes/Monetization/vignette.png', cornerSize=150) self.characters = Sprite( parent=self, align=uiconst.CENTER, state=uiconst.UI_DISABLED, left=self.CHARACTERS_LEFT, top=10, texturePath='res:/UI/Texture/classes/Monetization/characters.png', width=299, height=355) self.content = ContainerAutoSize(parent=self, align=uiconst.CENTER, left=self.CONTENT_LEFT, width=340) EveCaptionLarge( parent=self.content, align=uiconst.TOTOP, text=localization.GetByLabel( 'UI/SkillQueue/MultiTrainingOverlay/MultiplePilotTraining')) EveLabelMedium( parent=self.content, align=uiconst.TOTOP, top=4, text=localization.GetByLabel( 'UI/SkillQueue/MultiTrainingOverlay/MultiTrainingMessageTop')) itemCont = ContainerAutoSize(parent=self.content, align=uiconst.TOTOP, alignMode=uiconst.TOTOP, top=12) Frame(bgParent=itemCont, texturePath= 'res:/UI/Texture/classes/Monetization/item_well_frame.png', cornerSize=2) itemIconCont = ContainerAutoSize(parent=itemCont, align=uiconst.TOLEFT, padding=(8, 8, 0, 8)) Icon(parent=itemIconCont, align=uiconst.TOPLEFT, state=uiconst.UI_DISABLED, size=64, typeID=typeMultiTrainingToken) Sprite(parent=itemIconCont, align=uiconst.TOPLEFT, state=uiconst.UI_DISABLED, texturePath='res:/UI/Texture/classes/InvItem/bgNormal.png', width=64, height=64) EveLabelLargeBold(parent=itemCont, align=uiconst.TOTOP, padding=(8, 8, 24, 0), text=evetypes.GetName(typeMultiTrainingToken)) InfoIcon(parent=itemCont, align=uiconst.TOPRIGHT, top=8, left=8, typeID=typeMultiTrainingToken) self.estimatePriceLabel = EveLabelMedium(parent=itemCont, align=uiconst.TOTOP, padding=(8, 0, 8, 6), color=Color.GRAY5) buyButtonCont = FlowContainer(parent=itemCont, align=uiconst.TOTOP, padding=(8, 0, 8, 8), contentSpacing=(8, 0)) MultiTrainingBuyButtonIsk(parent=buyButtonCont, align=uiconst.NOALIGN, typeID=typeMultiTrainingToken) MultiTrainingBuyButtonAur(parent=buyButtonCont, align=uiconst.NOALIGN, types=[typeMultiTrainingToken]) EveLabelMedium( parent=self.content, align=uiconst.TOTOP, top=12, text=localization.GetByLabel( 'UI/SkillQueue/MultiTrainingOverlay/MultiTrainingMessageBottom' )) dismissCont = FlowContainer(parent=self.content, align=uiconst.TOTOP, padding=(8, 24, 8, 0), contentAlignment=CONTENT_ALIGN_CENTER, contentSpacing=(8, 4)) Button(parent=dismissCont, align=uiconst.NOALIGN, label=localization.GetByLabel( 'UI/SkillQueue/MultiTrainingOverlay/Dismiss'), func=lambda *args: self.Dismiss()) self.suppressCheckbox = Checkbox( parent=dismissCont, align=uiconst.NOALIGN, width=200, text=localization.GetByLabel('UI/Common/SuppressionShowMessage'), checked=self.suppressed, callback=self.OnSuppressChanged) def OnSuppressChanged(self, checkbox): self.suppressed = self.suppressCheckbox.GetValue() @classmethod def IsSuppressed(cls): return settings.user.suppress.Get(cls.SUPPRESS_KEY, False) @property def suppressed(self): return self.IsSuppressed() @suppressed.setter def suppressed(self, suppressed): if suppressed: settings.user.suppress.Set(self.SUPPRESS_KEY, suppressed) else: settings.user.suppress.Delete(self.SUPPRESS_KEY) sm.GetService('settings').SaveSettings() def ShouldDisplay(self): if self.suppressed: return False if sm.GetService('skillqueue').SkillInTraining() is not None: return False queues = sm.GetService( 'skillqueue').GetMultipleCharacterTraining().items() characterData = sm.GetService('cc').GetCharacterSelectionData() activeQueues = 1 + len(queues) usedQueues = 0 for characterDetails in characterData.details.values(): isTraining = characterDetails.GetSkillInTrainingInfo( )['currentSkill'] is not None if characterDetails.charID != session.charid and isTraining: usedQueues += 1 return usedQueues == activeQueues def Display(self): self.Load() self.Enable() self.AnimShow() def Load(self): self.UpdateEstimatedPrice() self.suppressCheckbox.SetValue(self.suppressed) def UpdateEstimatedPrice(self): try: tokenAveragePrice = GetAveragePrice(typeMultiTrainingToken) except KeyError: tokenAveragePrice = None if not tokenAveragePrice: text = localization.GetByLabel( 'UI/SkillQueue/MultiTrainingOverlay/EstimatedPriceUnknown') else: amount = RoundISK(tokenAveragePrice) text = localization.GetByLabel( 'UI/SkillQueue/MultiTrainingOverlay/EstimatedPrice', amount=amount) self.estimatePriceLabel.SetText(text) def Dismiss(self): self.Disable() self.AnimHide() def AnimShow(self): self.Show() animations.FadeTo(self, duration=0.4) if not self.compactMode: animations.FadeTo(self.characters, timeOffset=0.3) animations.FadeTo(self.content, timeOffset=0.3) def AnimHide(self): animations.FadeOut(self, duration=0.4) def EnterCompactMode(self): if self.compactMode: return self.compactMode = True animations.FadeOut(self.characters, duration=0.2) animations.MorphScalar(self.characters, 'left', startVal=self.characters.left, endVal=self.CHARACTERS_LEFT - 60, duration=0.3) animations.MorphScalar(self.content, 'left', startVal=self.content.left, endVal=0, duration=0.3) def ExitCompactMode(self): if not self.compactMode: return self.compactMode = False animations.FadeIn(self.characters, duration=0.2) animations.MorphScalar(self.characters, 'left', startVal=self.characters.left, endVal=self.CHARACTERS_LEFT, duration=0.3) animations.MorphScalar(self.content, 'left', startVal=self.content.left, endVal=self.CONTENT_LEFT, duration=0.3) def UpdateAlignment(self, budgetLeft=0, budgetTop=0, budgetWidth=0, budgetHeight=0, updateChildrenOnly=False): if budgetWidth < 640: self.EnterCompactMode() else: self.ExitCompactMode() return super(MultiTrainingOverlay, self).UpdateAlignment(budgetLeft, budgetTop, budgetWidth, budgetHeight, updateChildrenOnly)
class AutoBotWindow(Window): """ An Insider window which makes it easy to debug UI containers """ default_windowID = 'AutoBotWindow' default_width = 360 default_height = 300 default_topParentHeight = 0 default_minSize = (default_width, default_height) default_caption = 'AutoBot Control Box' def ApplyAttributes(self, attributes): Window.ApplyAttributes(self, attributes) self.CreateLocationSelector() self.CreateSecurityFilter() self.CreateShipSelector() self.CreatePasses() self.CreateButtons() self.CreateLogDisplay() def CreateButtons(self): buttonCont = FlowContainer(name='SubCategoryButtons', parent=self.sr.main, centerContent=True, align=uiconst.TOBOTTOM, contentSpacing=(2, 1), state=uiconst.UI_PICKCHILDREN, padding=(0, 4, 0, 4)) Button(parent=buttonCont, label='Roll out!!', func=self.StartBot, align=uiconst.NOALIGN, padding=2) Button(parent=buttonCont, label='Stop', func=self.StopBot, align=uiconst.NOALIGN, padding=2) Button(parent=buttonCont, label='Clear Log', func=self.ClearLogs, align=uiconst.NOALIGN, padding=2) def CreateLocationSelector(self): EveLabelSmall( parent=self.sr.main, text= '<color=orange>This is a tool for automating visits to solar systems and locations within them. There are several actions available while visiting each location.', align=uiconst.TOTOP, padding=4) EveLabelSmall(parent=self.sr.main, text='Systems, Constellations or Regions', align=uiconst.TOTOP, padding=4) self.locationsEdit = EditPlainText(parent=self.sr.main, align=uiconst.TOTOP, height=50, padding=4) def CreateSecurityFilter(self): secCont = Container(parent=self.sr.main, height=20, padding=2, align=uiconst.TOTOP) EveLabelSmall(parent=secCont, text='Security Band:', align=uiconst.TOLEFT, padding=4) EveLabelSmall(parent=secCont, text='Min Security', align=uiconst.TOLEFT, padding=4) self.minSecEdit = SinglelineEdit(parent=secCont, name='minSec', width=30, floats=(-1.0, 1.0, 1), align=uiconst.TOLEFT, padTop=-3, setvalue='-1.0') EveLabelSmall(parent=secCont, text='Max Security', align=uiconst.TOLEFT, padding=4) self.maxSecEdit = SinglelineEdit(parent=secCont, name='maxSec', width=30, floats=(-1.0, 1.0, 1), align=uiconst.TOLEFT, padTop=-3, setvalue='1.0') def CreateShipSelector(self): cont = Container(parent=self.sr.main, name='ship_options', align=uiconst.TOTOP, height=20) self.spawnShipCheckbox = Checkbox(parent=cont, align=uiconst.TOLEFT, text='Spawn new ship', checked=False, padLeft=8, callback=self.OnChangeSpawnShip, width=150) Container(parent=cont, width=16, align=uiconst.TOLEFT) EveLabelSmall(parent=cont, text='DNA', align=uiconst.TOLEFT, padding=4) self.dnaEdit = SinglelineEdit(parent=cont, setvalue='DNA:593:2528:20197', align=uiconst.TOLEFT, width=200) def CreatePasses(self): EveLabelSmall(parent=self.sr.main, text='Actions for each system visited', align=uiconst.TOTOP, padding=4) self.CreateSystemPass(1) self.CreateSystemPass(2) def CreateSystemPass(self, passNumber): def GetLocationsMenu(menuParent): passConfig = GetPassConfig()[passNumber] menuParent.AddHeader(text='Locations to visit') for groupId in (const.groupAsteroidBelt, const.groupStargate, const.groupStation): menuParent.AddCheckBox( text=cfg.invgroups.Get(groupId).groupName, checked=groupId in passConfig['locations'], callback=(ToggleLocationGroupForPass, passNumber, groupId)) menuParent.AddDivider() menuParent.AddHeader(text='Actions') menuParent.AddCheckBox(text='Nuke location', checked=passConfig['nuke'], callback=(ToggleNuke, passNumber)) passConfig = { 'locations': {const.groupAsteroidBelt}, 'nuke': False, 'enabled': passNumber == 1, 'minTime': 1 } GetPassConfig()[passNumber] = passConfig menuCont = Container(name='pass%d' % passNumber, parent=self.sr.main, align=uiconst.TOTOP, height=20, padLeft=4) cont = Container(parent=menuCont, width=100, align=uiconst.TOLEFT) Checkbox(parent=cont, text='Enable Pass %s' % passNumber, align=uiconst.CENTERLEFT, checked=passConfig['enabled'], callback=lambda checkbox: SetPass(checkbox, passNumber), width=200) cont = Container(parent=menuCont, width=100, align=uiconst.TOLEFT) EveLabelSmall(parent=cont, text='Min time (sec)', align=uiconst.CENTERRIGHT, left=4) SinglelineEdit( parent=menuCont, ints=(1, 999), OnChange=lambda textValue: SetPassMinTime(textValue, passNumber), setvalue=passConfig['minTime'], align=uiconst.TOLEFT, width=50) UtilMenu(menuAlign=uiconst.TOPRIGHT, parent=menuCont, align=uiconst.TOLEFT, GetUtilMenu=GetLocationsMenu, label='Options', texturePath='res:/UI/Texture/Icons/38_16_229.png', closeTexturePath='res:/UI/Texture/Icons/38_16_230.png') def CreateLogDisplay(self): self.logEdit = EditPlainText(parent=self.sr.main, align=uiconst.TOALL, readonly=True, padTop=4) def OnChangeSpawnShip(self, checkbox): if checkbox.GetValue(): self.dnaEdit.SetReadOnly(False) self.dnaEdit.opacity = 1.0 else: self.dnaEdit.SetReadOnly(True) self.dnaEdit.opacity = 0.5 def StartBot(self, *args): config = GetConfig() locations = SplitLocationsText(self.locationsEdit.GetValue()) config['locations'] = locations config['minSecurity'] = self.minSecEdit.GetValue() config['maxSecurity'] = self.maxSecEdit.GetValue() if self.spawnShipCheckbox.GetValue(): config['shipDna'] = self.dnaEdit.GetValue() else: config['shipDna'] = None sm.GetService('autobot').StartBot() self.logUpdated = AutoTimer(2000, self.UpdateLogText) def PauseBot(self, *args): sm.GetService('autobot').PauseBot() def StopBot(self, *args): sm.GetService('autobot').StopBot() self.logUpdated = None def ClearLogs(self, *args): sm.GetService('autobot').ClearLogs() def UpdateLogText(self): logLines = sm.GetService('autobot').logLines self.logEdit.SetValue('\n'.join([str(x) for x in reversed(logLines)]))
class ProbeTooltipCheckboxRow(ProbeTooltipButtonBase): deleteFunction = None editFunction = None def ApplyAttributes(self, attributes): ProbeTooltipButtonBase.ApplyAttributes(self, attributes) self.checkBox = Checkbox(groupname=attributes.groupName, align=uiconst.CENTER, checked=attributes.checked, retval=attributes.retval, wrapLabel=True, prefstype=None, width=16, height=16, state=uiconst.UI_DISABLED) self.AddCell(self.checkBox, cellPadding=(5, 1, 4, 1)) self.deleteFunction = attributes.deleteFunc self.editFunction = attributes.editFunc self.label = EveLabelSmall(text=attributes.text, bold=True, align=uiconst.CENTERLEFT, autoFitToText=True, width=128) self.AddCell(self.label, colSpan=1 if attributes.filterIndex is not None else 2, cellPadding=(0, 2, 6, 2)) if attributes.filterIndex is not None: shortcutObj = ShortcutHint(text=str(attributes.filterIndex)) self.AddCell(shortcutObj, cellPadding=(2, 2, 2, 0)) return shortcutObj def OnDelete(self, *args): if self.deleteFunction: self.state = uiconst.UI_DISABLED if callable(self.deleteFunction): self.deleteFunction() elif isinstance(self.deleteFunction, tuple): func, args = self.deleteFunction func(*args) uicore.animations.FadeOut(self, duration=0.5, callback=self.Close) def OnEdit(self, *args): if callable(self.editFunction): self.editFunction() elif isinstance(self.editFunction, tuple): func, args = self.editFunction func(*args) def OnClick(self, *args): self.checkBox.ToggleState() if self.func: self.func(self.checkBox.data['value'], self.checkBox.GetValue()) def GetMenu(self): m = [] if self.editFunction: m.append((localization.GetByLabel('UI/Inventory/Filters/Edit'), self.OnEdit)) if self.deleteFunction: m.append( (localization.GetByLabel('UI/Common/Delete'), self.OnDelete)) return m
class ChannelPasswordWindow(Window): MAX_TRIES = 3 def ApplyAttributes(self, attributes): Window.ApplyAttributes(self, attributes) self.title = attributes.title self.channelID = attributes.channelID self.channelName = attributes.channelName self.displayName = attributes.displayName self.SetMinSize([250, 250]) self.SetCaption(localization.GetByLabel('UI/Menusvc/PasswordRequired')) self.SetTopparentHeight(0) self.tries = 0 settings.user.ui.Set('%sPassword' % self.channelName, '') parentGrid = LayoutGrid(parent=self.sr.main, columns=1, state=uiconst.UI_PICKCHILDREN, align=uiconst.TOPLEFT, left=10, top=4) topLabel = EveLabelMedium(text=attributes.title, state=uiconst.UI_DISABLED, align=uiconst.TOPLEFT, width=300) parentGrid.AddCell(cellObject=topLabel) passwordLabel = localization.GetByLabel( 'UI/Menusvc/PleaseEnterPassword') self.passwordLabel = EveLabelMedium(text=passwordLabel, state=uiconst.UI_DISABLED, align=uiconst.TOPLEFT, padTop=10) parentGrid.AddCell(cellObject=self.passwordLabel) self.passwordEdit = SinglelineEdit(name='passwordEdit', align=uiconst.TOTOP, passwordCharacter=u'\u2022', top=4) parentGrid.AddCell(cellObject=self.passwordEdit) savePasswordLabel = localization.GetByLabel('UI/Chat/SavePassword') self.rememberPwdCb = Checkbox(text=savePasswordLabel, configName='rememberPwdCb', retval=1, checked=0, groupname=None, align=uiconst.TOTOP) parentGrid.AddCell(cellObject=self.rememberPwdCb) parentGrid.RefreshGridLayout() self.btnGroup = ButtonGroup(parent=self.sr.main, idx=0) self.btnGroup.AddButton( localization.GetByLabel('UI/Chat/ChannelWindow/JoinChannel'), self.TryPassword, ()) self.btnGroup.AddButton(localization.GetByLabel('UI/Common/Cancel'), self.Close, ()) self.height = self.btnGroup.height + parentGrid.height + self.sr.headerParent.height + parentGrid.top + 10 self.width = parentGrid.width + 2 * parentGrid.left self.MakeUnResizeable() self.MakeUnMinimizable() self.MakeUncollapseable() def TryPassword(self): password = self.passwordEdit.GetValue() password = password.strip() if len(password) < 1: eve.Message('CustomInfo', { 'info': localization.GetByLabel('UI/Common/PleaseTypeSomething') }) return self.tries += 1 savePassword = self.rememberPwdCb.GetValue() didWork = sm.GetService('LSC').TryOpenChannel(self.channelID, self.channelName, password, savePassword) if didWork is True: self.Close() return self.passwordEdit.SetValue('') uicore.Message('uiwarning03') self.passwordLabel.text = localization.GetByLabel( 'UI/Menusvc/PleaseTryEnteringPasswordAgain') if self.tries >= self.MAX_TRIES: if didWork is False and password is not None: sm.GetService('LSC').OpenChannel( self.channelID, 0, ('LSCWrongPassword', { 'channelName': self.displayName })) self.Close()
class PerformanceBenchmarkWindow(Window): default_caption = 'Performance Tools' default_windowID = 'PerformanceToolsWindowID' default_width = 220 default_height = 200 default_topParentHeight = 0 default_minSize = (default_width, default_height) default_wontUseThis = 10 def ApplyAttributes(self, attributes): Window.ApplyAttributes(self, attributes) self.lastPitch = 0.0 self.lastYaw = 0.0 self.camLock = False self.benchmarkDuration = BENCHMARK_DEFAULT_DURATION_IN_MS self.benchmarkRunning = False self.sceneDirector = SceneDirector() self.testOptions = [('classic cube of death', CUBE_CLASSIC), ('capital wrecks of death', CUBE_CAPITAL_WRECKS), ('AmarrCube', CUBE_AMARR), ('CaldariCube', CUBE_CALDARI), ('GallenteCube', CUBE_GALLENTE), ('MinmatarCube', CUBE_MINMATAR), ('UltraLODCube', CUBE_LOD), ('Add More Here', CUBE_ADD_MORE_HERE)] self.testCaseDescription = { CUBE_CLASSIC: 'Spawns a cube with a lot of different ships.', CUBE_CAPITAL_WRECKS: 'Spawns a cube with a lot of wrecks.', CUBE_AMARR: 'Spawns a cube of Amarr ships.', CUBE_CALDARI: 'Spawns a cube of Caldari ships.', CUBE_GALLENTE: 'Spawns a cube of Gallente ships.', CUBE_MINMATAR: 'Spawns a cube of Minmatar ships.', CUBE_LOD: 'Spawns a cube of ships around the camera.', CUBE_ADD_MORE_HERE: 'Does nothing useful.' } self.camPresetOptions = [('None', CAMERA_PRESET_NONE), ('Deathcube Far', CAMERA_PRESET_FAR), ('Deathcube Near', CAMERA_PRESET_NEAR), ('Deathcube UltraLOD', CAMERA_PRESET_ULTRA_LOD)] self._AddHeader('Test Cases') self._SetupTestCasePanel(self.sr.main) self._AddHeader('Camera') self._SetupCameraPanel(self.sr.main) self._AddHeader('Duration') self._SetupDurationPanel(self.sr.main) self.benchmarkButton = Button(name='myButton', parent=self.sr.main, align=uiconst.CENTERBOTTOM, label='Start Benchmark', func=self.ToggleBenchmark, width=40, padding=(0, 0, 0, 6)) def _AddHeader(self, text): EveHeaderSmall(parent=self.sr.main, text=text, align=uiconst.TOTOP, padding=(8, 6, 0, 3)) def _SetupTestCasePanel(self, mainCont): cont = Container(name='cont', parent=mainCont, align=uiconst.TOTOP, padLeft=4, padRight=4, height=40) self.testCombo = Combo(parent=cont, align=uiconst.TOTOP, options=self.testOptions, callback=self.TestComboChanged) self.testCombo.SetHint(self.testCaseDescription[1]) buttonBox = Container(name='buttonBox', parent=cont, align=uiconst.TOTOP, padTop=3, height=20) self.stayHereCheckbox = Checkbox(parent=buttonBox, text=u'Stay where you are', align=uiconst.TOLEFT, checked=False, height=18, width=120) Button(parent=buttonBox, label='Spawn', align=uiconst.TORIGHT, func=self.SpawnTestcase, width=40, height=18) Button(parent=buttonBox, label='Clear', align=uiconst.TORIGHT, func=self.sceneDirector.ClearAll, width=40, height=18) Button(parent=buttonBox, label='Damage', align=uiconst.TORIGHT, func=self.sceneDirector.ApplyDamage, width=40, height=18, hint='Wait for ships to load before calling this') def _SetupCameraPanel(self, mainCont): presetCont = Container(name='presetCont', parent=mainCont, align=uiconst.TOTOP, height=20, padLeft=4, padRight=4) Label(name='presetCombo', parent=presetCont, align=uiconst.TOLEFT, width=40, text='Preset') self.cboCamPresets = Combo(parent=presetCont, align=uiconst.TOTOP, options=self.camPresetOptions, callback=self.OnCamPreset) pitchCont = Container(name='pitchCont', parent=mainCont, align=uiconst.TOTOP, height=20, padLeft=4, padRight=4) Label(name='pitchLabel', parent=pitchCont, align=uiconst.TOLEFT, width=40, padTop=3, text='Pitch') self.pitchField = SinglelineEdit(name='pitchField', parent=pitchCont, align=uiconst.TOTOP, floats=[-90.0, 90.0, 1], setvalue=str(self.lastPitch)) self.pitchField.OnChange = self.OnCamChange yawCont = Container(name='yawCont', parent=mainCont, align=uiconst.TOTOP, height=20, padLeft=4, padRight=4) Label(name='yawLabel', parent=yawCont, align=uiconst.TOLEFT, width=40, padTop=3, text='Yaw') self.yawField = SinglelineEdit(name='yawField', parent=yawCont, align=uiconst.TOTOP, floats=[-180.0, 180.0, 1], setvalue=str(self.lastYaw)) self.yawField.OnChange = self.OnCamChange panCont = Container(name='panCont', parent=mainCont, align=uiconst.TOTOP, height=20, padLeft=4, padRight=4) Label(name='panLabel', parent=panCont, align=uiconst.TOLEFT, width=40, padTop=3, text='Pan') self.panField = SinglelineEdit( name='panField', parent=panCont, align=uiconst.TOTOP, ints=[MIN_PAN_DISTANCE, MAX_PAN_DISTANCE], setvalue=0) self.panField.OnChange = self.OnCamChange buttonBox = Container(name='buttonBox', parent=mainCont, align=uiconst.TOTOP, padTop=3, height=20) Button( parent=buttonBox, label='Capture camera coords', align=uiconst.TORIGHT, func=self.OnStoreCurrentCameraValues, width=40, height=18, hint= 'Captures the current camera coordinates and saves them in the input fields' ) uthread.new(self._GetCurrentCameraValues) def _SetupDurationPanel(self, parent): maxSeconds = int(BENCHMARK_MAX_DURATION_IN_MS / 1000) defaultSeconds = int(BENCHMARK_DEFAULT_DURATION_IN_MS / 1000) self.durationSlider = Slider( name='mySlider', parent=parent, minValue=1, maxValue=maxSeconds, startVal=defaultSeconds, increments=[i + 1 for i in xrange(maxSeconds)], onsetvaluefunc=self._OnTimeChanged, align=uiconst.TOTOP, padLeft=10, padRight=10) self.progress = Gauge(name='progress', parent=parent, color=Color.WHITE, align=uiconst.TOTOP, padTop=20, padLeft=10, padRight=10) self._OnTimeChanged(self.durationSlider) def _OnTimeChanged(self, slider): self.benchmarkDuration = slider.GetValue() * 1000 def TestComboChanged(self, *args): self.testCombo.SetHint( self.testCaseDescription[self.testCombo.GetValue()]) def OnCamChange(self, *args): if self.camLock: return self.lastPitch = float(self.pitchField.GetValue()) self.lastYaw = float(self.yawField.GetValue()) self.pan = int(self.panField.GetValue()) self.sceneDirector.SetCamera(self.lastYaw, self.lastPitch, self.pan) def OnCamPreset(self, *args): presId = self.cboCamPresets.GetValue() if presId == 0: return pitch, yaw, pan = CAMERA_PRESETS[presId] self.camLock = True self.pitchField.SetValue(pitch) self.yawField.SetValue(yaw) self.panField.SetValue(pan) self.camLock = False self.OnCamChange() def _GetMemoryUsage(self): try: meg = 1.0 / 1024.0 / 1024.0 mem, pymem, workingset, pagefaults, bluemem = blue.pyos.cpuUsage[ -1][2] return mem * meg except: pass return 0 def ToggleBenchmark(self, *args): self.progress.SetValue(0) def _thread(): frameTimes = [] graphData = {} t0 = blue.os.GetWallclockTime() startTime = blue.os.GetWallclockTime() startMem = self._GetMemoryUsage() while self.benchmarkRunning: blue.synchro.Yield() t1 = blue.os.GetWallclockTime() ms = float(blue.os.TimeDiffInUs(t0, t1)) / 1000.0 t0 = t1 frameTimes.append(ms) timeFromStartInMs = float(blue.os.TimeDiffInUs(startTime, t1)) / 1000.0 graphData[timeFromStartInMs] = ms if blue.os.TimeDiffInMs(startTime, t1) > self.benchmarkDuration: self.benchmarkRunning = False break self.progress.SetValue(timeFromStartInMs / self.benchmarkDuration, animate=False) frameTimes.sort() median = frameTimes[len(frameTimes) / 2] minMS = frameTimes[0] maxMS = frameTimes[-1] summed = reduce(lambda x, y: x + y, frameTimes) avg = summed / len(frameTimes) result = 'Min: %0.1fms Max: %0.1fms\n' % (minMS, maxMS) result += 'Median: %0.1fms %0.1ffps\n' % (median, 1000.0 / median) result += 'Average: %0.1fms %0.1ffps\n' % (avg, 1000.0 / avg) endMem = self._GetMemoryUsage() result += 'Start Memory Usage: %0.1fmb\n' % (startMem, ) result += 'End Memory Usage: %0.1fmb\n' % (endMem, ) ResultDialog.Open(resultText=result, graphData=graphData) self.benchmarkButton.SetLabel('Start Benchmark') if self.benchmarkRunning: self.benchmarkRunning = False else: self.benchmarkRunning = True self.benchmarkButton.SetLabel('Stop Benchmark') uthread.new(_thread) def OnStoreCurrentCameraValues(self, *args): self._GetCurrentCameraValues() def _GetCurrentCameraValues(self): self.camLock = True cam = sm.GetService('sceneManager').GetActiveCamera() self.lastPitch = math.degrees(cam.pitch) self.lastYaw = math.degrees(cam.yaw) self.pan = pan = ClampPan(int(cam.GetZoomDistance())) self.pitchField.SetValue(self.lastPitch) self.yawField.SetValue(self.lastYaw) self.panField.SetValue(self.pan) self.camLock = False self.OnCamChange() def SpawnTestcase(self, *args): testID = self.testCombo.GetValue() stayHere = self.stayHereCheckbox.GetValue() startPos = self.sceneDirector.GoToAndReturnStartPosition(stayHere) self.sceneDirector.SpawnTestcase(testID, startPos)