NAME

IUP::Manual::01_Introduction - Basic introduction to IUP concept

IUP MANUAL

INTRODUCTION

IUP uses an abstract layout model based on the boxes-and-glue paradigm from the TeX typesetting system. This model makes the dialog creation task more flexible and independent from the graphics system's resolution.

IUP has four important concepts that are implemented in a very different way from other toolkits.

  • First is the control creation timeline. When a control is created it is not immediately mapped to the native system. So some attributes will not work until the control is mapped. The mapping is done when the dialog is shown or manually calling IupMap for the dialog. You can not map a control without inserting it into a dialog.

  • Second is the attribute system. IUP has only a few functions because it uses string attributes to access the properties of each control. So get used to IupSetAttribute and IupGetAttribute, because you are going to use them a lot.

  • Third is the abstract layout positioning. IUP controls are never positioned in a specific (x,y) coordinate inside the dialog. The positioning is always calculated dynamically from the abstract layout hierarchy. So get used to the IupFill, IupHbox and IupVbox controls that allows you to position the controls in the dialog.

  • Fourth is the callback system.

IUP ELEMENTS

IUP contains several user interface controls. The IUP's main characteristic is the use of native elements. This means that the drawing and management of a button or text box is done by the native interface system, not by IUP. This makes the application's appearance more similar to other applications in that system. On the other hand, the application's appearance can vary from one system to another.

But this is valid only for the standard controls, many additional controls are drawn by IUP. Composition controls are not visible, so they are independent from the native system.

Each control has an unique creation function, and all of its management is done by means of attributes and callbacks, using functions common to all the controls. This simple but powerful approach is one of the advantages of using IUP.

Controls are automatically destroyed when the dialog is destroyed.

Currently available IUP elements:

Every IUP based application has the main IUP::Dialog object and a set of other child GUI objects. Example:

 use IUP ':all';
 my $dlg = IUP::Dialog->new( TITLE=>"Test Dialog", MARGIN=>"10x10", child=>
             IUP::Vbox->new([
               IUP::Button->new( TITLE=>"This is testing demo Button1"),
               IUP::Button->new( TITLE=>"This is testing demo Button2"),
             ])
           );
 $dlg->Show;
 IUP->MainLoop;

For more info see separate documents:

ATTRIBUTES CONCEPT

Attributes are used to change or consult properties of elements. Each element has a set of attributes that affect it, and each attribute can work differently for each element. Depending on the element, its value can be computed or simply verified. Also it can be internally stored or not.

Attribute names are always upper case, lower case names will not work. But attribute values like "YES", "NO", "TOP", are case insensitive, so "Yes", "no", "top", and other variations will work.

If not defined their value can be inherited from the parent container.

Using Attributes

Attributes are a way to send and obtain information to and from elements. They are used by the application to communicate with the user interface system, on the other hand callbacks are used by the application to receive notifications from the system that the user or the system itself has interacted with the user interface of the application.

The ways of setting an attribute value:

 #via standard SetAttribute() call
 $element->SetAttribute("ATTRNAME", "VALUE");
 
 #via standard SetAttribute() call + using fat-comma
 $element->SetAttribute( ATTRNAME=>"VALUE" );
 
 #setting more attributes at once - via standard SetAttribute()
 $element->SetAttribute( ATTRNAME1=>"VALUE1", ATTRNAME2=>"VALUE2" );
 
 #via accessor
 $element->TITLE("Text");
 
 #setting attributes during element creation
 $element = IUP::Label->new( TITLE=>"Text", ATTRNAME1=>"VALUE1", ATTRNAME2=>"VALUE2" );
 
 #which is equivalent to
 $element = IUP::Label->new();
 $element->SetAttribute("TITLE", "Text");
 $element->SetAttribute("ATTRNAME1", "VALUE1");
 $element->SetAttribute("ATTRNAME2", "VALUE2");

When an attribute is updated (Set) it is stored internally at the hash table of the control only if the control class allows it. If the value is undef, the attribute will also be removed from the hash table and the default value will be used if there is one defined. Finally the attribute is updated for the children of the control if they do not have the attribute defined in their own hash table.

The ways of getting an attribute value:

 #via GetAttribute() call
 $value = $element->GetAttribute("ATTRNAME");
  
 #getting more attributes at once - via GetAttribute()
 ($val1, $val2, $val3) = $element->GetAttribute( "ATTRNAME1", "ATTRNAME2", "ATTRNAME3" );
 
 #via accessor
 $value = $element->TITLE;
 

