4. Ogre: Object Oriented GUI Toolkit




4.0. Introduction to Ogre


See: Graphics.
See: Events.


Lush provides all the necessary graphic primitives for programming a graphics interface.

It is rather easy to build simple graphic interfaces using these primitives. For instance, the function snpaint implements a simple drawing program for drawing lines and rectangles using low level primitives.

Graphic interfaces however become quickly complex. The class browser described in the last chapter of this document contains various features, like menus, buttons, requesters, selectors and scrollbars. A direct program would be overwhelmingly complex.

This is why people have developped various toolkits which handle automatically a large part of this complexity. The Ogre library is such a toolkit entirely written using the Lush object oriented language. This manual describes how to build programs with this library.

In the Ogre library, each component of a graphics interface, a button for example, is implemented as an object which is an instance of a subclass of class VisualObject .

The class of such an object defines both the appeareance of the object and its response to user input. Defining a new type of object (e.g. a menu) is thus just a matter of defining a new subclass of VisualObject .

There is a wide variety of such object classes:

There are two programming levels with the Ogre library. At the simplest level, you just use the provided classes for defining your interface. At the second level, you define subclasses of the standard Ogre classes in order to create new kind of graphic components.



4.1. Ogre Tutorial


Here is the transcript of a trivial call to the ogre library. You must first initialize the Ogre library by calling function ogre :
? (ogre)
 [ogre.lsh] (autoload)
= idle-hook

Let us then open a window ww containing a message string and a button arranged in a column named cc :

? (setq ww 
    (new windowobject 0 0 400 300 "Essai"
      (setq cc (new column (new string "Press button to beep")
                           (new stdbutton "Beeper"
                                    (lambda(c) (beep))) ) ) ) )
= ::windowobject:e3100

When you click on the button, the callback function (lambda(c) (beep)) is called and produces an audible beep. Let us add now a check box into the column:

? (==> cc insert (new checkbox "check me"  
                   (lambda(c) 
                        (printf "Check box state is %l\n" 
                                  (==> c getdata))))))
= ()

The callback function takes one argument. This argument is the check box object that we can query using method getdata . Let us add now an editable string named ee into the column:

? (==> cc insert (setq ee (new editstring 18 "hello")))  
;; Argument 18 is the field width.
= ()
? (==> ee setdata "hello people")
= ()
? (==> ee getdata)
= "hello people"

Again we can manipulate the state of the editable string using method setdata and getdata . You may have noticed that the button width has changed when we have inserted the editable string. The column indeed manage its contents in order to keep them properly aligned. We can indeed move and resize the column as a whole:

? (==> cc move 50 70)
= (50 20 129 84)
? (==> cc resize 250 120)
= (50 20 250 100)

We can even add into the column a small object which lets you move the column with the mouse:

? (==> cc insert (new dragarea 50 20))
= () 

Arguments 50 and 20 are the width and height of this object. Since the drag area is inserted into a column, its width is adjusted to the column width.

Let us add a row with two exclusive buttons:

? (==> cc insert (new row (new radiobutton "choice1")
                          (new radiobutton "choice2") ) )
= ()

We can get (or set) the complete state of the column with a single message getdata (or setdata ):

