def _SliderOnMotion(self, event): if not self._sliderDown: return # Calc current position in normalized units x0 = self._getNormalizedCurrentPos(event) # Reset before updating self._range = Range(self._refRange) # New normalized position dx = x0 + self._sliderRefx offset = self._fullRange.min if self._sliderDown == 1: # Move on left edge self._range.min = self._fullRange.range * dx + offset elif self._sliderDown == 3: # Move on right edge self._range.max = self._fullRange.range * dx + offset elif self._sliderDown == 2: # Move whole slider ra2 = self._refRange.range / 2.0 mi = self._fullRange.range * dx - ra2 + offset ma = self._fullRange.range * dx + ra2 + offset self._range.Set(mi,ma) # Limit and update self._limitRangeAndSetText() self._eventSliding.Set() self._eventSliding.Fire() self.Draw()
def __init__(self, parent): Box.__init__(self, parent) # init size self.position.w = 300 self.position.h = 40 # Slider specific stuff self._fullRange = Range(0,1) self._range = Range(0,1) self._refRange = Range(0,1) # For sliding self._showTicks = False # Set bgcolor and edge self.bgcolor = (0.6, 0.8, 0.6) self._frontColor = 0.5, 0.7, 0.9 self.edgeWidth = 1 # A slider should respond to mouse self.hitTest = True # Create label centered at the box self._label = Label(self) self._label.position = 0,0,1,1 self._label.halign = 0 self._label.bgcolor = None # State variables self._isOver = False self._sliderDown = False self._sliderRefx = 0.0 # Pool of labels for tickmarks, to reuse them self._wobjects = [] # So we can have Text objects self._labelPool = {} # Calculate dots now self._SliderCalcDots() # Create new events self._eventSliding = BaseEvent(self) self._eventSliderChanged = BaseEvent(self) # To changes appearance on mouse over self.eventEnter.Bind(self._SliderOnEnter) self.eventLeave.Bind(self._SliderOnLeave) # Bind to events self.eventMouseDown.Bind(self._SliderOnDown) self.eventMouseUp.Bind(self._SliderOnUp) self.eventMotion.Bind(self._SliderOnMotion) self.eventPosition.Bind(self._SliderCalcDots)
def _SliderOnDown(self, event): # Calc positions in normalized units x0 = self._getNormalizedCurrentPos(event) x1, x2 = self._getNormalizedSliderLimits() # Determine offset w,h = self.position.size offset = 8.0 / max(w,h) if x0 < x1+offset: # Move on left edge self._sliderDown = 1 self._sliderRefx = x1 - x0 elif x0 > x2-offset: # Move on right edge self._sliderDown = 3 self._sliderRefx = x2 - x0 else: self._sliderDown = 2 # Move middle self._sliderRefx = (x1+x2)/2.0 - x0 # Store original self._refRange = Range(self._range) # Update self.Draw()
def GetLimits(self): """ GetLimits() Get the limits of the 2D axes as currently displayed. This can differ from what was set by SetLimits if the daspectAuto is False. Returns a tuple of limits for x and y, respectively. Note: the limits are queried from the twod camera model, even if this is not the currently used camera. """ # get camera cam = self.camera if not isinstance(cam, cameras.TwoDCamera): cam = self._cameras['TwoDCamera'] # Calculate viewing range for x and y fx = abs(1.0 / cam._zoom) fy = abs(1.0 / cam._zoom) # correct for window size w, h = self.position.size w, h = float(w), float(h) if w / h > 1: fx *= w / h else: fy *= h / w # calculate limits tmp = fx / 2 / self.daspectNormalized[0] xlim = Range(cam._view_loc[0] - tmp, cam._view_loc[0] + tmp) tmp = fy / 2 / self.daspectNormalized[1] ylim = Range(cam._view_loc[1] - tmp, cam._view_loc[1] + tmp) # return return xlim, ylim
def SetLimits(self, rangeX=None, rangeY=None, rangeZ=None, margin=0.02): """ SetLimits(rangeX=None, rangeY=None, rangeZ=None, margin=0.02) Set the limits of the scene. For the 2D camera, these are taken as hints to set the camera view. For the 3D camear, they determine where the axis is drawn. Returns a 3-element tuple of visvis.Range objects. Parameters ---------- rangeX : (min, max), optional The range for the x dimension. rangeY : (min, max), optional The range for the y dimension. rangeZ : (min, max), optional The range for the z dimension. margin : scalar Represents the fraction of the range to add for the ranges that are automatically obtained (default 2%). Notes ----- Each range can be None, a 2 element iterable, or a visvis.Range object. If a range is None, the range is automatically obtained from the wobjects currently in the scene. To set the range that will fit all wobjects, simply use "SetLimits()" """ # Check margin if margin and not isinstance(margin, float): raise ValueError('In SetLimits(): margin should be a float.') # if tuples, convert to ranges if rangeX is None or isinstance(rangeX, Range): pass # ok elif hasattr(rangeX, '__len__') and len(rangeX) == 2: rangeX = Range(rangeX[0], rangeX[1]) else: raise ValueError( "Limits should be Ranges or two-element iterables.") if rangeY is None or isinstance(rangeY, Range): pass # ok elif hasattr(rangeY, '__len__') and len(rangeY) == 2: rangeY = Range(rangeY[0], rangeY[1]) else: raise ValueError( "Limits should be Ranges or two-element iterables.") if rangeZ is None or isinstance(rangeZ, Range): pass # ok elif hasattr(rangeZ, '__len__') and len(rangeZ) == 2: rangeZ = Range(rangeZ[0], rangeZ[1]) else: raise ValueError( "Limits should be Ranges or two-element iterables.") rX, rY, rZ = rangeX, rangeY, rangeZ if None in [rX, rY, rZ]: # find outmost range wobjects = self.FindObjects(base.Wobject) for ob in wobjects: # Ask object what it's limits are tmp = ob._GetLimits() if not tmp: continue tmpX, tmpY, tmpZ = tmp # Check for NaNs if tmpX.min * 0 != 0 or tmpX.max * 0 != 0: tmpX = None if tmpY.min * 0 != 0 or tmpY.max * 0 != 0: tmpY = None if tmpZ.min * 0 != 0 or tmpZ.max * 0 != 0: tmpZ = None # update min/max if rangeX: pass elif tmpX and rX: rX = Range(min(rX.min, tmpX.min), max(rX.max, tmpX.max)) elif tmpX: rX = tmpX if rangeY: pass elif tmpY and rY: rY = Range(min(rY.min, tmpY.min), max(rY.max, tmpY.max)) elif tmpY: rY = tmpY if rangeZ: pass elif tmpZ and rZ: rZ = Range(min(rZ.min, tmpZ.min), max(rZ.max, tmpZ.max)) elif tmpX: rZ = tmpZ # default values if rX is None: rX = Range(-1, 1) if rY is None: rY = Range(0, 1) if rZ is None: rZ = Range(0, 1) # apply margins if margin: if rangeX is None: tmp = rX.range * margin if tmp == 0: tmp = margin rX = Range(rX.min - tmp, rX.max + tmp) if rangeY is None: tmp = rY.range * margin if tmp == 0: tmp = margin rY = Range(rY.min - tmp, rY.max + tmp) if rangeZ is None: tmp = rZ.range * margin if tmp == 0: tmp = margin rZ = Range(rZ.min - tmp, rZ.max + tmp) # apply to each camera for cam in self._cameras.values(): cam.SetLimits(rX, rY, rZ) # return return rX, rY, rZ
def _GetPolarLimits(self): if not self._points: return None else: return Range(self._angs.min(), self._angs.max()), \ Range(self._mags.min(), self._mags.max())
def fset(self, value): if not isinstance(value, Range): value = Range(value) self._SetClim(value)
def __init__(self): self._colormap = Colormap() self._clim = Range(0, 1)
def fset(self, value): self._range = Range(value) self._limitRangeAndSetText() # self._eventSliderChanged.Set() self._eventSliderChanged.Fire()
class BaseSlider(Box): """ BaseSlider(parent) Abstract slider class forming the base for the Slider and RangeSlider classes. """ def __init__(self, parent): Box.__init__(self, parent) # init size self.position.w = 300 self.position.h = 40 # Slider specific stuff self._fullRange = Range(0,1) self._range = Range(0,1) self._refRange = Range(0,1) # For sliding self._showTicks = False # Set bgcolor and edge self.bgcolor = (0.6, 0.8, 0.6) self._frontColor = 0.5, 0.7, 0.9 self.edgeWidth = 1 # A slider should respond to mouse self.hitTest = True # Create label centered at the box self._label = Label(self) self._label.position = 0,0,1,1 self._label.halign = 0 self._label.bgcolor = None # State variables self._isOver = False self._sliderDown = False self._sliderRefx = 0.0 # Pool of labels for tickmarks, to reuse them self._wobjects = [] # So we can have Text objects self._labelPool = {} # Calculate dots now self._SliderCalcDots() # Create new events self._eventSliding = BaseEvent(self) self._eventSliderChanged = BaseEvent(self) # To changes appearance on mouse over self.eventEnter.Bind(self._SliderOnEnter) self.eventLeave.Bind(self._SliderOnLeave) # Bind to events self.eventMouseDown.Bind(self._SliderOnDown) self.eventMouseUp.Bind(self._SliderOnUp) self.eventMotion.Bind(self._SliderOnMotion) self.eventPosition.Bind(self._SliderCalcDots) @property def eventSliding(self): """ Event fired when the user is sliding the slider. This can occur manu times during one sliding-opertaion. """ return self._eventSliding @property def eventSliderChanged(self): """ Event fired when the user releases the moude while changing the slider. """ return self._eventSliderChanged @PropWithDraw def fullRange(): """ The full possible range for this slider. """ def fget(self): return self._fullRange def fset(self, value): self._fullRange = Range(value) self._limitRangeAndSetText() return locals() @PropWithDraw def showTicks(): """ Whether to show tickmarks (default False). """ def fget(self): return self._showTicks def fset(self, value): self._showTicks = bool(value) return locals() def _SliderOnEnter(self, event): self._isOver = True self.Draw() def _SliderOnLeave(self, event): self._isOver = False self.Draw() def _SliderOnDown(self, event): # Calc positions in normalized units x0 = self._getNormalizedCurrentPos(event) x1, x2 = self._getNormalizedSliderLimits() # Determine offset w,h = self.position.size offset = 8.0 / max(w,h) if x0 < x1+offset: # Move on left edge self._sliderDown = 1 self._sliderRefx = x1 - x0 elif x0 > x2-offset: # Move on right edge self._sliderDown = 3 self._sliderRefx = x2 - x0 else: self._sliderDown = 2 # Move middle self._sliderRefx = (x1+x2)/2.0 - x0 # Store original self._refRange = Range(self._range) # Update self.Draw() def _SliderOnMotion(self, event): if not self._sliderDown: return # Calc current position in normalized units x0 = self._getNormalizedCurrentPos(event) # Reset before updating self._range = Range(self._refRange) # New normalized position dx = x0 + self._sliderRefx offset = self._fullRange.min if self._sliderDown == 1: # Move on left edge self._range.min = self._fullRange.range * dx + offset elif self._sliderDown == 3: # Move on right edge self._range.max = self._fullRange.range * dx + offset elif self._sliderDown == 2: # Move whole slider ra2 = self._refRange.range / 2.0 mi = self._fullRange.range * dx - ra2 + offset ma = self._fullRange.range * dx + ra2 + offset self._range.Set(mi,ma) # Limit and update self._limitRangeAndSetText() self._eventSliding.Set() self._eventSliding.Fire() self.Draw() def _SliderOnUp(self, event): # Update values self._SliderOnMotion(event) # Release self._sliderDown = 0 # Update self._eventSliderChanged.Set() self._eventSliderChanged.Fire() def _limitRangeAndSetText(self): """ _limitRangeAndSetText() To limit the range of the slider and to set the slider text. Different slider implementation want to do this differently. """ pass # Abstact method def _getNormalizedCurrentPos(self, event): """ _getNormalizedCurrentPos(event) Get the current mouse position as a normalized range unit (between 0 and 1, with the fullRange as a references). """ w,h = self.position.size if w > h: return float(event.x) / self.position.width else: return float(event.y) / self.position.height def _getNormalizedSliderLimits(self): """ _getNormalizedSliderLimits() Get the current limits of the slider expressed in normalized units (between 0 and 1, with the fullRange as a references). """ # Short names R1 = self._range R2 = self._fullRange # factor = R2.range x1 = (R1.min - R2.min) / factor x2 = x1 + R1.range / factor # return x1, x2 def _GetBgcolorToDraw(self): """ Can be overloaded to indicate mouse over in buttons. """ clr = list(self._bgcolor) if self._isOver: clr = [c+0.05 for c in clr] return clr def _getformat(self): """ Get the format in which to display the slider limits. """ if self._fullRange.range > 10000: return '%1.4g' elif self._fullRange.range > 1000: return '%1.0f' elif self._fullRange.range > 100: return '%1.1f' elif self._fullRange.range > 10: return '%1.2f' else: return '%1.4g' def _SliderCalcDots(self, event=None): # Init dots dots1, dots2 = Pointset(2), Pointset(2) # Get width height w,h = self.position.size # Fill pointsets if w > h: i = 5 while i < h-5: dots1.append(2,i); dots1.append(5,i) dots2.append(-2,i); dots2.append(-5,i) i += 3 else: i = 5 while i < w-5: dots1.append(i,2); dots1.append(i,5) dots2.append(i,-2); dots2.append(i,-5) i += 3 self._dots1, self._dots2 = dots1, dots2 def OnDraw(self): # Draw bg color and edges Box.OnDraw(self) # Margin d1 = 2 d2 = d1+1 # Get normalize limits t1, t2 = self._getNormalizedSliderLimits() # Get widget shape w, h = self.position.size # Calculate real dimensions of patch if w > h: x1, x2 = max(d2, t1*w), min(w-d1, t2*w) y1, y2 = d1, h-d2 # dots1 = self._dots1 + Point(x1, 0) dots2 = self._dots2 + Point(x2, 0) # diff = abs(x1-x2) # self._label.textAngle = 0 else: x1, x2 = d2, w-d1 y1, y2 = max(d1, t1*h), min(h-d2, t2*h) # dots1 = self._dots1 + Point(0, y1) dots2 = self._dots2 + Point(0, y2) # diff = abs(y1-y2) # self._label.textAngle = -90 # Draw slider bit clr = self._frontColor gl.glColor(clr[0], clr[1], clr[2], 1.0) # gl.glBegin(gl.GL_POLYGON) gl.glVertex2f(x1,y1) gl.glVertex2f(x1,y2) gl.glVertex2f(x2,y2) gl.glVertex2f(x2,y1) gl.glEnd() # Draw dots if True: # Prepare gl.glColor(0,0,0,1) gl.glPointSize(1) gl.glDisable(gl.GL_POINT_SMOOTH) # Draw gl.glEnableClientState(gl.GL_VERTEX_ARRAY) if isinstance(self, RangeSlider) and diff>5: gl.glVertexPointerf(dots1.data) gl.glDrawArrays(gl.GL_POINTS, 0, len(dots1)) if diff>5: gl.glVertexPointerf(dots2.data) gl.glDrawArrays(gl.GL_POINTS, 0, len(dots2)) gl.glDisableClientState(gl.GL_VERTEX_ARRAY) if self._showTicks: # Reset color to black gl.glColor(0,0,0,1) # Draw ticks if w>h: p0 = Point(0, h) p1 = Point(w, h) delta = Point(0,3) halign, valign = 0, 0 xoffset, yoffset = -8, -2 else: p0 = Point(w, h) p1 = Point(w, 0) delta = Point(3,0) halign, valign = -1, 0 xoffset, yoffset = 5, -8 # Get tickmarks ticks, ticksPos, ticksText = GetTicks(p0, p1, self._fullRange) newLabelPool = {} linePieces = Pointset(2) for tick, pos, text in zip(ticks, ticksPos, ticksText): pos2 = pos + delta # Add line piece linePieces.append(pos); linePieces.append(pos2) # Create or reuse label if tick in self._labelPool: label = self._labelPool.pop(tick) else: label = Label(self, ' '+text+' ') label.bgcolor = '' # Position label and set text alignment newLabelPool[tick] = label label.halign, label.valign = halign, valign label.position.x = pos2.x + xoffset label.position.w = 16 label.position.y = pos2.y + yoffset # Clean up label pool for label in self._labelPool.values(): label.Destroy() self._labelPool = newLabelPool # Draw line pieces gl.glLineWidth(1) gl.glEnableClientState(gl.GL_VERTEX_ARRAY) gl.glVertexPointerf(linePieces.data) gl.glDrawArrays(gl.GL_LINES, 0, len(linePieces)) gl.glDisableClientState(gl.GL_VERTEX_ARRAY)
def fset(self, value): self._fullRange = Range(value) self._limitRangeAndSetText()