You are looking at historical revision 25662 of this page. It may differ significantly from its current revision.

Tutorial on the Iup Graphical User Interface toolkit

Iup is a small and easy to use GUI toolkit, originally written in pure C, but accompanied by an optional resource language LED, to make life easier. It has later been ported to Lua and other scripting languages, and nowadays it is considered Lua's native GUI-toolkit. Thanks to Thomas Chust Chicken and Racket ports exist as well.

Unfortunately, the documentation is somewhat scattered in the internet:

Chicken port of the Iup GUI library

the official API docs.

IUP "portable user interface" GUI library.

Hence you need to consult the original C documentation very often. So it seems appropriate to start with an example (Hello World, you guess it) showing how a C program is translated to Scheme. This way you'll become comfortable writing Scheme programs while using the original C documentation. But before that let me recapitulate some design principles of Iup.

Iup's design principles

Iup programs consist of dialogs, which communicate with each other. A dialog can contain only one widget, usually a container, which in turn can contain other widgets, containers included. For widgets to be visible, they must transparently be mapped to native widgets of the system: Gtk+ or Motif under X11, WinAPI under Windows or Cocoa with a third party extension under Mac OS X.

The mapping happens only once a dialog is shown. Destroying a dialog after its use destroys the included widgets as well. Hence, only dialogs need to be destroyed at the end of a program.

Like other GUI-toolkits, interaction with the user happens within a main loop. But what makes Iup stand out of the crowd are two principles:

First: No widget is ever positioned with explicit coordinates. Everything is done logically by nesting containers and positioning widgets like fill. This facilitates matters considerably.

Second: The appearance of all widgets and dialogs is controlled by attributes, their behaviour by callbacks. This makes the library small.

In C, attribute names as well as values are strings and attribute setting is a separate step from object construction. In Scheme a little more syntactic sugar is available: Attribute names are usually keywords, which can be passed directly to widget constructors. Attribute values can be almost anything you want, including handles and anything that can sensibly be converted to a string.

When you get or set an attribute explicitly, you can also use strings or symbols as attribute names. Getting is done (in Scheme) by the attribute function, setting by the attribute-set! procedure or a generalized set!, i.e. either by

(attribute-set! widget name: val) or (set! (attribute widget name:) val)

whichever you prefer. The same applies to callbacks, which are get and set by callback and callback-set! respectively.

In Scheme's Iup callbacks are functions of one or more arguments, including self, which can return a symbol, for example 'close, to close a dialog, or 'default, to keep it open. In C, on the other hand, the return values are #define'd integers.

Hello World

Let's start with the most trivial version, in C and in Chicken:

hello0.c


#include <iup.h>
#include <stdlib.h>

int main (int argc, char *argv[]) {
  IupOpen(&argc, &argv);
  IupShow(IupDialog(IupLabel ("Hello, world!")));
  IupMainLoop();
  IupClose();
  return 0;
}

hello0.scm


(use iup)
(show (dialog (label "Hello, world!")))
(main-loop)
(exit 0)

Note, that initializing and closing iup disappears in Chicken, since it is done when inporting iup. Note also, that the Chicken names are much friendlier than the C ones: Chicken's module system makes Iup prefixes superfluous, they can be added, if needed, with appropriate import clauses.

Now a version which shows, how to use attributes and callbacks, again in C, and in two Chicken versions. The first is almost a literal translation of the C version, the second a condensed version, where all attributes are set in the creation process.

hello1.c


#include <iup.h>
#include <stdlib.h>

int exit_cb (void) {
  return IUP_CLOSE;
}

int main (int argc, char *argv[]) {

  // declare widgets
  Ihandle *btn, *lbl, *vb, *dlg;

  // initialize iup
  IupOpen(&argc, &argv);
  
  // create widgets and set their attributes
  btn=IupButton("&Ok", "");
  IupSetCallback(btn,"ACTION", (Icallback) exit_cb);
  IupSetAttribute(btn, "EXPAND", "Yes");
  IupSetAttribute(btn, "TIP", "Exit button");
  
  lbl=IupLabel("Hello,world!");

  vb=IupVbox(lbl, btn);
  IupSetAttribute(vb, "GAP", "10");
  IupSetAttribute(vb, "MARGIN", "10x10");
  IupSetAttribute(vb, "ALIGNMENT", "ACENTER");

  dlg=IupDialog(vb);
  IupSetAttribute(dlg, "TITLE", "Hello");

  // Map widgets and show dialog
  IupShow(dlg);

  // Wait for user interaction
  IupMainLoop();

  // Clean up
  IupDestroy(dlg);
  IupClose();
  return EXIT_SUCCESS;
}