? (==> cc getdata)
= (() "hello people" () t)
? (==> cc setdata '(t "goodbye" t ()))
= ()

The Ogre library provides many more complex object, as shown in the following example:

? (setq h (new filerequester ww))
= ::filerequester:f3ef0
? (==> h popup)
= ::filerequester:f3ef0
? (==> h getdata)
= "/home/leon"

Let us add now a button for destoying the window.

? (==> ww insert (new stdbutton "Bye Bye." 
                     (lambda(c) (==> thiswindowobject delete)) ) )
= ()

This button ends the tutorial.



4.1.0. Calling Ogre in a Lush Script


Ogre provides a simple way to write GUI applications. The best way to turn an Ogre program into a standalone application is to write an executable Lush script.

Here is an example of a very Lush script that opens up an Ogre window and runs until that window is closed by the user:

  #!/bin/sh
  exec lush "$0" "$@"
  !#
  ;; A simple Ogre GUI demo
  (ogre)
  (wait (new autowindowobject 10 10 100 100 "Simple Lush GUI Demo" 
          (new column
            (new stdbutton "    hit me    " (lambda (c) (printf "OUCH\n")))
           (new stdbutton "    feed me   " (lambda (c) (printf "CRUNCH\n"))))))
The wait function takes one argument. It causes Lush to sit around and keep processing events until the argument is nil. When the argument becomes nil (presumably as the result of processing an event), wait returns.

In the above example, the argument to wait is the WindowObject (i.e. the Ogre window) in which the buttons reside. When the user closes the window, this object is destroyed, hence wait returns, terminating the script.

Using wait in a script that runs an Ogre application is a necessity because scripts terminate as soon as the evaluation of the content of the script terminates. Since the constructors of Ogre applications return immediately (to allow for Ogre apps to run simultaneously with the Lush main prompt), the script woould open the Ogre window and terminate immediately if we did not use wait .



4.2. The Ogre Class Library


All the objects must interact in order to be drawn at the proper location and with the proper ordering. Similarly, user events (e.g. a mouse click) must be dispateched towards the object located below the mouse.

The kernel of the Ogre library ensures these interaction by defining how messages are propagated between the objects in a graphic interface.



4.2.0. Ogre Methods


Event dispatching is mostly performed by the Container class. A container dispatches the events messages to its children according to simple rules. Keyboard events are sent to the ``active'' object. All other events are sent to the object located under the mouse pointer.

Repainting is managed asynchronously. When you want to redraw an object, you must send a message expose to this object to tell the Ogre system to schedule a repainting operation. When the system becomes idle, the Ogre library sends a repaint message to all objects to repaint with a proper ordering which ensures that the topmost objects are repainted last.

Similarly, you never change the location of an object directly. You send message move , resize or moveresize which tell the Ogre system to relocate an object. The Ogre library then enforces all the rules of the container objects, performs a global recomputation of the location of all objects and places the objects by sending them a message geometry .

In general, most operation on the Ogre objects are implemented using two messages.

When you want to perform a certain operation, you must call the request message and not the implementation message. The Ogre library will call the implementation message for you at a proper time and with the proper order.

When you define a new class of Ogre objects, you must define the implementation method only. The corresponding request message will be inherited from the superclass.

Here is a list of the most useful message pairs:

+-------------------+------------------+------------------+
| Operation         | Request          | Implementation   |
+-------------------+------------------+------------------+
| Drawing           | expose           | repaint          |
|                   |                  | repaint-bw       |
|                   |                  | repaint-color    |
|                   |                  | backpaint        |
|                   |                  | backpaint-bw     |
|                   |                  | backpaint-color  |
+-------------------+------------------+------------------+
| Moving            | move             | geometry         |
|   and resizing    | moverel          | manage-geometry  |
|                   | resize           | compute-geometry |
|                   | moveresize       |                  |
+-------------------+------------------+------------------+
| Making an         | insert           | realize          |
|   object visible  | remove           |                  |
+-------------------+------------------+------------------+



4.2.1. Ogre Class Hierarchy


There are in fact two major kinds of classes:

Here is a display of the current class hierarchy in the Ogre library. Classes displayed with a star are the abstract classes.

  visualobject *
    control *
      editstring
        editnumber
        editsecretstring
      button *
        stdbutton
          tinybutton
        checkbox
          radiobutton
        filereqbutton
      menuitem
      knob *
        dragarea
        sizearea
      slider *
        hslider
        vslider
        scrollbar *
          hscrollbar
          vscrollbar
      textpane
    container *
      form *
        windowobject *
          autowindowobject *
        requester
          warningrequester
          errorrequester
          yesnorequester
            filerequester
            printrequester
         viewer
         selector
         edittext
       column
         menupopup
       row
       grid
       frame
         framesize
       viewerhole
    emptyspace
    darkspace
    string
    icon
    menu
      choicemenu

Here is the use of the main abstract classes:



4.3. Ogre Utility Functions




4.3.0. Initializing the Ogre library




4.3.0.0. (ogre)
[DE] (ogre.lsh)


A single function named Ogre loads and initializes the library. You must call this function on top of each file involved with a graphics interface. Function Ogre is often defined as an autoload function which loads the Ogre library and calls the actual Ogre function.

This function initializes the library and sets up the event dispatcher. In particular, it creates the object ogre-task and defines the functions event-hook and idle-hook . If the library was already initialized, function Ogre returns immediatly.



4.3.0.1. ogre-task
[VAR] (ogre.lsh)


See: (event-hook)
See: (idle-hook)
See: (process-pending-events)


The object located in variable ogre-task is set up by function ogre . This object performs three central tasks in the Ogre library:

When Lush is waiting for user commands on the standard input, the Ogre library manages events asynchronously. The user can thus either type lisp commands or activate graphic interfaces.

When a Lush program is running, however, the Ogre library manages events when the function process-pending-events is called. It is a good practice to call this function a few times during long programs.



4.3.0.2. (ogre-close-all)
[DE]


Closes all open ogre windows.



4.3.1. Error Handling in the Ogre Library


See: Errors in Lush.
See: (debug-hook)
See: Interruptions in Lush.
See: (break-hook)


The Ogre library runs Lush functions whenever an event occurs.

An error condition occurs when these functions are incorrectly designed. The error message is printed as usual, but you are not prompted for a debug toplevel.

An interruption occurs if you type Ctrl-C in the Lush console. The break message is printed as usual, but you are not prompted for a break toplevel.

If you wish to be prompted for these debugging utilities, you must redefine functions ogre-debug-hook and ogre-break-hook . Here is a simple way to achieve this:

        (setq ogre-debug-hook nice-debug-hook)
        (setq ogre-break-hook nice-break-hook)



4.3.2. Ogre Color Palette


Rendering a graphic interface strongly depends on the capabilities of your screen.

Ogre provides a way to test if you are using a black and white or a color screen. It also provides several utility functions for displaying three dimensional looking objects.



4.3.2.0. color-palette
[VAR] (ogre.lsh)


See: (color [ c ])


If you are using a black and white display, this variable contains the empty list. You can then select three colors using function color .

If you are using a color display, this variable contains an array containing the color numbers used by Ogre for displaying an object. Several variables are used to name these colors:

palette-left                 (for rendering light)
palette-right                (for rendering shadow)
palette-up                   (for rendering raised objects)
palette-down                 (for rendering depressed objects)     
palette-disabled             (for rendering disabled texts)
palette-selected             (for rendering selected objects)



4.3.2.1. (new-palette r g b)
[DE] (ogre.lsh)


See: (alloccolor r g b )
See: (==> windowobject palette p )


This function creates a new palette array whose dominant color is defined by its RGB component r , g and b .

You can then store the resulting array into variable color-palette for redefining the default palette. You can also pass the new palette to an existing window object using message palette .



4.3.2.2. (getcolor colname)
[DE] (ogre.lsh)


See: (color [ c ])


This function returns the color number for the color named n in the current palette. Although any number can be passed as argument n , we suggest using one of the predefined symbols palette-left , palette-right , palette-up , palette-down , palette-disabled or palette-selected for specifying a color. The resulting color number can then be applied using function color .

This function is equivalent to:

  (color-palette <colname>)



4.3.2.3. (setcolor colname)
[DE] (ogre.lsh)


See: (color [ c ])


This function sets the current color to the color named n in the current palette. Although any number can be passed as argument n , we suggest using one of the predefined symbols palette-left , palette-right , palette-up , palette-down , palette-disabled or palette-selected for specifying a color.

This function is equivalent to:

  (color (getcolor <colname>))



4.3.2.4. (fill-background x y w h)
[DE] (ogre.lsh)


See: (fill-rect x y w h )


This function fills a rectangle with the background color palette-up of the current palette. The 3d rendering functions are designed for being called on such a background.



4.3.2.5. (draw-up-rect x y w h)
[DE] (ogre.lsh)


See: (draw-rect x y w h )


This function draws the border of a rectangle using the colors defined in the current palette. The border only is drawn and appears as a slightly raised line.



4.3.2.6. (draw-up-round-rect x y w h)
[DE] (ogre.lsh)


See: (draw-round-rect x y w h [ r ])


This function draws the border of a rectangle with round corners using the colors defined in the current palette. The border only is drawn and appears as a slightly raised line.



4.3.2.7. (fill-up-rect x y w h [c])
[DE] (ogre.lsh)


See: (fill-rect x y w h )


This function fills a rectangle using color number c and draws a border in order to give the illusion of a rectangle located above the background.

The default value for c is the color number indicated by palette-up .



4.3.2.8. (fill-down-rect x y w h [c])
[DE] (ogre.lsh)


See: (fill-rect x y w h )


This function fills a rectangle with the color number c and draws a border in order to give the illusion of a rectangle located below the background.

The default value for c is the color number indicated by palette-down .



4.3.2.9. (fill-up-round-rect x y w h [c])
[DE] (ogre.lsh)


See: (fill-round-rect x y w h [ r ])


This function fills a rectangle with round corners using color number c and draws a border in order to give the illusion of a rectangle located above the background.

The default value for c is the color number indicated by palette-up .



4.3.2.10. (fill-down-round-rect x y w h [c])
[DE] (ogre.lsh)


See: (fill-round-rect x y w h [ r ])


This function fills a rectangle with round corners using the color number c and draws a border in order to give the illusion of a rectangle located below the background.

The default value for c is the color number indicated by palette-down .



4.3.2.11. (fill-up-circle x y r [c])
[DE] (ogre.lsh)


See: (fill-circle x y r )


This function fills a circle using color number c and draws a border in order to give the illusion of a circle located above the background.

The default value for c is the color number indicated by palette-up .



4.3.2.12. (fill-down-circle x y r [c])
[DE] (ogre.lsh)


See: (fill-circle x y r )


This function fills a circle using color number c and draws a border in order to give the illusion of a circle located below the background.

The default value for c is the color number indicated by palette-down .



4.3.3. Ogre Fonts


Font names used by the font function used to be device dependent. A couple of functions have been defined for selecting fonts in a device independent way.



4.3.3.0. (ogre-font size [serifp [monospacep [boldp [italicp]]]])
[DE]


Selects a font of size size. The font family is chosen according to flags serifp and monospacep . The style is chosen according to flags boldp and italicp .



4.3.3.1. (font-18)
[DE] (ogre.lsh)


Convenience function. Same as (ogre-font 18 () () () ()) .



4.3.3.2. (font-12b)
[DE] (ogre.lsh)


Convenience function. Same as (ogre-font 12 () () t ()) .



4.3.3.3. (font-12)
[DE] (ogre.lsh)


Convenience function. Same as (ogre-font 12 () () () ()) .



4.3.3.4. (font-8f)
[DE] (ogre.lsh)


Convenience function. Same as (ogre-font 12 () t () ()) .



4.3.3.5. (font-8)
[DE] (ogre.lsh)


Convenience function. Same as (ogre-font 8 () () () ()) .



4.4. Visual Objects


Class VisualObject is the root of the Ogre class tree and defines the default appearance (nothing) and the default response to user input (nothing too) of a graphics interface component.

Class VisualObject however defines most request messages which are inherited by the graphic components. It also defines the default implementation of most implementation messages.

Four slots are defined by class VisualObject :

(defclass visualobject object
  (rect (0 0 0 0))
  oldrect
  itscontainer
  window )


4.4.0. (new VisualObject w h)
[CLASS] (ogre.lsh)


Creates and return a new instance of class VisualObject . Arguments w and h are the width and the height of the object.

This constructor is seldom used for creating new instances. Derived classes (e.g. Control ) usually call this constructor method within their own constructor method in order to initialize the VisualObject part of their instances.



4.4.1. VisualObject Request Messages


Class VisualObject defines request messages inherited by most other objects for performing two central tasks:

Unless you have a thorough knowledge of the internals of Ogre, you should neither redefine nor override these messages when defining a subclass of VisualObject .



4.4.1.0. (==> VisualObject expose [rect])
[MSG] (ogre.lsh)


Message expose tells the Ogre library that a visual object needs to be repainted. Argument rect indicates with more accuracy which rectangle in the current window must be repainted. When argument rect is ommited, the entire object rectangle is considered.

Exposure messages are propagated down until they reaches the window object. The clipped rectangle are then added to the damaged area list. Repainting is usually performed when the event queue becomes empty.



4.4.1.1. (==> VisualObject repair-damaged)
[MSG] (ogre.lsh)


Message repair-damaged starts the repainting operation without delay. When this message is sent to an Ogre object, the Ogre system immediatly repaints the damaged areas.



4.4.1.2. (==> VisualObject moveresize x y w h)
[MSG] (ogre.lsh)


Message moveresize ask the Ogre library to redefine the rectangle associated to an Ogre object. Arguments x and y are the coordinates of the topleft corner of the rectangle. Arguments w and h are respectively the width and the height of the rectangle.

This request is then signaled to the object's container which gets a chance to redefine its own geometry and to enforce a particular layout. When these recomputations are finished, the Ogre library effectively calls method geometry to relocate the objects.



4.4.1.3. (==> VisualObject move x y)
[MSG] (ogre.lsh)


Message move is used for changing the location of the topleft corner of the object's rectangle to coordinates x and y . It actually calls method moveresize .



4.4.1.4. (==> VisualObject moverel xr yr)
[MSG] (ogre.lsh)


Message moverel is used for adding xr and yr to the coordinates of the topleft corner of the object's rectangle. It actually calls method moveresize .



4.4.1.5. (==> VisualObject resize w h)
[MSG] (ogre.lsh)


Message resize is used for changing the width and height of the object's rectangle to w and h . It actually calls method moveresize .



4.4.1.6. (==> VisualObject geometry x y w h)
[MSG] (ogre.lsh)


See: (==> Container manage-geometry)
Method geometry performs a geometry change on a given object. Unlike method moveresize , the change takes place immediatly with all the overhead of recomputing the global position of all objects.

Method geoemtry is normally called by the method manage-geometry defined by the container objects for enforcing a particular layout. You may call this method directly (this is a backward compatibility requirement), although it is more efficient to use method moveresize .



4.4.1.7. (==> VisualObject front x y w h)
[MSG] (ogre.lsh)


See: (==> Container manage-geometry)
Although the repainting process becomes inefficient, object rectangles may overlap. Methods front performs an immediate geometry change and places the object on top of the object stack.



4.4.1.8. (==> VisualObject back x y w h)
[MSG] (ogre.lsh)


See: (==> Container manage-geometry)
Although the repainting process becomes inefficient, object rectangles may overlap. Methods back performs an immediate geometry change and places the object at the bottom of the object stack.



4.4.2. VisualObject Implementation Methods


Implementation methods are overriden by each subclass of VisualObject in order to define the behavior of each type of object. Class VisualObject provides a default implementation for four types of implementation methods:

4.4.2.0. (==> VisualObject realize window)
[MSG] (ogre.lsh)


This method is called whenever an object is associated to a window (realized) or dissociated from a window (unrealized).

The default definition of method realize is given below.

(defmethod visualobject realize (w)
  (when (setq window w)
    (==> this compute-geometry)
    (==> itscontainer change-geometry) )
  (==> this expose rect) )

Subclasses of VisualObject may override this default definition. The new definition however must call the superclass method realize in order to perform the essential tasks described above.

Before overriding method realize , you should also consider overriding method compute-geometry instead of method realize .



4.4.2.1. (==> VisualObject compute-geometry)
[MSG] (ogre.lsh)


Method compute-geometry is called when the object is realized and when a change of the object state changes the geometry requirements of the object.

This method must either return an empty list or compute the minimal size of the object's rectangle and enforce this minimal size by sending a message resize and return the new rectangle rect .

The default method compute-geometry just returns the empty list. Class String for instance overrides this method to compute the size of the string text and resizes the string object to the correct size.



4.4.2.2. (==> VisualObject backpaint)
[MSG] (ogre.lsh)


Method backpaint is called by the Ogre library for repainting the background of an object. In the case of a container object, this method is called before repainting the contents of the object.

The default method backpaint tests wether you have a black and white or a color display and calls method backpaint-bw or backpaint-color respectively. It is therefore advisable to override methods backpaint-bw and backpaint-color instead of backpaint .



4.4.2.3. (==> VisualObject backpaint-bw)
[MSG] (ogre.lsh)


Method backpaint-bw is called by the Ogre library for repainting the background of an object on a black and white display. In the case of a container object, this method is called before repainting the contents of the object.

The default backpaint-bw method just clears the object's rectangle with the background color color-bg . This is suitable for most cases.



4.4.2.4. (==> VisualObject backpaint-color)
[MSG] (ogre.lsh)


Method backpaint-bw is called by the Ogre library for repainting the background of an object on a color display. In the case of a container object, this method is called before repainting the contents of the container object.

The default backpaint-color method just clears the object's rectangle with the background color defined in the current palette. This is suitable for most cases.



4.4.2.5. (==> VisualObject repaint)
[MSG] (ogre.lsh)


Method repaint is called by the Ogre library for repainting the foreground of an object. In the case of a container object, this method is called after repainting the contents of the container object.

The default method repaint tests wether you have a black and white or a color display and calls method repaint-bw or repaint-color respectively. It is therefore advisable to override methods repaint-bw and repaint-color instead of repaint .



4.4.2.6. (==> VisualObject repaint-bw)
[MSG] (ogre.lsh)


Method repaint is called by the Ogre library for repainting the foreground of an object on a black and white display. In the case of a container object, this method is called after repainting the contents of the container object.

The default method repaint-bw does nothing.



4.4.2.7. (==> VisualObject repaint-color)
[MSG] (ogre.lsh)


Method repaint is called by the Ogre library for repainting the foreground of an object on a color display. In the case of a container object, this method is called after repainting the contents of the container object.

The default method repaint-color does nothing.



4.4.3. Event Methods


See: (==> Control activate d )
See: Events.


Whenever the user performs certain mouse of keyboard actions, the Lush kernel generates an event as explained in the preceding chapter.

When the Ogre library detects an event in a window, it builds an ordered list of objects eligible for handling the event. An event message is then send to the object with highest priority. If the event method returns the symbol ignored , the library proceed with the next object in the ordered list. This process stops as soon as an object accepts the event (i.e. until an event message returns a value different from symbol ignored .)

Starting with the highest priority, the objects eligible for receiving event messages are:

Class VisualObject defines a default method for the event messages. These default methods just reject the event by returning symbol ignored .

In practice, the default event rejection mechanism ensures that mouse events are handled by the object located below the mouse cursor and keyboard events are handled by the actived objects. It is however possible to change these settings by overriding the event methods of objects with a higher priority.



4.4.3.0. (==> VisualObject mouse-down x1 y1)
[MSG] (ogre.lsh)


See: (eventinfo)


Method mouse-down is called when the mouse button is depressed. Arguments x1 and y1 indicate the location of the mouse cursor in the current window when the mouse button has been depressed.

You can use function eventinfo to find the name of the mouse button and the state of the shift and control keys. Names returned by function eventinfo are quite machine dependent however.



4.4.3.1. (==> VisualObject mouse-drag x1 y1 x2 y2)
[MSG] (ogre.lsh)


Method mouse-drag is called whenever the mouse is moved while the mouse button is depressed. Arguments x1 and y1 indicate the location of the mouse cursor in the current window when the mouse button was first depressed. Arguments x2 and y2 indicate the coordinates of the mouse cursor after the move.



4.4.3.2. (==> VisualObject mouse-up x1 y1 x2 y2)
[MSG] (ogre.lsh)


Method mouse-up is called when the mouse button is released. Arguments x1 and y1 indicate the location of the mouse cursor in the current window when the mouse button was first depressed. Arguments x2 and y2 indicate the coordinates of the mouse cursor when the button was released.



4.4.3.3. (==> VisualObject keypress c x y)
[MSG] (ogre.lsh)


Method keypress is called whenever an ASCII key is hit. Argument c is a string which contains a single character for that key. Arguments x and y are the location of the mouse cursor when the key was hit.



4.4.3.4. (==> VisualObject arrow-left x y)
[MSG] (ogre.lsh)


See: (eventinfo)


Method arrow-left is called whenever the user types the left arrow key. Arguments x and y are the location of the mouse cursor when the key was hit.

You can use function eventinfo to find the exact name of the key and the state of the shift and control keys. Key names returned by function eventinfo are quite machine dependent however.



4.4.3.5. (==> VisualObject arrow-right x y)
[MSG] (ogre.lsh)


See: (eventinfo)


Method arrow-right is called whenever the user types the right arrow key. Arguments x and y are the location of the mouse cursor when the key was hit.

You can use function eventinfo to find the exact name of the key and the state of the shift and control keys. Key names returned by function eventinfo are quite machine dependent however.



4.4.3.6. (==> VisualObject arrow-up x y)
[MSG] (ogre.lsh)


See: (eventinfo)


Method arrow-up is called whenever the user types the up arrow key. Arguments x and y are the location of the mouse cursor when the key was hit.

You can use function eventinfo to find the exact name of the key and the state of the shift and control keys. Key names returned by function eventinfo are quite machine dependent however.



4.4.3.7. (==> VisualObject arrow-down x y)
[MSG] (ogre.lsh)


See: (eventinfo)


Method arrow-down is called whenever the user types the down arrow key. Arguments x and y are the location of the mouse cursor when the key was hit.

You can use function eventinfo to find the exact name of the key and the state of the shift and control keys. Key names returned by function eventinfo are quite machine dependent however.



4.4.3.8. (==> VisualObject help x y)
[MSG] (ogre.lsh)


See: (eventinfo)


Method help is called whenever the user types the system dependent help key. Arguments x and y are the location of the mouse cursor when the key was hit.

The help key under Windows is function key F1. The help key under X11 can be configured using program xmodmap .

You can use function eventinfo to find the exact name of the key and the state of the shift and control keys. Key names returned by function eventinfo are quite machine dependent however.



4.4.3.9. (==> VisualObject fkey x y)
[MSG] (ogre.lsh)


See: (eventinfo)


Method fkey is called whenever the user types a key which does not correspond to an ASCII character and yet cannot be processed as an arrow key or a help key. You must then use function eventinfo to analyze the keyname and process the event.

Since key names returned by function eventinfo are quite machine dependent, your event handling procedure should use this name as a hint rather than expecting well defined values.

Remark: All operating systems define certain hot keys for various purposes. Lush cannot override these assignments. Under Windows for instance, keys F9, F10 and CTRL-F4 are directly processed by the operating system and never passed to WinLush.



4.4.3.10. (==> VisualObject size w h)
[MSG] (ogre.lsh)


Method size is called whenever the geometry of an object changes in response to a user interaction or to a change in a related object.



4.5. Control Objects


See: Visual Objects.
See: Event Methods.


Class Control is the abstract class for interactive graphics objects like buttons, check boxes, menu items, etc...

Since class Control is a subclass of class VisualObject , all the properties and methods of class VisualObject also apply to class Control . In addition, class Control provides more support for defining the interactive graphics objects.



4.5.0. (new Control w h f)
[CLASS] (ogre.lsh)


See: Ogre Callbacks.


Creates and return a new instance of class Control . Arguments w and h are the width and the height of the control object. Argument f is the callback function for this control object.

This constructor is seldom used for creating new instances. Derived classes (e.g. Button ) usually call this constructor method within their own constructor method in order to initialize the Control part of their instances.



4.5.1. Enabling or Disabling a Control Object


When disabled, the control object ignores all user interaction. This is signalled by having the control rendered with a specific appearance. A disabled button on a black and white display is rendered with a dithering pattern. The label of disabled button on a color display is rendered with a light gray color instead of black.

The enabled/disabled status of a control object is stored in the slot disabled defined by class Control .

Implementation methods usually test slot disabled before performing their task. Repainting methods must change the rendering colors according to the enabled/disabled status of the object is disabled. Event methods must ignore event messages when the object is disabled.

Two request methods, enable and disable , are defined by class Control for changing the enabled/disabled status of an object:



4.5.1.0. (==> Control disable)
[MSG] (ogre.lsh)


If message disable is sent to an enabled control object, the object is disabled. If message disable is send to an already disabled control object, the object's disable count is increased.



4.5.1.1. (==> Control enable)
[MSG] (ogre.lsh)


When message enable is sent to a control object, the object's disable count is decreased by one. The object is enabled when this count reaches zero.

The disabled count feature proves useful for disabling an object either permanently or temporarily:



4.5.1.2. (new DisableLock c1...cn)
[CLASS] (ogre.lsh)


It is often useful to disable a button during the execution of some Lush program and to restore its initial state. This task could be achieved by sending messages disable and enable .

If however an error occurs during the program execution, the button would remain disabled. The best way to solve this problem consists in creating a lock object defined by class DisableLock .

If you wish to temporarily disable object c1 to cn , proceed as follows:

(let ((lock (new DisableLock c1...cn)))
        ;;; call your Lush program here
        (......) )

When created, the lock object sends a message disable to the objects c1 to cn . The lock is destroyed when you leave the let instruction. The lock destructor then sends a messages enable to our objects c1 to cn .

If an error occurs during the execution of the Lush program, the lock is destroyed by the garbage collector and the objects retrived to their initial state.



4.5.2. Activation of a Control Object


The active control object receives all the event messages that were not processed by the objects located below the mouse cursor. Only one object might be actived in a given window at a given instant.

Activation is especially useful for redirecting keyboard events toward objects containing some editable text. Having the keyboard events processed by the object located under the mouse often seems unnatural because the keyboard does not move physically like a mouse.

The user activates such an editable object with a mouse click in the object rectangle. It is customary in Ogre that the editable objects ignore the keyboard events unless they are active. Most keyboard events are then unconditionnally directed to the active object without regard to the position of the mouse cursor.

On the other hand, it is often useful to implement accelerator keys for performing tasks usually achieved by menu items or buttons. Accelerator key events must be defined by the containers managing the related objects. This definition ensures that accelerator keys events are not sent to the active object but handled directly.

The activation status of a control object is stored in slot activated (sic) defined by class Control . This slot contains a non nil value if the control object is active. Implementation methods of editable objects usually test slot activated before performing their task. Repainting methods must indicate the activation status of an object. Event methods must ignore event messages unless the object is actived.

Two request methods are defined by class Control for testing or changing the activation status of an object. These methods ensure that one object only is actived in a given window.



4.5.2.0. (==> Control activate d)
[MSG] (ogre.lsh)


Changes the activation status of the target object to d . If argument d is () , the target object is deactived. If argument d is t , the target object is actived and the previous active object is desactived.



4.5.3. Appearance of a Control Object


Class Control defines a slot named text which contains whatever data is useful for defining the appearance of a control object. In most cases so far, this slot contains a single string which is either a button label or a checkbox caption.

Two request methods are defined by class Control for obtaining and changing the contents of this slot:



4.5.3.0. (==> Control settext d)
[MSG] (ogre.lsh)


This request methods changes the contents of the slot text of the target object to the value given by argument d .

Since this change causes a general change in the object appearance, the object is sent a message compute-geometry for redefining its geometry requirements and a message expose for updating the display. Sending message settext sometimes triggers a global relocation of all objects in the window.



4.5.3.1. (==> Control gettext)
[MSG] (ogre.lsh)


This request method returns the contents of slot text . It is prefered to use this method rather than accessing directly the slot text because complex control objects may use other slots for controlling the appearance of the object.



4.5.4. State of a Control Object


Class Control defines a slot named data which contains whatever data is useful for storing the state of a control object resulting from the user interaction. For instance, slot data of a check box contains a boolean value. Similarly, slot data of an editable string contains the current value of the string.

Three methods hasdata , setdata and getdata are used for obtaining and changing the state of a control object. These methods are more implementation method than request methods. Several subclasses of Control override these methods in order to pre-process or post-process the state information.

These methods are mostly useful because they provide an abstract way to save and restore the state of a collection of control objects. For instance, a container object can save or restore the state of all its descendants with a single message.



4.5.4.0. (==> Control setdata d)
[MSG] (ogre.lsh)


This method changes the state of a control object to d

The default method sets the slot data of the target object to the value given by argument d . Since this change usually changes the object appearance, the object is sent a message expose for updating the display.



4.5.4.1. (==> Control getdata)
[MSG] (ogre.lsh)


This method returns the state of a control object.

The default method just returns the contents of slot data . It is prefered to use this method rather than accessing directly the slot data because complex control objects may use other slots for controlling the state of the object.



4.5.4.2. (==> Control hasdata)
[MSG] (ogre.lsh)


If an object contains some state information, this method returns the object itself. If an object contains no state information, this method returns the empty list.

Method hasdata is used to test if an object provides an adequate implementation for methods setdata and getdata . The default method hasdata indicated that there is some state information in the control object. Certain subclasses, like push button, override this method in order to signal that they carry no state information.



4.5.5. Ogre Callbacks


See: Window Objects.
See: Popup Requesters.
See: Forms.
See: Menus.


Each control object has a callback function. Callback functions are executed when certain event messages are received. For example, a push button executes the callback function when it is depressed.

Callbacks functions are called with one argument which is the caller object. They are executed within the caller scope and therefore directly access the slots of the caller object. In addition certain local variables are set:

Three methods are implemented by class Control for handling callback functions.



4.5.5.0. (==> Control setcall f)
[MSG] (ogre.lsh)


Message setcall redefines the callback function of a target object to be function f . Trouble will surely occur if the argument f is not a function with one argument or an empty list.



4.5.5.1. (==> Control execute)
[MSG] (ogre.lsh)


Message execute starts the callback function with the object itself as argument. The object is disabled while the callback function is running.



4.5.5.2. (==> Control trigger)
[MSG] (ogre.lsh)


Message trigger asks the object to simulate an user action. When a push button receives a trigger message, for example, it is drawn as depressed, executes the callback function and is redrawn as usual.

The default implementation defined by class Control just calls method execute . Subclasses of Control usually override method trigger by sending false event messages to the object.



4.6. Container Objects


See: Visual Objects.


Class Container is the abstract class for container objects. A container object manages several objects called its sons. Sons are only visible through the rectangle of the container. The container dispatches event messages, propagates repainting messages, controls the geometry of its sons and performs a couple of other critical tasks.

Since class Container is a subclass of class VisualObject , all the properties and methods of class VisualObject also apply for class Container . Class Container however defines new slots and new methods for handling container objects.

Subclasses of Container are very frequently defined for defining structuring container whose sons are arranged according to a certain layout. Classes Row and Column are examples of such subclasses.



4.6.0. (new Container x y w h ...contents...)
[CLASS] (ogre.lsh)


Creates a new container object. Arguments x , y , w and h describe the initial rectangle of the container object. The arguments denoted as ...contents... are graphical objects initially managed by the container object.

This constructor is seldom used for creating new instances. Derived classes (e.g. Row ) usually call this constructor method within their own constructor method in order to initialize the Control part of their instances.



4.6.1. Repainting


When it is time to repaint the contents of a container, the container object receives a message backpaint for rendering its background. The objects managed by the container are then rendered on top of this background. Finally the container object receives a message repaint for drawing above the managed objects.

During this operation, the clipping rectangle is the container object's rectangle. Only the portion of the sons which overlap the container's rectangle are rendered.



4.6.2. Inserting an Removing Objects


Three request method are implemented for inserting new objects into a container or removing inserted objects from a container.



4.6.2.0. (==> Container insert what)
[MSG] (ogre.lsh)


Inserts object what on top of the objects located in the container.

When an object is inserted into a container, the coordinates of the topleft corner of the container's rectangle are added to the coordinates of the object's rectangle. Therefore, if the initial rectangle of an object is located at cordinates (0, 0) , the object appears on the topleft corner of the container.

If there is a policy for the layout of the container, the new layout is computed and each object in the container is moved, resized and repainted.



4.6.2.1. (==> Container remove what)
[MSG] (ogre.lsh)


Removes object what from the container.

When an object removed from a container, the coordinates of the topleft corner of the container's rectangle are subtracted from the coordinates of the object's rectangle. Inserting the object again thus inserts the object at the same location with respect to the container's topleft corner.



4.6.2.2. (==> Container removall)
[MSG] (ogre.lsh)


Removes all objects managed by the container.



4.6.3. Geometry Management


Class Container implements the core of the geometry management system of the Ogre library. This system aims at providing containers with the opportunity of enforcing certain geometry policies on their sons. For instance:

These structuring containers make Ogre more attractive and easier to use than aksing the programmer to precompute the position of each object for all the interface configurations. Yet, geometry management is the most difficult component of the Ogre library.

Containers define the geometry policy using only two implementation methods, compute-geometry and manage-geometry . Here are the steps involved in a geometry computation:

The hidden part of the iceberg lies in the global computation of the object's location. If the container decides to change its geometry requirements during step 2, the container of the container then receives a message compute-geometry and gets a chance to participate to this geometry discussion. When this second container sets the first container's geometry, it calls the first container's method geometry which calls the first container's method manage-geometry and effectively performs step 3.

Important Note: The geometry management system has been significantly revamped in Lush. It is now faster and skinnier. Old programs still work correctly unless they redefine method geometry of class WindowObject .



4.6.3.0. (==> Container compute-geometry)
[MSG] (ogre.lsh)


The implementation method compute-geometry is called when the container is realized and when a change in their object state changes the geometry requirements of the object.

This method must compute the minimal size of the container on the basis of the information stored in the slots rect of the managed objects or cached in the list of managed objects stored in slot contents of the container. This method may enforce a minimal size by sending a message resize .

The default method compute-geometry just returns the empty list.

Example:

Class Row defines the following method compute-geometry which computes the minimal size of a row:

(defmethod row compute-geometry ()
  (when window
    (let* ((height (sup (cons 0 (all (((son x y w h) contents)) h))))
           (width (sum (all (((son x y w h) contents)) w))) )
      (==> this resize (+ width (* hspace (length contents))) height)
      rect ) ) )



4.6.3.1. (==> Container manage-geometry)
[MSG] (ogre.lsh)


The implementation method manage-geometry is called when it is time to locate the sons of the container on the basis of the final rectangle assigned to the container.

This method must compute the final rectangle of all the managed objects according to the container's rectangle (found in slot rect of the container) and according to the managed object initial rectangles (found in slot rect of the managed objects and cached in the list of managed objects located in slot contents of the container.) Method manage-geometry then sends a message geometry to the managed objects in order to assign a final rectangle to these objects.

The default method manage-geometry defined in class Container does nothing. A secondary mechanism just moves the managed objects in order to maintain their position with respect to the topleft corner of the container's rectangle.

Example:

Class Row defines the following method manage-geometry which arranges the managed objects in a row starting on the left of the container's rectangle.

(defmethod row manage-geometry ()
  (let (((x y w h) rect))
    (incr x (div hspace 2))
    (each ((i contents))
      (let ((w (nth 3 i)))  ;; get the object's width
         (==> (car i) geometry x y w h)
         (incr x (+ w hspace)) ) ) ) )



4.6.3.2. (new GeometryLock c)
[CLASS] (ogre.lsh)


A significant amount of time is spent in geometry management when many objects are inserted into a realized container. It is then advisable to postpone the geometry until all objects have been inserted.

Such a task is accomplished by creating an object instance of class GeometryLock as follows:

(let ((lock (new GeometryLock c)))
        ;;; insert your objects here into container c
        (==> c insert ...) )

When created, the lock sets a flag in container c which suspend the usual geometry management. When the lock is destroyed, the flag is cleared and the geometry management is started once. If an error occurs during the object insertion, the lock is destroyed by the garbage collector and the container is left with an acceptable state.



4.6.4. Control Management


Five request methods are defined by class Container for handling as a whole several control objects managed by a container or by its sons.



4.6.4.0. (==> Container disable)
[MSG] (ogre.lsh)


When a container receives a message disable , all the control objects managed by the container or by its sons receive a message enable . This is useful for controlling the enabled/disabled state of several control objects at once.
(defmethod container disable ()
  (each ((i contents))
    (==> (car i) disable) ) )



4.6.4.1. (==> Container enable)
[MSG] (ogre.lsh)


When a container receives a message enable , all the control objects managed by the container or by its sons receive a message enable . This is useful for controlling the enabled/disabled state of several control objects at once.
(defmethod container enable ()
  (each ((i contents))
    (==> (car i) enable) ) )



4.6.4.2. (==> Container hasdata)
[MSG] (ogre.lsh)


Method hasdata returns the list of stateful control objects managed by the container of by any of its sons. This is achived by concatenating the result of running method hasdata on all the objects managed by the container.
(defmethod container hasdata ()
  (flatten (all ((i contents)) (==> (car i) hasdata))) )



4.6.4.3. (==> Container getdata)
[MSG] (ogre.lsh)


Method getdata returns the list of states returned by all control objects managed by the container of by any of its sons.
(defmethod container getdata ()
  (all ((i (==> this hasdata)))
    (==> i getdata) ) )



4.6.4.4. (==> Container setdata d)
[MSG] (ogre.lsh)


Method getdata sets the states of all control objects managed by the container of by any of its sons using list d which is usually returned by a call to method getdata .
(defmethod container setdata (d)
  (each ((i (==> this hasdata))
         (j d) )
    (==> i setdata j) ) )



4.7. Container Flavors


This chapter presents various flavors of predefined containers. Class Form define a container abstract class for implementing composite objects. Class WindowObject defines a toplevel container associated to a window on your screen. Structuring containers help organizing the layout of a graphic interface.



4.7.0. Forms


See: Ogre Callbacks.


Class Form is an abstract class used to group several cooperating objects into a single Ogre component. This component can then be inserted into a window or a requester.

Class Form is a trivial subclass of class Container . Class Form adds three properties to standard containers.

These properties are handy for designing complex graphics objects composed of several components as subclasses of Form . Several classes, like class WindowObject , class Requester and class Viewer , are implemented as subclasses of Form .

Moreover, a form object is sometimes considered as an extended control object. For instance, we can gather a slider and an editable numeric field into a form object and use this object like an usual control object.

This is achieved by defining a subclass of Form whose constructor builds the elements of the composite object and keeps a pointer to these object in some of its slots. This subclass then must define methods hasdata , setdata , getdata , execute and setcall like those of a control object. Method hasdata usually returns this . The other methods are usually forwarded to the components of the composite object.



4.7.0.0. (new Form ...contents...)
[CLASS] (ogre.lsh)


Creates a new form object managing objects ...contents... . There is no need to provide a default size for a form object since the form size is derived from the component sizes and location.



4.7.1. Window Objects


See: Events.


Class WindowObject is a subclass of class Form which implements the link between a physical window and its managed ogre objects.

A window object is a toplevel container. Inserting a window object into another container is an almost certain cause of trouble.

Whole graphics interface are often defined as subclasses of WindowObject . Such subclasses usually contain new slots for storing interface specific data. Callback functions then send messages to thiswindowobject . These messages then are executed within the interface scope.



4.7.1.0. (new WindowObject x y w h name ...contents...)
[CLASS] (ogre.lsh)


Creates a window object managing objects ...contents... .

When a window object is created, the constructor creates a window on the screen named name with width w and height h . If both arguments x and y are 0 , the position of this window is defined by the default rule of your computer. If both arguments are positive, they define the position of the topleft corner of the window.

Exemple:

;;; First of all, initialize Ogre !
? (ogre)
= idle-hook
;;; create a window with a button
? (setq win (new WindowObject 100 100 300 300 "Example"
                        (setq b (new stdbutton "Hello"             ;; its name
                                          (lambda(c) (beep)) )) )) ;; its callback
= ::WindowObject:06f00
;;; Now we remove the button b from win
? (==> win remove b)

Note: The event handler of the newly created window is the corresponding Ogre window object. You can thus interactively obtain the Ogre window object for a given window by typing (setq w (waitevent)) and clicking into the corresponding window.



4.7.1.1. (new AutoWindowObject x y w h name contents)
[CLASS] (ogre.lsh)


Lush provides an additional class named AutoWindowObject . Unlike class WindowObject , class AutoWindowObject manages a single object contents and dynamically resizes the window to the size of the managed object.

The constructor arguments w and h are only hints for sizing the window. They may be empty lists instead of numbers. The size of the window is eventually given by the size of its contents.



4.7.1.2. WindowObject Request Methods




4.7.1.2.0. (==> windowobject palette p)
[MSG] (ogre.lsh)


See: Ogre Color Palette.
Message palette redefines the color palette used by Ogre for repaining the objects managed by the windowobject. This method sets slot color-palette of the window object and calls expose in order to repaint the window.

Argument p can be the empty list (for black and white display) or a palette returned by function new-palette (for color display). The color palette selection is enforced even if you do not use an adequate screen.



4.7.1.2.1. (==> windowobject setmodal m)
[MSG] (ogre.lsh)


Message setmodal affects the redirection of event messages by defining a model object. When a modal object is defined, all events are redirected to this object. This is useful for implementing requesters that prevent the user to reach the other components of the interface.

4.7.1.2.2. (==> windowobject getmodal)
[MSG] (ogre.lsh)


Returns the current modal object in the window object or the empty list if no modal object is defined.



4.7.1.2.3. (==> windowobject read-event)
[MSG] (ogre.lsh)


See: Event Lists.
Method read-event returns the next available event in the window associated to the window object. Events are returned as standard Lush event lists. If no events are pending, method read-event blocks.



4.7.1.2.4. (==> windowobject manage-event event)
[MSG] (ogre.lsh)


See: Event Lists.
Method manage-event processes a Lush event list event and sends a corresponding event message to the proper object in the window object.



4.7.1.3. WindowObject Implementation Methods


When defining a graphic interface as a subclass of class WindowObject you may override three methods:

4.7.1.3.0. (==> windowobject delete)
[MSG] (ogre.lsh)


Method delete is called when the user deletes the onscreen window using the window manager features. In the same spirit, we suggest you to call method delete whenever you destroy a window object.

The default method delete just deletes the window object. You may override this method, for instance, to pop up a confirmation dialog to the user.



4.7.1.3.1. (==> windowobject manage-geometry)
[MSG] (ogre.lsh)


Beside its normal use, method manage-geometry is also called when you resize the window with the mouse. The mouse action is actually converted into a size event which is processed using the usual geometry management functions.

The default method manage-geometry does nothing. Overriding the method manage-geometry in a window object is often useful for adjusting the size of the window object components to the onscreen window size.



4.7.1.3.2. (==> windowobject compute-geometry)
[MSG]


Method compute-geometry usually computes the minimal size of the object and enforces this geometry using method resize . In the case of a window object, the actual size of the onscreen window is also adjusted.

The default method compute-geometry does nothing. You may override this method to adjust automatically the size of the onscreen window to the mimial size of its contents.



4.7.2. Structuring Containers


See: Container Objects.


Structuring containers are used for designing the layout of a graphics interface. They arrange their sons according to a certain policy. Ogre provides three class of structuring containers: class Row , class Column and class Grid .

These containers inherit all the slots and methods of an ordinary container. They just define specific methods compute-geometry and manage-geometry to enforce their layout policy.

In addition, two classes are provided for padding a row or a column with some space, class EmptySpace and class DarkSpace .



4.7.2.0. (new Row ...contents...)
[CLASS] (ogre.lsh)


See: (==> Container insert what )
See: (==> Container remove what )
See: Control Management.


Returns a new row object managing the objects specified by ...contents... .

Class Row defines a structuring container which aligns its contents horizontally from left to right. The height of a row is determined by the managed object whose required height is largest.

An empty space is inserted between the objects. This space is defined by slot hspace of the row object and defaults to 4 points.



4.7.2.1. (new Column ...contents...)
[CLASS] (ogre.lsh)


See: (==> Container insert what )
See: (==> Container remove what )
See: Control Management.


Returns a new column object managing the objects specified by ...contents... .

Class Column defines a structuring container which aligns its contents vertically from top to bottom. The width of a column is determined by the managed object whose required width is largest.

An empty space is inserted between the objects. This space is defined by slot vspace of the column object and defaults to 4 points.

Example:

;; Creates a window with three buttons
? (setq win 
        (new WindowObject 100 100 300 300 "Essai"
                (new Column
                  (new StdButton "One" (lambda(d) (print 1)))
                  (new StdButton "Two" (lambda(d) (print 2)))
                  (new StdButton "Three" (lambda(d) (print 3))))))
= ::WindowObject:06f00



4.7.2.2. (new Grid cols ...contents...)
[CLASS] (ogre.lsh)


See: (==> Container insert what )
See: (==> Container remove what )
See: Control Management.


Returns a new grid object with cols columns and managing the objects specified by ...contents... .

Class Grid defines a structuring container which aligns its contents in a grid with cols columns. The grid is filled left to right. The width of each column is determined by the object of the column whose required width is largest. The height of each row is determined by the object of the row whose required height is largest.

Empty spaces are inserted between rows and columns. These spaces are defined by slot vspace and hspace of the grid object and defaults to 4 points.



4.7.2.3. (new EmptySpace w [h] )
[CLASS] (ogre.lsh)


Extra spaces may be added into a structuring container by inserting an emptyspace object. Such an object has no response to user events and is uniformly filled with the background color.

Class EmptySpace is a class of emptyspace objects. The constructor expression above returns a new emptyspace object of minimal width w and minimal height h . When argument h is omitted, a square minimal space is assumed.

Of course, the minimal geometry specifications interact with the geometry management of structuring conteners. It is seldom necessary to define all the sizes of an emptyspace object.

Exemple:

;;; Creates a window with three buttons
;;; with a 20 pixels space between button 2 and button 3
? (setq win 
        (new WindowObject 100 100 300 300 "Essai"
                (new Column
                  (new StdButton "One" (lambda(d) (print 1)))
                  (new StdButton "Two" (lambda(d) (print 2)))
                  (new EmptySpace 20)
                  (new StdButton "Three" (lambda(d) (print 3))) )))
= ::WindowObject:06f00



4.7.2.4. (new DarkSpace w [h] )
[CLASS] (ogre.lsh)


Similarly you can insert a darkpace object into a structuring container. On a black and white display, a darkspace is displayed as a black area. On a color display, a darkspace is displayed as a raised area.

Class DarkSpace is a class of emptyspace objects. The constructor expression above returns a new emptyspace object of minimal width w and minimal height h . When argument h is omitted, a square minimal space is assumed.

Of course, the minimal geometry specifications interact with the geometry management of structuring conteners. Specifying a single argument of 4 , for instance, will define a minimal width and height of 4 points. If such a darkspace object is inserted in a column, the width of object will be increased up to the column width, effectively displaying a 4 points thick line.

Exemple:

;;; Creates a window with three buttons
;;; with a 3 pixels line between button 2 and button 3
? (setq win 
        (new WindowObject 100 100 300 300 "Essai"
                (new Column
                  (new StdButton "One" (lambda(d) (print 1)))
                  (new StdButton "Two" (lambda(d) (print 2)))
                  (new DarkSpace 3)
                  (new StdButton "Three" (lambda(d) (print 3))))))
= ::WindowObject:06f00



4.8. Buttons


Buttons are small interactive area which can be used for triggering an action or storing boolean states. Ogre provides four class of buttons:

All these classes are subclasses of Control . Buttons thus inherit all the slots and methods defined in class Control .



4.8.0. Push Buttons


A push button invokes a specific action when the user clicks the mouse button while the pointer is located above the button image. Two kinds of push buttons are defined by the Ogre library.



4.8.0.0. (new StdButton label call)
[CLASS] (ogre.lsh)


See: (font-12b)
See: (==> Control settext d )
See: (==> Control gettext)
See: (==> Control setcall f )


Class StdButton implements a standard push button. The label of a standard push button is displayed using the font set by the function stored in slot textfont , which default to a 12 points bold font font-12b .

The constructor expression returns a push button whose name is given by string label . This label may be changed by sending a message settext . When the button is depressed, the callback function call is executed. The button remains disabled while the callback function has not returned.

Example:

;;; A window with a 3 state label
? (setq win 
        (new WindowObject 100 100 300 300 "Essai"
                (new StdButton "One"
                        (lambda(caller)
                                (==> caller settext
                                        (selectq (==> caller gettext)
                                                ("One" "Two")
                                                ("Two" "Three")
                                                (t     "One") ) ) ) ) ) )
= :WindowObject:06f00



4.8.0.1. (new TinyButton label call)
[CLASS] (ogre.lsh)


See: (font-12b)
See: (==> Control settext d )
See: (==> Control gettext)
See: (==> Control setcall f )


Class TinyButton implements a push button with a reduced size. A tiny push button is slightly smaller than a standard push button because the label is written using a smaller font font-12 .

The constructor expression returns a push button whose name is given by string label . This label may be changed by sending a message settext . When the button is depressed, the callback function call is executed. The button remains disabled while the callback function has not returned.



4.8.1. Check Boxes


A check box is composed of a small square button followed by a descriptive text. When the user clicks on the square or on the text, the state of the small square changes.

Class CheckBox implements check box buttons. Since class CheckBox is a subclass of class Control , all the slots and methods defined for control objects are inherited.



4.8.1.0. (new CheckBox label call)
[CLASS] (ogre.lsh)


See: (==> Control settext d )
See: (==> Control gettext)
See: (==> Control setdata d )
See: (==> Control getdata)
See: (==> Control setcall f )


Returns a new check box whose descriptive text is given by string label . When a check box is depressed, its state changes and the callback function call is executed.

You can query or change the state of a check box ( t or () ) by sending messages getdata and setdata . The descriptive text can be modified using settext .

Example:

;;; A window with a check box that controls 
;;; the enable/disable state of a push button
? (setq win 
        (new WindowObject 100 100 300 300 "Essai"
          (new column
                (setq thebutton 
                        (new StdButton "beep" 
                                (lambda(c) (beep)) ))
                (new CheckBox "Disable button"
                                (lambda(c)
                                        (if (==> c getdata)
                                                (==> thebutton disable)
                                          (==> thebutton enable) ) ) ) ) ) )



4.8.1.1. (new ImageButton up-image down-image disabled-image call)
[CLASS] (ogre.lsh)


See: (==> Control setcall f )


Class ImageButton implements a push button whose appearance is an image drawn with rgb-draw-matrix . Each of the first three arguments must be an idx2 or an idx3 of ubytes containing the pixel data (greyscale if an idx2, RGB if an idx3 with at least 3 elements in the last dimension). up-image is the image shown when the button is up, down-image when it is pushed, disabled-image when it is disabled. The A (alpha) component, if present, is ignored. call is the callback function called when the button is clicked.

Here is an example that shows how to create down and disabled image of an ImageButton from an up image.

  (libload "libimage/image-io")
  (libload "libimage/rgbaimage")
  (ogre)
  (setq up (image-read-rgba "my-button-image.png"))
  (setq down (idx-copy up))
  (rgbaim-contbright up down -1 0)
  (setq disabled (idx-copy up))
  (rgbaim-contbright up disabled 0.5 40)
  (setq btn (new ImageButton up down disabled (lambda (c) (printf "coucou\n"))))
  (setq window (new windowobject 10 10 200 200 "test" btn))



4.8.1.2. (new StdButtonBg text up-image down-image disabled-image call)
[CLASS] (ogre.lsh)


See: (==> Control setcall f )


This works just like an StdButton except that the image of the button is an RGBA or grayscale image passed as argument (instead of the boring blueish rounded rectangle of StdButton ). The text is displayed on top of the image. The three images passed as argument will be used respectively as the up button image, the clicked (down) button image, and the disabled button image. The text is drawn in black over the background image, so the image colors should not be too dark. The background images are automatically sized/resized to fit the text (without necessarily preserving the aspect ratio). The images must be idx2 (for grayscale images) or idx3 with the last dimension equal to 4 (RGBA images). Tha A (alpha) component is ignored.

Here is an example that shows how to create an StdButtonBg from one of the standard icons:

  (libload "libimage/image-io")
  (libload "libimage/rgbaimage")
  (setq icondir (concat-fname lushdir "lsh/libogre/icons"))
  (ogre)
  (setq btn 
    (new StdButtonBg
      "Click Me"
      (image-read-rgba (concat-fname icondir "button-brushed-metal-02-up.png"))
      (image-read-rgba (concat-fname icondir "button-brushed-metal-02-down.png"))
      (image-read-rgba (concat-fname icondir "button-brushed-metal-02-disabled.png"))
      (lambda (c) (printf "coucou\n"))))
  (setq window (new windowobject 10 10 200 200 "test" btn))
  (==> btn disable)
  (==> btn enable)



4.8.2. Exclusive Buttons


Exclusive button are two-state buttons which cooperate with the other buttons in the same container in order to ensure that at most one button is in a positive state.

Class RadioButton implements exclusive buttons. Since class RadioButton is a subclass of class CheckBox , all the slots and methods defined for checkbox and control objects are inherited.



4.8.2.0. (new RadioButton label call)
[CLASS] (ogre.lsh)


See: (==> Control settext d )
See: (==> Control gettext)
See: (==> Control setdata d )
See: (==> Control getdata)
See: (==> Control setcall f )


Returns a new check box whose descriptive text is given by string label . You can query or change the state of a check box ( t or () ) by sending messages getdata and setdata . The descriptive text can be modified using settext .

You must insert a radiobutton in a container containing only radiobuttons. Whenever the user clicks on a radiobutton, the state of all the other radiobuttons in the container becomes () , while the state of the clicked radiobutton becomes t and the callback function call is called.

Example:

;;; A window with a three radio buttons 
;;; building a three state choice
? (setq win 
        (new WindowObject 100 100 300 300 "Essai"
                ;; create a common callback function
                (let ((call (lambda(d) 
                                        (printf "%s has been selected\n"
                                                (==> d gettext) ) )))
                          (new column
                                (new radiobutton "choice 1" call) 
                                (new radiobutton "choice 2" call) 
                                (new radiobutton "choice 3" call) ) ) ) )

Remarks:



4.8.3. File Requester Button


A file requester button is composed of a small square button which contains an icon. When the button is depressed, a file requester is poped up.

A file requester button is usually associated with a string editor, which displays the file selected in the requester.

See: File Requester.
See: Editable Strings.




4.8.3.0. (new FileReqButton areqmsg aedstring)
[CLASS]


Returns a new file requester button. Argument areqmsg is the introductory message of the requester associated with the button. Argument aedstring is the string editor associated with the button.



4.9. Character String Objects


Ogre provides several classes for handling character string:



4.9.0. Fixed Strings


Class String is used for creating a caption text which does not respond to user interaction. Such objects are useful for displaying explanatory text or short message. Class String is a subclass of class VisualObject . This is not a control object because it has no user interaction capabilities.



4.9.0.0. (new String text)
[CLASS] (ogre.lsh)


See: (==> Control settext d )
See: (==> Control gettext)


Creates a new string object displaying text text . The text displayed by a string object may be changed using settext like the text of a control object.

The text is displayed using a font set by the fonction stored in slot textfont of the string object. This font default to a standard 12 points font.



4.9.1. Editable Strings


See: Regular Expressions.
See: Activation of a Control Object.
See: (==> Control setdata d )
See: (==> Control getdata)
See: (==> Control setcall f )


An editable string is a single line text editor.

An editable string object becomes actived when the user clicks the mouse button above its rectangle. Keypress and arrow events then are bound to editing functions according to a keymap stored in global variable EditStringKeymap .

The text edited by an editable string is controlled by the value of the slot regex of the editable string. This slot contains a regular expression which must match the text at all times. If an editing action results in a non-matching text, the action is discarded and a beep is emited.



4.9.1.0. (new EditString minsize [defaulttext])
[CLASS] (ogre.lsh)


Creates a new editable string displaying at least minsize characters. The initial value of the text is specified by the optional string argument defaulttext .

Example:

;;; A window with two editable strings
? (setq win 
        (new WindowObject 100 100 300 300 "Essai"
                 (new grid 2
                        (new string "First string:")
                        (new editstring 16 "number one")
                        (new string "Second string:")
                        (new editstring 16 "number two") ) ) )



4.9.1.1. EditStringKeymap
[VAR] (ogre.lsh)


The global variable EditStringKeymap contains the keymap for EditString objects as a list of key bindings. Every key binding has the form (char action) where char is a one character string and action is a symbol identifying a specific editing action.

Every typed character is matched against the keymap.

The default keymap is loosely modeled after the Emacs text editor:

(setq EditStringKeymap
 '(     ("\n"          execute)         ;; <LineFeed>
        ("\r"          execute)         ;; <Enter> or <Return>
        ("\b"          backspace        ;; <ctrl-H> or <Backspace>
        ("\x7f"        backspace)       ;; <Delete>
        ("\^D"         delete-char)     ;; <Ctrl-D>
        ("Delete"      delete-char)     ;; Key <Delete>
        ("\^A"         begin-of-line)   ;; <Ctrl-A>
        ("Home"        begin-of-line)   ;; Key <Home>
        ("\^E"         end-of-line)     ;; <Ctrl-E>
        ("End"         end-of-line)     ;; Key <End>
        ("\^F"         arrow-right)     ;; <Ctrl-F> and <Right>
        ("\^B"         arrow-left)      ;; <Ctrl-B> and <Left>
        ("\^P"         arrow-up)        ;; <Ctrl-P> and <Up>
        ("\^N"         arrow-down)      ;; <Ctrl-N> and <Down>
        ("\^K"         kill)            ;; <Ctrl-K>
        ("\^Y"         yank) ) )        ;; <Ctrl-Y>

The binding second elements, actions, are the names of methods defined by class EditString to perform the various editing tasks. The valid actions are:



4.9.2. Editable Numbers


See: Regular Expressions.
See: (==> Control setdata d )
See: (==> Control getdata)
See: (==> Control setcall f )




4.9.2.0. (new EditNumber minsize [defaultvalue])
[CLASS] (ogre.lsh)


Class EditNumber is a subclass of class EditString used for editing numeric fields. It checks that the text is a valid number using a regumar expression stored in slot regex at construction time. In addition, the methods setdata and getdata have been modified to handle numbers instead of strings.

Argument minsize is the minimal number of characters dislayed in the object. The initial value of the number is specified by the optional number argument defaultvalue .

When sent to an editable numeric string, message setdata requires a numerical argument. Similarly, message getdata returns a number or the empty list when no text has been entered.



4.9.3. EditSecretString


This subclass of EditString works exactly like EditString but always display the string character as a string of "x" .



4.9.4. Multiline Text Editor


See: (==> Control setdata d )
See: (==> Control getdata)
See: (==> Control setcall f )
See: Forms.




4.9.4.0. (new EditText w h [default])
[CLASS] (ogre.lsh)


Creates a new edittext object (i.e. a text editor with both a vertical and horizontal scrollbar). Argument w is the number of visible columns. Argument h is the number of visible lines.

Class EditText is a subclass of Forms that defines composite object containing a TextPane object and two scroll bars. The text editor is actually implemented by class TextPane described hereafter.

Class EditText forwards messages setdata , getdata , read-file and write-file to this underlying TextPane object.
See: (new TextPane w h [ def editp vs hs ])
See: (==> TextPane getdata)
See: (==> TextPane setdata arg )
See: (==> TextPane read-file fname )
See: (==> TextPane write-file fname )




4.9.4.1. (new TextPane w h [def editp vs hs])
[CLASS] (ogre.lsh)


Creates a new TextPane object. Class TextPane is a subclass of Control . It implements a simple multi-line text editor.

4.9.4.2. TextPaneKeymap
[VAR] (ogre.lsh)


This A-list contains the associations between key strokes and editing methods executed by a TextPane object. The default keymap is loosely based on the Emacs key bindings.
(setq TextPaneKeymap
 '(     ("\n"     execute)
        ("\r"     execute)
        ("\b"     backspace)
        ("\x7f"   backspace)
        ("\^A"    begin-of-line)
        ("\^B"    arrow-left)
        ("\^D"    delete-char)
        ("\^E"    end-of-line)
        ("\^F"    arrow-right)
        ("\^K"    kill)
        ("\^N"    arrow-down)
        ("\^P"    arrow-up)
        ("\^V"    page-down)
        ("\^Y"    yank) 
        ("Delete" delete-char)
        ("C-Home" begin-of-text)
        ("C-End"  end-of-text)
        ("Home"   begin-of-line)
        ("End"    end-of-line)
        ("Prior"  page-up)
        ("Next"   page-down)
        ("\x1b"   metakey "\x1b")
        ("\x1b<"  begin-of-text)
        ("\x1b>"  end-of-text)
        ("\x1bv"  page-up)
  ) )

