Menu

Widgets

Hugh Greene

Although there are plenty of cross-platform widget systems, each brings
its own set of problems to the table, be it in terms of size,
appearance, simplicity, or behavior. Seeking as always to unify and
simplify systems, ENIGMA brings its own widget API to the table. This
document serves as its official specification.

Functions in this API will be defined under the wgt_
C-Namespace. All instantiation functions shall
return an integer by which the new widget can be identified.

Bear in mind that this is a pretty intertwined mess, and should be
regarded as such.

Windows

The wgt_window_create(w,h) shall
create an invisible window of a specified size. Windows can contain at
most one container or widget, as per the GTK design.

Containers

The widget API shall provide two container classes; dynamic and static.
The names describe their behavior in placement, not in allocation.

Dynamic

The dynamic container shall allow the user to specify a text-based
layout for widgets to be added. The layout is generated from a string
representing individually labeled cells. A cell is given dimensions
based on the smallest chain of adjacent labels. For example, consider
this string:

  "AAAAAAAA#"
  "AAAAAAAA#"
  "BBBBCCCC#"
  "BBBBDDEF"

Should a layout be constructed from that string, it would contain six
cells of progressively decreasing size, Cell 'A' being the largest,
cells 'E' and 'F' being smallest.

Static

This layout has not been implemented in any widget system. The
Static layout class allows for absolute placement of any number of
additional widgets at absolute coordinates inside the layout.

Widgets

Each widget shall provide a function to indicate the preferred size.

The following widgets shall be offered:

  1. Buttons, via wgt_button_create()
  2. Combo Boxes, via
    wgt_combobox_create()
  3. Single-line Text Input, via
    wgt_textline_create()
  4. Check boxes, via
    wgt_checkbox_create()
  5. Radio button, via
    wgt_radio_create() (support varies)
  6. More ([not yet implemented])

Interfacing with widgets

While many languages provide callback systems to handle widget presses,
EDL does not yet have this functionality, and is presently not
thread-safe. Until this changes, a purely static method of handling
widget events must be used. The widget system shall be responsible for
handling events at the C++ level and keeping track of their occurrence
until the EDL half can accept them through wrapper functions.

Each widget defines its own wrappers.

Menus

Menus shall be specified using three interfaces; simplified,
intermediate, and procedural. The former two formats shall accept a
single string specifying the entire contents of the menu. The latter
shall use functions to construct menus requiring stock images, or for
menu factories.

Simplified

As in the GML specification, simplified menu strings contain only
plain-text items separated by the pipe character ("|"). An underscore
before a character denotes a shortcut. A single hyphen as an item name
indicates a separator. This standard is used by
show_menu().

Ex: "Item 1|Item 2|Item 3|-|Exit"

Intermediate

Similar to the 'Simplified' spec, Intermediate shall offer more menu
features using macros at the beginning or end of items. This standard is
used by show_menu_ext().

  1. A single-hyphen item shall still indicate a separator.
  2. A greater-than sign ('>') at the beginning chall indicate a
    Sub-menu.
  3. A less-then sign ('\<') at the beginning shall indicate that the
    current item belongs on the next menu up.
    • A single-less-than item shall indicate the end of a submenu.
  4. A forward slash ('/') at the beginning shall indicate a disabled
    item.
  5. Macros "[]" and "[*]" shall indicate an unchecked and checked
    checkbox item, respectively, when placed at the beginning of an item
    name.
  6. Macros "()" and "(*)" shall indicate an inactive an active radio
    button item, respectively, when placed at the beginning of an item
    name.

Ex: "Item 1|Item 2|Item 3|-|>Submenu|/Item 4|Item 5|\<|[]Checkbox
with Item 6|[*]Checked box for Item 7|-|()Radio with Item
8|(*)Ticked Radio with Item 9|Item 10"

Procedural

It is unlikely that a procedural interface will actually be implemented
as no method has yet been determined for specifying icons or other
fancier menu resources that genuinely require such a format.

Generic

All widgets, including layout containers, shall be able to be tested for
existence using wgt_exists().

Each widget not offering its own size function may be assigned a
requested (but not forced, absolute) size using
wgt_set_size().

Any widget may be destroyed with
widget_destroy(wgt).

Layout

Windows shall be managed using layout managers, as in Java.