When an attribute is retrieved (Get) it will first be checked at the control class. If not defined then it checks in the hash table. If not defined it checks its parent hash table and so forth, until it reaches the dialog. And finally if still not defined then a default value is returned (the default value can also be undef).

Notice that the parent recursion is done only at the parent hash table, the parent control class is not consulted.

The control class can update or retrieve a value even if the control is not mapped. When the control is not mapped and its implementation can not process the attribute, then the attribute is simply stored in the hash table. After the element is mapped its attributes are re-processed to be updated in the native system and they can be removed from the hash table at that time.

All this flexibility turns the attribute system very complex with several nuances. If the attribute is checked before the control is mapped and just after, its value can be completely different. Depending on how the attribute is stored its inheritance can be completely ignored.

Attribute names are always upper case, lower case names will not work. But attribute values like "YES", "NO", "TOP", are case insensitive, so "Yes", "no", "top", and other variations will work.

Boolean attributes accept the values:

  • 1, "YES", "ON" or "TRUE" for true

  • 0, "NO", "OFF", undef or "FALSE" for false

Even if in the documentation is only one of these combinations.

There are attributes common to all the elements. In some cases, common attributes behave differently in different elements, but in such cases, there are comments in the documentation of the element explaining the different behavior.

Attribute accessors

Attribute accessors are build at run-time via perl's AUTOLOAD feature.

It means that:

 $val = $element->ANY_UPPERCASE_ATTR_NAME;
 $element->ANY_OTHER_UPPERCASE_ATTR_NAME(123);

is automatically turned into:

 $val = $element->GetAttribute('ANY_UPPERCASE_ATTR_NAME');
 $element->SetAttribute('ANY_OTHER_UPPERCASE_ATTR_NAME', 123);

Inheritance

Elements included in other elements can inherit their attributes. There is an inheritance mechanism inside a given child tree.

This means, for example, that if you set the "MARGIN" attribute of a Vbox containing several other elements, including other Vboxes, all the elements depending on the attribute "MARGIN" will be affected, except for those who the "MARGIN" attribute is already defined.

Please note that not all attributes are inherited. As general rules the following attributes are NON inheritable always:

  • Essential attributes like VALUE, TITLE, SIZE, RASTERSIZE, X and Y

  • Id numbered attributes (like "1" or "MARK1:1")

  • Handle names (like "CURSOR", "IMAGE" and "MENU")

  • Pointers that are not strings (like WID)

  • Read-only or write-only attributes

  • Internal attributes that starts with "_IUP"

Inheritable attributes are stored in the hash table so the SetAttribute / GetAttribute logic can work, even if the control class store it internally. But when you change an attribute to NULL, then its value is removed from the hash table and the default value if any is passed to the native system.

When consulted the attribute is first checked at the control class. If not defined then it checks in the hash table. If not defined in its hash table, the attribute will be inherited from its parent's hash table and so forth, until it reaches the root child (usually the dialog). But if still then the attribute is not defined a default value for the element is returned (the default value can also be NULL).

When changed the attribute change is propagated to all children except for those who the attribute is already defined in the hash table.

But some attributes can be marked as non inheritable at the control class.

Non inheritable attributes at the element are not propagated to its children. If an attribute is not marked as non inheritable at the element it is propagated as expected, but if marked as non inheritable at a child, that child will ignore the propagated value.

Since Vbox, Hbox, and other containers have only a few registered attributes, by default an unknown attribute is treated as inheritable, that's why it will be automatically propagated.

An example: the IMAGE attribute of a Label is non inheritable, so when checked at the Label it will return NULL if not defined, and the Label parent tree will not be consulted. If you change the IMAGE attribute at a Vbox that contains several Labels, the child Labels will not be affected.

Availability

Although attributes can be changed and retrieved at any time there are exceptions and some rules that must be followed according to the documentation of the attribute:

  • read only: the attribute can not be changed. Ignored when set.

  • write only: the attribute can not be retrieved. Normally used for action attributes. Returns NULL, or eventually some value set before the element was mapped.

  • creation only: it will be used only when the element is mapped on the native system. So set it before the element is mapped. Ignored when set after the element is mapped.

Creating an IUP element - for example button with text label "Hello":

  my $demo_button = IUP::Button->new( TITLE=>"Ok" );

If you want the same button with changed background color, you can:

  • specify BGCOLOR attribute value when creating the element:

     my $demo_button = IUP::Button->new( TITLE=>"Hello", BGCOLOR=>"0 255 0" );
     
  • or using BGCOLOR accessor:

     my $demo_button = IUP::Button->new( TITLE=>"Hello" );
     $demo_button->BGCOLOR("0 255 0");
  • or via SetAttribute method:

     my $demo_button = IUP::Button->new( TITLE=>"Hello" );
     $demo_button->SetAttribute("BGCOLOR", "0 255 0");