The first element of each association describes the keystroke or keystroke combination. This string can contain an ASCII character, a string containing a keystroke combination, or a function key name. The leading character of keystroke combinations must be associated to method metakey . The function key names may be preceded by "C-" and "S-" to indicate that the control or shift key must be depressed.

The rest of the association specify which action should be called when the corresponding keystroke is typed by the user. The following actions are supported:



4.9.4.3. (==> TextPane setdata arg)
[MSG] (ogre.lsh)


Sets the text in a TextPane. Argument arg specifies a default contents as a string or a list of strings. Single strings are searched for TAB and NL characters and splitted into multiple strings (one per line).



4.9.4.4. (==> TextPane getdata)
[MSG] (ogre.lsh)


Returns a list of strings representing all lines of the text pane.



4.9.4.5. (==> TextPane read-file fname)
[MSG] (ogre.lsh)


Reads the contents of text file fname into the text pane.



4.9.4.6. (==> TextPane write-file fname)
[MSG] (ogre.lsh)


Writes the contents of the text pane into file fname .



4.10. Icons


An icon is a simple object which displays a greyscale or colormapped picture. The Icon class is somewhat superseded by the Ogrimage class.



4.10.0. (new icon mat &optional [sx [sy [map]]])
[CLASS]


Returns a new icon.

