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

templatePreviewWindow.py (19360B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\planet\templatePreviewWindow.py
      2 from __future__ import print_function
      3 import math
      4 import random
      5 import blue
      6 import mathext
      7 import monolithconfig
      8 import evetypes
      9 import uthread2
     10 from carbonui import uiconst, Align, TextColor
     11 from carbonui.text.styles import TextHeader, TextBody, TextDetail
     12 from carbonui.control.button import Button
     13 from carbonui.control.checkbox import Checkbox
     14 from carbonui.control.slider import Slider
     15 from carbonui.control.window import Window
     16 from carbonui.primitives.container import Container
     17 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     18 from carbonui.primitives.sprite import Sprite
     19 from clientsettings.setting import UserSettingNumeric
     20 from carbonui.uicore import uicore
     21 from carbonui.util.color import Color
     22 from eve.client.script.ui.control.infoIcon import MoreInfoIcon
     23 from player_messaging.client.ui_message import message_player
     24 from eve.client.script.ui.control.eveLoadingWheel import LoadingWheel
     25 from eve.client.script.ui.shared.planet.colonyTemplateLoading import LoadPiTemplate
     26 from eve.client.script.ui.shared.planet.planetConst import *
     27 from eve.client.script.ui.shared.planet.planetUIPins import TemplatePins
     28 from eve.common.script.planet.colonyData import ColonyData
     29 from eve.common.script.planet.surfacePoint import SurfacePoint
     30 from eve.common.script.util.planetCommon import RADIUS_DRILLAREAMIN, RADIUS_DRILLAREAMAX
     31 import inventorycommon.const as invConst
     32 from eveplanet.client.templates.templateConst import ExtractionTypes, ProcessedTypes, RefinedTypes, SpecializedTypes, AdvancedTypes, TemplateDictKeys, TemplatePinDataDictKeys
     33 from localization import GetByLabel
     34 from urllib3.packages.ordered_dict import OrderedDict
     35 EXTRACT_PRODUCTS = set(ExtractionTypes.itervalues())
     36 PRODUCTION_PRODUCTS = set(ProcessedTypes.itervalues()).union(set(RefinedTypes.itervalues())).union(set(SpecializedTypes.itervalues())).union(set(AdvancedTypes.itervalues()))
     37 COMMENT_MAX_WIDTH = 60
     38 DEFAULT_DRILL_RADIUS = (RADIUS_DRILLAREAMIN + RADIUS_DRILLAREAMAX) / 2.0
     39 RING_NAME = 'RotationGizmoRings'
     40 MIN_RING = 2
     41 MAX_RING = 999999
     42 CURSOR_PATH = 'res:/UI/Cursor/cursor32_x2.png'
     43 BASE_MIN_RANGE = 0.012
     44 PI_TEMPLATE_FUSCATION_CONFIG_ID = 'pi_template_fuscation'
     45 
     46 class TemplatePreviewWindow(Window):
     47     default_windowInstanceID = u'TemplatePreviewWindow'
     48     default_fixedWidth = 400
     49     default_fixedHeight = 300
     50     default_caption = localization.GetByLabel('UI/PI/TemplatePreviewWindow')
     51     default_windowID = u'TemplatePreviewWindow'
     52     default_analyticID = 'pi_template_preview_window'
     53     surfacePoints = []
     54 
     55     def ApplyAttributes(self, attributes):
     56         super(type(self), self).ApplyAttributes(attributes)
     57         self.contentCont = None
     58         self.template = attributes.get('template', None)
     59         self.planet = attributes.get('clientPlanet', None)
     60         self.verticalReversed = False
     61         self.compressed = None
     62         self.buildIndicatorPins = []
     63         self.pinMover = PinMover()
     64         uthread2.start_tasklet(self.DoInit)
     65 
     66     def DoInit(self):
     67         self.lw = LoadingWheel(name='loadingWheel', parent=self.content, align=uiconst.CENTER, state=uiconst.UI_NORMAL, pos=(0, 0, 160, 160), opacity=1.0, idx=0)
     68         self.lw.Show()
     69         self.CompressPins(self.template.loadedTemplate[TemplateDictKeys.PinData])
     70         message_player(localization.GetByLabel('UI/PI/PreprocessDone'))
     71         self.lw.Hide()
     72         self.ConstructLayout()
     73         self.FocusToCmdCtr()
     74 
     75     def ConstructLayout(self):
     76         self.contentCont = cont = ContainerAutoSize(name='contentCont', parent=self.content, align=uiconst.TOTOP, padding=8, callback=self.OnContSizeChanged)
     77         comment = self.template.loadedTemplate[TemplateDictKeys.Comments]
     78         comment = comment if len(comment) < COMMENT_MAX_WIDTH else u'{0}...'.format(comment[:COMMENT_MAX_WIDTH])
     79         TextHeader(name='commentLabel', parent=cont, text=comment, align=Align.TOTOP, state=uiconst.UI_NORMAL, bold=True)
     80         TextBody(parent=cont, align=uiconst.TOTOP, text=localization.GetByLabel('UI/PI/PreviewDescription'), top=8)
     81         ctrlCont = Container(name='ctrlCont', parent=cont, align=Align.TOTOP, top=8)
     82         btn = Button(name='RefocusButton', parent=ctrlCont, align=uiconst.TOPRIGHT, pos=(0, 0, 32, 32), hint=localization.GetByLabel('UI/PI/FocusToCmdCtr'), func=self.FocusToCmdCtr, texturePath='res:/UI/Texture/Planet/icons/focusIcon.png')
     83         ctrlCont.height = btn.height
     84         ReRenderOnReturn = lambda *args: self.InvokeRerenderLines()
     85         self.doCompressCb = Checkbox(align=uiconst.TOTOP, name='CompressCheckBox', text=localization.GetByLabel('UI/PI/DoCompress'), checked=True, hint=localization.GetByLabel('UI/PI/DoCompressHint'), parent=ctrlCont, enabled=not monolithconfig.enabled(PI_TEMPLATE_FUSCATION_CONFIG_ID), callback=ReRenderOnReturn, padRight=btn.width)
     86         TextDetail(parent=cont, text=GetByLabel('UI/PI/Horiz'), align=Align.TOTOP, color=TextColor.SECONDARY)
     87         self.ConstructSliders(cont)
     88         ReRenderOnReturn()
     89         self.DrawGizmo()
     90         bottomCont = ContainerAutoSize(parent=cont, align=Align.TOTOP, alignMode=Align.TOTOP, top=16)
     91         buttonCont = ContainerAutoSize(parent=bottomCont, align=Align.TORIGHT)
     92         btn = Button(name='ConfirmButton', parent=buttonCont, align=uiconst.TOPRIGHT, label=localization.GetByLabel('UI/PI/Confirm'), func=self.Confirm)
     93         bottomCont.minHeight = btn.height
     94 
     95     def ConstructSliders(self, cont):
     96         ySetting = UserSettingNumeric('pi_template_y', default_value=0.0, min_value=-180.0, max_value=180.0)
     97         ySetting.set(0)
     98         ySetting.on_change.connect(self.OnYSettingChanged)
     99         self.ySlider = Slider(parent=cont, align=uiconst.TOTOP, setting=ySetting, on_dragging=self.OnYDragging)
    100         TextDetail(parent=cont, text=GetByLabel('UI/PI/AxisA'), align=Align.TOTOP, color=TextColor.SECONDARY)
    101         xSetting = UserSettingNumeric('pi_template_x', default_value=0.0, min_value=-180.0, max_value=180.0)
    102         xSetting.set(0)
    103         xSetting.on_change.connect(self.OnXSettingChanged)
    104         self.xSlider = Slider(parent=cont, align=uiconst.TOTOP, setting=xSetting, on_dragging=self.OnXDragging)
    105         TextDetail(parent=cont, text=GetByLabel('UI/PI/AxisB'), align=Align.TOTOP, color=TextColor.SECONDARY)
    106         zSetting = UserSettingNumeric('pi_template_z', default_value=0.0, min_value=-180.0, max_value=180.0)
    107         zSetting.set(0)
    108         zSetting.on_change.connect(self.OnZSettingChanged)
    109         self.zSlider = Slider(parent=cont, align=uiconst.TOTOP, setting=zSetting, on_dragging=self.OnZDragging)
    110 
    111     def OnContSizeChanged(self, *args, **kwds):
    112         if self.contentCont:
    113             height = self.contentCont.height + self.contentCont.padTop + self.contentCont.padBottom
    114             _, height = self.GetWindowSizeForContentSize(height=height)
    115             self.SetFixedHeight(height)
    116 
    117     def OnXSettingChanged(self, value, *args):
    118         self.pinMover.x = value
    119         self.InvokeRerenderLines()
    120 
    121     def OnXDragging(self, slider, *args):
    122         self.pinMover.x = slider.GetValue()
    123         self.InvokeRerenderLines()
    124 
    125     def OnYSettingChanged(self, value, *args):
    126         self.pinMover.y = value
    127         self.InvokeRerenderLines()
    128 
    129     def OnYDragging(self, slider, *args):
    130         self.pinMover.y = slider.GetValue()
    131         self.InvokeRerenderLines()
    132 
    133     def OnZSettingChanged(self, value, *args):
    134         self.pinMover.z = value
    135         self.InvokeRerenderLines()
    136 
    137     def OnZDragging(self, slider, *args):
    138         self.pinMover.z = slider.GetValue()
    139         self.InvokeRerenderLines()
    140 
    141     def UpdateSliderValues(self):
    142         self.xSlider.SetValue(self.pinMover.x)
    143         self.ySlider.SetValue(self.pinMover.y)
    144         self.zSlider.SetValue(self.pinMover.z)
    145 
    146     def InvokeRerenderLines(self, *args):
    147         pinMover = self.pinMover
    148         degX = 0
    149         degY = 0
    150         degZ = 0
    151         try:
    152             degX = -float(pinMover.x)
    153             degY = float(pinMover.y)
    154             degZ = float(pinMover.z)
    155         except:
    156             pass
    157 
    158         self.ReRenderPins(degX, degY, degZ)
    159         self.ReRenderLines(degX, degY, degZ)
    160 
    161     def FocusToCmdCtr(self, *args):
    162         sm.GetService('planetUI').planetNav.cameraController.camera.OrbitToSurfacePoint(self.surfacePoints.values()[0][0], newZoom=sm.GetService('planetUI').planetNav.cameraController.camera.zoomLinear, initStartPos=False)
    163 
    164     def ReRenderPins(self, degX, degY, degZ):
    165         self.surfacePoints = OrderedDict()
    166         origPinData = self.template.loadedTemplate[TemplateDictKeys.PinData]
    167         pinData = origPinData
    168         if self.doCompressCb.checked:
    169             pinData = self.CompressPins(pinData)
    170         for pinCount, pin in enumerate(pinData):
    171             origPin = self.template.loadedTemplate[TemplateDictKeys.PinData][pinCount]
    172             point = SurfacePoint(theta=pin[TemplatePinDataDictKeys.Longi], phi=pin[TemplatePinDataDictKeys.Lat], radius=1.05)
    173             self.surfacePoints[str(origPin)] = (point.GetRotatedSurfacePoint(degX, degY, degZ), pin[TemplatePinDataDictKeys.PinTypeID])
    174 
    175         if not self.buildIndicatorPins:
    176             self.InitPins()
    177         i = 0
    178         for point, typeID in self.surfacePoints.values():
    179             newPoint = SurfacePoint(theta=point.theta, phi=point.phi, radius=1.0)
    180             self.buildIndicatorPins[i].SetLocation(newPoint)
    181             i += 1
    182 
    183     def InitPins(self):
    184         i = 0
    185         for pin in self.buildIndicatorPins:
    186             pin.Remove()
    187 
    188         clientPlanet = sm.GetService('planetUI').GetCurrentPlanet()
    189         colony = clientPlanet.GetColony(session.charid)
    190         if colony is None:
    191             colony = clientPlanet.GetNewColony(session.charid)
    192             colony.SetColonyData(ColonyData(session.charid, None))
    193         for point, typeID in self.surfacePoints.values():
    194             newPoint = SurfacePoint(theta=point.theta, phi=point.phi, radius=1.0)
    195             color = self._GetPinTypeColor(typeID)
    196             newPin = TemplatePins(newPoint, typeID, evetypes.GetGroupID(typeID), sm.GetService('planetUI').pinOthersTransform)
    197             newPin.SetCircleColor(color)
    198             i += 1
    199             newPin.SetLocation(newPoint)
    200             self.buildIndicatorPins.append(newPin)
    201 
    202     def ReRenderLines(self, degX, degY, degZ):
    203         self.surfacePoints = OrderedDict()
    204         origPinData = self.template.loadedTemplate[TemplateDictKeys.PinData]
    205         pinData = origPinData
    206         if self.doCompressCb.checked:
    207             pinData = self.CompressPins(pinData)
    208         for pinCount, pin in enumerate(pinData):
    209             origPin = self.template.loadedTemplate[TemplateDictKeys.PinData][pinCount]
    210             point = SurfacePoint(theta=pin[TemplatePinDataDictKeys.Longi], phi=pin[TemplatePinDataDictKeys.Lat], radius=1.05)
    211             pinTypeID = pin[TemplatePinDataDictKeys.PinTypeID]
    212             color = self._GetPinTypeColor(pinTypeID)
    213             self.surfacePoints[str(origPin)] = (point.GetRotatedSurfacePoint(degX, degY, degZ), color)
    214 
    215     def _GetPinTypeColor(self, pinTypeID):
    216         if evetypes.GetGroupID(pinTypeID) in (invConst.groupStoragePins, invConst.groupSpaceportPins):
    217             color = Color.BLUE
    218         elif evetypes.GetGroupID(pinTypeID) == invConst.groupExtractionControlUnitPins:
    219             color = Color.GREEN
    220         elif pinTypeID in TYPEIDS_PROCESSORS:
    221             color = Color.ORANGE
    222         else:
    223             color = Color.RED
    224         return color
    225 
    226     def Confirm(self, *args):
    227         result = LoadPiTemplate(self.surfacePoints, self.template)
    228         if result:
    229             message_player(GetByLabel('UI/PI/LoadedFromTemplate'))
    230         self.Close()
    231 
    232     def CompressPins(self, pinData):
    233         if self.compressed:
    234             return self.compressed
    235         forProcessing = []
    236         for id, pin in enumerate(pinData):
    237             forProcessing.append([id, [pin[TemplatePinDataDictKeys.Longi], pin[TemplatePinDataDictKeys.Lat]]])
    238 
    239         minDist = BASE_MIN_RANGE
    240         doFuscation = 1 if monolithconfig.enabled(PI_TEMPLATE_FUSCATION_CONFIG_ID) else 0
    241         forProcessing = adjust_coordinates(forProcessing, minDist, 2, doFuscation)
    242         forProcessing = sorted(forProcessing, key=lambda coord: coord[0])
    243         self.compressed = []
    244         for id, pin in enumerate(forProcessing):
    245             self.compressed.append({TemplatePinDataDictKeys.PinTypeID: pinData[id][TemplatePinDataDictKeys.PinTypeID],
    246              TemplatePinDataDictKeys.Longi: pin[1][0],
    247              TemplatePinDataDictKeys.Lat: pin[1][1]})
    248 
    249         return self.compressed
    250 
    251     def DrawGizmo(self, len = 1.1):
    252         CLD = sm.GetService('planetUI').curveLineDrawer
    253         try:
    254             CLD.ClearLines(RING_NAME)
    255         except:
    256             pass
    257 
    258         CLD.CreateLineSet(RING_NAME, sm.GetService('planetUI').planetTransform)
    259         RED = (1, 0.2, 0.2, 5)
    260         BLUE = (0.2, 1, 0.2, 5)
    261         GREEN = (0.2, 0.2, 1, 5)
    262         for i in range(91):
    263             i = i * 4 + 0.5
    264             CLD.DrawLine(RING_NAME, SurfacePoint(math.sin(math.radians(i - 1)) * len, 0, math.cos(math.radians(i - 1)) * len), SurfacePoint(math.sin(math.radians(i)) * len, 0, math.cos(math.radians(i)) * len), 3.0, BLUE, BLUE)
    265 
    266         for i in range(91):
    267             i = i * 4 + 0.5
    268             CLD.DrawLine(RING_NAME, SurfacePoint(0, math.sin(math.radians(i - 1)) * len, math.cos(math.radians(i - 1)) * len), SurfacePoint(0, math.sin(math.radians(i)) * len, math.cos(math.radians(i)) * len), 3.0, RED, RED)
    269 
    270         for i in range(91):
    271             i = i * 4 + 0.5
    272             CLD.DrawLine(RING_NAME, SurfacePoint(math.sin(math.radians(i - 1)) * len, math.cos(math.radians(i - 1)) * len, 0), SurfacePoint(math.sin(math.radians(i)) * len, math.cos(math.radians(i)) * len, 0), 3.0, GREEN, GREEN)
    273 
    274         CLD.SubmitLineset(RING_NAME)
    275 
    276     def Close(self, **kwargs):
    277         super(TemplatePreviewWindow, self).Close(kwargs)
    278         self._Close()
    279 
    280     def _Close(self, *args):
    281         try:
    282             for pin in self.buildIndicatorPins:
    283                 pin.Remove()
    284 
    285             cld = sm.GetService('planetUI').curveLineDrawer
    286             cld.ClearLines(RING_NAME)
    287             cld.SubmitLineset(RING_NAME)
    288             lineSet = cld.GetLineSet(RING_NAME)
    289             if lineSet in sm.GetService('planetUI').planetTransform.children:
    290                 sm.GetService('planetUI').planetTransform.children.remove(lineSet)
    291             cld.RemoveLineSet(RING_NAME)
    292         except Exception as e:
    293             print('except = ', e)
    294 
    295 
    296 class PinMover(object):
    297 
    298     def __init__(self):
    299         self._x = 0
    300         self._y = 0
    301         self._z = 0
    302         self._theta = 0
    303 
    304     @property
    305     def x(self):
    306         return self._x
    307 
    308     @x.setter
    309     def x(self, value):
    310         if value > 180:
    311             value -= 360
    312         elif value < -180:
    313             value += 360
    314         self._x = self._ClampValue(value)
    315 
    316     @property
    317     def y(self):
    318         return self._y
    319 
    320     @y.setter
    321     def y(self, value):
    322         self._y = self._ClampValue(value)
    323 
    324     @property
    325     def z(self):
    326         return self._z
    327 
    328     @z.setter
    329     def z(self, value):
    330         self._z = self._ClampValue(value)
    331 
    332     def _ClampValue(self, value):
    333         if value > 180:
    334             value -= 360
    335         elif value < -180:
    336             value += 360
    337         return mathext.clamp(value, -180, 180)
    338 
    339 
    340 def StartDraggingTemplate(x, y):
    341     wnd = TemplatePreviewWindow.GetIfOpen()
    342     if not wnd:
    343         return
    344     firstPinTheta = wnd.template.loadedTemplate[TemplateDictKeys.PinData][0][TemplatePinDataDictKeys.Longi]
    345     originalX = wnd.pinMover.x
    346     originalY = wnd.pinMover.y
    347     originalZ = wnd.pinMover.z
    348     uthread2.StartTasklet(UpdateOften, wnd, x, y, originalX, originalY, originalZ, firstPinTheta)
    349 
    350 
    351 def UpdateOften(wnd, prevX, prevY, originalX, originalY, originalZ, theta = 0):
    352     isMouseDown = uicore.uilib.leftbtn
    353     if wnd.destroyed or not isMouseDown:
    354         return
    355     zoomLinear = sm.GetService('planetUI').planetNav.cameraController.camera.zoomLinear
    356     x = uicore.uilib.x
    357     y = uicore.uilib.y
    358     pinMover = wnd.pinMover
    359     newY = (x - prevX) * zoomLinear * 0.2 + originalY
    360     pinMover.y = newY
    361     newX = (y - prevY) * -math.sin(theta) * zoomLinear * 0.2 + originalX
    362     pinMover.x = newX
    363     newZ = (y - prevY) * -math.cos(theta) * zoomLinear * 0.2 + originalZ
    364     pinMover.z = newZ
    365     compareVal = 75 * zoomLinear * 0.75
    366     if math.fabs(originalX - pinMover.x) > compareVal or math.fabs(originalY - pinMover.y) > compareVal:
    367         wnd.FocusToCmdCtr()
    368     wnd.UpdateSliderValues()
    369     wnd.InvokeRerenderLines()
    370     uthread2.Yield()
    371     uthread2.start_tasklet(UpdateOften, wnd, prevX, prevY, originalX, originalY, originalZ, theta)
    372 
    373 
    374 def scale_away(coord, target, factor):
    375     x_diff = coord[1][0] - target[1][0]
    376     y_diff = coord[1][1] - target[1][1]
    377     return [coord[0], [target[1][0] + factor * x_diff, target[1][1] + factor * y_diff]]
    378 
    379 
    380 def move_closer(coord, target, step_size):
    381     x_diff = target[1][0] - coord[1][0]
    382     y_diff = target[1][1] - coord[1][1]
    383     distance = (x_diff ** 2 + y_diff ** 2) ** 0.5
    384     if distance == 0:
    385         return coord
    386     return [coord[0], [coord[1][0] + step_size * x_diff / distance, coord[1][1] + step_size * y_diff / distance]]
    387 
    388 
    389 def distance_between(coord1, coord2):
    390     SP1 = SurfacePoint(theta=coord1[1][0], phi=coord1[1][1])
    391     SP2 = SurfacePoint(theta=coord2[1][0], phi=coord2[1][1])
    392     return SP1.GetDistanceToOther(SP2)
    393 
    394 
    395 def is_move_valid(coord, other_coords, MinDist):
    396     for other in other_coords:
    397         if distance_between(coord, other) < MinDist:
    398             return False
    399 
    400     return True
    401 
    402 
    403 def adjust_coordinates(coordList, minDist, expansion_factor, forcedFuscation = 0):
    404     target = coordList[0]
    405     expanded_coords = sorted(coordList[1:], key=lambda coord: distance_between(coord, target))
    406     expanded_coords = [ scale_away(coord, target, expansion_factor + forcedFuscation * expansion_factor * random.random()) for coord in expanded_coords ]
    407     adjusted_coords = [target] + expanded_coords
    408     step_size = minDist * 0.01
    409     max_iterations = 10000
    410     iteration = 0
    411     unchangedIterationCount = 0
    412     message_player(localization.GetByLabel('UI/PI/PreprocessingMsg', pct=0))
    413     while iteration < max_iterations:
    414         somethingChanged = False
    415         for i in range(1, len(adjusted_coords)):
    416             new_position = move_closer(adjusted_coords[i], target, step_size)
    417             if is_move_valid(new_position, adjusted_coords[:i] + adjusted_coords[i + 1:], minDist):
    418                 if adjusted_coords[i] != new_position:
    419                     somethingChanged = True
    420                 adjusted_coords[i] = new_position
    421 
    422         iteration += 1
    423         if iteration % 30 == 0:
    424             if not TemplatePreviewWindow.GetIfOpen():
    425                 message_player(localization.GetByLabel('UI/PI/PreprocessTerminated'))
    426                 return
    427         if iteration % 1000 == 0:
    428             message_player(localization.GetByLabel('UI/PI/PreprocessingMsg', pct=iteration * 100.0 / max_iterations), flash_existing=False)
    429         if somethingChanged:
    430             unchangedIterationCount = 0
    431         else:
    432             if unchangedIterationCount > 20:
    433                 break
    434             unchangedIterationCount += 1
    435         blue.pyos.BeNice()
    436 
    437     return adjusted_coords