Slider Object customization

Is there an easy way to modify the existing Vision slider component? I would like to change the blue track color, and make the slider object a pointed shape, instead of the circle. I was hoping there would be a different pointer object on the exchange, but did not find anything. Was going to try to script one/ build my own, but figured I would see if anybody had any recommendations first.

Probably not; some more details in this thread:

I experimented with this, and I didn’t find it to difficult too do with layered shapes and scripting.
Here is the result:




image

Here is a tutorial for anybody who wants to replicate this:

  • Create a container named CustomSliderComponent
  • Use the rectangle tool to create a rectangle in the container named BackDrop that fills the entire container
  • Add a slider to the container, name it CoreComponent, and resize the slider, so it completely fills the container
  • Add a comma zero to the end of the background color to make the slider transparent:
  • image
  • Add four custom “Color” properties to the slider named backDropColor, leftOfPointerColor, rightOfPointerColor, and pointerColor. Then, set the colors to whatever you are going to want them to be
  • Bind the BackDrop’s “Stroke Paint” and “Fill Paint” properties to the Core Component’s backDropColor custom property
  • Use the rectangle tool again to draw a rectangle in the container that covers the entire slider, name it RightValues, and bind it’s “Stroke Paint” and “Fill Paint” properties to the rightOfPointerColor custom property of the CoreComponent:
  • image
  • Copy the RightValues rectangle, and paste a new rectangle directly on top of the copied rectangle. I recommend using Ctrl+P (Size and Position Dialog Box) to ensure that the new rectangle is exactly on top of the RightValues rectangle.
  • Give this new rectangle the name “LeftValues” and bind its “Fill Paint” and “Stroke Paint” properties to the CoreComponent’s leftOfPointerColor custom property. Lastly, change the width of the LeftValues rectangle to approximately half it the width of the slider:
  • image
  • Use the polygon tool to create a custom shape for the pointer within the container. Then, name the shape “Pointer” and bind its “Fill Paint” property to the “pointerColor” custom property of the CoreComponent:
  • image
  • The Project Browser should now look like this:
  • image
  • Add this script the Pointer’s mouseDragged event handler:
abslutePointerWidth = event.source.relWidth*(event.source.parent.getComponent('BackDrop').getSize().getWidth()/event.source.parent.getComponent('BackDrop').relWidth)
if event.x > event.source.parent.getComponent('BackDrop').getSize().getWidth()-abslutePointerWidth:
	system.gui.transform(event.source, event.source.parent.getComponent('BackDrop').getSize().getWidth()-abslutePointerWidth)
elif event.x < 0:
	system.gui.transform(event.source, 0)
else:
	system.gui.transform(event.source, event.x)
event.source.parent.getComponent('CoreComponent').value = int(event.source.parent.getComponent('CoreComponent').minimum+((event.source.parent.getComponent('CoreComponent').maximum-event.source.parent.getComponent('CoreComponent').minimum)*event.source.relX)/(event.source.parent.getComponent('BackDrop').relWidth-event.source.relWidth))
event.source.parent.getComponent('LeftValues').relWidth = (event.source.parent.getComponent('BackDrop').relWidth-event.source.relWidth)-((event.source.parent.getComponent('BackDrop').relWidth-event.source.relWidth)-event.source.relX)
  • Add this script to the CoreComponent’s mousePressed event handler:
if event.source.value > event.source.maximum:
	event.source.value = event.source.maximum
elif event.source.value < event.source.minimum:
	event.source.value = event.source.minimum	
event.source.parent.getComponent('Pointer').relX = ((event.source.parent.getComponent('BackDrop').relWidth-event.source.parent.getComponent('Pointer').relWidth)*(event.source.value-event.source.minimum))/(event.source.maximum-event.source.minimum)
event.source.parent.getComponent('LeftValues').relWidth = (event.source.parent.getComponent('BackDrop').relWidth-event.source.parent.getComponent('Pointer').relWidth)-((event.source.parent.getComponent('BackDrop').relWidth-event.source.parent.getComponent('Pointer').relWidth)-event.source.parent.getComponent('Pointer').relX)

I’ve tested this component in a published state with different window sizes and everything works. Here is the result:
image

image

5 Likes

I did a custom slider with mouse press action, tag value binding changed and Mouse dragged. I have start with the tutorial of @justinedwards.jle I just dont use the componant slider of igntion to do it. Its work fine but dont have the ability to use ‘snap to ticks’ and ‘defer update’ (This can be done for sure).The componant can be resize and use negative min and max value.

CustomSliderComponent.zip (12.8 KB)

3 Likes

I like your use of a linear scale instead of an actual slider for the core component. It works quite well!

2 Likes

And how could I adapt this code if the slider is in a vertical position? I tried to adapt it, but I'm not very good with coding. Can you help me? Below, I show how I tried to adapt it.