Presently, the only defined layout manager is Table.

Table Layout

As it is the only layout manager currently defined, a table layout is
created with the function
wgt_layout_create. This layout is
dynamically resizable--it will allocate space to widgets in the window
as needed to condense into the allotted space, and will calculate the
minimum required space to hold its children. This layout will not allow
the window to be reduced past that size.

Static Layout

This layout is planned. It does not yet exist and may never exists. The
plan for this layout is simply to allow the user to place all child
windows manually and size them accordingly.

Inclusion

A unified widget system became a necessary part of ENIGMA when Design
Mode
was introduced in R3. The original, called
"Build Mode", utilized Win32API to create its own window. To allow this
to work on each platform without serious recoding, the system was
unified. Code for a replica of the original "Build Mode" layout is as
follows, using the new system:

To create the window (EDL/GML):

  local int window = wgt_window_create(480, 96);
  local int layout = wgt_layout_create(window,
      "OOOOOOO#"
      "PUXYWHS#"
      "FRGGIIS"
      , 2, 2);
  local int cbbobj, bpause, bfreeze, bundo, bredo, bstop, tegx, tegy, tegw, tegh, cbgrid, cbiso;
    wgt_layout_insert_widget(layout, "O", cbbobj =  wgt_combobox_create("object0|object1|object2|cat|hat|box|wall|toilet|cloud|mushroom"));
    wgt_layout_insert_widget(layout, "P", bpause =  wgt_button_create("Pause"));
    wgt_layout_insert_widget(layout, "F", bfreeze = wgt_button_create("Freeze"));
    wgt_layout_insert_widget(layout, "U", bundo =  wgt_button_create("Undo"));
    wgt_layout_insert_widget(layout, "R", bredo =  wgt_button_create("Redo"));
    wgt_layout_insert_widget(layout, "X", tegx =   wgt_textline_create("X",3));
    wgt_layout_insert_widget(layout, "Y", tegy =   wgt_textline_create("Y",3));
    wgt_layout_insert_widget(layout, "W", tegw =   wgt_textline_create("W",3));
    wgt_layout_insert_widget(layout, "H", tegh =   wgt_textline_create("H",3));
    wgt_layout_insert_widget(layout, "G", cbgrid = wgt_checkbox_create("Grid"));
    wgt_layout_insert_widget(layout, "I", cbiso =  wgt_checkbox_create("Iso"));
    wgt_layout_insert_widget(layout, "S", bstop =  wgt_button_create("Stop"));
    wgt_window_show(window);

  local int i = 101;

To monitor the window:

  if (!wgt_exists(window))
    return 0;
  if (wgt_button_get_pressed(bstop)) exit(0);
  else if (wgt_button_get_pressed(bpause)) room_caption = "Color chose: " + string(get_color($FF0000));
  else if (wgt_button_get_pressed(bfreeze)) room_caption = "Combobox selection: " + wgt_combobox_get_selected_text(cbbobj) + "["_+_string(wgt_combobox_get_selection(cbbobj))_+_"](" + string(wgt_combobox_get_selection(cbbobj)) + ")";
  else if (wgt_button_get_pressed(bundo)) room_caption = "File chose: '"+get_open_filename("Images|*.png; *.jpg; *.jpeg; *.gif|Sources|*.c; *.cpp|Headers|*.h; *.hpp","tacos.png") + "'";
  else if (wgt_button_get_pressed(bredo)) room_caption = "Menu result: " + string(show_menu_ext(32,32,"test|of|menus|-|>Project|/Save|Close|<|[]Checkbox|[*]Checked|-|()Radio|(*)Radiod|etc"));
  else if (i++ > 100)
  {
    room_caption = string(wgt_checkbox_get_checked(cbgrid) ? "Drawing ":"Ignoring ")

    + (wgt_checkbox_get_checked(cbiso) ? "an isometric" : "a rectilinear")
    + " grid of size " + wgt_textline_get_text(tegx) + " * " + wgt_textline_get_text(tegy)
    + " starting at (" + wgt_textline_get_text(tegw) + ", "  + wgt_textline_get_text(tegh) + ")"
    ;
    i=101;
    return 0;
  } else return 0;
  i = 0;

Related

Wiki: Design_Mode

MongoDB Logo MongoDB