Some interface elements can contain one or more elements, as is the case of dialogs, lists and boxes. In such cases, the object's element list items can be accessed by indexing the object containing them, as can be seen in this example:

 $mybox = IUP::Hbox->new( child=>[ $bt1, $bt2, $bt3] );
 #XXX-FIXME THIS DOES NOT WORK IN PERL
 $mybox->[0]->FGCOLOR("255 0 0");   # changes bt1 foreground color
 $mybox->[1]->FGCOLOR("255 0 255"); # changes bt2 foreground color

CALLBACKS CONCEPT

IUP is a graphics interface library, so most of the time it waits for an event to occur, such as a button click or a mouse leaving a window. The application can inform IUP which callback to be called, informing that an event has taken place. Hence events are handled through callbacks, which are just functions that the application register in IUP.

The events are processed only when IUP has the control of the application. After the application creates and shows a dialog it must return the control to IUP so it can process incoming events. This is done in the IUP main event loop. And it is usually done once per application. One exception is the display of modal dialogs. These dialogs will have their own event loop and the previous shown dialogs will stop receiving events until the modal dialog returns.

Using Callbacks

Callbacks are used by the application to receive notifications from the system that the user or the system itself has interacted with the user interface of the application. On the other hand attributes are used by the application to communicate with the user interface system.

Even though callbacks have different purposes from attributes, they are also associated to an element by means of an name.

The ways of setting callback:

 sub cb_handler1 {
   #...
 }
 
 sub cb_handler2 {
   #...
 }

 #via standard SetCallback() call
 $element->SetCallback("ACTION", \&cb_handler1);
 
 #via standard SetCallback() call + using fat-comma
 $element->SetAttribute( ACTION=>\&cb_handler1 );
 
 #using anonymous function
 $element->SetCallback( ACTION=>sub { IUP->Message('Hi!') } );
 
 #setting more callbacks at once
 $element->SetAttribute( ACTION=>\&cb_handler1, K_ANY=>\&cb_handler2 );
 
 #via accessor
 $element->ACTION(\&cb_handler2);

 #setting attributes during element creation
 $element = IUP::Button->new( TITLE=>"Text", ACTION=>\&cb_handler1, K_ANY=>\&cb_handler2 );
 
 #which is equivalent to
 $element = IUP::Button->new();
 $element->SetAttribute( TITLE=>"Text" );
 $element->SetCallback( ACTION=>\&cb_handler1 );
 $element->SetCallback( K_ANY=>\&cb_handler2 );

Callbacks do NOT have inheritance like attributes.

All callbacks receive at least the reference to the element which activated the action as a parameter $self. Each callback handler has given set of parameters e.g. BUTTON_CB callback expects handler function like:

 sub button_cb_handler {
   my ($self, $button, $pressed, $x, $y, $status) = @_;
   #...
 }

Always check documentation for specific callback to get the information about expected hanler function.

The callbacks should return one of the following values:

  • IUP_DEFAULT: Proceeds normally with user interaction. In case other return values do not apply, the callback should return this value.

  • IUP_CLOSE: Call ExitLoop after return. Depending on the state of the application it will close all windows and exit the application. Applies only to some actions.

  • IUP_IGNORE: Makes the native system ignore that callback action. Applies only to some actions.

  • IUP_CONTINUE: Makes the element to ignore the callback and pass the treatment of the execution to the parent element. Applies only to some actions.

IUP_DEFAULT will automatically be returned if no value is returned from callback handler.

Only some callbacks support the last 3 return values. Check each callback documentation. When nothing is documented then only IUP_DEFAULT is supported.

An important detail when using callbacks is that they are only called when the user actually executes an action over an element. A callback is not called when the programmer sets a value via SetAttribute. For instance: when the programmer changes a selected item on a list, no callback is called.

The order of callback calling is system dependent. For instance, the RESIZE_CB and the SHOW_CB are called in different order in Win32 and in X-Windows when the dialog is shown for the first time.

Callback accessors

XXX-FIXME-ADD ACCESSOR TABLE

MainLoop

IUP is an event-oriented interface system, so it will keep a loop “waiting” for the user to interact with the application. For this loop to occur, the application must call the MainLoop function, which is generally used right before IUP::Close.

When the application is closed by returning IUP_CLOSE in a callback, calling ExitLoop or by hiding the last visible dialog, the function MainLoop will return.

The LoopStep and the Flush functions force the processing of incoming events while inside an application callback.