
Description and Use of the widget's description database.
========================================================

One of the goals for Radical is for it to be as extensible as possible (and
this as easily as possible of course). Given the number of widgets in gtk+
proper, as well as all the widgets found in the additional libraries that we
might want to support at some point (GNOME, gtkextra, GtkAda, ...), it is
fundamental that adding new widgets to the GUI builder doesn't require a lot of
coding.

The basic idea is thus that each possible widget or component should be
described in a database file, with enough information for the GUI builder and
the code generators to manipulate that widget and generate code for it.

Of course, we still need some code to instantiate the widget and modify its
properties. This code could be automatically generated and compiled from the
high-level description found in the database document.


Contents of the database file
=============================

A lot of information needs to be given in this file (ideally, everything should
be described there, so that the actual code for the GUI builder or the code
generators doesn't have any hard-coded special handling).

Here is a first list of required data:
  - "type name"
  - "type of widget"
    one of "container", "dialog", ... The list should be extensible, for
    instance if we get a "database" widget one day. At the interface level,
    this means that the icon for the widget will go in a notebook page with
    the given name
  - "file"
    header/spec file in which the widget is described. We need to specify
    this for each supported language.
  - "icon"
    icon (file name) to use in the gui builder (tree + widget selection)
  - "new"
    Function (and parameters) to use to create a new instance of the widget.
  - "min_children"
    minimal number of children (0 for non-container widgets)
  - "max_children"
    maximal number of children (0 for non-container widgets, 1 for children
    of Gtk_Bin, -1 for most containers to indicate an unlimited number)
  - "parent"
    name of the parent widget.
  - "interfaces"
    name of the interfaces that the widget implements (gtk+-2.0 only)
  - "signals"
    list of all the new signals defined by that widget type. This should
    include their parameters, return values, ... A documentation string should
    be tolerated, for display in the GUI builder.
  - "properties"
    List of properties of the widget that can be changed at the GUI level. This
    can for instance be the text associated with a label, the icon for a
    button, ... A documentation string should be allowed. A default value should
    be provided whenever appropriate so that the GUI builder can display as
    much information about the widget as possible. Associated with the default
    value, a flag should tell whether the default is known to Gtk+ or to the
    GUI builder only. This will in particular allow code generators to cut their
    output.
    Each property is associated with a list of subprograms used to modify it
    or get its value. Different subprogram names can be given for every
    language.
  - "children_add"
    Function to use to add children. Gtk+'s containers typically have several
    such function (pack_start, pack_end, add, append_widget, ...).
    It might be nice to find of a general way to describe which one should
    preferably be used, and in what cases. For Gtk_Box, Add is a synonym for
    Pack_Start_Defaults.
    There are several additional parameters that might need to be specified
    as well (coordinates for Gtk_Fixed, Shrink for Pack_Start, ...)
  - "children_type"
    name of the ancestor that a child must have. For instance, menus only
    support Menu_Item children, and not general widgets.
  - "style"
    what can be changed in the style (there is no point in changing the
    background of a label for instance, although changing the foreground
    make sense). This could be an indication for the GUI builder to
    transparently generate an intermediate event_box, in case the user has
    chosen to change the background anyway (FAQ for gtk+, would be nice to
    handle automatically).
  - "flags"
    A lot of general flags are needed (can the widget have the focus for
    keyboard events, default event mask,...). These will be integrated as
    we go along.
  - "default children"
    List of the children that are pre-created when a container is instantiated.
    For instance, a file selection widget has several such widgets. When such
    a widget is selected, the GUI builder first identifies the parent (widget
    with a name), and then find which of its children was selected by comparing
    the actual widgets with the fields of the container structure.
    Note that these default children might depend on which constructor was
    used.

Format of the database file
===========================

One suggestion is to create one database file per library (ie one for gtk,
one for gtk+extra, ...). This makes handling a little bit easier (no need
to copy several hundreds files). On the other hand, this also means that
finding the actual description of a widget within the file is a little bit
more cumbersome.

As a result, it seems best to allow each file to contains from one to several
widgets, leaving the organization itself to the library maintainer.

Also, to make things more readable, it seems a good idea to allow for fields
to be optional (for instance, non-container widgets do not need to specify
min_children or max_children).

Given all the requirements above, XML seems a very appropriate format.
It allows for optional fields, fields with default values, attributes to
fields, any order, ... And its syntax can be described in XML itself.

See Annex A for technical description of the database, and Annex B for
an example of its use.

Interface between the database and the GUI builder
==================================================

A certain number of functions need to be callable from the GUI builder, for
instance to create a new instance of a widget or to get/set its properties.

This "glue code" can be automatically generated from the database file, in
a format suitable for use by the GUI builder. Note that, since the GUI
builder is written in Ada, we only need to generate Ada code for the
interface.

This means that it is very easy to interface to any C widget library (through
pragma Import), but is not possible for other-languages libraries (though
they most probably provide a C interface as well).

The following information at least is needed:

  - Creating a new instance
    That/these functions should take no argument and return the newly created
    widget. Any argument needed by the actual underlying call (for
    gtk_button_new_with_label for instance) is extracted from the required
    fields, as indicated in the database file.

  - Setting properties
    Probably the best way is to have a single function, that takes three
    arguments: the widget, the field name as a string, and a reference to
    the "widget inspector" in the GUI builder. Let that function extract the
    value itself.

  - Destroying an instance and freeing the memory


Interface between the database and the code generators
======================================================

The GUI builder doesn't generate any external code itself. Instead, it
delegates to external code generators.

Each of them will of course read the actual interface from the saved
XML file. However, there is a number of information that they can extract
from the database file, like the list of header files to include when a
widget is used, the function to call to instantiate the widget, ...
This will hopefully make the code generators easier to write.

Note: another possible approach would be to have the code generator also
generic and have all the necessary information in the description file to
generate the code directly.


Annex A: XML Schema description of the format
=============================================

The format below is described in XMLSchema.

??? Unfinished. A number of elements and attributes are not defined yet.

??? Scenario: We create a Gtk_Button (with a default child which is the
    label). If the user modifies the label, it is updated dynamically
    (referencing the child automatically???(1)). If the user sets an icon,
    the child becomes a box with both the child and the icon.
    The problem is to describe this in this database file...

Some properties can not be changed dynamically (according to Glade): number
of columns in the ctree for instance. In that case, we should transparently
destroy the ctree and recreate a new one (and put back all the children
if needed). These properties are identified with a special attribute
"recreate" set to true.


<schema xmlns="http://www.w3.org/2000/08/XMLSchema">

 <xsd:annotation>
   <xsd:documentation>Widget database schema</xsd:documentation>
 </xsd:annotation>

 <!--  The language attribute is used for elements that can have language-
       specific values -->

 <attribute name="lang">
    <simpleType><restriction base="string">
       <enumeration value="C" />
       <enumeration value="Ada" />
    </restriction></simpleType>
 </attribute>

<!--  The format used for constructors. In some languages, the constructors
      return the type that was just created. In other languages, this is the
      first argument, that is set to the value of the new object -->

<element name="constructors_format">
    <simpleType><restriction base="string">
        <enumeration value="return" />
        <enumeration value="out" />
    </restriction></simpleType>
</element>

<!--  Name conversion algorithm. This function is called to convert function
      names from a language to another one. They are called every time no
      other specific translation is given for an item. -->
<element name="name_convert">
    <complexType><simpleContent>
        <extension base="string">
            <attribute ref="src" use="default" value="C">
            <attribute ref="dest" use="required">
        </extension>
    </simpleContent></complexType>
 </element>

 <!--  Type used to describe the arguments to signal handlers or of
       properties. -->

 <complexType name="argument_type">

 </complexType

 <!--  Top level element -->

 <element name="library">
    <complexType><sequence>
       <element ref="requires"    minOccurs="0" maxOccurs="unbounded" />
       <element ref="constructors_format" minOccurs="0" maxOccurs="unbounded"/>
       <element ref="name_convert" minOccurs="0" maxOccurs="unbounded" />
       <element ref="widget-type" minOccurs="1" maxOccurs="unbounded" />
    </sequence></complexType>
 </element>

 <!--  First element: list of required modules -->

 <element name="requires">
    <complexType><sequence>
       <element name="name"    type="string" />
       <element name="version" type="string" />
    </sequence></complexType>
 </element>

 <!--  Header defines the name(s) of files to #include, with,...
       This is basically a string, with an optional lang attribute for the
       language. -->

 <element name="header">
    <complexType><simpleContent>
        <extension base="string">
            <attribute ref="lang" use="default" value="C">
        </extension>
    </simpleContent></complexType>
 </element>

 <!--  An interface that the widget implements -->

 <element name="interface" type="IDREF" />

 <!--  The name of a widget. This depends on the language -->

 <element name="name">
    <complexType><simpleContent>
        <extension base="string">
            <attribute ref="lang" use="default" value="C" />
        </extension>
    </simpleContent></complexType>
 </element>

<!--  Definition of parameters for subprograms -->
<element name="extra_arg">
    <complexType>
        <extension base="argument_type">
            <!--  Name of the field from which to extract the value -->
            <attribute name="field" type="string" use="optional" />
        </extension>
    </complexType>
</element>

 <!--  A signal defined by the widget
      You do not need to specify the first argument, since this is always
      the widget. Only the extra arguments need to be defined. -->

 <element name="signal">
    <complexType>
        <sequence>
            <element name="documentation" type="string"
                minOccurs="0" maxOccurs="1" />
            <element name="return"        type="argument_type"
                minOccurs="0" maxOccurs="1" default="void" />
            <element ref="extra_arg"      minOccurs="0" maxOccurs="unbounded"/>
        </sequence>
        <attribute name="name" type=string" />
    </complexType>
 </element>

 <!--  Global element: definition of a widget -->

 <element name="widget_type">
    <complexType>
       <all>
          <element ref="header"      minOccurs="0" maxOccurs="unbounded" />
          <element ref="interface"   minOccurs="0" maxOccurs="unbounded" />
          <element ref="name"        minOccurs="0" maxOccurs="unbounded" />
          <element ref="signal"      minOccurs="0" maxOccurs="unbounded" />
          <element name="child_type" type="IDREF" />
          <element ref="add_child"   minOccurs="0" maxOccurs="unbounded" />
          <element ref="property"    minOccurs="0" maxOccurs="unbounded" />
          <element ref="style"                                           />
          <element ref="flag"        minOccurs="0" maxOccurs="unbounded" />
          <element ref="new"         minOccurs="0" maxOccurs="unbounded" />
       </all>
       <attribute name="id"           type="ID" />
       <attribute name="page"         type="string" />
       <attribute name="min_children" use="default" value="0" />
       <attribute name="max_children" use="default" value="0" />
       <attribute name="parent"       type="IDREF" />
       <attribute name="icon"         type="string" />
       </attribute>
    </complexType>
 </element>

</schema>


Annex B: Example of database file
==================================

Here is an example for a gtk+ database

<?xml version="1.0"?>
<library>

   <!--  List of required libraries for this module -->
   <requires>  <name>gtk+</name>  <version>1.2.8</version>  </requires>

   <!--  Indicate how constructors work in each language -->
   <constructors_format lang="Ada">out</constructors_format>
   <constructors_format lang="C">return</constructors_format>

   <!--  Default name conversion function -->
   <name_convert src="C" dest="Ada">convert_name</name_convert>

   <!--  First widget defined: Gtk_Button -->

   <widget_type id="gtkbutton"
                page="container"
                min_children="0"
                max_children="1"
                parent="gtkbin"
                icon="button.xpm">

      <!--  Header files -->
      <header lang="C">   gtkbutton.h </header>
      <header lang="Ada"> Gtk.Button  </header>

      <!--  Interfaces implemented: none -->
      <!--   <interface name="..." />    -->

      <!--  Type names for all the languages -->
      <name lang="C">   GtkButton  </name>
      <name lang="Ada"> Gtk_Button </name>

      <!--  Creating a new instance of the widget.
            First parameter or return type is always the new widget, and
            this is not specified. Only other parameters need to be. -->
      <new>
          <subprogram lang="C">   gtk_button_new </subprogram>
          <subprogram lang="Ada"> Gtk_New        </subprogram>
      </new>
      <new default="yes">
          <subprogram lang="C">   gtk_button_new_with_label  </subprogram>
          <subprogram lang="Ada"> Gtk_New                    </subprogram>
          <extra_arg type="string"><field_value name="label"/></extra_arg>

          <!--  This constructor builds default children -->
          <default-child name="child1" type="gtkbutton"
             <get lang="C"> $1->child </get>
             <get lang="Ada"> Get_Child </get>
             <property-value name="label"><field_value name="label"/>
               </property-value> 
        </default-child>

      </new>

      <!--  List of new signals defined in this class -->
      <signal name="pressed">
         <documentation>Called everytime the button is pressed</documentation>
         <return>void</return>
      </signal>
      <signal name="released">
         <documentation>Called everytime the button is released</documentation>
      </signal>

      <!--  Function used to add children -->
      <add_child>
         <subprogram lang="C">   gtk_container_add</subprogram>
         <subprogram lang="Ada"> Add              </subprogram>
      </add_child>
      <add_child>
         <subprogram lang="C">   gtk_box_pack_start</subprogram>
         <extra_arg field="shrink" type="boolean" />
              <!-- ???depends on the child. Should we have default value -->
      </add_child>

      <!--  Possible type of children -->
      <child_type>gtkwidget</child_type>

      <!--  Public properties for that widget -->
      <property name="in_button" read-only="true" type="boolean"
            default="false">
         <documentation>True if the cursor is inside the button</documentation>
         <get lang="C"> $1->in_button </get>
         <get lang="Ada"> Get_In_Button($1) </get>
      </property>

      <!-- ??? Needs much more work: the C macro is still unclear. It also
           needs to remove the previous child, in case we go from text to
           icon for instance... -->
      <property name="label" type="string" default="">
         <documentation>The text displayed in the button</documentation>
         <set lang="C"> gtk_label_set_text (GTK_BIN ($1)->child, $2) </set>
         <get lang="C"> gtk_label_get (GTK_BIN ($1)->child, &$2) </get>
      </property>

      <!--  Meaningful style fields -->
      <style> foreground background </style>

      <!--  Flags -->
      <flag name="eventmask">0x0000000000</flag>
   </widget_type>


   <!--  File selection widget. This one has default children -->

   <widget_type id="gtkfileselection"
                page="dialogs"
                min_children="0"
                max_children="0"
                parent="gtkwindow"
                icon="fileselection.xpm">

          ....

        <!--  Declare one of the default children, and override one of its
              properties -->

        <default-child name="OK button" type="gtkbutton"
             <get lang="C"> $1->ok_button </get>
             <get lang="Ada"> Get_Ok_Button </get>
             <property-value name="label">OK</property-value>
        </default-child>

   </widget_type>


   <!--  Columned Tree. This widget has a property that can only be changed
         by recreating the widget -->

   <widget_type id="gtkctree"  ... >
      <property name="columns" type="integer" default="3"
                recreate="true">
         <documentation>Number of columns in the widget</documentation>
      </property>
   </widget_type>

</library>
