colonyTemplateWindow.py (33227B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\planet\colonyTemplateWindow.py 2 import blue 3 import base64 4 import eve.client.script.ui.shared.planet.planetUtil as planetUtil 5 import eveformat 6 import eveicon 7 import inventorycommon.const as invConst 8 import json 9 import logging 10 import os 11 import uthread2 12 from bannedwords.client import bannedwords 13 from carbonui import uiconst, TextColor, Align, PickState, IdealSize 14 from carbonui.text.styles import TextHeader, TextBody, TextDetail 15 from carbonui.button.menu import MenuButtonIcon, MenuButton 16 from carbonui.control.button import Button 17 from carbonui.control.buttonIcon import ButtonIcon 18 from carbonui.control.contextMenu.menuData import MenuData 19 from carbonui.control.dragdrop.dragdata import BaseDragData 20 from carbonui.control.scrollContainer import ScrollContainer 21 from carbonui.control.window import Window 22 from carbonui.primitives.container import Container 23 from carbonui.primitives.containerAutoSize import ContainerAutoSize 24 from carbonui.primitives.fill import Fill 25 from carbonui.primitives.flowcontainer import FlowContainer 26 from carbonui.primitives.layoutGrid import LayoutGrid 27 from carbonui.primitives.sprite import Sprite 28 from carbonui.uianimations import animations 29 from carbonui.uicore import uicore 30 from carbonui.util.color import Color 31 from clientsettings.setting import UserSettingString 32 from eve.client.script.ui import eveColor 33 from eve.client.script.ui.control.eveLabel import Label 34 from eve.client.script.ui.inflight.overview.overviewScrollEntry import get_distance_in_kilometers 35 from eve.client.script.ui.quickFilter import QuickFilterEdit 36 from eve.client.script.ui.shared.planet import planetConst 37 from eve.client.script.ui.shared.planet.colonyTemplate import ColonyTemplate 38 from eve.client.script.ui.shared.planet.colonyTemplateFilters import SETTING_KEY_CMD_CNTR, SETTING_KEY_EXTRACT_TYPE, SETTING_KEY_PROCESSED, SETTING_KEY_REFINED, SETTING_KEY_SPECIALIZED, SETTING_KEY_ADVANCED, SETTING_KEY_PLANET_TYPE, GetValidTemplates, CMD_CTR_LELVES 39 from eve.client.script.ui.shared.planet.colonyTemplateLoading import PreviewLoad 40 from eve.client.script.ui.shared.planet.pinContainers.storageIcon import StorageIcon 41 from eve.client.script.ui.shared.planet.planetCommon import GetTierByTypeID 42 from eve.client.script.ui.shared.planet.planetConst import * 43 from eve.client.script.ui.shared.planet.templateSavingUtil import ConfirmExportWnd, GetDefaultStoragePath, SaveToLocalFile 44 from eve.common.script.util.planetCommon import RADIUS_DRILLAREAMIN, RADIUS_DRILLAREAMAX 45 from eveplanet.client.templates.templateConst import * 46 from localization import GetByLabel 47 from player_messaging.client.ui_message import message_player, prompt_player_fsd_dialog 48 COMMENT_MAX_WIDTH = 60 49 DEFAULT_DRILL_RADIUS = (RADIUS_DRILLAREAMIN + RADIUS_DRILLAREAMAX) / 2.0 50 51 class ColonyTemplateWindow(Window): 52 default_height = IdealSize.SIZE_480 53 default_width = IdealSize.SIZE_480 54 default_minSize = (350, IdealSize.SIZE_240) 55 default_caption = GetByLabel('UI/PI/PITemplates') 56 default_windowID = u'ColonyTemplateWindow' 57 default_analyticID = 'pi_template_window' 58 __notifyevents__ = ['OnPITemplatesUpdated', 'OnTemplateDeleted'] 59 60 def ApplyAttributes(self, attributes): 61 super(ColonyTemplateWindow, self).ApplyAttributes(attributes) 62 self.clipChildren = True 63 self._loadingTemplates = False 64 self._blockTemplateLoading = False 65 self._templateLoadingPending = False 66 self.planetEditModeContainer = attributes.get('target') 67 self.ConstructUI() 68 self.AsyncLoadTemplatesFromLocal() 69 sm.RegisterNotify(self) 70 71 def ConstructUI(self): 72 self.ConstructTextFilter() 73 bottomRightCont = Container(name='bottomRightcont', parent=self.content, align=uiconst.TOBOTTOM, height=24, clipChildren=True) 74 self.numTemplatesLabel = TextBody(name='numTemplatesLabel', parent=bottomRightCont, align=uiconst.CENTERLEFT, color=TextColor.SECONDARY, bold=True) 75 self.scroll = ScrollContainer(parent=self.content, align=uiconst.TOALL, top=16) 76 77 def ConstructTextFilter(self): 78 self.textFilterSetting = UserSettingString('PI_template_text_filter', '') 79 filterCont = ContainerAutoSize(name='filterCont', parent=self.content, align=Align.TOTOP, alignMode=Align.TOTOP) 80 mb = MenuButton(parent=filterCont, hint=GetByLabel('UI/Fitting/FittingWindow/ImportAndExport'), texturePath=eveicon.export, get_menu_func=self._get_import_export_menu) 81 mbi = MenuButtonIcon(parent=filterCont, align=uiconst.CENTERLEFT, left=mb.left + mb.width + 8, widht=24, height=24, texturePath=eveicon.filter, iconSize=16, get_menu_func=self._GetMenuMoreOptions) 82 self.filterEdit = QuickFilterEdit(name='searchField', parent=filterCont, hintText=GetByLabel('UI/Inventory/Filter'), maxLength=64, align=uiconst.TOTOP, OnClearFilter=self.OnFilterEditCleared, padLeft=mbi.left + mbi.width + 8, setvalue=self.textFilterSetting.get()) 83 self.filterEdit.ReloadFunction = self.OnFilterEdit 84 85 def OnFilterEdit(self): 86 self.RecordTextFieldChanges() 87 88 def OnFilterEditCleared(self): 89 self._RecordTextFieldChanges() 90 91 @uthread2.debounce(0.5) 92 def RecordTextFieldChanges(self): 93 self._RecordTextFieldChanges() 94 95 def _RecordTextFieldChanges(self): 96 filterText = self.filterEdit.GetValue().strip().lower() 97 self.textFilterSetting.set(filterText) 98 self.AsyncLoadTemplatesFromLocal() 99 100 def OnPITemplatesUpdated(self): 101 self.AsyncLoadTemplatesFromLocal() 102 103 def AsyncLoadTemplatesFromLocalForFilters(self, *args): 104 if self._blockTemplateLoading: 105 return 106 if self._loadingTemplates: 107 self._templateLoadingPending = True 108 return 109 uthread2.start_tasklet(self.InvokeLoadTemplatesFromLocal) 110 111 def AsyncLoadTemplatesFromLocal(self, *args): 112 if self._loadingTemplates: 113 self._templateLoadingPending = True 114 return 115 uthread2.start_tasklet(self.InvokeLoadTemplatesFromLocal) 116 117 def InvokeLoadTemplatesFromLocal(self): 118 if self.destroyed: 119 return 120 if self._loadingTemplates: 121 self._templateLoadingPending = True 122 return 123 self._templateLoadingPending = False 124 self._loadingTemplates = True 125 try: 126 self.scroll.Flush() 127 templatesToLoad, numTotalTemplates = self._GetValidTemplatesAndTotalNum() 128 self.UpdateFilteredText(len(templatesToLoad), numTotalTemplates) 129 timeOffsetValue = 0.1 130 for i, temp in enumerate(templatesToLoad): 131 try: 132 templateEntry = ColonyTemplateEntry(parent=self.scroll, colonyTemplate=temp, height=135, align=uiconst.TOTOP, target=self.planetEditModeContainer, fileName=temp.filename) 133 except: 134 logging.error(u'File {0} cannot be interpreted'.format(temp.filename)) 135 continue 136 137 uicore.animations.FadeTo(templateEntry, 0, 1.0, duration=0.65, timeOffset=i * timeOffsetValue) 138 139 finally: 140 self._loadingTemplates = False 141 if self._templateLoadingPending: 142 self.AsyncLoadTemplatesFromLocal() 143 144 def _GetValidTemplatesAndTotalNum(self): 145 allTemplates = self._LoadFromLocal() 146 currentPlanet = sm.GetService('planetUI').GetCurrentPlanet() 147 currentPlanetRadius = currentPlanet.GetPlanetRadius() / 1000 if currentPlanet else None 148 filterText = self.filterEdit.GetValue().strip().lower() 149 validTemplates = GetValidTemplates(allTemplates, currentPlanetRadius, filterText) 150 return (validTemplates, len(allTemplates)) 151 152 def UpdateFilteredText(self, numValidTemplates, numTotalTemplates): 153 numFilteredout = max(0, numTotalTemplates - numValidTemplates) 154 if numValidTemplates < 1: 155 if self.planetEditModeContainer: 156 if numFilteredout: 157 notFoundText = GetByLabel('UI/PI/NoTemplatesFoundWithFilter', numFilteredOut=numFilteredout) 158 else: 159 notFoundText = GetByLabel('UI/PI/NoTemplatesFoundInPiView') 160 else: 161 notFoundText = GetByLabel('UI/PI/NoTemplatesFound') 162 self.scroll.ShowNoContentHint(notFoundText) 163 if numFilteredout > 0: 164 filtered_text = GetByLabel('UI/Inventory/NumFiltered', numFiltered=numFilteredout) 165 else: 166 filtered_text = '' 167 text = GetByLabel('UI/PI/NumTemplates', numTemplates=numValidTemplates, numFilteredTxt=filtered_text) 168 if numFilteredout > 0: 169 text = eveformat.color(text, eveColor.SUCCESS_GREEN) 170 self.numTemplatesLabel.text = text 171 172 def OnTemplateDeleted(self): 173 templatesToLoad, numTotalTemplates = self._GetValidTemplatesAndTotalNum() 174 self.UpdateFilteredText(len(templatesToLoad), numTotalTemplates) 175 176 def _GetMenuMoreOptions(self, *args): 177 menu = MenuData() 178 cmdCenterLV = self.CreateListOfSelectionsOfMenuData(CMD_CTR_LELVES, SETTING_KEY_CMD_CNTR) 179 planetTypesToShow = self.CreateListOfSelectionsOfMenuData(PlanetTypes.itervalues(), SETTING_KEY_PLANET_TYPE, True) 180 extractTypesToShow = self.CreateListOfSelectionsOfMenuData(ExtractionTypes.itervalues(), SETTING_KEY_EXTRACT_TYPE, True) 181 processedTypesToShow = self.CreateListOfSelectionsOfMenuData(ProcessedTypes.itervalues(), SETTING_KEY_PROCESSED, True) 182 refinedTypesToShow = self.CreateListOfSelectionsOfMenuData(RefinedTypes.itervalues(), SETTING_KEY_REFINED, True) 183 specializedTypesToShow = self.CreateListOfSelectionsOfMenuData(SpecializedTypes.itervalues(), SETTING_KEY_SPECIALIZED, True) 184 advancedTypesToShow = self.CreateListOfSelectionsOfMenuData(AdvancedTypes.itervalues(), SETTING_KEY_ADVANCED, True) 185 menu.AddEntry(text=GetByLabel('UI/PI/CmdCtrLV'), subMenuData=cmdCenterLV) 186 menu.AddEntry(text=GetByLabel('UI/PI/PlanetTypes'), subMenuData=planetTypesToShow) 187 menu.AddEntry(text=evetypes.GetCategoryNameByCategory(invConst.categoryPlanetaryResources), subMenuData=extractTypesToShow) 188 menu.AddSeparator() 189 menu.AddEntry(text=localization.GetByMessageID(evetypes.GetGroupNameIDByGroup(invConst.groupBasicCommodities)), subMenuData=processedTypesToShow) 190 menu.AddEntry(text=localization.GetByMessageID(evetypes.GetGroupNameIDByGroup(invConst.groupRefinedCommodities)), subMenuData=refinedTypesToShow) 191 menu.AddEntry(text=localization.GetByMessageID(evetypes.GetGroupNameIDByGroup(invConst.groupSpecializedCommodities)), subMenuData=specializedTypesToShow) 192 menu.AddEntry(text=localization.GetByMessageID(evetypes.GetGroupNameIDByGroup(invConst.groupAdvancedCommodities)), subMenuData=advancedTypesToShow) 193 menu.AddSeparator() 194 currentPlanet = sm.GetService('planetUI').GetCurrentPlanet() 195 if currentPlanet: 196 menu.AddCheckbox(text=GetByLabel('UI/PI/HideInapprop'), setting=SettingsHideInappropriateRadius) 197 SettingsHideInappropriateRadius.on_change.connect(self.AsyncLoadTemplatesFromLocal) 198 menu.AddEntry(text=GetByLabel('UI/Commands/Refresh'), func=self.InvokeLoadTemplatesFromLocal) 199 return menu 200 201 def CreateListOfSelectionsOfMenuData(self, iterable, settingString, isInputTypeID = False): 202 menuDataInstance = MenuData() 203 checkBoxes = [] 204 sortedValues = sorted(iterable, key=lambda x: (localization.GetByMessageID(evetypes.GetNameID(x)) if isInputTypeID else unicode(x))) 205 for value in sortedValues: 206 settingBool = UserSettingBool(settings_key=settingString.format(str(value)), default_value=False) 207 settingBool.on_change.connect(self.AsyncLoadTemplatesFromLocalForFilters) 208 label = localization.GetByMessageID(evetypes.GetNameID(value)) if isInputTypeID else unicode(value) 209 newChkBox = menuDataInstance.AddCheckbox(text=label, setting=settingBool) 210 checkBoxes.append(newChkBox) 211 212 def DoAll(action): 213 self._blockTemplateLoading = True 214 for ckbox in checkBoxes: 215 ckbox.setting.set(action) 216 217 self._blockTemplateLoading = False 218 self.AsyncLoadTemplatesFromLocal() 219 220 menuDataInstance.AddEntry(text=GetByLabel('UI/Common/DeselectAll'), func=lambda : DoAll(False)) 221 menuDataInstance.AddEntry(text=GetByLabel('UI/Common/SelectAll'), func=lambda : DoAll(True)) 222 return menuDataInstance 223 224 def LoadFromClipboard(self, *args): 225 warnResult = prompt_player_fsd_dialog('CustomWarning', {'header': GetByLabel('UI/Generic/Warning'), 226 'warning': GetByLabel('UI/PI/LoadWarning')}, buttons=uiconst.OKCANCEL) 227 if warnResult != uiconst.ID_OK: 228 return 229 newJSON = blue.clipboard.GetClipboardUnicode() 230 if newJSON is None: 231 return 232 if len(newJSON) > 65536: 233 warnResult = prompt_player_fsd_dialog('CustomWarning', {'header': GetByLabel('UI/Generic/Warning'), 234 'warning': GetByLabel('UI/PI/TemplateTooLong')}, buttons=uiconst.OKCANCEL) 235 if warnResult != uiconst.ID_OK: 236 return 237 try: 238 newTemplate = ColonyTemplate(unicode(newJSON), None) 239 PreviewLoad(newTemplate) 240 except UserError as e: 241 raise 242 except Exception as e: 243 logging.exception('PI Templates: Error while saving file') 244 prompt_player_fsd_dialog('CustomError', {'error': GetByLabel('UI/PI/ErrorLoadingFromClipboard')}) 245 246 def SaveFromClipboard(self, *args): 247 newJSON = blue.clipboard.GetClipboardUnicode() 248 SaveToLocalFile(newJSON, encoding='unicode-escape') 249 250 def SaveFromLink(self, url): 251 newJSON = url 252 warnResult = prompt_player_fsd_dialog('CustomWarning', {'header': GetByLabel('UI/Generic/Warning'), 253 'warning': GetByLabel('UI/PI/LoadWarning')}, buttons=uiconst.OKCANCEL) 254 if warnResult != uiconst.ID_OK: 255 return 256 if len(newJSON) > 65536: 257 warnResult = prompt_player_fsd_dialog('CustomWarning', {'header': GetByLabel('UI/Generic/Warning'), 258 'warning': GetByLabel('UI/PI/TemplateTooLong')}, buttons=uiconst.OKCANCEL) 259 if warnResult != uiconst.ID_OK: 260 return 261 SaveToLocalFile(newJSON) 262 263 def _LoadFromLocal(self): 264 files = [] 265 defaultStoragePath = GetDefaultStoragePath() 266 if not os.path.exists(defaultStoragePath): 267 try: 268 os.makedirs(defaultStoragePath) 269 files = os.listdir(defaultStoragePath) 270 except: 271 message_player(GetByLabel('UI/PI/FailedOnCreatingDirectory', path=defaultStoragePath)) 272 273 try: 274 files = os.listdir(defaultStoragePath) 275 except: 276 try: 277 os.makedirs(defaultStoragePath) 278 files = os.listdir(defaultStoragePath) 279 except: 280 message_player(GetByLabel('UI/PI/FailedOnCreatingDirectory', path=defaultStoragePath)) 281 282 templates = [] 283 for singleTemp in files: 284 try: 285 with open(os.path.join(defaultStoragePath, singleTemp)) as tempStream: 286 templates.append(ColonyTemplate(tempStream.read(), singleTemp)) 287 except Exception as e: 288 pass 289 290 templates = sorted(templates, key=lambda x: x.description.lower()) 291 return templates 292 293 def _get_import_export_menu(self): 294 m = MenuData() 295 if self.planetEditModeContainer is not None: 296 m.AddEntry(text=GetByLabel('UI/PI/LoadFromClipboard'), func=self.LoadFromClipboard) 297 m.AddEntry(text=GetByLabel('UI/PI/SaveFromClipboard'), func=self.SaveFromClipboard) 298 m.AddSeparator() 299 if self.planetEditModeContainer and self.planetEditModeContainer.IsCommandCenterPresent(): 300 m.AddEntry(text=GetByLabel('UI/PI/ExportToClipboard'), func=lambda *args: self.planetEditModeContainer.CopyTemplateToClipboard()) 301 m.AddEntry(text=GetByLabel('UI/PI/ExportToFileLong'), func=lambda *args: self.planetEditModeContainer.SaveTemplateToFile()) 302 return m 303 304 305 class ColonyTemplateEntry(ContainerAutoSize): 306 isDragObject = True 307 default_state = uiconst.UI_NORMAL 308 default_bgColor = (0, 0, 0, 0.6) 309 default_clipChildren = True 310 default_padding = (0, 0, 0, 8) 311 default_minHeight = 60 312 default_alignMode = Align.TOTOP 313 314 def ApplyAttributes(self, attributes): 315 super(type(self), self).ApplyAttributes(attributes) 316 self.colonyTemplate = attributes.get('colonyTemplate') 317 self.fileName = attributes.get('fileName') 318 self.storagePath = GetDefaultStoragePath() 319 self.planetEditModeContainer = attributes.get('target') 320 self.ConstructFrameAndBackground() 321 self.innerCont = ContainerAutoSize(name='innerCont', parent=self, padding=16, align=Align.TOTOP) 322 self.ConstructFirstRow() 323 self.ConstructComment() 324 self.ConstructSecondRow() 325 326 def ConstructFrameAndBackground(self): 327 texturePath = planetUtil.backgroundTexturePath.get(self.colonyTemplate.originalPlanetType) 328 bgPlanetSprite = Sprite(parent=self, texturePath=texturePath, align=uiconst.TOPRIGHT, state=uiconst.UI_DISABLED, opacity=0.2, pos=(0, 0, 1138, 411)) 329 330 def AddLoadBtn(self, cont): 331 btnCont = ContainerAutoSize(parent=cont, align=Align.TORIGHT) 332 if self.planetEditModeContainer: 333 plnet = sm.GetService('planetUI').GetCurrentPlanet() 334 if plnet is not None and self.colonyTemplate.restricted and plnet.planetTypeID not in [PlanetTypes.BARREN, PlanetTypes.TEMPERATE]: 335 btn = Button(parent=btnCont, label=GetByLabel('UI/Generic/NotAvailableShort'), enabled=False, align=Align.BOTTOMRIGHT) 336 else: 337 btn = Button(parent=btnCont, label=GetByLabel('UI/Generic/Load'), func=self.PreviewLoad, align=Align.BOTTOMRIGHT) 338 cont.minHeight = max(cont.minHeight, btn.height) 339 340 def DeleteTemplate(self, *args): 341 fileName = self.fileName 342 fullpath = u'{0}'.format(os.path.join(self.storagePath, fileName)) 343 templateName = self.colonyTemplate.description 344 result = prompt_player_fsd_dialog('DeletePITemplate', {'templateName': templateName}, modal=True, buttons=uiconst.YESNO) 345 if result != uiconst.ID_YES: 346 return 347 try: 348 os.remove(fullpath) 349 self.Disable() 350 sm.ScatterEvent('OnTemplateDeleted') 351 animations.FadeOut(self, duration=0.5, sleep=True) 352 self.Close() 353 except Exception as e: 354 raise 355 356 def CopyTemplate(self, *args): 357 self.CopyToClipboard() 358 359 def ConstructComment(self): 360 cont = ContainerAutoSize(name='commentCont', parent=self.innerCont, align=Align.TOTOP, alignMode=Align.TOTOP, top=16) 361 btnCont = Container(parent=cont, align=Align.TORIGHT, width=50) 362 ButtonIcon(parent=btnCont, texturePath=eveicon.trashcan, pos=(0, 0, 16, 16), align=uiconst.TOPRIGHT, func=self.DeleteTemplate, hint=GetByLabel('UI/Common/Buttons/Delete')) 363 ButtonIcon(parent=btnCont, texturePath=eveicon.copy, pos=(32, 0, 16, 16), align=uiconst.TOPRIGHT, func=self.CopyTemplate, hint=GetByLabel('UI/PI/CopyPlainText')) 364 comment = self.colonyTemplate.description 365 commentLabel = TextHeader(name='commentLabel', parent=cont, text=comment if len(comment) < COMMENT_MAX_WIDTH else u'{0}...'.format(comment[:COMMENT_MAX_WIDTH]), align=Align.TOTOP, state=uiconst.UI_NORMAL, bold=True) 366 commentLabel.hint = comment 367 commentLabel.isDragObject = True 368 commentLabel.Draggable_blockDrag = False 369 commentLabel.GetDragData = self.GetDragData 370 commentLabel.PrepareDrag = self.PrepareDrag 371 commentLabel.GetMenu = self.GetMenu 372 373 def ConstructSecondRow(self): 374 cont = ContainerAutoSize(name='secondRow', parent=self.innerCont, align=Align.TOTOP, height=30, alignMode=Align.TOTOP, top=16) 375 self.AddLoadBtn(cont) 376 if len(self.colonyTemplate.extractTypes) > 0: 377 additionalText = '' 378 textColor = TextColor.SECONDARY 379 if self.planetEditModeContainer is not None: 380 plnet = sm.GetService('planetUI').GetCurrentPlanet() 381 if plnet is not None and self.colonyTemplate.originalPlanetType != plnet.planetTypeID: 382 textColor = Color.YELLOW 383 additionalText = GetByLabel('UI/PI/MightNotSuitable') 384 exctItemAmount = self._GetAllProducts(self.colonyTemplate.extractSourceCount) 385 text = TextDetail(parent=cont, text=GetByLabel('UI/PI/Common/Extraction'), align=Align.TOTOP, color=textColor, pickState=PickState.ON) 386 text.hint = additionalText 387 iconCont = FlowContainer(parent=cont, align=Align.TOTOP, top=4, contentSpacing=(8, 8)) 388 sortedExtractTypes = sorted(exctItemAmount.keys(), key=lambda x: (GetTierByTypeID(x), evetypes.GetName(x))) 389 for typeID in sortedExtractTypes: 390 c = Container(parent=iconCont, align=uiconst.TOPLEFT, color=(0, 0, 0, 1.4), pos=(0, 0, 32, 32)) 391 icon = StorageIcon(parent=c, align=uiconst.TOPLEFT, width=self.height, typeID=typeID, pos=(0, 0, 32, 32)) 392 Fill(parent=c, color=(0, 0, 0, 0.2)) 393 394 if len(self.colonyTemplate.productTypes) > 0: 395 top = 8 if self.colonyTemplate.extractTypes else 0 396 text = TextDetail(parent=cont, text=GetByLabel('UI/PI/Common/Production'), align=Align.TOTOP, color=TextColor.SECONDARY, top=top) 397 pdItemAmount = self._GetAllProducts(self.colonyTemplate.productSourceCount) 398 iconCont = FlowContainer(parent=cont, align=Align.TOTOP, top=4, contentSpacing=(8, 8)) 399 sortedProducts = sorted(pdItemAmount.keys(), key=lambda x: (GetTierByTypeID(x), evetypes.GetName(x))) 400 for typeID in sortedProducts: 401 c = Container(parent=iconCont, align=uiconst.TOPLEFT, color=(0, 0, 0, 1.4), pos=(0, 0, 32, 32)) 402 icon = StorageIcon(parent=c, align=uiconst.TOPLEFT, width=self.height, typeID=typeID, pos=(0, 0, 32, 32)) 403 Fill(parent=c, color=(0, 0, 0, 0.2)) 404 405 def ConstructFirstRow(self): 406 labelOffset = 2 407 grid = LayoutGrid(name='firstRow', parent=self.innerCont, align=Align.TOTOP, columns=4, cellSpacing=(30, 0)) 408 planetCont = ContainerAutoSize(name='planetCont', parent=grid, align=Align.CENTERLEFT, pickState=PickState.ON, hint=GetByLabel('UI/PI/PlanetTypes')) 409 planetIcon = Sprite(parent=planetCont, texturePath=eveicon.planet_management, pos=(0, 0, 16, 16), align=Align.CENTERLEFT, pickState=PickState.OFF, color=TextColor.SECONDARY) 410 planetTypeName = TextDetail(parent=planetCont, text=GetByLabel(planetConst.PLANETTYPE_NAMES[self.colonyTemplate.originalPlanetType]), left=labelOffset + planetIcon.width, align=Align.CENTERLEFT, color=TextColor.SECONDARY) 411 cmdCtrCont = ContainerAutoSize(name='cmdCtrCont', parent=grid, align=Align.CENTERLEFT, pickState=PickState.ON, hint=GetByLabel('UI/PI/CmdCtrLV')) 412 cmdCtr = Sprite(parent=cmdCtrCont, texturePath='res:/UI/Texture/Planet/icons/commandCenter_16.png', pos=(0, 0, 16, 16), align=Align.CENTERLEFT, pickState=PickState.OFF, color=TextColor.SECONDARY) 413 textColor = TextColor.SECONDARY if sm.GetService('skills').GetEffectiveLevel(appConst.typeCommandCenterUpgrade) >= self.colonyTemplate.commandCenterLV else TextColor.DANGER 414 cmdCtllv = TextDetail(parent=cmdCtrCont, text=GetByLabel('UI/PI/CommandCenterLevel', level=self.colonyTemplate.commandCenterLV + 1), left=labelOffset + cmdCtr.width, color=textColor, align=Align.CENTERLEFT) 415 radiusCont = ContainerAutoSize(name='radiusCont', parent=grid, align=Align.CENTERLEFT, pickState=PickState.ON, hint=GetByLabel('UI/PI/RadiusOfPlanet')) 416 radiusIcon = Sprite(parent=radiusCont, texturePath='res:/UI/Texture/Planet/icons/radius.png', pos=(0, 0, 16, 16), align=Align.CENTERLEFT, pickState=PickState.OFF, color=TextColor.SECONDARY) 417 radiusText = TextDetail(parent=radiusCont, text=get_distance_in_kilometers(self.colonyTemplate.radiusOfPlanet), left=labelOffset + radiusIcon.width, align=Align.CENTERLEFT, color=TextColor.SECONDARY) 418 templatePinCont = ContainerAutoSize(name='templatePinCont', parent=grid, align=Align.CENTERLEFT, pickState=PickState.ON) 419 templatePinIcon = Sprite(name='templatePinIcon', parent=templatePinCont, texturePath='res:/UI/Texture/Planet/icons/templatePins.png', pos=(0, 0, 16, 16), align=Align.CENTERLEFT, pickState=PickState.OFF, color=TextColor.SECONDARY) 420 templateData = self.colonyTemplate.loadedTemplate 421 templatePinCont.LoadTooltipPanel = self.LoadTemplatePinsTooltip 422 numPins = len(templateData[TemplateDictKeys.PinData]) 423 TextDetail(parent=templatePinCont, text=numPins, left=templatePinIcon.width + labelOffset, align=Align.CENTERLEFT, color=TextColor.SECONDARY) 424 if self.planetEditModeContainer is not None: 425 plnet = sm.GetService('planetUI').GetCurrentPlanet() 426 if plnet is not None: 427 if self.colonyTemplate.radiusOfPlanet * 1000.0 < plnet.radius: 428 radiusText.SetTextColor(Color.YELLOW) 429 radiusCont.SetHint(GetByLabel('UI/PI/HintOversizedPlanet')) 430 else: 431 radiusText.SetTextColor(TextColor.SECONDARY) 432 radiusCont.SetHint(GetByLabel('UI/PI/RadiusOfPlanet')) 433 if self.colonyTemplate.originalPlanetType != plnet.planetTypeID: 434 planetTypeName.SetTextColor(Color.YELLOW) 435 planetCont.SetHint(GetByLabel('UI/PI/MightNotSuitable')) 436 if self.colonyTemplate.restricted and plnet.planetTypeID not in [PlanetTypes.BARREN, PlanetTypes.TEMPERATE]: 437 planetTypeName.SetTextColor(Color.RED) 438 planetCont.SetHint(GetByLabel('UI/PI/NotSuitableDueToCruelEnv')) 439 440 def DoReRender(self, a): 441 message_player(GetByLabel('UI/PI/Loading')) 442 uthread2.sleep(0.5) 443 message_player(GetByLabel('UI/PI/LoadCompleted')) 444 planetUI = sm.GetService('planetUI') 445 planetUI.myPinManager.ReRender() 446 sm.GetService('planetUI').FocusCameraOnCommandCenter() 447 self.planetEditModeContainer.ResetBuildbuttons(falser=True) 448 sm.ScatterEvent('OnEditModeChanged', True) 449 450 def _GetAllProducts(self, products): 451 ret = defaultdict(int) 452 for typeID, amount in products.iteritems(): 453 ret[typeID] += amount 454 455 return ret 456 457 def PreviewLoad(self, *args): 458 return PreviewLoad(self.colonyTemplate) 459 460 def CopyToClipboard(self, *args): 461 blue.clipboard.SetClipboardData(self.colonyTemplate.rawTemplate.decode('unicode-escape')) 462 message_player(GetByLabel('UI/PI/Copied'), flash_existing=False) 463 464 def UpdateDescription(self): 465 templateCopy = self.colonyTemplate.loadedTemplate.copy() 466 defaultNote = templateCopy[TemplateDictKeys.Comments] 467 wnd = ConfirmExportWnd.Open(defaultNote=defaultNote, captionPath='UI/PI/RenameTemplate', okPath='UI/PI/SaveTemplate') 468 wnd.SetParent(uicore.layer.planet) 469 wnd.ShowDialog(modal=True) 470 retval = wnd.result 471 if retval is None: 472 return 473 note = retval.get('note', '') 474 bannedwords.check_words_allowed(note) 475 templateCopy[TemplateDictKeys.Comments] = note 476 jsonText = json.dumps(obj=templateCopy, sort_keys=True).decode('unicode-escape') 477 fileName = u'{0}'.format(os.path.join(GetDefaultStoragePath(), self.colonyTemplate.filename)) 478 SaveToLocalFile(jsonText, fileName, encoding='unicode-escape') 479 480 def GetMenu(self): 481 menuData = MenuData() 482 menuData.AddEntry(GetByLabel('UI/PI/RenameTemplate'), lambda : self.UpdateDescription()) 483 return menuData 484 485 def GetDragData(self): 486 from utillib import KeyVal 487 template = KeyVal() 488 plnName = GetByLabel(planetConst.PLANETTYPE_NAMES[self.colonyTemplate.originalPlanetType]) 489 templateName = GetByLabel('UI/PI/TemplateOf', planetType=plnName) 490 templateDragData = PITempateDragData(templateName, self.colonyTemplate.rawTemplate) 491 return [templateDragData] 492 493 @classmethod 494 def PrepareDrag(cls, dragContainer, dragSource, *args): 495 dragData = dragContainer.dragData[0] 496 displayText = eveformat.truncate_text_ignoring_tags(dragData.templateName, 24, '...') 497 label = Label(parent=dragContainer, text=u'{0}({1}+)'.format(displayText, len(dragData.rawTemplate)), align=uiconst.TOPLEFT, bold=True) 498 Fill(parent=dragContainer, color=(0, 0, 0, 0.3), padding=(-10, -2, -10, -2)) 499 dragContainer.width = label.textwidth 500 dragContainer.height = label.textheight 501 return (2, label.textheight) 502 503 def LoadTemplatePinsTooltip(self, tooltipPanel, *args): 504 templateData = self.colonyTemplate.loadedTemplate 505 pinsByType = defaultdict(int) 506 normalPinsByGroupID = defaultdict(int) 507 for pin in templateData[TemplateDictKeys.PinData]: 508 pinType = pin[TemplatePinDataDictKeys.PinTypeID] 509 if planetUtil.IsTypeHighTechProcessor(pinType): 510 pinsByType[PIN_HIGH] += 1 511 elif planetUtil.IsTypeAdvancedProcessor(pinType): 512 pinsByType[PIN_ADV] += 1 513 elif planetUtil.IsTypeBasicProcessor(pinType): 514 pinsByType[PIN_BASIC] += 1 515 else: 516 groupID = evetypes.GetGroupID(pinType) 517 normalPinsByGroupID[groupID] += 1 518 519 if pinsByType or normalPinsByGroupID: 520 tooltipPanel.LoadStandardSpacing() 521 tooltipPanel.columns = 3 522 else: 523 return 524 525 def AddPinEntry(texturePath, text, countText): 526 Sprite(parent=tooltipPanel, align=uiconst.CENTERLEFT, pos=(0, 0, 22, 22), texturePath=texturePath, color=TextColor.SECONDARY) 527 tooltipPanel.AddTextBodyLabel(text=text) 528 tooltipPanel.AddTextBodyLabel(text=countText) 529 530 if pinsByType: 531 for identifier, labelPath in [(PIN_BASIC, 'UI/PI/BasicIndustryFacilities'), 532 (PIN_ADV, 'UI/PI/AdvancedIndustryFacilities'), 533 (PIN_HIGH, 'UI/PI/HighTechProdPlant'), 534 ('other', 'UI/PI/OtherPins')]: 535 if identifier in pinsByType: 536 texturePath = planetUtil.GetTexturePath(identifier) 537 countText = pinsByType[identifier] 538 text = GetByLabel(labelPath) 539 AddPinEntry(texturePath, text, countText) 540 541 for groupID, pinCount in normalPinsByGroupID.iteritems(): 542 groupName = evetypes.GetGroupNameByGroup(groupID) 543 texturePath = planetUtil.GetTexturePath(None, groupID) 544 AddPinEntry(texturePath, groupName, pinCount) 545 546 numLinks = len(templateData[TemplateDictKeys.LinkData]) 547 numRoutes = len(templateData[TemplateDictKeys.RouteData]) 548 if numLinks: 549 AddPinEntry('res:/UI/Texture/Planet/icons/link.png', GetByLabel('UI/PI/Common/Links'), numLinks) 550 if numRoutes: 551 AddPinEntry('', GetByLabel('UI/PI/Common/Routes'), numRoutes) 552 553 554 class PITempateDragData(BaseDragData): 555 check_link_fits = True 556 557 def __init__(self, templateName, rawTemplate): 558 super(PITempateDragData, self).__init__() 559 self.templateName = templateName 560 self.displayText = templateName 561 self.rawTemplate = rawTemplate 562 563 def get_link(self): 564 return self._template_link() 565 566 def _template_link(self): 567 url = format_pi_template_url(self.rawTemplate) 568 text = u'{0}({1}+)'.format(self.templateName, len(url)) 569 import evelink.client 570 return evelink.Link(url=url, text=text) 571 572 573 PIScheme = 'colonytemplate' 574 575 def register_link_handlers(registry): 576 registry.register(PIScheme, _handle_link, hint=_get_link_hint) 577 578 579 def _handle_link(url): 580 newJSON = _parse_url(url) 581 ColonyTemplateWindow.Open().SaveFromLink(newJSON) 582 583 584 def _get_link_hint(url): 585 newJSON = _parse_url(url) 586 loaded = json.loads(newJSON) 587 hint = u'{0}<br><br>{1}'.format(loaded[TemplateDictKeys.Comments], GetByLabel('UI/PI/ClickToSaveToLocal')) 588 return hint 589 590 591 def _parse_url(url): 592 url = unicode(url).replace(u'colonytemplate:', '') 593 url = base64.b64decode(decompressFromUnicode(url)) 594 return url 595 596 597 def format_pi_template_url(content): 598 return u'{0}:{1}'.format(PIScheme, compressToUnicode(base64.b64encode(content))) 599 600 601 def compressToUnicode(text): 602 while len(text) % 2 != 0: 603 text += '\x00' 604 605 unicode_text = u'' 606 for i in range(0, len(text), 2): 607 ord_val = (ord(text[i]) << 8) + ord(text[i + 1]) 608 unicode_text += unichr(ord_val) 609 610 return unicode_text 611 612 613 def decompressFromUnicode(unicode_text): 614 text = u'' 615 for ch in unicode_text: 616 ord_val = ord(ch) 617 text += chr(ord_val >> 8 & 255) 618 text += chr(ord_val & 255) 619 620 return text.rstrip('\x00')