hello11.scm

Here is a translation to Scheme ...


(use iup)

(define (cb-exit self) 'close)

(define btn (button))
(set! (callback btn action:) cb-exit)
(set! (attribute btn title:) '&Ok)
(set! (attribute btn expand:) 'Yes)
(set! (attribute btn tip:) "Close button")

(define lbl (label "Hello World!")) 

(define vb (vbox lbl btn))
(attribute-set! vb gap: 10)
(attribute-set! vb margin: '15x15)
(attribute-set! vb alignment: 'ACENTER)

(define dlg (dialog vb))
(attribute-set! dlg title: 'Hello)

(show dlg)
(main-loop)
(destroy! dlg)
(exit 0)

Note, how the upper-case C-names of attributes change to lower-case Chicken-keywords (by the way, Chicken-keywords can be either written with a trailing colon or a leading hash-colon, but I prefere the former, which looks nicer).

Note also, that attribute values can be numbers or symbols as well. The Iup convention is to use "Yes" and "No" as boolean values. In Scheme you can use symbols as well. And last, but not least, note the tips: attribute, which defines tooltips, and the ampersand in the button's title, which defines a shortcut, Alt+underlined-character, to execute the callback.

hello12.scm

... and here a condensed version.


(use iup)

(define dlg
  (dialog
    (vbox
      (label "Hello, World!")
      (button title: '&Ok
              expand: 'Yes
              tip: "Close button"
              action: (lambda (self) 'close))
      gap: 10
      alignment: 'ACENTER
      margin: '15x15)
    title: 'IUP))

(show dlg)
(main-loop)
(destroy! dlg)
(exit 0)

Note, how smoothly the indentation reflects the logical representation of the dialog.

The LED resource language

The condensed version above can be almost literally transformed into a LED resource file, which can be either loaded into a C program or a Scheme program. Those resources are interpreted at runtime, so that even in a compiled program the resource can be changed afterwards, provided the identifiers remain consistent.

The form of a LED-declaration looks as follows


widget=widget-type[attribute-name=attribute-value, ...](arg, ...)

where the attributes' names and values are written without enclosing quotes, but interpreted as strings.

Here is an example and its use in Chicken.

hello.led


btn = button[TIP = "Close window", EXPAND = Yes]("&Ok", 0)

dlg = dialog[TITLE = Hello](
            vbox[GAP = 10, MARGIN = 15x15, ALIGNMENT = ACENTER](
                label("Hello world!"),
                btn))

hello13.scm


(use iup)

(load/led "hello.led")

(callback-set! (handle-ref "btn")
               action: (lambda (self) 'close))

(define dlg (handle-ref "dlg"))

(show dlg)
(main-loop)
(destroy! dlg)
(exit 0)

Note, that the LED-import is done via load/led and the identification of LED-names with Chicken-variables via handle-ref.

Note also, that btn must have a name, because we need to set the callback, which can not be a string.

You can compile hello13.scm with csc and change hello.led afterwards. Try it out and play with some attributes, for example, remove the EXPAND attribute from btn and set it for label, ...

Porting some examples from the Iup Distribution

Now we'll show, how some predefined widgets work. For that we'll port some of the C-examples.

fill.scm

The following dialog shows, how different positions of the fill widget change the dialog's appearance.


(use iup)

;;; Create frame with left aligned button
(define frame-left
  (frame
    (hbox
      (button title: '&Left
              tip: "Left button"
              action: (lambda (self)
                        (print "Stay in with Left button")
                        'default))
      (fill))))
(set! (attribute frame-left title:) "Left aligned")

;;; Create frame with centered button
(define frame-center
  (frame
    (hbox
      (fill)
      (button title: '&Center
              tip: "Central button"
              action: (lambda (self)
                        (print "Way out with Central button")
                        'close))
      (fill))))
(attribute-set! frame-center title: "Centered")

;;; Create frame with right aligned button
(define frame-right
  (frame
    (hbox
      (fill)
      (button title: '&Right
              tip: "Right button"
              action: (lambda (self)
                        (print "Way out with Right button")
                        'close)))
    title: "Right aligned"))

; Note, that callbacks should return a symbol.
; Only the symbol 'close of the action: callbacks closes the dialog!

;;; Create dialog with these three frames
(define dlg
  (dialog
    (vbox
      frame-left
      frame-center
      frame-right)))
(set! (attribute dlg size:) 120)
(set! (attribute dlg title:) 'Fill)

(show dlg)
(main-loop)
(destroy! dlg)
(exit 0)

hbox.scm

This dialog shows, how horizontal boxes within vertical ones work.


(use iup)

(define dlg
  (dialog
    (vbox
      (frame
        (hbox (fill)
              (button "1" "" size: "30x30")
              (button "2" "" size: "30x40")
              (button "3" "" size: "30x50")
              (fill)
              alignment: "ATOP"
              gap: 10
              size: 200)
        title: "alignment: ATOP gap: 10 size: 200"
        gap: 10
        size: 200)
      (frame
        (hbox (fill)
              (button "1" "" size: "30x30")
              (button "2" "" size: "30x40")
              (button "3" "" size: "30x50")
              (fill)
              alignment: "ACENTER"
              gap: 20)
        title: "alignment: ACENTER gap: 20"
        gap: 20)
      (frame
        (hbox (fill)
              (button "1" "" size: "30x30")
              (button "2" "" size: "30x40")
              (button "3" "" size: "30x50")
              (fill)
              alignment: "ABOTTOM"
              size: 150)
        title: "alignment: ABOTTOM size: 150"
        size: 150))
    title: "Hbox"))

(show dlg x: 'center y: 'center)
(main-loop)
(destroy! dlg)

Now a dialog with a menu and submenus, one of whose items call a predefined message-dialog.


(use iup iup-dialogs)

(define item-open (menu-item "&Open"))

(define item-save (menu-item "&Save"))

(define item-undo (menu-item "&Undo" active: "NO"))

(define item-exit (menu-item "E&xit"))
(set! (callback item-exit action:)
      (lambda (self) 'close))

(define file-menu
  (menu item-open 
        item-save 
        (menu-separator)
        item-undo
        item-exit))

(define item-about (menu-item "&About"))
(define (about-cb self)
  (show (message-dialog value: "Information goes here ...") modal?: #t)
  'default)
(callback-set! item-about action: about-cb)

(define help-menu
  (menu item-about))

(define mnu
  (menu (menu-item "&File" file-menu)
        (menu-item "&Help" help-menu)))
;(set! (handle-name mnu) "mymenu")

(define dlg (dialog (canvas "")))
(set! (attribute dlg menu:) mnu);"mymenu")
(set! (attribute dlg title:) "Menu")

(show dlg)
(main-loop)
(exit 0)

Note, that the underlined characters behave differently in menus and submenus. In the former they execute their callbacks with the Alt prefix, in the latter without.

Note also, that predefined dialogs can only be shown with the modal?: attribute set.

filedlg.scm

Now we use two predefined dialogs, file-dialag and message-dialog. You should note, that they are mapped to gtk-dialogs!


(use iup)

(define (popup dlg . args)
  (apply show dlg #:modal? #t  args)
  (destroy dlg))

(define dlg (file-dialog title: "File save"
                         dialogtype: 'SAVE
                         filter: "*.led"
                         filterinfo: "Iup resource file"))

(popup dlg x: 'center y: 'center)

(let ((status (attribute dlg status:)))
  (cond
    ((string=? status "1")
     (popup
       (message-dialog value: (string-append  "New File: "
                                              (attribute dlg value:)))))
    ((string=? status "0")
     (popup
       (message-dialog value: (string-append  "File already exists: "
                                              (attribute dlg value:)))))
    ((string=? status "-1")
     (popup
       (message-dialog value: "File-dialog: Operation Canceled")))))

(destroy! dlg)
(exit 0) 

Note, that the status: attribute of the file-dialog is a string!

multiline.scm

Now, we'll show how widgets within a dialog can communicate whith each other. The trick is, that Iup can reference widgets by name, or, to be more precise, by string name. You have seen this in the LED example above: In LED a widget is named by a string and constructed by the LED interpreter. To use it in Scheme, you reference the widget proper from its name via handle-ref. This can be done without LED as well. But then you must give the widget a string name via handle-name-set! or the generalized version (set! (handle-name widget) name).

The following dialog contains two textboxes, one of them multiline, a dropdown listbox and some buttons, allowing to get or set the multiline attributes. Please take note, how handle-ref and handle-name is used.


(use iup)

(define (message title value)
  (show (message-dialog title: title value: value) #:modal? #t))

;; setter and getter
;; widgets are referenced by name
(define (set-attribute keyword)
  (let (
    (msg (sprintf "Attribute ~A set with value ~A"
                  keyword (attribute single value:)))
    (multi (handle-ref "multi"))
    (single (handle-ref "single"))
    )
    (attribute-set! multi keyword (attribute single value:))
    (message "Set attribute" msg)
    'default))

(define (get-attribute keyword)
  (let (
    (msg (sprintf "Attribute ~A get with value ~A"
                  keyword (attribute multi keyword)))
    (multi (handle-ref "multi"))
    (single (handle-ref "single"))
    )
    (attribute-set! single value: (attribute multi keyword))
    (message "Get attribute" msg)
    'default))

;; callback generator
(define (cb keyword)
  (lambda (self)
    (let ((lb (handle-ref "lb")))
      (if (eqv? (string->number (attribute lb value:)) 1)
        (set-attribute keyword)
        (get-attribute keyword))
      'default)))

;; buttons
(define btn-append
  (button title: '&Append
          action: (cb append:)))

(define btn-insert
  (button title: '&Insert
          action: (cb insert:)))

(define btn-border
  (button title: '&Border
          action: (cb boarder:)))

(define btn-caret
  (button title: '&Caret
          action: (cb caret:)))

(define btn-readonly
  (button title: '&Readonly
          action: (cb readonly:)))

(define btn-selection
  (button title: '&Selection
          action: (cb selection:)))

(define btn-selectedtextbox
  (button title: 'Selected&textbox
          action: (cb selectedbox:)))

(define btn-nc
  (button title: '&Nc
          action: (cb nc:)))

(define btn-value
  (button title: '&Value
          action: (cb value:)))

;; other widgets
(define lb (listbox #:1 'set #:2 'get value: 1 dropdown: 'Yes))
(define multi (textbox expand: 'Yes multiline: 'Yes))
(define single (textbox expand: 'horizontal))

;; name those other widgets, so that they can be referenced by name
(set! (handle-name lb) "lb")
(set! (handle-name multi) "multi")
(set! (handle-name single) "single")

;; the dialog
(define dlg
  (dialog (vbox multi
                (hbox lb
                      single)
                (hbox btn-append btn-insert btn-border btn-caret
                      btn-readonly btn-selection)
                (hbox btn-selectedtextbox btn-nc btn-value))
          title: "Multiline example"
          size: 'HALFxQUARTER))

(show dlg x: 'center y: 'center)
(main-loop)
(destroy! dlg)
(exit 0)

There is one caveat in the listbox: The lines must be denoted with prefixed keyword notation, 1: will not work, for example!

gauge-led.scm

Now a dialog with a gauge and a timer, written with a led resource.

Creates a gauge with 5 control buttons. The first button stops and starts the Gauge. The second one starts the Gauge. The third one reduces its speed. The fourth one increases its speed. The fifth one shows or hides the percentage inside the Gauge.

We start with the resource:


# play image (pause button)
img-play = image[1="0 0 0",2="BGCOLOR"](22,22,
  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2
 ,2,2,2,2,2,2,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 )
 
# start image (start button) 
img-start = image[1="0 0 0",2="BGCOLOR"](22,22,
  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,1,1,2,2,2,2,2,2,2,2,1,1,2,2,2,2,2,2
 ,2,2,2,2,1,1,2,2,2,2,2,2,1,1,1,1,2,2,2,2,2,2
 ,2,2,2,2,1,1,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2
 ,2,2,2,2,1,1,2,2,1,1,1,1,1,1,1,1,2,2,2,2,2,2
 ,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2
 ,2,2,2,2,1,1,2,2,1,1,1,1,1,1,1,1,2,2,2,2,2,2
 ,2,2,2,2,1,1,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2
 ,2,2,2,2,1,1,2,2,2,2,2,2,1,1,1,1,2,2,2,2,2,2
 ,2,2,2,2,1,1,2,2,2,2,2,2,2,2,1,1,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 )

# rewind image (decelerate button) 
img-rewind = image[1="0 0 0",2="BGCOLOR"](22,22,
  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,1,2,2,2,2,1,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,1,1,2,2,2,1,1,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,1,1,1,2,2,1,1,1,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,1,1,1,1,2,1,1,1,1,2,2,2,2,2,2,2
 ,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,1,1,1,1,2,1,1,1,1,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,1,1,1,2,2,1,1,1,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,1,1,2,2,2,1,1,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,1,2,2,2,2,1,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 )

# forward image (accelerate button)
img-forward = image[1="0 0 0",2="BGCOLOR"](22,22,
  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,1,2,2,2,2,1,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,1,1,2,2,2,1,1,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,1,1,1,2,2,1,1,1,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,1,1,1,1,2,1,1,1,1,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2
 ,2,2,2,2,2,2,2,1,1,1,1,2,1,1,1,1,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,1,1,1,2,2,1,1,1,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,1,1,2,2,2,1,1,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,1,2,2,2,2,1,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 )

# show image (show button) 
img-show = image[1="0 0 0",2="BGCOLOR"](22,22,
  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,1,1,2,2,2,2,1,1,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2
 ,2,2,2,2,2,1,2,2,2,1,1,1,2,2,2,2,1,2,2,2,2,2
 ,2,2,2,2,1,2,2,2,1,1,2,2,1,2,2,2,2,1,2,2,2,2
 ,2,2,2,1,2,2,2,2,1,1,1,2,1,2,2,2,2,2,1,2,2,2
 ,2,2,2,2,1,2,2,2,1,1,1,1,1,2,2,2,2,1,2,2,2,2
 ,2,2,2,2,2,1,2,2,2,1,1,1,2,2,2,2,1,2,2,2,2,2
 ,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,1,1,2,2,2,2,1,1,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,1,1,1,1,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
 ,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 )
 
start-btn = button[TIP="Reset", IMAGE=img-start]("start", 0)
pause-btn = button[TIP="Pause", IMAGE=img-play]("pause",0)
accelerate-btn = button[TIP="Accelerate", IMAGE=img-forward]( "accelerate", 0)
decelerate-btn = button[TIP="Rewind", IMAGE=img-rewind]( "decelerate", 0)
show-btn = button[TIP="Show", IMAGE=img-show]( "show", 0)

gauge-name=gauge[VALUE="0.84", EXPAND=YES]()
#gauge-name=GAUGE[VALUE="0.34", SIZE="QUARTERxEIGHTH"]()
command-box=hbox
(
  fill(),
  pause-btn,
  start-btn,
  decelerate-btn,
  accelerate-btn,
  show-btn,
  fill())

ok-btn =  button[TIP = "Close window", EXPAND = YES] ("&Ok", 0)

#end-box = HBOX(ok-btn)
end-box = HBOX(fill(), ok-btn, fill())

box=VBOX
(
  gauge-name,
  command-box,
  fill(),
  end-box
)

dlg = DIALOG[TITLE="Gauge", RESIZE=NO]
(
  box
)

And now the Scheme implementation


(use iup)

(define speed 0.00001)

;; callbacks

(define (ok-cb self) 'close)

(define (idle-cb self)
  (let (
    (value (string->number (attribute gauge-name value:)))
    (min (string->number (attribute gauge-name min:)))
    (max (string->number (attribute gauge-name max:)))
    )
    (set! (attribute gauge-name value:)
          (number->string (+ value speed)))
    (if (>= (string->number (attribute gauge-name value:)) max)
      (set! (attribute gauge-name value:) min))
    'default))

(define (pause-cb self)
  (if (not (attribute #f idle-action:))
    (set! (callback gauge-name idle-action:) (lambda (self) (idle-cb)))
    (set! (callback gauge-name idle-action:) #f))
  'default)

(define (start-cb self)
  (set! (attribute gauge-name value:)
        (attribute gauge-name min:))
  'default)

(define (accelerate-cb self)
  (set! speed (* 2 speed))
  (if (> speed 1.0) (set! speed 1.0))
  'default)

(define (decelerate-cb self)
  (set! speed (/ speed 2))
  'default)

(define (show-cb self)
  (if (attribute gauge-name show-text:)
    (begin
      (attribute-set! gauge-name show-text: 'No)
      (attribute-set! gauge-name dashed: 'Yes))
    (begin
      (attribute-set! gauge-name show-text: 'Yes)
      (attribute-set! gauge-name dashed: 'No))))

;; load resources
(load/led "gauge.led")

(define dlg (handle-ref "dlg"))
(define gauge-name (handle-ref "gauge-name"))

;; set callbacks
(callback-set! (handle-ref "pause-btn") action: pause-cb)
(callback-set! (handle-ref "start-btn") action: start-cb)
(callback-set! (handle-ref "accelerate-btn") action: accelerate-cb)
(callback-set! (handle-ref "decelerate-btn") action: decelerate-cb)
(callback-set! (handle-ref "show-btn") action: show-cb)
(callback-set! (handle-ref "ok-btn") action: ok-cb)

(define tim (timer #:time 100 #:action-cb idle-cb))
(attribute-set! tim run: 'Yes) ; doesn't work in constructor

(show dlg)
(main-loop)
(destroy! dlg)
(exit 0)

Concluding remark

All these examples show, that Iup is really easy to use ...

Author

Juergen Lorenz

Initial version

Nov 25, 2011

Last updated

Dec 04, 2011