panContainer.py (8446B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\control\panContainer.py 2 from carbonui.primitives.container import Container 3 from carbonui.primitives.containerAutoSize import ContainerAutoSize 4 from carbonui.const import UI_PICKCHILDREN, TOPLEFT, UICURSOR_DRAGGABLE, UI_NORMAL, CENTER 5 import geo2 6 import uthread 7 import blue 8 from carbonui.primitives.transform import Transform 9 from carbonui.uicore import uicore 10 11 class PanContainer(Container): 12 default_name = 'PanContainer' 13 default_panSpeed = 8.0 14 default_panAmount = 2.0 15 default_callback = None 16 default_state = UI_NORMAL 17 default_clipChildren = True 18 default_panLeft = 0.0 19 default_panTop = 0.0 20 default_border = (10, 10, 10, 10) 21 default_axisLockMargin = 50 22 default_isPanRelativeToContentSize = True 23 24 def GetCursor(self): 25 if not (self.IsClampedHorizontally() and self.IsClampedVertically()): 26 return UICURSOR_DRAGGABLE 27 28 def ApplyAttributes(self, attributes): 29 Container.ApplyAttributes(self, attributes) 30 self.panSpeed = attributes.Get('panSpeed', self.default_panSpeed) 31 self.panAmount = attributes.Get('panAmount', self.default_panAmount) 32 self.callback = attributes.Get('callback', self.default_callback) 33 self._border = None 34 self.border = attributes.Get('border', self.default_border) 35 self._panLeft = attributes.Get('panLeft', self.default_panLeft) 36 self._panTop = attributes.Get('panTop', self.default_panTop) 37 self.axisLockMargin = attributes.Get('axisLockMargin', self.default_axisLockMargin) 38 self.isPanRelativeToContentSize = attributes.Get('isPanRelativeToContentSize', self.default_isPanRelativeToContentSize) 39 self._scale = 1.0 40 self.panUpdateThread = None 41 self.panTarget = None 42 self.transform = Transform(parent=self, align=TOPLEFT, state=UI_PICKCHILDREN, scalingCenter=(0.5, 0.5)) 43 self.mainCont = ContainerAutoSize(name='mainCont', parent=self.transform, align=CENTER, state=UI_PICKCHILDREN) 44 45 def OnMouseMove(self, *args): 46 if uicore.uilib.leftbtn and not uicore.uilib.rightbtn and not uicore.IsDragging(): 47 k = self.panAmount / self.scale 48 self.Pan(k * uicore.uilib.dx, k * uicore.uilib.dy) 49 50 def Pan(self, dx = 0, dy = 0): 51 if self.panTarget is None: 52 self.panTarget = geo2.Vector(0, 0) 53 if self.IsClampedHorizontally(): 54 dx = 0 55 if self.IsClampedVertically(): 56 dy = 0 57 self.panTarget += geo2.Vector(dx, dy) 58 if not self.panUpdateThread: 59 self.panUpdateThread = uthread.new(self._PanUpdateThread) 60 61 def IsClampedHorizontally(self, includeMargin = True): 62 width = self.transform.width 63 parWidth, _ = self.GetAbsoluteSize() 64 bLeft, _, bRight, _ = self.border 65 margin = self.axisLockMargin if includeMargin else 0 66 if width < parWidth - bLeft - bRight + margin: 67 return True 68 return False 69 70 def IsClampedVertically(self, includeMargin = True): 71 height = self.transform.height 72 _, parHeight = self.GetAbsoluteSize() 73 _, bTop, _, bBottom = self.border 74 margin = self.axisLockMargin if includeMargin else 0 75 if height < parHeight - bTop - bBottom + margin: 76 return True 77 return False 78 79 def PanTo(self, panLeft, panTop, animate = True, duration = None, timeOffset = 0.0, sleep = False): 80 if animate: 81 if not duration: 82 length = geo2.Vec3Distance((panLeft, panTop, 0), (self.panLeft, self.panTop, 0)) 83 duration = max(0.1, length * self.scale) 84 uicore.animations.MorphScalar(self, 'panLeft', self.panLeft, panLeft, duration=duration, timeOffset=timeOffset) 85 uicore.animations.MorphScalar(self, 'panTop', self.panTop, panTop, duration=duration, timeOffset=timeOffset, sleep=sleep) 86 else: 87 self.panLeft = panLeft 88 self.panTop = panTop 89 90 def PanToMouseOver(self, duration = None, timeOffset = 0.0, sleep = False): 91 panLeft, panTop = self.GetMousePositionProportional() 92 if not duration: 93 length = geo2.Vec2Length((panLeft - self.panLeft, panTop - self.panTop)) 94 if length < 0.2: 95 return 0.0 96 duration = max(0.3, length * 0.4) 97 self.PanTo(panLeft, panTop, duration=duration, timeOffset=timeOffset, sleep=sleep) 98 return duration 99 100 def GetMousePositionProportional(self): 101 x = uicore.uilib.x 102 y = uicore.uilib.y 103 left, top, width, height = self.transform.GetAbsolute() 104 x = (x - left) / float(width) 105 y = (y - top) / float(height) 106 x = max(0.0, min(x, 1.0)) 107 y = max(0.0, min(y, 1.0)) 108 return (x, y) 109 110 def GetScale(self): 111 return self._scale 112 113 def SetScale(self, value): 114 self._scale = value 115 self.transform.scale = (value, value) 116 self.FlagAlignmentDirty() 117 118 scale = property(GetScale, SetScale) 119 120 def _PanUpdateThread(self): 121 while True: 122 if self.panTarget is None or not self.mainCont.children: 123 break 124 distLeft = geo2.Vec2Length(self.panTarget) 125 if distLeft == 0: 126 break 127 dist = self.panSpeed / blue.os.fps 128 if distLeft < 1.0: 129 dist *= 1.0 / distLeft 130 dist = min(dist, 1.0) 131 toMove = geo2.Vec2Scale(self.panTarget, dist) 132 self.panTarget -= toMove 133 dx, dy = toMove 134 if self.isPanRelativeToContentSize: 135 totalPanWidth = self.mainCont.width 136 totalPanHeight = self.mainCont.height 137 else: 138 minLeft, maxLeft, minTop, maxTop = self._GetPanningConstraints() 139 totalPanWidth = maxLeft - minLeft 140 totalPanHeight = maxTop - minTop 141 if totalPanWidth > 0: 142 self.panLeft -= dx / totalPanWidth 143 if totalPanHeight > 0: 144 self.panTop -= dy / totalPanHeight 145 blue.synchro.Yield() 146 147 self.panUpdateThread = None 148 self.panTarget = None 149 150 def GetPanLeft(self): 151 return self._panLeft 152 153 def SetPanLeft(self, value): 154 self._panLeft = max(0.0, min(value, 1.0)) 155 self.FlagAlignmentDirty() 156 157 panLeft = property(GetPanLeft, SetPanLeft) 158 159 def GetPanTop(self): 160 return self._panTop 161 162 def SetPanTop(self, value): 163 self._panTop = max(0.0, min(value, 1.0)) 164 self.FlagAlignmentDirty() 165 166 panTop = property(GetPanTop, SetPanTop) 167 168 def UpdateAlignment(self, *args, **kwds): 169 budget = super(PanContainer, self).UpdateAlignment(*args, **kwds) 170 self._UpdateTransformPos() 171 return budget 172 173 def _UpdateTransformPos(self): 174 self.transform.width = self.mainCont.width * self.scale 175 self.transform.height = self.mainCont.height * self.scale 176 minLeft, maxLeft, minTop, maxTop = self._GetPanningConstraints() 177 diff = minTop - maxTop 178 self.transform.top = maxTop + diff * self._panTop 179 diff = minLeft - maxLeft 180 self.transform.left = maxLeft + diff * self._panLeft 181 if self.callback: 182 self.callback() 183 184 def _GetPanningConstraints(self): 185 width, height = self.transform.width, self.transform.height 186 parWidth, parHeight = self.GetAbsoluteSize() 187 bLeft, bTop, bRight, bBottom = self.border 188 if self.IsClampedHorizontally(includeMargin=False): 189 minLeft = maxLeft = (bRight - bLeft + parWidth - width) / 2 190 else: 191 minLeft = parWidth - width - bLeft 192 maxLeft = bRight 193 if self.IsClampedVertically(includeMargin=False): 194 minTop = maxTop = (bBottom - bTop + parHeight - height) / 2 195 else: 196 minTop = parHeight - height - bTop 197 maxTop = bBottom 198 return (minLeft, 199 maxLeft, 200 minTop, 201 maxTop) 202 203 def SetBorder(self, border): 204 if isinstance(border, int): 205 self._border = (border, 206 border, 207 border, 208 border) 209 else: 210 self._border = border 211 self.FlagAlignmentDirty() 212 213 def GetBorder(self): 214 return self._border 215 216 border = property(GetBorder, SetBorder) 217 218 def Flush(self): 219 self.mainCont.Flush()