Argument mat is a 2D matrix containing the data to be represented as rectangles using 64 gray levels. By default, the values lower than 0 will be black and the values beyond 1 will be white.

Arguments sx and sy are the width and height of each rectangle.

Argument cmap may be a 1D integer matrix defining 64 colors. When it is defined, its colors are used instead of gray levels.

See: (gray-draw-matrix x y mat minv maxv apartx aparty )
See: (color-draw-matrix x y mat minv maxv apartx aparty cmap )




4.11. OgrImage


An OgrImage is a simple object which displays a color or greyscale picture. An OgrImage can be used advantageously in combination with the ImageViewer class.



4.11.0. (new OgrImage m)
[CLASS]


return a new OgrImage that will display picture m . m must be an IDX2 (greyscale image) or IDX3 whose last dimension must be 1 (grayscale), 3 (RGB), or 4 (RGBA).



4.11.1. (==> OgrImage get-selected)
[MSG]


return the rectangle last selected by the user by clicking and dragging the mouse on the image.



4.12. ImageViewer


An ImageViewer is a scrollable viewing area for an OgrImage.



4.12.0. (new ImageViewer w h m [scroll])
[CLASS]


Create a new image viewer which will display image m in a scrollable viewing area of size w , h . If the optional scroll argument is true, the image scrolling will follow scrollbar dragging, whereas if scroll is nil or absent, the scrolling is only performed when the mouse button is released. Here is an example:
  (libload "libimage/image-io")
  (setq m (image-read-rgb (concat-fname lushdir "lsh/libimage/demos/sample.jpg")))
  (ogre)
  (setq w (new WindowObject 10 10 400 400 "asd" (new ImageViewer 340 340 m t)))



