UI Elements everywhere

One of the most certifiably useful things that the text editor can do is embed GUI elements inside the main flow of the text. A simple right-click is all you need to start setting variables equal to sliders, graphs and other more esoteric objects. But this means that, to change a parameter, you have to open up the code and look for it. Sometimes this gets tedious and a little error prone: how about using TheCanvas as a place to put sliders, graphs and other things?

The following code snipped does just that:

slider1= sheetSlider("slider1")
xySlider2 = sheetXY("xySlider2")
aGraph = sheetGraph("aGraph")

print slider1.get()
print xySlider2.get()
print aGraph.get().get(0.2)

slider1.set(0.5)
xySlider2.set( (0.2, 0.6))

The first three lines, when executed, will make a slider (that lets you pick a single float between 0 and 1), an XYSlider (two floats) and a graph (a mapping from 0->1).

The latter two can be expanded, just like they can be expanded in the main editor:

Now these "important numbers" can be edited without opening up the body of the document

And they can also be resized by grabbing their right-most margin while holding down shift. More Canvas emebeddable widgets are coming soon (sheetCombo for example). Now that the framework is in place, anything that it makes sense to port over to the canvas will.

Tutorial

If you want to see more, the Canvas GUI Embedding features are covered in this downloadable tutorial.

sheet_X_() conventions

The signatures for the sheetSlider (and sheetXYSlider &c} functions are as follows (note, you can always get these by using ⌘-period completion):

def sheetSlider(name, initialValue=None, update=None):
....

Specifically you can set initialValue to be a value that is used only when the widget is created for the first time. You can optionally pass in a function to be called when the slider is updated.

So, in practice, you'll have something like:

def setBg(x):
    print "background now %f " % (x)

bgSlider = sheetSlider("bg color", initialValue=0.5, update=setBg)

See how the update method is called with a single argument — the function that you'd like called.

An important note about callbacks + the Processing Plugin

If you are using the Processing Plugin you should note that callbacks might not quite work as you'd expect. Sure the example above works if you use it in Field, even in an element that has been marked as being "bridged" to the Processing environment.

But this doesn't quite work:

def setBg(x):
    print "background now %f " % (x)
    # this call doesn't do what you'd expect
    background(255*x)

bgSlider = sheetSlider("bg color", initialValue=0.5, update=setBg)

It doesn't work because the callback gets called when you wiggle the slider which isn't when Processing is in the middle of drawing things. So you are ignored.

To fix this use the @InProcessing decorator:

@InProcessing
def setBg(x):
    print "background now %f " % (x)
    background(255*x)

bgSlider = sheetSlider("bg color", initialValue=0.5, update=setBg)

Placement

Sometimes it makes sense to have these on-sheet components off to the right hand side. Sometimes, however, it makes more sense to have these components below the element that made them:

The optional parameter below=1 makes this happen:

x = sheetSlider("banana", below=1)
y = sheetXY("peach", below=1)
z = sheetGraph("pear", below=1)

The most obvious use of this is that you can use graphs inside timelines for key-framey things:

In this case, mySlider.get().get(_t) will get you the value at the "time" of the slider. See VisualElementLifecycles for more on where _t comes from, on what that red bar is doing, see SubTimeSliders.

Deleting elements

Finally there's a sheetDeleteUI(name) function that eliminates UI things that you have created.

If you'd like to embed your own (or anybody else's) Swing components into the canvas, take a look at SwingIntegration.