rangeSelector.py (18724B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\control\rangeSelector.py 2 from carbon.common.script.util.mathCommon import FloatCloseEnough 3 from carbonui import uiconst 4 from carbonui.primitives.container import Container 5 from carbonui.primitives.gridcontainer import GridContainer 6 from carbonui.primitives.line import Line 7 from carbonui.primitives.sprite import Sprite 8 from eve.client.script.ui.control import eveLabel 9 from eve.client.script.ui.control.themeColored import SpriteThemeColored, FillThemeColored 10 from carbonui.uicore import uicore 11 MAINSIDEMARGIN = 6 12 RANGECOLOR = (0.6, 13 0.6, 14 0.6, 15 1) 16 OUTOFRANGECOLOR = (0.2, 17 0.2, 18 0.2, 19 1) 20 21 class RangeSelector(Container): 22 default_state = uiconst.UI_NORMAL 23 24 def ApplyAttributes(self, attributes): 25 Container.ApplyAttributes(self, attributes) 26 self._fixedFromProportion = None 27 self._fixedToProportion = None 28 self._minRange = None 29 self._maxRange = None 30 rangeParent = Container(parent=self, align=uiconst.TOTOP, height=attributes.barHeight or 9, padding=(MAINSIDEMARGIN, 31 8, 32 MAINSIDEMARGIN, 33 0), state=uiconst.UI_NORMAL) 34 rangeParent.OnMouseDown = (self.StartMoveRange, rangeParent) 35 rangeParent.OnMouseUp = (self.StopMoveRange, rangeParent) 36 rangeParent.OnMouseMove = (self.MoveRange, rangeParent) 37 for name in ('from', 'to'): 38 parent = Container(parent=rangeParent) 39 rangeContainer = SizeCappedContainer(name='rangeContainer', parent=parent, align=uiconst.TOLEFT_PROP) 40 rangeContainer._background = FillThemeColored(bgParent=rangeContainer, opacity=0.8) 41 rangeContainer._pointer = SpriteThemeColored(parent=rangeContainer, align=uiconst.TOPRIGHT, pos=(-8, -7, 16, 16)) 42 setattr(self, '_' + name + 'Range', rangeContainer) 43 configName = '_' + name + 'Handle' 44 handle = Container(parent=self, name=configName, align=uiconst.TOPLEFT, state=uiconst.UI_NORMAL, pos=(0, 45 0, 46 MAINSIDEMARGIN * 2, 47 32), idx=0) 48 handle.OnMouseDown = (self.StartMoveHandle, handle) 49 handle.OnMouseUp = (self.StopMoveHandle, handle) 50 handle.OnMouseMove = (self.MoveHandle, handle) 51 setattr(self, configName, handle) 52 53 self._background = FillThemeColored(name='backgroundFill', bgParent=rangeParent, opacity=0.8) 54 self._incrementsParent = Container(parent=self, align=uiconst.TOTOP, height=16, padding=(MAINSIDEMARGIN, 55 2, 56 MAINSIDEMARGIN, 57 0), name='_incrementsParent') 58 self._increments = None 59 self._callbackData = None 60 self._fromProportion = attributes.fromProportion or 0.0 61 self._toProportion = attributes.toProportion or 1.0 62 self._canInvert = bool(attributes.canInvert) 63 self.height = 48 64 self.UpdateRanges() 65 self.UpdateHandles() 66 self.OnIncrementChange = attributes.OnIncrementChange 67 self.OnChange = attributes.OnChange 68 self.OnEndDragChange = attributes.OnEndDragChange 69 70 def StartMoveHandle(self, handle, btn): 71 l, t, w, h = handle.GetAbsolute() 72 handle.grab = (uicore.uilib.x - l, uicore.uilib.y - t) 73 74 def StopMoveHandle(self, handle, btn): 75 self._EnforceMaxRange(handle) 76 handle.grab = None 77 if self._increments and (self._fromProportion == self._toProportion or self._toProportion == 0 and self._fromProportion == 1.0): 78 if handle is self._toHandle: 79 for increment, incrementData in self._increments: 80 if increment - self._minRange >= self._toProportion: 81 self._toProportion = increment 82 self.UpdateRanges() 83 self.UpdateHandles() 84 self._DoOnChangeCallback(onEndDrag=True) 85 return 86 87 self._toProportion = self._increments[1][0] 88 self.UpdateRanges() 89 self.UpdateHandles() 90 self._DoOnChangeCallback(onEndDrag=True) 91 return 92 if handle is self._fromHandle: 93 for increment, incrementData in reversed(self._increments): 94 if increment + self._minRange <= self._fromProportion: 95 self._fromProportion = increment 96 self.UpdateRanges() 97 self.UpdateHandles() 98 self._DoOnChangeCallback(onEndDrag=True) 99 return 100 101 self._fromProportion = self._increments[-2][0] 102 self.UpdateRanges() 103 self.UpdateHandles() 104 self._DoOnChangeCallback(onEndDrag=True) 105 return 106 if self.OnEndDragChange: 107 self._DoOnChangeCallback(onEndDrag=True) 108 109 def _EnforceMaxRange(self, handle): 110 if not self._increments or self._maxRange is None: 111 return 112 if not self.IsOverMaxRange(self._fromProportion, self._toProportion): 113 return 114 if handle is self._toHandle: 115 nextIncrements = self.GetNextIncrements(self._toProportion, 'toHandle') 116 for prop in nextIncrements: 117 if not self.IsOverMaxRange(self._fromProportion, prop): 118 self._toProportion = prop 119 break 120 121 elif handle is self._fromHandle: 122 nextIncrements = self.GetNextIncrements(self._fromProportion, 'fromHandle') 123 for prop in nextIncrements: 124 if not self.IsOverMaxRange(prop, self._toProportion): 125 self._fromProportion = prop 126 break 127 128 self.UpdateRanges() 129 self.UpdateHandles() 130 131 def GetNextIncrements(self, prop, handleName): 132 lowerThanProp = [] 133 higherThanProp = [] 134 for increment, _ in self._increments: 135 if increment >= prop: 136 higherThanProp.append(increment) 137 else: 138 lowerThanProp.append(increment) 139 140 if handleName == 'fromHandle': 141 return higherThanProp + lowerThanProp 142 else: 143 lowerThanProp.reverse() 144 higherThanProp.reverse() 145 return lowerThanProp + higherThanProp 146 147 def IsOverMaxRange(self, fromProp, toProp): 148 if self._maxRange is None: 149 return False 150 adjustedToProp = self.GetAdjustedToProporations(fromProp, toProp) 151 rangeProp = adjustedToProp - fromProp 152 if FloatCloseEnough(rangeProp, self._maxRange): 153 return False 154 return rangeProp > self._maxRange 155 156 def GetAdjustedToProporations(self, fromProp, toProp): 157 if fromProp > toProp: 158 return toProp + 1.0 159 return toProp 160 161 def MoveHandle(self, handle, *args): 162 if getattr(handle, 'grab', None): 163 x, y = handle.grab 164 l, t, w, h = handle.parent.GetAbsolute() 165 handle.left = pos = min(w - handle.width, max(0, uicore.uilib.x - x - l)) 166 r = w - handle.width 167 proportion = pos / float(r) 168 incrementData = None 169 closest = self.RoundToIncrement(proportion) 170 if closest is not None: 171 proportion = closest 172 if not self._canInvert: 173 if handle is self._fromHandle: 174 self._fromProportion = min(proportion, self._toProportion) 175 if handle is self._toHandle: 176 self._toProportion = max(proportion, self._fromProportion) 177 else: 178 if handle is self._fromHandle: 179 self._fromProportion = proportion 180 if handle is self._toHandle: 181 self._toProportion = proportion 182 self.UpdateRanges() 183 self.UpdateHandles() 184 self._DoOnChangeCallback() 185 186 def StartMoveRange(self, rangeParent, btn): 187 l, t, w, h = rangeParent.GetAbsolute() 188 rangeParent.startProportion = ((uicore.uilib.x - l) / float(w), self._fromProportion, self._toProportion) 189 190 def StopMoveRange(self, rangeParent, btn): 191 rangeParent.startProportion = None 192 if self.OnEndDragChange: 193 self._DoOnChangeCallback(onEndDrag=True) 194 195 def MoveRange(self, rangeParent, *args): 196 if getattr(rangeParent, 'startProportion', None): 197 l, t, w, h = rangeParent.GetAbsolute() 198 newProportion = (uicore.uilib.x - l) / float(w) 199 startProportion, fromProportion, toProportion = rangeParent.startProportion 200 diff = newProportion - startProportion 201 if fromProportion > toProportion: 202 if diff < 0: 203 self._toProportion = max(0.0, toProportion + diff) 204 self._fromProportion = self._toProportion + (fromProportion - toProportion) 205 else: 206 self._fromProportion = min(1.0, fromProportion + diff) 207 self._toProportion = self._fromProportion - (fromProportion - toProportion) 208 elif diff < 0: 209 self._fromProportion = max(0.0, fromProportion + diff) 210 self._toProportion = self._fromProportion + (toProportion - fromProportion) 211 else: 212 self._toProportion = min(1.0, toProportion + diff) 213 self._fromProportion = self._toProportion - (toProportion - fromProportion) 214 closest = self.RoundToIncrement(self._fromProportion) 215 if closest is not None: 216 self._fromProportion = closest 217 closest = self.RoundToIncrement(self._toProportion) 218 if closest is not None: 219 self._toProportion = closest 220 self.UpdateRanges() 221 self.UpdateHandles() 222 self._DoOnChangeCallback() 223 224 def SetMinRange(self, minRange): 225 self._minRange = minRange 226 self.UpdateRanges() 227 self.UpdateHandles() 228 229 def SetMaxRange(self, maxRange): 230 isChanging = self._maxRange != maxRange 231 self._maxRange = maxRange 232 self._EnforceMaxRange(self._toHandle) 233 self.UpdateRanges() 234 self.UpdateHandles() 235 if isChanging: 236 self._DoOnChangeCallback(True) 237 238 def SetFixedRange(self, fixedFromProportion = None, fixedToProportion = None): 239 self._fixedFromProportion = fixedFromProportion 240 if fixedFromProportion is not None: 241 self._fromProportion = fixedFromProportion 242 self._fromHandle.display = False 243 self._fromRange._pointer.display = False 244 else: 245 self._fromHandle.display = True 246 self._fromRange._pointer.display = True 247 self._fixedToProportion = fixedToProportion 248 if fixedToProportion is not None: 249 self._toProportion = fixedToProportion 250 self._toHandle.display = False 251 self._toRange._pointer.display = False 252 else: 253 self._toHandle.display = True 254 self._toRange._pointer.display = True 255 self.UpdateRanges() 256 self.UpdateHandles() 257 258 def SetIncrements(self, increments): 259 self._incrementsParent.Flush() 260 maxMarkerSize = 0 261 labels = [] 262 self._increments = [] 263 if increments: 264 last = increments.pop(-1) 265 stepSize = 1.0 / len(increments) 266 c = GridContainer(parent=self._incrementsParent, lines=1, columns=len(increments)) 267 i = 0 268 for incrementData in increments: 269 label = incrementData[0] 270 markerSize = incrementData[1] 271 inc = Container(parent=c, align=uiconst.TOALL) 272 if markerSize: 273 maxMarkerSize = max(maxMarkerSize, markerSize) 274 Line(parent=inc, align=uiconst.TOPLEFT, width=1, height=markerSize) 275 self._increments.append((i * stepSize, incrementData)) 276 if label: 277 if label.startswith('res:'): 278 s = Sprite(parent=inc, texturePath=label, width=16, height=16, align=uiconst.CENTER, idx=0, top=-2, color=(1, 1, 1, 0.7)) 279 labels.append(s) 280 else: 281 l = eveLabel.EveLabelSmall(parent=inc, text=label, left=-MAINSIDEMARGIN) 282 if i == 0: 283 l.left = max(-MAINSIDEMARGIN, -l.textwidth / 2) 284 else: 285 l.left = -l.textwidth / 2 286 labels.append(l) 287 i += 1 288 289 label = last[0] 290 markerSize = last[1] 291 inc = Container(parent=self._incrementsParent, align=uiconst.TORIGHT, width=1, idx=0) 292 if markerSize: 293 maxMarkerSize = max(maxMarkerSize, markerSize) 294 Line(parent=inc, align=uiconst.TOPLEFT, width=1, height=markerSize) 295 self._increments.append((i * stepSize, last)) 296 if label: 297 if label.startswith('res:'): 298 s = Sprite(parent=inc, texturePath=label, width=16, height=16, align=uiconst.CENTER, idx=0, top=-2, color=(1, 1, 1, 0.7)) 299 labels.append(s) 300 else: 301 l = eveLabel.EveLabelSmall(parent=inc, text=label, align=uiconst.TOPRIGHT) 302 l.left = max(-MAINSIDEMARGIN, -l.textwidth / 2) 303 labels.append(l) 304 self._EnforceMaxRange(self._toHandle) 305 maxHeight = 0 306 for l in labels: 307 l.top += maxMarkerSize 308 maxHeight = max(l.top + l.height, maxHeight) 309 310 self._incrementsParent.height = maxHeight 311 self.height = sum([ each.height + each.padTop + each.padBottom for each in self.children if each.align == uiconst.TOTOP ]) 312 313 def RoundToIncrement(self, proportion, getIncrementData = False): 314 closest = None 315 closestDiff = None 316 closestData = None 317 if self._increments: 318 for increment, incrementData in self._increments: 319 diff = abs(proportion - increment) 320 if closestDiff is None or diff < closestDiff: 321 closest = increment 322 closestDiff = diff 323 closestData = incrementData 324 325 if getIncrementData: 326 return (closest, closestData) 327 return closest 328 329 def UpdateRanges(self): 330 if self._fixedFromProportion is not None: 331 fromProportion = self._fixedFromProportion 332 else: 333 fromProportion = self._fromProportion 334 if self._fixedToProportion is not None: 335 toProportion = self._fixedToProportion 336 else: 337 toProportion = self._toProportion 338 self._fromRange.width = fromProportion 339 self._toRange.width = toProportion 340 if fromProportion > toProportion: 341 self._toRange.parent.SetOrder(0) 342 self._toRange._background.SetColorType(uiconst.COLORTYPE_UIHILIGHT) 343 self._toRange._pointer.LoadTexture('res:/UI/Texture/classes/RangeSelector/rightPointer.png') 344 self._toRange._pointer.top = -7 345 self._fromRange._background.SetColorType(uiconst.COLORTYPE_UIBASECONTRAST) 346 self._fromRange._pointer.LoadTexture('res:/UI/Texture/classes/RangeSelector/leftPointerDown.png') 347 self._fromRange._pointer.top = 0 348 self._background.SetColorType(uiconst.COLORTYPE_UIHILIGHT) 349 else: 350 self._fromRange.parent.SetOrder(0) 351 self._fromRange._background.SetColorType(uiconst.COLORTYPE_UIBASECONTRAST) 352 self._fromRange._pointer.LoadTexture('res:/UI/Texture/classes/RangeSelector/leftPointer.png') 353 self._fromRange._pointer.top = -7 354 self._toRange._background.SetColorType(uiconst.COLORTYPE_UIHILIGHT) 355 self._toRange._pointer.LoadTexture('res:/UI/Texture/classes/RangeSelector/rightPointerDown.png') 356 self._toRange._pointer.top = 0 357 self._background.SetColorType(uiconst.COLORTYPE_UIBASECONTRAST) 358 359 def UpdateHandles(self): 360 l, t, w, h = self.GetAbsolute() 361 r = w - self._fromHandle.width 362 if self._fixedFromProportion is not None: 363 fromProportion = self._fixedFromProportion 364 else: 365 fromProportion = self._fromProportion 366 if self._fixedToProportion is not None: 367 toProportion = self._fixedToProportion 368 else: 369 toProportion = self._toProportion 370 self._fromHandle.left = int(r * fromProportion) 371 self._toHandle.left = int(r * toProportion) 372 373 def _DoOnChangeCallback(self, onEndDrag = False): 374 if self._callbackData != (self._fromProportion, self._toProportion): 375 if self.OnChange: 376 self.OnChange(self._fromProportion, self._toProportion) 377 if self.OnIncrementChange: 378 fromIncr, fromData = self.RoundToIncrement(self._fromProportion, getIncrementData=True) 379 toIncr, toData = self.RoundToIncrement(self._toProportion, getIncrementData=True) 380 self.OnIncrementChange(self, fromData, toData, fromIncr, toIncr) 381 self._callbackData = (self._fromProportion, self._toProportion) 382 if onEndDrag and self.OnEndDragChange: 383 fromIncr, fromData = self.RoundToIncrement(self._fromProportion, getIncrementData=True) 384 toIncr, toData = self.RoundToIncrement(self._toProportion, getIncrementData=True) 385 self.OnEndDragChange(self, fromData, toData, fromIncr, toIncr) 386 387 def _OnSizeChange_NoBlock(self, *args): 388 self.UpdateHandles() 389 390 391 class SizeCappedContainer(Container): 392 393 @apply 394 def displayRect(): 395 fget = Container.displayRect.fget 396 397 def fset(self, value): 398 Container.displayRect.fset(self, value) 399 ro = self.renderObject 400 if ro: 401 ro.displayWidth = max(0.0001, self._displayWidth) 402 ro.displayHeight = max(0.0001, self._displayHeight) 403 404 return property(**locals()) 405 406 @apply 407 def displayWidth(): 408 fget = Container.displayWidth.fget 409 410 def fset(self, value): 411 Container.displayWidth.fset(self, value) 412 ro = self.renderObject 413 if ro: 414 ro.displayWidth = max(0.0001, self._displayWidth) 415 416 return property(**locals()) 417 418 @apply 419 def displayHeight(): 420 fget = Container.displayHeight.fget 421 422 def fset(self, value): 423 Container.displayHeight.fset(self, value) 424 ro = self.renderObject 425 if ro: 426 ro.displayHeight = max(0.0001, self._displayHeight) 427 428 return property(**locals())