4.12.1. (==> ImageViewer get-selected)
[MSG]


return the rectangle last selected by the user by clicking and dragging the mouse on the image.



4.13. Menus


A menu is a popup column associated to a menu button. When the mouse is depressed on the menu button, a popup column appears and the user may drag the mouse over an item in the column. When the mouse button is released, the item is selected, its callback function is executed and the popup column disappears.

Menus are implemented with three classes:

The constructor of class Menu sets up all these objects in a single call.



4.13.0. Standard Menus




4.13.0.0. (new Menu menuname label1 call1 ... labelN callN )
[CLASS] (ogre.lsh)


Creates a menu button labelled menuname linked to a menu popup composed of items defined by the pairs label1 , call1 to labelN , callN . Argument labeli is the name of the i th menu item. Argument calli is the callback associated to the i th menu item.

Example:

;;; A window with a menu composed of 3 items
? (setq win 
      (new WindowObject 100 100 300 300 "Essai"
          (new menu "Test Menu"
                ;; the first item toggles its check mark
                "Toggle" 
                (lambda(item) (==> item setdata (not (==> item getdata))))
                ;; the second item activates the bell
                "Bell"   
                (lambda(item) (beep))
                ;; the third one destroy this interface
                ;; remenber that <thiswindowobject> always
                ;; refer to the closest window object.
                "Quit"     
                (lambda(item) (==> thiswindowobject delete)) ) ) )