abslutePointerHeight = event.source.relHeight * (event.source.parent.getComponent('BackDrop').getSize().getHeight() / event.source.parent.getComponent('BackDrop').relHeight)
if event.y > event.source.parent.getComponent('BackDrop').getSize().getHeight() - abslutePointerHeight:
    system.gui.transform(event.source, event.source.parent.getComponent('BackDrop').getSize().getHeight() - abslutePointerHeight)
elif event.y < 0:
    system.gui.transform(event.source, 0)
else:
    system.gui.transform(event.source, event.y)

event.source.parent.getComponent('CoreComponent').value = int(event.source.parent.getComponent('CoreComponent').minimum + ((event.source.parent.getComponent('CoreComponent').maximum - event.source.parent.getComponent('CoreComponent').minimum) * event.source.relY) / (event.source.parent.getComponent('BackDrop').relHeight - event.source.relHeight))

event.source.parent.getComponent('LeftValues').relHeight = (event.source.parent.getComponent('BackDrop').relHeight - event.source.relHeight) - ((event.source.parent.getComponent('BackDrop').relHeight - event.source.relHeight) - event.source.relY)
if event.source.value > event.source.maximum:
    event.source.value = event.source.maximum
elif event.source.value < event.source.minimum:
    event.source.value = event.source.minimum

event.source.parent.getComponent('Pointer').relX = ((event.source.parent.getComponent('BackDrop').relWidth - event.source.parent.getComponent('Pointer').relWidth) * (event.source.value - event.source.minimum)) / (event.source.maximum - event.source.minimum)

event.source.parent.getComponent('LeftValues').relWidth = (event.source.parent.getComponent('BackDrop').relWidth - event.source.parent.getComponent('Pointer').relWidth) - ((event.source.parent.getComponent('BackDrop').relWidth - event.source.parent.getComponent('Pointer').relWidth) - event.source.parent.getComponent('Pointer').relX)
1 Like

Way back when I initially worked on this, I hadn't yet developed a reliable way to transform components within templates, so I relied on additional shapes embedded in the component to get relative dimensions. The way I do this sort of thing now is much simpler.

Here is a reworked vertical version of @gpellicelli's scale for you to study:
customVerticalSlider.zip (12.2 KB)

3 Likes

Thank you very much for your help. I really appreciate it

1 Like

I've been studying how CustomVerticalSlider works and I've understood some things, but not all. Right now, my knowledge still doesn't reach that level. I tried to adjust it to my need, which is to make the 'value' property bidirectional and be able to write to it from a numeric text field, but I was unsuccessful in trying to adapt it. Could you help me or give me a push to solve it?

It would be tricky to convert the way I scripted it. Basically, everything needs to be flipped around so the value drives the position instead of the position driving the value. That way, every movement of the pointer sets the value property, and then the propertyChange event handler can set the position.

...or the value can be set directly without the pointer being moved, and the propertyChange event handler will then set the position.

Basically, change this:

def getValueFromPosition(self, newPosition):
	# Get the min and max positions in pixels from the getMinMaxPositions custom method
	minPosition, maxPosition = self.getMinMaxPositions()
	
	# Get the min and max value custom property values from the template
	maxValue = self.parent.valueMax
	minValue = self.parent.valueMin
	
	# Determine how far newPosition is between minPosition and maxPosition as a fraction
	# Use a turnary operator to eliminate the possibility of dividing by zero
	ratio = ((newPosition - minPosition) / (maxPosition - minPosition)) if maxPosition != minPosition else 0
	
	# Scale the value to be between minValue and maxValue using the ratio
	scaledValue = maxValue - (ratio * (maxValue - minValue))
	
	# Set the new position custom property, so it will not need to be recalculated
	# ...by the propertyChange event handler that drives the transformations
	self.newPosition = newPosition
	
	# Assign the scaled value to the templates value property
	self.parent.value = scaledValue

to this:

def getPositionFromValue(self, newValue):
	# Get the min and max value custom property values from the template
	maxValue = self.parent.valueMax
	minValue = self.parent.valueMin
	
	# Get the min and max positions in pixels from the getMinMaxPositions custom method
	minPosition, maxPosition = self.getMinMaxPositions()
	
	# Determine how far the new value is between minPosition and maximum allowed value as a fraction
	# Use a turnary operator to eliminate the possibility of dividing by zero
	ratio = ((newValue - minValue) / (maxValue - minValue)) if maxValue != minValue else 0
	
	# Scale the value to be between minPosition and maxPosition using the ratio and return it as the newPosition for the pointer
	return maxPosition - (ratio * (maxPosition - minPosition))

Then, drive the transformation from the template's propertyChange event handler like this:

if event.propertyName == 'value':
	pointer = event.source.getComponent('Pointer')
	newPosition = pointer.getPositionFromValue(event.newValue)
	system.gui.transform(pointer, newY = newPosition)

In any case, I went ahead and updated the vertical slider, so it has the desired behavior. Here it is:
customVerticalSlider_v1.1.zip (13.0 KB)

1 Like