USING: accessors arrays combinators kernel locals math math.functions math.geometry math.ranges opengl opengl.gl opengl.glu processing.shapes sequences ui.gadgets ui.gadgets.worlds ui.render ui ui.gadgets.panes ; IN: good-ui-citizen ! The Factor user interface toolkit is OpenGL based. The graphical ! building blocks of the toolkit are called 'gadgets' (what other ! toolkits call 'widgets'). ! ! One nice thing about OpenGL is it's so easy to change the coordinate ! system to suit your needs (using the glOrtho function for ! example). ! ! However, the situation isn't so easy when you're implementing a new ! gadget which wants it's own coordinate system. When you write a new ! gadget, you have to ensure that it's a "good citizen" of the ui ! toolkit. It should play well with other gadgets. ! ! The litmus test for good behaviour is to call 'gadget.' on your ! gadget in a listener. It should render in the history without ! disturbing the rest of the workspace. ! ! The example below demonstrates how to construct a gadget which ! establishes it's own coordinate system. ! ! Unfortunately, it shouldn't be as difficult as it is. ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! Make a 'setup-viewport' word. ! ! This is an interface to 'gl-viewport' which establishes a viewport ! for a particular gadget in a window. ! ! Such a utility word should probably be offered as a part of the core ! ui library. ! ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! : screen-y* ( gadget -- loc ) { [ find-world height ] [ screen-loc second ] [ height ] } cleave + - ; : screen-loc* ( gadget -- loc ) { [ screen-loc first ] [ screen-y* ] } cleave 2array ; : setup-viewport ( gadget -- gadget ) dup { [ screen-loc* ] [ dim>> ] } cleave gl-viewport ; ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! Implement '' ! ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! A gadget which draws plots the sine curve from -10 to 10 TUPLE: < gadget ; ! Have a default size of 400x400 M: pref-dim* ( -- dim ) drop { 400 400 } ; ! Where all the magic happens M:: draw-gadget* ( SINE -- ) ! Switch to GL_PROJECTION mode. Save the matrix. Push identity matrix. GL_PROJECTION glMatrixMode glPushMatrix glLoadIdentity ! Establish our coordinate system -10 10 -10 10 gluOrtho2D ! Switch to GL_MODELVIEW mode. Save the matrix. Push identity matrix. GL_MODELVIEW glMatrixMode glPushMatrix glLoadIdentity ! Specify the viewport for ourself. SINE setup-viewport drop ! Do what we came here to do! -10 10 0.5 [ dup sin 2array ] map line-strip ! processing.shapes can change this mode. ! Make sure we're back in 'fill-mode' fill-mode ! Restore the GL_PROJECTION and GL_MODELVIEW matrices. GL_PROJECTION glMatrixMode glPopMatrix glLoadIdentity GL_MODELVIEW glMatrixMode glPopMatrix glLoadIdentity ! Restore the coordinate system that the ui world expects. SINE find-world { [ drop 0 ] [ width ] [ height ] [ drop 0 ] } cleave -1 1 glOrtho ! Restore the viewport for the world. SINE find-world setup-viewport drop ; ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! These words demo the gadget. The first will open in a ! new window. The second will output a to the listener ! history. : sine-gadget-window ( -- ) new-gadget "Sine" open-window ; : sine-gadget. ( -- ) new-gadget gadget. ; ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! Go forth, and write elegant Factor gadgets.