4.13.0.1. (==> Menu finditems label)
[MSG] (ogre.lsh)


Message finditems returns the menu items matching argument label .

4.13.0.2. (==> Menu disable ...labels...)
[MSG] (ogre.lsh)


See: (==> Menu finditems label )


When a menu receives a message disable , it sends a message disable to all menu items identified by the arguments ...labels... . Therefore, the corresponding menu items are disabled.

Each argument of message disable is interpreted like the argument label of message finditems. It can be the empty list, a number or a string.



4.13.0.3. (==> Menu enable ...labels...)
[MSG] (ogre.lsh)


See: (==> Menu finditems label )


When a menu receives a message disable , it sends a message disable to all menu items identified by the arguments ...labels... . Therefore, the corresponding menu items are disabled.

Each argument of message disable is interpreted like the argument label of message finditems. It can be the empty list, a number or a string.



4.13.0.4. (new MenuItem label call)
[CLASS] (ogre.lsh)


Creates a new menu item labelled label . Argument call indicates the callback function for this menu item. Menu items may be inserted into a menu popup by sending a message insert to the menu object.



4.13.0.5. (==> Menu insert menuitem)
[MSG] (ogre.lsh)


Message insert inserts a new menu item menuitem in the menu popup.



4.13.0.6. (==> Menu remove menuitem)
[MSG] (ogre.lsh)


Message insert removes new menu item menuitem from the menu popup.



4.13.1. Choice Menus


This class implements a multiple choice item. This object display a menu mark and the name of the currently selected item. When the user clicks on it, a menu popup is displayed and the user can select another item.

Choice menus supports the methods of standard menus, in addition to their own methods.



4.13.1.0. (new ChoiceMenu [items [callback]])
[CLASS]


Creates a new choice menu that lets the user choose among the items specified in list of strings items . When argument items is unspecified, selection is impossible.



4.13.1.1. (==> choicemenu setitems items)
[MSG]


Changes the items that the user can select with the choice menu to be the strings of list items . As a side effect, the current selection is reset to the empty list.



4.13.1.2. (==> choicemenu setdata d)
[MSG]


Selects string d in the choice menu.



4.13.1.3. (==> choicemenu getdata)
[MSG]


Returns the string selected in the choice menu.



4.13.1.4. (==> choicemenu setcall callback)
[MSG]


Sets the callback function



4.13.1.5. (==> choicemenu disable)
[MSG]


Disables a choicemenu.



4.13.1.6. (==> choicemenu enable)
[MSG]


Enables a choicemenu.



4.14. Popup Requesters


A requester is a prepared form containing a collection of graphical objects. When the requester receives a message popup , the form is displayed in the middle of the window and receives all event messages until it receives a message popdown .

Requesters are useful for asking the user to provide additional information about an action trigerred by a button or a menu item. The callback function of the button or menu item then just send a message popup to the requester which performs all the remaining tasks.



4.14.0. Requester


Class Requester is a subclass of Form which implements the basic mechanisms of a requester. When the requester receives a message popup , the requester is inserted into a predefined window object until reception of a message popdown .

Example:

;;; A window with a button that pops a requester up.
;;; The requester contains an editstring and two buttons.
;;; 1- Create the window
? (setq win 
          (new WindowObject 100 100 300 300 "Essai"
                (setq thebutton
                        (new StdButton "Pop the requester up"
                                (lambda(d) (==> therequester popup)) ))))
= ::WindowObject:06f00
;;; 2- Create the requester
? (setq therequester
        (new Requester win
          (new Column
                ;; The first button pops the requester down
                ;; Variable <thisrequester> always refers to the closest
                (new StdButton "Pop the requester down"
                        (lambda(d)
                          (==> thisrequester popdown)) )
                ;; The second button changes the label of the popup button
                (new EditString 8 "Pop it up again")
                (new StdButton "Change label"
                        (lambda(d)
                          (==> thebutton settext
                                ;; Collective <getdata> on the requester!
                                (car (==> thisrequester getdata)))))))))
= ::Requester:0702c



4.14.0.0. (new Requester support ...contents...)
[CLASS] (ogre.lsh)


Creates a new requester containing objects ...contents... . This requester will be inserted into the window object containing object support upon recpetion of a message popup .



4.14.0.1. (==> Requester popup)
[MSG] (ogre.lsh)


When a requester receives message popup , it is inserted in the middle of the window object defined at requester creation time.

All event messages are then directed to the requester. Since no other component of the interface toplevel is active, it is advisable to insert a button whose action consists in sending message popdown to the requester itself.



4.14.0.2. (==> Requester popdown)
[MSG] (ogre.lsh)


A popped requester is removed from its window object when it receives a message popdown . The usual event dispatching is then restored.



4.14.0.3. (==> Requester popuplock)
[MSG] (ogre.lsh)


Message popuplock behaves very much like message popup . Unlike message popup , message popuplock blocks until the requester receives a message popdown . When message popuplock returns, the window object state is normal again.

Example:

;;; Pop up the requester defined above in this section and block:
? (==> therequester popuplock)
;;; Lush only returns when you activate the 'popdown' button
= ()



4.14.0.4. (==> Requester popuphard)
[MSG] (ogre.lsh)


Message popuphard is an even more drastic form of popuplock . It pops up the requester and blocks until the requester is popped down like message popuplock .

While message popuphard is active, no other window object accepts user events. If the user click in another Ogre window, the computer beeps and put the window containing the requester above all other window on the screen.

Message popuphard is useful for requesting an information which requires immediate attention from the user.



