Screens are designed with a layout editor, which compiles the design into bytecode. The resulting object is then used with a single-file library.
3.2 No more graphical editor.
3.1 First version with pure bytecode format.
3.0 Many improvements, including initalization
and gfx_event function.
2.16 Code is now completely bytecode.
2.15 Initial remote display work.
2.14 Partial Windows port.
2.12 Flexible font system. Removed dependency on freetype.
2.11 Last version with FreeType.
2.5 Log widget, initial Android port and improved editor.
2.3 Standalone code generator, independent of the library.
2.2 Layout editor is now written with the layout editor.
2.1 First version with the layout editor.
2.0 Transitioning from 1.4 to 2.x.
1.4 Bugfix release.
1.3 New widgets and slight modifications to event system.
GL-gfx A fork of 1.2 which can also use OpenGL.
1.2 Improvement of widget object system.
1.0 Initial.
./build.shfrom there. The resulting binary will be in
layout/gfxlayPut this binary somewhere in $PATH and you're done. There is nothing else to install. You may now remove the source tree.
Let's look at its options.
gfxlay: unknown option -k gfxlay: usage: gfxlay [options] input-file options: -d <file> Definitions output file (C header) -n Suppress version checking in definitions output (C header) -s Suppress version definition in definitions output (C header) -H <file> Combined C header output file (lib+data) -e <file> Definitions output file (CSV) -a <file> Array output file -b <file> Binary output file -C <file> Combined C source output file (lib+data) -c <file> Library code output file -h <file> Library header output file -u Disassemble input -U Compile input and disassemble the result -t <int> Run input binary file, with the given screen number -r Remove input binary file after exit (only for -t) -T <screen> Compile and run input file with given screen name -v Print version information and exitAfter editing your design file, you'll run gfxlay from the command line or from a makefile to generate the necessary output files. In normal usage, you'll need
The option -d creates a C header which contains enumerations naming screens, widgets and icons in your design file. You will use these names to talk to the library about what to do.
The option -a creates a C source file which contains the bytecode necessary to run your GUI. The data in there gets passed to the library automatically by the gfx_init function.
The above setup works quite well for developing a program. If you want to simplify your distributed source tree, you can use the -H and -C options to combine library code and GUI description into two files; one header and one source file.
Remaining options are normally for internal use by gfxlay or for developing
the library. They are pretty self-explanatory I think.
While linking, you will need to compile in your GUI data file and bring
in some system libraries:
Now, in order to initialize the GUI system, you need to call gfx_init().
This takes a single argument on Linux/X11 (display name) and Windows
(HINSTANCE). Most of the time, you will pass NULL here.
For Android, it's a little more complicated, which I will describe further
down.
In order to display something, you need to enter a screen. When you
do so, widgets in it are created and laid out by the library according
to your design. You don't need to call create_button or something.
Screens form
a stack. After you enter a screen, you will leave it in order to
return to the previous screen. This is accomplished by
Using the Library
In order to use the library, you need to first include the necessary
headers. Here I use some generic names, how you name these is up to you.
#include "libgfx.h"
#include "guidata.h"
The first one contains definitions relating to the library, while the
second defines screens and widgets in your GUI. All files generated
by gfxlay are C files. You should wrap them in extern "C"
blocks if you need C++.
program: main.o <some other objects> guidata.o
$(CC) $(LFLAGS) -o $@ $^ $(LIBS) -lXext -lX11 -lm
For targets other than X11, only -lm is required.
gfx_screen(<screen_id>);
...
gfx_leave_screen();
screen_id is just an integer constant from your guidata.h.
Once you display a screen, you can interact with the widgets on that
screen by using the functions in libgfx.h.
Look at the widgets section for reference.
In order to read events from the user, the gfx_event function shall be used:
gfx_event_t event; while(!quit) { if (gfx_event(&event)) switch(event.type) { ... case GFXEV_QUIT: quit= 1; break; ... } }This function returns non-zero if there was a reportable event. Otherwise, some other event was read and it needs to be restarted.
The event type is always an integer constant. This can be
void gfx_timer_start(int ident, int ms); void gfx_timer_stop(int ident);The ident is a non-negative integer, which is independent of anything else. It can be any value. When a timer expires, it generates an event with type GFXEV(ident,TIMEOUT). The timer then stays inactive until gfx_timer_start() is called again. You can optionally cancel it before it expires using the gfx_timer_stop() function. If you give a negative integer for the ident field, these functions do nothing. So, -1 is a good sentinel value for variables holding timer identifiers.
The following functions are used to manage monitored file descriptors:
void gfx_monitor_file(int fd, int ident, int R,int W,int X); void gfx_stop_monitor_file(int fd,int ident);The ident is a simple integer constant determined by you. The R, W and X arguments are flags which tell the system which events to monitor: reading, writing and exceptions.
When a monitored event occurs, a gfx event is generated with type:
void gfx_set_state(int wno, int state); int gfx_get_state(int wno);These two functions manage the state of a widget such as a check-box, toggle button etc.
void gfx_set_selected(int wno,int sel); int gfx_get_selected(int wno);These are used to manage the selected item in a list, dropdown etc.
void gfx_set_fgbg(int wno, int fg, int bg);Some widgets support changing colors at run time.
char* gfx_get_text(int wno); void gfx_set_text(int wno,char *str);Things like text entries, labels, buttons respond to these kinds of requests.
void gfx_clear(int wno); void gfx_insert(int wno,int pos, char *text,void *user,unsigned int* icon); void gfx_remove(int wno, int pos, void **Ruser);These are used to insert/remove items. Lists, dropdowns etc support these operations. The position is an index which starts at 0.
If pos is out of bounds for insertion (ie. too big or negative), the item is appended to the list. For removal, the last element is removed in this case.
The widgets can also store some user data along with the item, which is stored and retrieved as shown. There is no way to modify an item once it's inserted. A removal and re-insertion is necessary.
FIXME: document the icon parameter.
GFXEV(widgetnumber,BUTTON_PRESS) or GFXEV(widgetnumber,BUTTON_RELEASE)The x and y coordinates of the event are relative to the canvas buffer origin. The rest of the event is the same as a normal button press/release event.
In addition to this, mouse movement reports can also be obtained. These look similar to the press and release events. The type is:
GFXEV(widgetnumber,POINTER_MOVE)The following functions should be used to start and stop mouse position reporting. While mouse position reporting for the canvas is active, there is no other event generated for mouse position changes.
void gfx_canvas_begin_report_mouse_position(int wno); void gfx_canvas_end_report_mouse_position(int wno);The reported coordinates are relative to buffer origin.
The widget includes its own buffer. You can set the size of this buffer using:
void gfx_canvas_setsize(int wno, int new_w, int new_h);Contents of the old buffer (if any) is copied to the new buffer. Using this function is mandatory, without a buffer the widget doesn't display anything. The widget automatically adds/removes scrollbars depending on the size of the buffer and the widget window.
In the layout editor, horizontal and vertical scrollers can be disabled. This doesn't affect the buffer sizes to be used. You can still use larger buffers but the widget will only display the top left part of the buffer. If you call the following function before setting any buffer size, a buffer will be created which is as big as the widget itself.
int gfx_canvas_get_buffer (int wno, unsigned int *W, unsigned int *H, unsigned int **B);If you call this function after you have set the buffer size, the function will simply give you back the set width and height, along with the created buffer.
When you get the buffer using the above function, the returned buffer is in RGB32 format. You can manipulate this buffer and then put your changes back using:
void gfx_canvas_update(int wno, int x, int y, int w, int h);
The widget also lets you make rectangular selections using the following functions:
void gfx_canvas_recsel_begin(int wno, gfx_event_t *ev); void gfx_canvas_recsel_end(int wno,int *Rx1,int *Ry1,int *Rx2,int *Ry2);The _begin function sets the first corner of the selection and starts tracking the mouse pointer position. The _end function returns this first corner and the second corner obtained from the mouse pointer position. The returned coordinates are sorted: x1 ≤ x2 and y1 ≤ y2.
Canvas widget can also print text on the buffer, using the builtin fonts.
void gfx_canvas_print(int wno, int font, int color, int x, int y, char *str);The text is blended onto the buffer contents, using the given foreground color.
The canvas can optionally show a zoom sub-window. The parameters are set using:
void gfx_canvas_set_zoom_params (int wno, int zf, int grid, unsigned int gridcolor,int w,int h);zf is the zoom factor. grid indicates the thickness of the grid lines. Give -1 here if you don't want grid lines. w and h give the dimensions of the zoom window.
void gfx_canvas_zoom(int wno,int x,int y);This function shows the zoom window. x and y are the coordinates of the main buffer pixel which will be displayed in the center of the zoom window. The position of the zoom window is adjusted automatically.
void gfx_canvas_hide_zoom(int wno);hides the zoom window. Call canvas_zoom() again to show it back.
Starting from 2.8, you can also have sprites in a canvas widget. These are ARGB32 images which can move around without affecting buffer contents. The following can be used for manipulating them:
int gfx_sprite_new(int wno,int func, int w,int h, uint32_t *data); void gfx_sprite_move(int wno,int sp, int x,int y); void gfx_sprite_show(int wno,int sp,int sho); void gfx_sprite_remove(int wno, int sp);In _new(), the return value is a sprite number valid for only the given widget. func is the function to be performed on the sprite and buffer data when it's displayed:
When you move the sprite, the coordinates refer to the top left of the given image data. You can move them partially or completely off the screen, it won't do any damage.
void gfx_insert (int wno,int pos, char *text, void *user,unsigned int* icon);If pos is -1, then the item is appended to the list. The icon is not used and should be NULL. The user pointer is returned along with the clicked item's position when a selection is made.
When the user chooses an option, the widget returns an event where the event's type equals the widget number. The key field contains the index of the clicked item. The usr field contains the user pointer passed along in the gfx_insert() call.
You can get the index of the selected item later on, using the function
int gfx_get_selected(int wno);The result is -1 if there is no selection.
You can select an item programmatically using:
void gfx_set_selected(int wno,int sel);If sel is -1, no item will be selected and the box will be empty.
char *gfx_filelist_get_directory(int wno); char** gfx_filelist_get_files(int wno); Returns all the files currently listed in the widget. The returned pointer can be freed in one go because the whole thing is in one block. The list is null terminated. Each entry has a prefix character indicating its type: 'D' (directory), 'F' (file) and 'U' (unknown). void gfx_filelist_set_directory(int wno,char *dir); void gfx_filelist_set_types(int wno, char **types); Sets the list of extensions to look for as explained in the file selector dialog section.When a directory is clicked, the list shows that directory. For other entries, an event is returned. The event type is the widget ident for a single click and GFXEV(ident,DOUBLE_CLICK) for a double click.
The 'string' field of the event contains the absolute path of the clicked file. This string doesn't contain a type prefix. This field must be freed by the user. WARNING Not handling click or double-click events will cause a memory leak from this field.
void gfx_iconlist_insert (int wno, int pos, char *text, unsigned int w, unsigned int h, unsigned int *data, int ival, void *pval);As always, if pos<0, then the item is inserted at the very beginning. data must not be NULL. It should be a valid rgb32 image with the given width and height. The given ival and pval values are associated with the item and are reported whenever the item gets selected thru a mouse click.
The widget emits an event with the following fields, when an item is clicked and gets selected:
void gfx_iconlist_updates(int wno, int upd);with upd==0. After doing your modifications in bulk, you should call the same function with upd==1. This way, the display isn't updated during the bulk operations, but delayed until upd==1.
You can use the regular gfx_remove, gfx_clear, gfx_set_selected and gfx_get_selected functions for other operations.
Now we have multi-select capability for icon lists. The following functions can be used to manipulate the selection:
void gfx_iconlist_get_selection(int wno,int *Rn, int **Rs); void gfx_iconlist_clear_selection(int wno);For get(), both output arguments are optional. The array in (*Rs) is terminated with a -1.
You can also permute the contents as follows:
void gfx_iconlist_permute(int wno, int N, int *P);N should be equal to the number of items in the list. It's used as a crosscheck to make sure that the user has the correct number of items.
The function
void gfx_iconlist_area(int wno, int *Rw, int *Rh);can be used to decide on an icon size. The returned dimensions are the size of the whole widget. A vertical scrollbar may be subtracted from the area later on.
gfx_logview_printf(WIDGET, fmt, ...);You can use the following function to make it easier to write such print calls:
void gfx_set_log(int widget);After this call, you can use loprintf/loprintv function as follows:
void loprintf(const char *fmt, ...); void loprintv(const char *fmt, va_list ap);All such calls will be displayed on the widget given to the _set_log() call. If the widget given there is -1, then loprintf() doesn't print anything.
void gfx_pixgrid_attribs (int pg, int *Rshown, unsigned int *Rw, unsigned int *Rh); void gfx_pixgrid_put (int pg, int x,int y, unsigned int *img, unsigned int iW,unsigned int iH, int src_x, int src_y, int copy_w, int copy_h); void gfx_pixgrid_putsimple(int pg, unsigned int *img);_attribs() is pretty self explanatory. *Rshown is nonzero iff the pixgrid is shown on the screen and is not obscured by a sub-window.
_put() displays the given portion of the supplied buffer. The buffer is in XRGB format. Bits 31-24: don't care, bits 23-16: red etc.
_putsimple() does the same thing as _put(), but with fixed arguments
int gfx_pixgrid_buffer (int pg, int *Rbpl, int *Rbpp, int *Rorder, unsigned char **Rbuffer); void gfx_pixgrid_update (int pg, int x,int y,int w, int h);_buffer() returns bytes per line, bytes per pixel and pixel order in addition to part of the window buffer where the pixgrid starts. Rorder is a 3-byte array with the following values upon return:
gfx_set_state(WIDGET_NUMBER, 1);This will set all the other radio buttons in the same group to OFF. If you want to make sure that nothing is set within the group, you can follow the above call with
gfx_set_state(WIDGET_NUMBER, 0);Initially, when a radio widget is shown, it's in OFF state. You can get the widget number of the selected radio button in a group by using the function
R= gfx_get_selected(WIDGET_NUMBER);where the widget number is that of any radio button within the intended group. R is -1 if no button is active.
int gfx_ask(char *title, char *buttons, char *fmt, ...);The confirmation dialog asks the user a question and returns an answer. If the user tries to close the window, -1 is returned. Otherwise, the index of the clicked button is returned.
The button string consists of a series of button labels, seperated by a particular character. This character is the first byte in the button string. For example:
"!OK!Cancel"describes a two-button dialog. Return value 0 corresponds to the OK button and 1 corresponds to the Cancel button.
fmt is a printf format, and the rest of the arguments are printf arguments.
title can be NULL.
char* gfx_select_file(int mode,char *init,char **types);The return value is a non-null, absolute file path if the dialog was not cancelled. Otherwise, it's null. mode is zero for loading files and 1 for saving files. init contains the initial value for the file name. This is interpreted relative to the current directory if it's not an absolute path.
types is an array of file types. Each entry looks like:
"Name (.ext1 .ext2)"Each of these strings will be displayed in a file type box and can be activated to filter the list of files according to the extensions given. The file types can also be listed hierarchially. If a file type string starts with a space, it's the child node of a previous entry with less number of leading spaces. For example:
"Image Files", " JPEG Images (.jpg .jpeg)", " Portable Network Graphics (.png)",Here, the JPEG and PNG entries are the children of the "Image Files" entry. The latter doesn't have any extensions associated with it. When the user selects the "Image Files" entry, files matching the extensions of any child node are shown. It's possible to nest these even deeply using more and more leading spaces, but I don't think more than two levels are very practical.
The dialog also checks for the existence of the selected file. If the
mode is 0 and a non-existant file name is entered, then the dialog doesn't
close. Also, if mode is 1 and an existing file is selected/entered, the
dialog will require user confirmation for overwriting it.
This will complicate matters when you want to align the labels.
I'd need to write the same expressions and thus identify the
labels anyway. The labels can be made private and won't be
a problem with the interface.
When you're editing screen coordinates, the same variables refer
to the dimensions of the application window.
In order to activate this behaviour, you need to define the name of
your activity in the compilation flags as follows:
You also need to declare the haveresult function in your activity class:
Do not forget to set hasCode="true" in AndroidManifest.xml and the code
lives under src/packagename/YourActivity.java
If the widget is supposed respond to click events, you need to install
a click handler at this point. You can change the parameters
of the click handler later on.
When the position of the widget changes, don't forget to update the
click handlers.
The click handler function should return 1 if the event has been
completely processed and shouldn't be propagated further. It should
return 0 if the event is to be reported to the user. This is your
chance to modify the event so that a click event is returned to
the user as an item selection event, for example.
The prototype for a click handler is:
There are library resources with the following types:
The layout editor can't edit library resources, but it should be possible to
do so later. All library resources are listed using macros like
RES_INT, RES_COLOR etc.
Later on, the layout editor will be able to merge .scr files and override
resources in one file from another.
The shown/notshown flag in a widget should be called 'enabled'.
The _remove() function returns 1 if the given position was valid. If Rusr
isn't NULL, then user data associted with the item is stored there. Here is
a way of getting rid of temporary user data:
The _selected() function returns -1 if there is no selected item. Otherwise,
the position of the selected item is returned.
If action is non-zero in the constructor, whenever the checkbox is clicked,
an event will be generated. The type field of the event will be equal to
the value of 'action' given here. The 'key' field of the event will be
equal to the state of the checkbox.
The _filter function installs a filter for the entry. The filter has
three arguments, the argument given as 'arg', a dummy argument which
should be ignored, and the event. If you return 0 from this function,
the event is processed as usual. If you return 1, then the event shouldn't
be processed any further.
click_action is an event number. When an element is clicked,
an event with this type is returned to the user. The following elements of
the event record is set:
FIXME: [001] insert() should also specify
whether the item is to be selected or not.
FIXME: [002] The returned array is malloc()ed each time. Maybe this should be
a member of the list struct and free()d automatically when the widget is
destroyed.
FIXME: [003] The list struct should contain a 'selected' field to record the
currently selected item. This will provide O(1) access to the selected item
for single-select lists. Currently, we're looping thru the list items even
for single-select lists.
Change Log
-3.1-
20210724 The output is now completely bytecode, helped by special
instructions to identify parts of the binary description.
20210724 User fonts can be added to the output file, but can only
be used in a canvas. Later on, all text-based widgets
shall be able to use whatever font we need.
20210724 gfxgen is no more. A gfxlay.nox is generated which is
meant to be used only for developing gfx itself. All other
functions are collected into gfxlay.
20210724 Code and data are now completely separated.
20210724 Internal improvements, getting rid of many output buffer
types.
20210724 The generate screen is now defunct. Code/data generation
can only be done from the command line.
-3.0-
20191112 Removed the timeout parameter from gfx_event.
20191110 Fixed a long-standing bug in alignment functionality
in the layout editor.
20191110 Resource save/load code removed from save.c
20191110 Window width/height/title is part of the GUI design
file.
20191110 Now there is a 'generate' screen. This gives me
options to generate a GUI in release/debug settings.
-2.16-
20191107 Removed library/. Everything is now in libsrc/
20191107 Incorporated lodepng. No longer dependent on libpng.
20191107 Library code is now stored compressed inside the
layout and gen binaries, using the incorporated miniz
code.
20191107 Icons for buttons now work. Multi-dpi icons.
20191107 Resource related code almost completely removed.
Just need to remove it from save.c
20191107 Icons are now part of the GUI description module.
20191107 Drastically reduced size of the source tarballs.
-2.15-
20191102 Generate bytecode instead of C.
20191102 gfxlay/gen no longer print out library code. Just the
bytecode necessary to use the library.
-2.14-
20191027 Added partial windows support.
20191027 Removed all t2c code. Now it's all shell scripts.
-2.13-
20190704 A new bug was introduced to the logviewer widget
along with the new font system. Now fixed.
20190704 User timers are now implemented on Linux.
-2.12-
20190614 Made a layout editor screen for custom fonts. Code
still needs to be written.
20190614 Combined the library into one U file. All that remains
is to modify the build scripts to use the new file
layout.
After that, I can simply make them straight C+H files.
20190614 On Android GFX_SAVE_STATE event is removed. Instead,
you now set a function pointer which is used to handle
this situation.
20190529 Now fonts are used dynamically, scaled according to
the DPI of the device.
-2.11-
20190528 Fixed a bug regarding window creation/destruction
on android.
20190528 Implemented monitor_file functionality for android.
20181015 Added the gfx_soft_keyboard() function for android.
20180515 Modified the pixgrid widget to provide access to the
window buffer directly.
20180515 Added loprintv.
-2.10-
20180120 Various changes, I forgot to record them here.
20180120 Android subsystem now can handle user-defined timers.
20180120 Android subsystem can receive user-generated messages
thru the haveresult() native.
-2.9-
20171104 Icon list widget is implemented.
-2.8-
20171102 Sprites are implemented.
20171102 Bug fixed in canvas mouse position reporting.
-2.7.3-
20171027 Progress bar widget is implemented.
-2.7.2-
20171024 loprintf
20171024 Log viewer can update itself even if a screen is
entered on top of it.
20171024 When a new screen is pushed, the old contents are now
stored in the previous screen, not the newly pushed
screen. This enables widget update while the screen is
in the background.
20171024 New image types graypix_t and colorpix_t are
implemented. These should be used instead of passing
a ton of function arguments.
-2.7-
20170115 Canvas zoom window.
20161228 Printing on canvas widget.
20161228 Canvas scrollbars can be disabled in the layout editor.
-2.6-
20160802 File list widget.
20160802 Slider widget.
20160616 Double click for lists. User resources are now
exported to the header so that they can be used for
lists etc.
-2.5-
20160529 Alignment function for the editor.
20160528 All widgets have their own attribute editors now.
20160527 Put the Android stuff back in.
20160525 Implemented the log viewer widget.
20160525 When a widget is created, the attributes screen is
shown automatically.
-2.4-
20160511 Cleaned up a lot of unused variables remaining from
older iterations.
20160511 Fixed a huge bug in canvas buffer setsize() function.
20160427 Fixed the subscreen handling code for the panel object
20160426 In tab order determination, I should have a way of
telling which widgets are visible. This is already
done by the can_focus flag. When a textentry gets
hidden, can_focus is set to zero, removing the widget
from the list of available widgets for focusing.
20160426 Automatic tab order for screens. Left-to-right,
top-to-bottom.
20160426 Spinner widget is implemented.
20160426 Internal timers are implemented.
20160418 Dropdown and list widgets now support the clear()
command.
-2.3-
20160411 Old layout editor is removed now. gfxgen takes its
place to generate the layout editor.
-2.2-
20160406 The layout editor now can edit its own layout file and
generate the GUI code for itself. This will be the
last version with the old layout editor in it.
20160404 The save file should contain the name of the generated
file, possibly encoded relative to the path of the
save file. Also the working screen size should be
stored in the save file. This is so now.
20160404 The generated C file should include the header
according to its own name. Currently, it simply
includes "gfx.h". This should change according to the
C file's name. i.e. "display.h" etc.
The generated source and header files are now
independent of each other. The source file already
contains the text of the header at the appropriate
place. This way, it doesn't have to include anything.
20160324 Canvas widget is implemented.
20160317 File selector is re-introduced, the list in the things
to do section is still valid.
20160313 Toggle button widget is implemented, as part of the
regular button widget.
Fixed a bug in the screen dimension computation.
Re-implemented the confirmation dialog.
-2.1-
20151225 A layout editor is implemented. Widgets are no longer
directly created by the user, you simply specify them
in the layout editor and the editor generates the
necessary code. The generated code creates the screens
and exports only the screen functions.
20151225 Pixgrid widget was implemented.
20151225 Android port is removed for now, but I have
framebuffer port.
-1.4-
20150915 Various bug fixes.
-1.3-
20150515 CheckBox widget is implemented.
20150513 Radio widget is implemented.
20150628 List widget interface is updated. The tuple array
stuff is gone. The new interface looks like the
dropdown widget interface.
20150704 _show() functions were imported into the widget object.
Now we only call gfx_show(no,show) for all widgets.
20150704 The focusable interface was dropped. Focus information
is now carried thru widget objects. Event handling is
done there too.
20150704 key_filter was implemented for the text entry widget.
20150712 File selector is implemented.
20150712 Toggle button is implemented.
20150712 Confirmation dialog is implemented.
-1.2-
20150510 Dropdown widget is implemented.
20150425 Now we don't have the array text_entries. We store
them in the normal widget list. Also, destruction is
now supported for text entries.
-1.1-
20150408 Lists, with and without icons
Things to Do
Roadmap
Things to Do
notebook This is done by panels now.
frame Panels should have these options: draw border, title,
title position..
gtk bookmarks are stored in:
They are stored in the ~/.config/gtk-3.0/bookmarks file
In older versions of Ubuntu they are stored in the ~/.gtk-bookmarks file.
The format is:
file:///path/to/folder Bookmark_name
Things I Won't Do
Bugs
API Documentation 2.x
Using the Code Generator
The source tree also includes a code generator without a GUI. This is
called gfxgen. Here is the usage for it:
gfxgen [-c source.c] [-h header.h] input.scr
The given source and header file paths override any paths stored
inside the input file. If these paths aren't given in the command line
or in the input file, then generic names are used. In this case, source
file is called 'gfx.c', inside the directory of the input file.
It's 'gfx.h' for the header file.
Using The Layout Editor
In the editor, when you're asked for widget coordinates, you can use the
variables WIDTH and HEIGHT to refer to the dimensions of the screen.
Initialization - X11
You should initialize the library using the following function:
int gfx_init(char *name, int width, int height, char *title);
Here, name is the X11 display name. width and height
are in pixels. The given title is for the main window of the
application.
Events
int gfx_event(unsigned int *msecs,gfx_event_t *Revent);
Will return non-zero if there is an event to be handled. If msecs is NULL,
then the function will wait until an event arrives. Otherwise, it will wait
for a maximum of (*msecs) milliseconds and will return zero if no event
was recieved during this time. In any case, if msecs is not NULL,
it contains the remaining wait time upon return.
Android Interface
Starting with 2.10, the gfx system is able to receive user-generated
messages from the Java environment. It works as follows: you start an
asynchronous task in the Java environment thru JNI and set up the java
code such that native function
void YourActivity::haveresult(int value);
gets called when it finishes. This native function is defined by the
gfx library. It constructs an event with type==GFXEV(value,JAVARESULT).
Upon receiving this event, you can query the fields of YourActivity to
get more detailed results.
cc '-DGFX_ANDROID_ACTIVITY="YourActivity"' -DGFX_ANDROID gfx.c
The double quotes are part of the definition because the code looks up
the code using this macro without any further processing, so it needs
to be a string literal.
class YourActivity extends NativeActivity
{
..
static { System.loadLibrary("sonamewithoutsuffix"); }
public static native void haveresult(int rcode);
..
}
The first static code is necessary because you need to load the .so
since you no longer use NativeActivity directly. The second line above
declares haveresult() properly.
Mandatory Functions to be Present in Your Android Activity Class
In order for the fonts to scale properly, we need the display DPI.
This is retrieved from the java world via the following function. Put
this in your activity class:
public int getDisplayDPI()
{
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
float xDpi = dm.xdpi;
float yDpi = dm.ydpi;
if (xDpi>yDpi) return (int) xDpi; else return (int) yDpi;
}
Writing New Widgets
You need to write a couple of mandatory functions:
The constructor will return a [widget_t*]. In the constructor, you need
to set the class identifier and the function pointers.
int click_handler_func(void *arg,gfx_event_t *event);
arg is typically a pointer to the widget object.
Using Scroll Bars
If your widget uses scrollbars, you can set the scrollbar position
using:
scrollbar_set_all(scrollbar, double start, end, step);
Here, start and end refer to the position of the slider in the scrollbar,
1.0 is the very end of the document and 0.0 is the beginning. step is
again a number between 0.0 and 1.0 and tells us how much the position
should progress when the arrow buttons are pressed. A good value is
viewport_h/document_h*0.8.
Resources
There are two kinds of resources: user and library. Library resources define
how the library drawn things look. For example, the folder icon in a file
selector is a library resource. An icon to be displayed inside a button is
a user resource. User resources are injected into the gfx.c source file using
a marker.
Coding Style
Externally visible names should start with gfx_. Internal names with gui_.
Some Notes About Tablet and Desktop Implementations
Differences between desktop and tablet programs:
- D: I specify screen size
T: The whole screen is used and its size is constant
- T: There are some events such as pause,resume, low memory etc.
D: There is nothing like that
- D: There is a keyboard attached at all times
T: A soft keyboard is needed. A hardware keyboard might be present
but I don't know how to activate it if there is one.
- D: Scrollbars and tiny controls make sense
T: They don't.
- T: It's possible to have multiple pointers due to multi-touch
D: Only one pointer is present
- T: The screen could be rotated, resulting in resize events
D: Resize events are normally disabled. If we enable them, we
get arbitrarily sized windows.
- T: There is no command line, init state is used.
D: Command line arguments are used, there is no init state.
- D: No polling is necessary to make things move.
T: We have to poll the system in order to get events like
WindowCreated etc. Otherwise, the whole thing hangs up.
In order to solve the polling problem, I could do the following:
- Make all callbacks return pretty much immediately, without
waiting for anyone to acknowledge.
- Do the actual work in these callbacks, but protect shared variables
using locks and such.
- Spin a new thread for events.
- Have the event and callback threads put some events on the queue.
- Make the main thread read from this queue only.
API Documentation
The following information relates to the 1.x series. In that series,
each widget was accessible thru its own functions. i.e. you said
gfx_text_entry_set_text() etc instead of gfx_set_text().
dropdown Widget
int gfx_dropdown(int x,int y,int w,int h,int action);
void gfx_dropdown_insert(int wno, int pos, const char *str, void *usr);
int gfx_dropdown_remove(int wno, int pos, void **Rusr);
void gfx_dropdown_select(int wno, int pos);
int gfx_dropdown_selected(int wno);
int gfx_dropdown_get(int wno, int pos, char **Rstr, void **Rusr);
Typical usage is as follows:
int dd;
// just a made-up integer for reporting
// selection change events.
dd= gfx_dropdown(x,y,w,h, EVENT_DROPDOWN1);
// if pos is -1, the item is appended to the
// list otherwise it's inserted at the given
// position.
gfx_dropdown_insert(dd, -1, "An item", itemdata);
// String to be shown. This string is
// copied into the widget.
// Data associated with the
// string. When the given
// string is selected, this
// pointer will be stored in
// the 'usr' field of the
// returned event.
gfx_show(dd, 1);
// The widget is initially hidden.
while(1)
if (gfx_event(NULL, &event))
switch(event.type)
{
case EVENT_DROPDOWN1:
// event.key is the position of the selected item
// event.usr is the data associated with the item
}
Currently, there is only one value for _show(). The widget can be shown,
but not hidden. I'll do that later.
// -1 means the end of the list. using
// this is much more efficient than using
// another position as there is no
// copying.
while(gfx_dropdown_remove(dd, -1, &ptr))
free(ptr);
The _get() function returns 0 if the position is outside the bounds of the
list. Otherwise, the string and user data are stored in the respective
pointers if not null.
radio Widget
// If group is -1, then this radio is in a group by itself.
// Otherwise, group should be the widget number of another
// radio widget. When this is the case, the two radio buttons
// are in the same group.
//
// action is an event number as always. ident is an arbitrary
// number which is used to identify the widget within its group.
int gfx_radio(int x,int y, int w,int h, const char *text,
int action, int ident, int group);
// Selects the given widget and clears the others in the group
void gfx_radio_set(int wno);
// Returns the 'ident' of the selected widget within the group.
// Returns -1 if nothing is selected yet.
int gfx_radio_get(int wno);
checkbox Widget
int gfx_checkbox(int x,int y, int w,int h, const char *text, int action);
void gfx_checkbox_set(int wno,int value);
int gfx_checkbox_get(int wno);
_get() returns -1 if the given widget can't be found.
text_entry Widget
int gfx_text_entry(int x, int y, int w, int h, char *initstr);
char *gfx_text_entry_get(int no);
void gfx_text_entry_set(int flags, int no, char *str);
void gfx_text_entry_filter(int wno, void *arg,
int (*f)(void *,void*, gfx_event_t*));
The widget is initially hidden, use gfx_show() to enable it. The string
returned by _get() is a copy of the text, you should free() it. The string
passed to _set() is copied along, you don't need to keep the reference
after the call.
list Widget
int gfx_list(int flags, int x,int y,int w,int h, int click_action);
flags can contain GFX_NOICON and GFX_MULTISELECT.
The former makes the list
never show any icons even if they are given along with element data.
void gfx_list_insert
(int widget, int pos, char *str, void *usr,
unsigned int *icon, unsigned int icon_w, unsigned int icon_h);
void gfx_list_delete(int widget, int pos, int N);
If pos is out of list bounds, the given item is inserted to or
deleted from the end of the list.
int gfx_list_selected(int wno);
int *gfx_list_selected_all(int wno);
void gfx_list_select(int wno, int pos,int sel);
The first one gets the 'first' selected item, to be used for single-select
lists. The second one returns an array of integers, terminated by -1. Each
integer in the array corresponds to the index of a selected item.