If you've done some programming you'll probably find nip very easy to
extend. This section sprints through a bit of it, see the programming chapter
(page ) for full details and a more formal definition of
the language.
The insides of nip are built with nip's own programming language. It's a pure lazy functional language, with classes. It's C's expression syntax (more or less) plus approximately Miranda/Haskell function syntax, plus some basic class stuff. nip's main window is a class browser for this programming language.
Click on File=>Program in nip's main window to pop up the programming window (see §4.5 for details on all the bits in the window), then in the edit area there type:
// add two things Fred a b = class { sum = a + b; }
This defines a class called Fred who's constructor takes two arguments, a and b. There's one member, called sum, which is a and b added together.
In the program window, click File=>Process text. This makes nip read what you typed, parse it, compile it and update itself. The program window should now look like Figure 2.10.
If you look back at the main nip window, a new top-level menu will have appeared called untitled. If you click on that, there will be a menu item called Fred. Let your mouse linger, and you'll see a tooltip too.
In the main window, type Fred 2 3 into the box at the bottom of the current column. Press Return and nip will make a Fred for you. Click on the down arrow to the left of your new Fred once to see the members of Fred (just sum in this case), click again to see the class parameters too. The main window should look like Figure 2.11.
Click to the right of b, type in a new value and press Return. The sum member should update. nip keeps track of dependencies between rows, but it also tracks dependencies inside rows, both ones that come from the class, and ones created by any edits you do to the class instance after creating it. You won't see it in a simple example, but nip also discovers and tracks dependencies which can arise at run time. Click on the text just to the right of the b button again, type a and press Return. Now edit a: press Return and both b and sum will update.
You can use Fred to add any two things together. Click on New=>New_slider to make a slider widget, press Ctrl-L (the keyboard shortcut for Edit=>Clone) to duplicate it, and finally click on untitled=>Fred. Open up the new Fred and try dragging some of the sliders around. The main window will look like Figure 2.12.
The sliders are classes too (instances of Slider). You can open them up and do strange things with them as well. Open up one of the sliders you made (eg. A2 in Figure 2.12) and change the from parameter to be A3.value. Now try dragging the sliders again.
Try dragging the sum slider. Now go back and drag one of the original sliders. You'll see that sum no longer updates, it's stuck at the last position you dragged it to. This is because there are now two things affecting the value of sum: the underlying code (the a + b inside Fred), and the position you dragged the slider representing sum to. nip has the rule that graphical edits (dragging the slider) override code. To make sum update again, right click on the sum button and select Clear edits from the pop up menu. Now drag one of the input sliders again, and sum will start updating once more.
Classes can inherit from other classes. Go back to the program window, click on File=>New=>Tool to clear the edit window, and type:
// multiply two things Jim a b = class Fred a b { product = a * b; }
This defines a class called Jim which inherits from Fred. Back in the main window, type Jim 4 5 into the bottom of the column. Click down once to expose the members (just product), click again to expose the parameters as well (a and b), and click a third time to expose the superclass member (which should be an instance of Fred). You can also open up the super member and see inside the Fred that this Jim is using as its superclass. See Figure 2.13
nip has about 15 different graphical classes like Slider. Whenever a row takes a new value, nip checks to see if that value is an instance of one of these special classes, and if it is, it will add a graphical element to the row display which represents that class's value. It builds the graphical part by looking inside the class for certain members (for example, the slider graphic looks for members called from, to and value). When you change the graphic (maybe by dragging the slider), nip rebuilds the class by looking inside for a edit member (eg. Slider_edit) or if that's not defined, a constructor member (eg. Slider).
You can make your own graphic widgets by subclassing nip's built-in ones. By selectively overriding default constructors and adding edit members, you can control how your new widget will behave in expressions, and how it will behave if it's edited graphically.
Make a new column, load up a sample image (use Insert=>Image from file), drag out two regions on it (double click on the thumbnail, hold down Ctrl and drag down and right). Your main window should look like Figure 2.14.
im_insert is a VIPS operation that puts one image inside another at an (x, y) position. VIPS operations work on VIPS images. The value member of an Image or Region is the VIPS image that underlies the nip row.
You can use im_insert to make a thing to join two images together. Back in the program window, click on File=>New=>Tool and enter:
// join two images left-right My_join a b = class Image value { shim = Slider 0 1000 0; value = im_insert a.value b.value (a.width + shim.value) 0; }
This defines a class My_join which subclasses the Image graphic. Don't be tempted to call it Join or even join. Both of these are already defined by the nip environment and lots of stuff will stop working if you redefine them.
Now select your two regions (click on the first one, shift-click on the second) and click on untitled=>My_join. A new My_join row will appear. Open it up and drag the slider to set the spacing between the two joined images. Go back to the image viewer for the image file you loaded and try dragging one of the regions. Figure 2.15 shows this class in action. The thing in Image=>Join=>Left_right is just a fancier version of this.