4.14.0.5. (==> Requester setsupport win)
[MSG] (ogre.lsh)


Message setsupport changes the support window of a requester.



4.14.1. Warning Requester


Class WarningRequester is a subclass of Requester . A warning requester contains only a String object. The actual text of the string is defined when you pop the warning requester up.



4.14.1.0. (new WarningRequester support)
[CLASS] (ogre.lsh)


Creates a new warning requester for displaying text in window object support .



4.14.1.1. (==> WarningRequester popup text)
[MSG] (ogre.lsh)


Message popup first sets the string's text to text and pops the requester up. The requester may be popped down by sending the usual message popdown.

Using a warning requester with messages popup and popdown allows for displaying messages indicating what is being computed.



4.14.1.2. (==> WarningRequester popuplock seconds text)
[MSG] (ogre.lsh)


Message popuplock first sets the string's text to text and pops the requester up during seconds seconds. When this delay is elapsed, the requester is popped down and method popuplock returns.

Using a warning requester with popuplock allows for displaying a temporary warning message.



4.14.2. Error Requester


Class ErrorRequester is a subclass of Requester . An error requester contains a String object and a button labelled "Ok" for popping the requester down. The actual text of the string is defined when you pop the error requester up.

Such a requester is very useful for signaling an error to the user. The user must depress the button "Ok" to remove the requester. This button actually sends a message popdown to the error requester.

Example:

;;; Assuming window object <win> already exists:
? (setq error-dialog (new ErrorRequester win))
= ::ErrorRequester:07120
? (==> error-dialog popup "Error message")
= ()



4.14.2.0. (new ErrorRequester support)
[CLASS] (ogre.lsh)


Creates a new error requester for displaying error messages in window object support .



4.14.2.1. (==> WarningRequester popup text)
[MSG] (ogre.lsh)


Message popup first sets the string's text to text and pops the requester up. The requester may be popped down by sending the usual message popdown.

Using a warning requester with messages popup and popdown allows for displaying messages indicating what is being computed.



4.14.2.2. (==> WarningRequester popuplock text)
[MSG] (ogre.lsh)


Message popuplock first sets the string's text to text and pops the requester up. The requester is popped down and method popuplock returns when the user depresses button "Ok" .



4.14.3. Yes/No Requester


Class YesNoRequester is a subclass of Requester for implementing yes/no requesters. A yes/no requester contains a user defined part, a positive button and a negative button.

Like usual requesters, yes/no requesters are popped up when they receive a message popup or popuplock . Both the positive and the negative button pop the yes/no requester down.

When you create the yes/no requester however, you specify a callback function.

If you have popped up the requester using message popuplock , you can also test which button has been depressed by looking at the value returned by message popupdown . This value is the empty list if the negative button has been depressed.

Slots yesbutton and nobutton of a yes/no requester contain the positive and negative buttons. These buttons may be programmatically actived by sending them a message trigger .



4.14.3.0. (new YesNoRequester support dialog yes no call)
[CLASS] (ogre.lsh)


Creates a new yes/no requester for displaying on the window object of object support .

Argument dialog is the user defined part of the requester. String yes is the label of the positive button. String no is the label of the negative button. Argument call is a callback function or the empty list.

Example:

;;; A button that pops up a yesnorequester
;;; for changing its label...
? (setq win 
        (new WindowObject 100 100 400 200 "Essai"
                (setq thebutton
                        (new StdButton "Hello"
                                (lambda(c) (==> theyesnoreq popup)) ))))
= ::windowobject:07010
? (setq theyesnoreq
        (new YesNoRequester win
                ;; The user defined part
                (new Column
                        (new String "Change button label")
                        (new EditString 8 "new label") )
                ;; The yes and no labels
                " Ok " "Cancel"
                ;; The callback
                (lambda(caller)
                        (==> thebutton settext
                                (car (==> caller getdata)) ))))))))
= ::yesnorequester:07040



4.14.3.1. (==> YesNoRequester settext yes no default)
[MSG] (ogre.lsh)


The label of the positive and negative buttons can be changed by sending a message settext to the yes/no requester. String yes becomes the label of the positive button. String no becomes the label of the negative button.

There is usually a default button indicated by a wider outline. This button is triggered if the user hits the carriage return key. This default button is usually the positive one, but may be changed with argument default of message settext .



4.14.3.2. (==> YesNoRequester setcall callback)
[MSG] (ogre.lsh)


Sets the callback function for the requester. Argument callback can be a function with one argument or the empty list.



4.14.3.3. (==> YesNoRequester ask yes no default)
[MSG] (ogre.lsh)


See: (==> YesNoRequester settext yes no default )
See: (==> Requester popuphard)


This message should be used with yes/no requesters whose user defined component is a single String object.

When such a requester receives message ask , it first sets the text of the string object to text and the button labels to yes and no . The default button is indicated by argument default .

The requester is then popped up using popuphard . The user can then press either the positive or the negative button. When the requester is popped down, message ask returns t or () according to the user answer.

Example:

