Widgets - hpgDesigns/hpgdesigns-dev.io GitHub Wiki
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:
- Buttons, via wgt_button_create()
- Combo Boxes, via wgt_combobox_create()
- Single-line Text Input, via wgt_textline_create()
- Check boxes, via wgt_checkbox_create()
- Radio button, via wgt_radio_create() (support varies)
- 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.
- Buttons can be probed for a press count using wgt_button_get_pressed().
- Text Line Inputs can be probed for the current text with wgt_textline_get_text(). In the future, it may pass that they may be probed for Enter press with wgt_textline_get_submits().
- Checkboxes can be tested for check state using wgt_checkbox_get_checked().
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().
- A single-hyphen item shall still indicate a separator.
- A greater-than sign ('>') at the beginning chall indicate a Sub-menu.
- 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.
- A forward slash ('/') at the beginning shall indicate a disabled item.
- Macros "[]" and "[*]" shall indicate an unchecked and checked checkbox item, respectively, when placed at the beginning of an item name.
- 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))_+_"](/hpgDesigns/hpgdesigns-dev.io/wiki/"-+-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;