;;; Creates a confirmation dialog in an exiting win <win>.
? (setq confirm-dialog 
        (new YesNoRequester win
                (new string "msg")         ; dummy message
                "yes" "no"                 ; dummy labels
                () )                       ; no callback
= ::yesnorequester:070c0
? (==> confirm-dialog ask 
        "Should I really do that"          ; the message
        "Proceed" "Please don't"           ; the button labels
        'no )                              ; the default
;;; Waiting for your answer...
= t or ()



4.14.4. Print Requester


See: (print-window w h [ destination ])


A print requester lets the user choose a valid destination for printing a graphics. Function getdata will return a string that can be used verbatim as the destination argument of function print-window .



4.14.4.0. (new PrintRequester w [callback])
[CLASS] (ogre.lsh)


See: Yes/No Requester.


Creates a new print requester for displaying in the window object w . The optional argument callback defines a callback function that will be called if the user presses button "Ok" (as usual with Yes/No Requesters.)



4.14.4.1. (==> PrintRequester getdata)
[MSG] (ogre.lsh)


See: (print-window w h [ destination ])
Returns a string that can be used directly as argument destination of function print-window .



4.14.5. File Requester


A file requester lets the user choose a filename using a list of files existing in various directories. The file requester contains a message string, a file selector, an editable filename string and two buttons labelled "Ok" and "Cancel" .

Starting from the current filename, the selector displays the contents of the directory. A first click on a selector item selects a file or directory and copies its name in the editable filename string. Alternatively, the user can type a filename in the filename field. The button "Ok" is disabled if the user types an invalid filename.

This selection is validated by a second click, by pressing the enter key or by depressing the button "Ok" .

Class FileRequester is a subclass of class YesNoRequester which implements the standard Ogre file requester.



4.14.5.0. (new FileRequester w [message flag filter callback])
[CLASS] (ogre.lsh)


See: Yes/No Requester.
Creates a new file requester for displaying in the window object w . The contents of the message string is indicated by the optional argument message . The callback function is indicated by the optional argument callback or may be set using message setcall .

Special behavior are selected by argument flag :



4.14.5.1. (==> FileRequester setdata fname)
[MSG] (ogre.lsh)


Sets the current file name of a FileRequester object to file or directory fname .



4.14.5.2. (==> FileRequester getdata)
[MSG] (ogre.lsh)


Gets the full current file name of a FileRequester object.



4.14.5.3. (==> FileRequester getdir)
[MSG] (ogre.lsh)


Gets the name of the directory displayed in the selector of a FileRequester object.



4.14.5.4. (==> FileRequester getbase)
[MSG] (ogre.lsh)


Returns the base name of the current filename selected in a FileRequester object. If the selected filename is a directory, this message returns the empty list.



4.14.5.5. (==> FileRequester setparm message flag [filter])
[MSG] (ogre.lsh)


Changes the parameters of a FileRequester object.



4.14.5.6. (==> FileRequester ask message flag [filter [fname]])
[MSG] (ogre.lsh)


Changes the parameters of a FileRequester object, sets the current filename to file or directory fname , pops up the requester and waits until the request is complete.

4.14.5.7. (ogre-ask-file winobj message flag [filter [fname]])
[DE]


This function popups a default filerequester in window win .

Other arguments are the same as for method ask of class FileRequester .

See: (==> FileRequester ask message flag [ filter [ fname ]])




4.15. Movable and Resizable Objects


Class DragArea and SizeArea define objects used for moving or resizing their container. Special container classes Frame and FrameSize define containers which may be moved and resized by the user.



4.15.0. (new DragArea w h)
[CLASS] (ogre.lsh)


Creates a new dragging area with minimal width w and minimal height h .

A dragging area appears as a rectangle with a gray outline. When you depress the mouse inside a dragging area, you can drag its container to another place.

Two slots affect the behavior of a dragging area:



4.15.1. (new SizeArea w h)
[CLASS] (ogre.lsh)


Creates a new sizing area with minimal width w and minimal height h .

A sizing area appears as two overlapping gray squares. When you depress the mouse inside a sizing area, you can change the size of its container. Just drag the mouse until you touch a container boundary. This container boundary then follows the mouse until you release the mouse button.

Two slots affect the behavior of a size area.



4.15.2. (new Frame x y w h ...contents...)
[CLASS] (ogre.lsh)


Creates a new frame at location x and y with minimal width w and minimal height h . The frame initally manage objects contents .

Class Frame is a subclass of class Container . A frame always contains a dragging area located in the background of the container. A frame thus is a container that the user can move.

Example:

? (setq win (new windowobject 0 0 400 400 "Essai"
                (new Frame 50 30 200 140 
                        (new stdbutton "Beep" 
                                (lambda(c) (beep)) ) ) ))



4.15.3. (new FrameSize x y w h ...contents...)
[CLASS] (ogre.lsh)


Creates a new sizable frame at location x and y with minimal width w and minimal height h . The frame initally manage objects contents .

Class FrameSize is a subclass of class Frame . A sizable frame always contains a dragging area located in the background of the container. A sizable frame also contains a small size area in its bottom right corner. A sizable frame thus is a container that the user can move and resize.

Example:

? (setq win (new windowobject 0 0 400 400 "Essai"
                (new FrameSize 50 30 200 140 
                        (new stdbutton "Beep" 
                                (lambda(c) (beep)) ) ) ))



4.16. Sliders and Scrollbars


Sliders and scrollbars are graphical objects for entering numerical values.

The user can grab and move the handle with the mouse. The user might also maintain the mouse button depressed on either side of the handle. In this case, the handle moves slowly towards the mouse pointer.

The standard callback function is called whenever the user releases the mouse button. An additional callback might be set up with message setdrag . This callback is called whenever the user moves the handle.

Sliders and scrollbars are implemented by a set of specialized subclasses of class Control .

Control                 abstract class for all controls
  Slider                abstract class for all sliders and scrollbars
    HSlider               horizontal sliders
    VSlider               vertical sliders
    Scrollbar           abstract class for all sliders and scrollbars
      HScrollbar          horizontal scrollbars 
      VScrollbar          vertical scrollbars

Example: Example:

? (setq win (new windowobject 100 100 400 200 "Sliders & Scrollbars"
                (new row
                  (new grid 2
                   (new emptyspace 100 100) 
                   (new vslider 0 100 ())
                   (new hslider 0 100 ()) 
                   (new emptyspace 10 10) )
                  (new grid 2
                   (new emptyspace 100 100) 
                   (new vscrollbar 100 ())
                   (new hscrollbar 100 ()) 
                   (new emptyspace 10 10) ) ) ) )



4.16.0. Sliders


Sliders are used for entering numerical values using an analog handle. Horizontal sliders are implemented by class HSlider . Vertical sliders are implemented by class VSlider . Both class HSlider and VSlider are subclasses of class Slider which implement a number of useful methods.



4.16.0.0. (new HSlider mini maxi [callback])
[CLASS] (ogre.lsh)


Returns a horizontal slider for entering integer values in the range mini to maxi . The callback function callback is called whenever the user releases the mouse button.



4.16.0.1. (new VSlider mini maxi [callback])
[CLASS] (ogre.lsh)


Returns a vertical slider for entering integer values in the range mini to maxi . The callback function callback is called whenever the user releases the mouse button.



4.16.0.2. (==> Slider setrange mini maxi)
[MSG] (ogre.lsh)


See: (==> Scrollbar setrange mini maxi [ prop ])


Message setrange redefines the minimal and maximal values allowed in a slider or a scrollbar.



4.16.0.3. (==> Slider setstep step)
[MSG] (ogre.lsh)


Message setstep redefines the possible increments of the values allowed in a slider or a scrollbar.

The initial increment is always 1. This initial increment ensures that the slider or scrollbar is limited to integer values. Specifying the empty list as an increment means that any value in the legal range are allowed.



4.16.0.4. (==> Slider setdrag call)
[MSG] (ogre.lsh)


Message setdrag sets up a secondary callback function which is called whenever the handle moves. Installing such a callback function is useful for displaying echo to the user.



4.16.1. Scrollbars


Scrollbars are a special kind of slider which are used for controling which information is displayed in other objects.

Scrollbars are implemented by classes HScrollbar and VScrollbar which are indirect subclasses of class Slider . All the methods defined by class Slider are thus inherited by scrollbars.



4.16.1.0. (new HScrollbar maxi [callback])
[CLASS] (ogre.lsh)


Returns a horizontal scrollbar for entering integer values in the range 0 to maxi . The callback function callback is called whenever the user releases the mouse button.



4.16.1.1. (new VScrollbar maxi [callback])
[CLASS] (ogre.lsh)


Returns a vertical scrollbar for entering integer values in the range mini to maxi . The callback function callback is called whenever the user releases the mouse button.



4.16.1.2. (==> Scrollbar setrange mini maxi [prop])
[MSG] (ogre.lsh)


See: (==> Slider setrange mini maxi )


Message setrange redefines the minimal and maximal values allowed in a scrollbar. When the optional argument prop is provided, the maximal value is reduced by prop and the value prop is used for defining the size of the knob. This is useful for scrolling lists of texts.



4.17. Composite Objects


This chapter describes a few standard objects composed of several elementary objects. Although composite objects usually are subclasses of Form , they obey the protocols defined for class Control .



4.17.0. Viewers


A viewer object display a rectangular portion of a particular object (the viewer's contents). The size of the visible part of this object depends on the viewer size. The user control which part of the object is visible by sending messages setpos or by using the optional scrollbars provided by the viewer.

Class Viewer implements viewer objects.



4.17.0.0. (new Viewer w h contents [hp vp])
[CLASS] (ogre.lsh)


Creates a new viewer on object contents . The viewer is w points wide and h points high. The optional argument hp (resp. vp ) is a boolean value ( t or () ) controling whether an horizontal (resp. vertical) scrollbar is displayed or not.

Example:

? (setq win (new WindowObject 0 0 400 200 "Essai"
                (new Viewer 300 150 
                        (new column (new stdbutton "One" ())
                                    (new emptyspace 60 60)
                                    (new stdbutton "Two" ())
                                    (new stdbutton "Three" ())
                                    (new stdbutton "Four" ()) )
                         t t) ) )



4.17.0.1. (==> Viewer setpos h v)
[MSG] (ogre.lsh)


Message setpos defines the visible portion of the contents of a viewer. This portion is a rectangle whose top left corner is located h pixels to the right and v pixels below the top left corner of the contents of the Viewer object.



4.17.0.2. (==> Viewer sethpos h)
[MSG] (ogre.lsh)


Message sethpos just change the horizontal coordinate of the visible portion of the contents of a viewer.



4.17.0.3. (==> Viewer setvpos v)
[MSG] (ogre.lsh)


Message setvpos just change the vertical coordinate of the visible portion of the contents of a viewer.



4.17.0.4. (==> Viewer setcontenu object)
[MSG] (ogre.lsh)


Message setcontenu changes the object viewed through a Viewer object. Argument object must be a valid graphic component.



4.17.1. Selectors


A selector is an object which allow the user to select one or several strings within a list of strings. Only a few strings are visible at a given time. A scrollbar located along the right side of the Selector object controls which strings are visible. Selected strings are hilighted.

Class Selector implements a selector object. The complete behavior of a selector is controlled by three slots of the selector object: multiple , call1 and call2 .

Two callback functions are called when the user selects items.



4.17.1.0. (new Selector nvisible [callback [items]])
[CLASS] (ogre.lsh)


Creates a new selector able to display nvisible strings at once.

Argument callback of the constructor controls the values of these flags.

Argument items optionally gives a list of strings initially displayed in the selector.



4.17.1.1. (==> Selector getdata)
[MSG] (ogre.lsh)


Message getdata returns the selected strings in a selector:

4.17.1.2. (==> Selector getdatanum)
[MSG] (ogre.lsh)


Instead of returning the strings themselves, like message getdata , message getdatanum returns the order number of the selected strings in a selector:

4.17.1.3. (==> Selector setdata data)
[MSG] (ogre.lsh)


Message setdata sets which strings are selected in a selector. The selected strings are displayed on a highlited background.

4.17.1.4. (==> Selector setpos pos)
[MSG] (ogre.lsh)


Message setpos makes the pos -th string appear on top of the selector and updates the scrollbar in accordance.



4.17.1.5. (==> Selector setitems items)
[MSG] (ogre.lsh)


Message setitems redefines a new list of strings items displayed in a selector and clears the current selection.

Since the minimal size of a selector depends on the width of the largest string in the item list, sending message setitems can trigger a geometry negociation and readjust the location of all interface components.



4.18. A Complete Example


Whole graphics interface are often defined as subclasses of class WindowObject . Such subclasses usually contain new slots for storing interface specific data. Callback functions then send messages to thiswindowobject . These messages then are executed within the interface scope.



4.18.0. The Class Browser "classtool"


This section describes a complete application of the Ogre library. This application is nothing but the standard Tlisp class browser. This class browser is invoked by typing the command (classtool) .



4.18.0.0. (classtool [cl])
[DE] (classtool.lsh)


Invokes the Lush class browser on class cl . The class browser displays the subclasses, superclasses, slots and methods of a class. Class object is assumed if no argument is specified.

The class browser interface is composed of a menu and six selectors:

The top of the class browser contains a menu and an information string. The information string displays the number of slots, the number of inherited slots, the number of methods and the number of inherited methods for the current class. The name of the menu is always the name of the current class, displayed in large characters.

The menu itself contains four items:



4.18.1. The Program "classtool"


Here is a review of the main components of the ``classtool'' program. You can look at the complete listing of this program in file:
     <lushdir>/lib/classtool.lsh

The first executable line of file "classtool.lsh" initializes the Ogre library by calling function ogre . This is necessary to ensure that the Ogre class library is properly loaded and initialized.

(ogre)

Then we define a subclass c-classtool of class WindowObject . This class contains several slots for referencing the major components of the interface.

(defclass c-classtool windowobject
  the-menu                ;; the menu
  the-string              ;; the information string
  the-i-classes           ;; the superclass selector
  the-i-slots             ;; the inherited slots selector
  the-i-methods           ;; the inherited methods selector
  the-classes             ;; the subclass selector
  the-slots               ;; the slots selector
  the-methods             ;; the method selector
  the-error-requester     ;; a signaling requester
  the-class-requester     ;; the requester
  cl )                    ;; the current class

We define then the constructor of class c-classtool . This constructor first calls the constructor of its superclass WindowObject and defines the contents of the window object. This very long call sets up the major components of the classtool interface.

All the interface is a single column which contains:

         (setq the-menu
             (new Menu "object"
                "Show Class"    
                (lambda(c) (==> thiswindowobject display-action))
                "Show Subtree"    
                (lambda(c) (==> thiswindowobject subtree-action))
                "Refresh" 
                (lambda(c) (==> thiswindowobject refresh-action))
                "Select"  
                (lambda(c) (==> the-class-requester popup))
                "Quit"    
                (lambda(c) (==> thiswindowobject delete)) ) )
  (setq :the-menu:textfont font-18)
  (==> the-menu compute-geometry)

The constructor of class c-classtool then creates two requesters.

  (setq the-error-requester 
        (new ErrorRequester this) )
  (setq the-class-requester 
        (new YesNoRequester this
             (new column
                  (new String "Type a class name")
                  (new DarkSpace 3)
                  (let ((x (new EditString 20)))
                    (setq :x:regex "[A-Za-z]?[-_|A-Za-z0-9]*") x) )
             " Ok " "Cancel"
             (lambda(c) (==> thiswindowobject select-action)) ) ) )

Method setclass is then defined. This method collects the class information for the selected class and updates the information displayed in the selectors.

It first checks that its argument is a valid class and pops up the error requester if this check is negative.

(defmethod c-classtool setclass(c)
  (if (not (and c (classp c)))
      (==> the-error-requester popup "This is not a valid class")

If the check is positive, method setclass displays a message "working" in the message string and force an immediate display update using message repair-damaged .

    (==> the-string settext "<<working>>")
    (==> this repair-damaged)

The menu title is then changed to the class name using method settext . Since the display update is delayed until all events are processed, this change becomes visible when all selectors are updated.

Method setclass then collects the class information into six lists: the subclass list ( cc ), the slot list ( cs ), the method list ( cm ), the superclass list ( ic ), the inherited slot list ( is ) and the inherited method list ( im ). We take a particular care of separating the various inherited classes by a dummy entry in the inherited lists.

This information is then loaded into the selectors using method setitems . The message string is then updated to the class statistics.

        (==> the-classes setitems cc)
        (==> the-slots setitems cs)
        (==> the-methods setitems (sort-list cm >))
        (==> the-i-classes setitems ic)
        (==> the-i-slots setitems is)
        (==> the-i-methods setitems im)
        (==> the-string settext 
             (sprintf "  %l: %d+%d slots, %d+%d methods"
                      cn (length cs) isc (length cm) imc) ) ) ) ) )

We define then the various action methods which are called by the menu items, by the selectors, or by the class selection requester.

Method classes-action is called when the user selects a class in the subclass or superclass requester. This method just sends a message setclass to switch to the new class.

(defmethod c-classtool classes-action(c)
  (let ((cn (==> c getdata)))
    (==> this setclass (apply scope (list (named cn)))) ) )

Method methods-action is called when the user selects a method in the method selector or the inherited method selector. Method methods-action first makes sure that the user did not select a dummy entry used for separating the classes in the inherited method selector. It uses then function pretty-method to print the definition of the selected method.

(defmethod c-classtool methods-action(c)
  (let ((m (==> c getdata))
        (cl cl))
    (when (<> (left m 5) "=====")
          (setq m (named m))
          (while (and cl ~(member m (methods cl)))
            (setq cl (super cl)) )
          (when cl
                (==> this repair-damaged)
                (==> c setdata ())
                (print) 
                (pretty-method cl m) ) ) ) )

Method refresh-action is called by the menu item "Refresh" . It just calls method setclass on the current class (from slot cl ) in order to reload the class information.

(defmethod c-classtool refresh-action()
  (==> this setclass cl) )

Method display-action is called by the menu item "Show Class" . It just prints the class definition when adequate.

(defmethod c-classtool display-action()
  (if (not (super cl))
      (beep)
    (print)
    (pprint (nconc (list 'defclass (classname cl) (classname (super cl))) 
                   (slots cl) )) ) )

Method subtree-action is called by the menu item "Show Subtree" . It just prints an indented list of the subclasses of the current class.

(defmethod c-classtool subtree-action()
  (let ((subtree (lambda(cl tb)
                   (tab tb)
                   (print (classname cl))
                   (each ((c (subclasses cl)))
                         (subtree c (+ tb 2)) ) ) ))
    (print)
    (subtree cl 2) ) )

Method select-action is called when the class selection requester pops down. It gets the class name typed by the user (using getdata ), normalize the name and calls method setclass again.

(defmethod c-classtool select-action()
  (let ((cn (car (==> the-class-requester getdata))))
    (if (regex-match "\\|.*\\|" cn)
        (setq cn (regex-subst "^\\|(.*)\\|$" "%0" cn))
      (setq cn (downcase cn)) )
    (==> this setclass (apply scope (list (named cn)))) ) )

We override then method keypress in order to define an accelerator key. Depressing the space bar pops up the class selection requester. All other keypress events are handled by the default method which just ignore these events.

(defmethod c-classtool keypress(c x y)
  (selectq c
    (" " (==> the-class-requester popup))
    (t (==> this (windowobject . keypress) c x y)) ) )

Finally the hook function classtool creates an instance of class c-classtool and sets the initial class displayed in the browser

(de classtool( &optional (cl object) )
    (when (symbolp cl) 
          (setq cl (eval cl)) )
    (when (not (classp cl)) 
          (error t "Not a class" cl) )
    (let ((w (new c-classtool)))
      (==> w setclass cl) ) )

In addition, an autoload function classtool is defined in file "stdenv.lsh" which loads file "classtool.lsh" and calls this function classtool .