___ _ | \(_)_ __ ___ | |) | | ' \/ -_) |___/|_|_|_|_\___|
Dialogs Made Easy
Internal Stuff
by Sven Sandberg
Dime's internal mechanisms allow you to add custom dialogf() formats without modifying the library. This text file intends to describe how to write an own Dime format. You are probably required to look at the code for some of the simpler formats that come with Dime in order to figure out how things work anyway (dbool.c and dstring.c should be the most descriptive ones). I'm not exactly sure that this will be useful for anybody except possibly myself, as a reference in the future when I have forgotten everything about Dime.
Since these are all internal functions, I can't promise that their APIs are set in stone. In particular, I'm planning to change the format of `dialogf_create_<MyFormat>()' and `dialogf_count_<MyFormat>()', and possibly some of the other related functions.
A custom dialogf() format consists of a set of functions and a call to `register_dialogf_format()'. `register_dialogf_formats()' will be given the format string that you want associated with the new format, along with function pointers to your functions and some more data which will be described later on.
The functions you need to write are listed below. Not all of them need to be implemented; if you don't need one of them, just pass `NULL' for it when you call `register_dialogf_format()'.
int dialogf_create_<MyFormat>(DIALOG *dialog, char *desc, char *arg_text,
va_list *args);
Function that you must implement if you want to write your own dialogf()
format.
Will be called when `dialogf()' constructs the dialog and should set up
the `DIALOG *' structures appropriately.
`dialog' is the `DIALOG' structure which should be filled in. `desc' is
the description text passed to `dialogf()' which belongs to this format.
`arg_text' is the modifier string between the brackets after the format.
`args' is a pointer to a `va_list' which you should read to get the extra
arguments passed. For more info on `va_list's, see any libc
documentation. The function should normally return 0 (see Advanced
Stuff for more info on what other return values are possible).
void dialogf_store_<MyFormat>(DIALOG *dialog);
Function that you may implement if you want to write your own dialogf()
format.
Will be called when the user clicks the OK button in the dialog. Its
purpose is to copy the information given by the user to wherever the
result should be stored.
void dialogf_reset_<MyFormat>(DIALOG *dialog);
Function that you may implement if you want to write your own dialogf()
format.
This function should take care of resetting the dialog object to reflect
the default value, as given by the parameters to `dialogf()'. Note that
since this function does that job, the `dialogf_create_<MyFormat>()'
function does not need to do it.
void dialogf_destroy_<MyFormat>(DIALOG *dialog);
Function that you may implement if you want to write your own dialogf()
format.
Will be called in the shut down code for `dialogf()'. If your
`dialogf_create_<MyFormat>()' function mallocates any data, this is
the place to free it.
void dialogf_count_<MyFormat>(char *arg_text);
Function that you must implement if you want to write your own dialogf()
format.
The count function. This function will be called by `dialogf()' before
anything else, and should return the number of `DIALOG *' structures that
need to be allocated. `arg_text' is the modifiers given by the person who
called `dialof()' inside the brackets after the format text.
int dialogf_outside_<MyFormat>(DIALOG *dialog);
Function that you may implement if you want to write your own dialogf()
format.
This is a bit on the complex side: An Allegro dialog can't be opened from
within a dialog proc. Therefore, you may need to implement this function,
which will be called safely outside any Allegro dialogs whenever the
dialog proc associated with this format returns `D_CLOSE'. This really is
ugly, but I couldn't find any other way to do it. Should return 0 if it
wants the dialog manager to redraw the background, and 1 if it takes care
of restoring the background itself.
There are some helper functions that you will probably find useful for parsing the modifier string.
int dime_get_int_arg(char **arg_text, int *out);
int dime_get_double_arg(char **arg_text, double *out);
int dime_get_string_arg(char **arg_text, char *out, int max_size);
int dime_get_strlist_arg(char **arg_text, STRLIST *out);
Return the next argument from `*arg_text', in different formats.
`dime_get_int_arg()' fills `*out' with an integer parsed from the
`*arg_text'. `dime_get_double_arg()' does the same for a double.
`dime_get_string_arg()' fills `out' with a string, which ends when the
`arg_text' ends or at the next comma not escaped with '%'.
`dime_get_strlist_arg()' adds several strings, separated by ';'
(semicolons escaped by '%' won't count), up to the next comma (commas
escaped by `%' won't count) or end of string. All the functions return a
combination of the following flags:
DIME_ARG_COMMA - The reading was interrupted by a comma in the string.
DIME_ARG_END - The reading was interrupted by end of string.
DIME_ARG_NONDIGIT - The reading was interrupted by something that was
not a digit.
DIME_ARG_DIGIT - The reading was interrupted by a digit.
DIME_ARG_READ - Something was actually read before the reading was
interrupted.
void inwards_bevel(DIALOG *dialog, int ofs, int white_space);
Draws the kind of bevel that is around Dime's text boxes in the area
given by `d'. If ofs is not 0, the bevel will grow by that number of
pixels. If the `white_space' flag is set, an extra one pixel wide border
of white will be drawn inside the bevel.
void register_dialogf_format(
char *specifier,
int handle_desc,
int (*dialog_count)(char *text),
int (*create_dialog)(DIALOG *dialog, char *desc, char *arg_text,
va_list *args),
void (*outside_func)(DIALOG *object),
void (*store_result)(DIALOG *object),
void (*reset_dialog)(DIALOG *object),
void (*destroy_data)(DIALOG *object));
When you have written the appropriate functions that take care of the
format, you just need to make `dialogf()' aware of your functions. This
is done by calling `register_dialogf_format()'. First parameter is the
format text. Eg the built-in format %int[] uses "int" here. If the
`handle_desc' flag is not set, `dialogf()' will take care of making a
dialog object for the description text, but if you want to handle that
yourself you could pass 0 instead. The rest of the parameters are the
pointers to the functions that you created earlier. `dialog_count()' and
`create_dialog()' must always be implemented. You will normally want to
pass NULL for the `outside_func', but see the description for that
function for info on when you need it. If the dialog object doesn't have
any custom data (like %line[] and %nothing[]), you may pass NULL for
`store_result' and `reset_dialog'. `destroy_data' can also be NULL, in
case you don't allocate any custom data when creating the dialog.
There are some obscure features that you normally won't need to know about:
Calling `dialogf()' recursively from `dialogf()'
`dialogf()' is written so that it is safe to call `dialogf()' recursively
from an `dialogf_outside_<MyFormat>()' function (this is of course
required for the %dialogf[] format, but also for the %wlist[],
%wstrlist[] and %wdatafile[] formats, which are implemented by opening a
new `dialogf()' window). In addition, a call to `dialogf()' can be split
up into five parts. `dialogf_start()' must be called first, and you are
not allowed to use the `DIALOGF_DIALOG *' after `dialogf_end()' has been
called, but between those calls you can happily call `dialogf_run()',
`dialogf_store_results()' and `dialogf_reset_dialog()' any number of
times you like and in any order you like.
DIALOGF_DIALOG *dialogf_start(char *title, int x_pos, int y_pos,
int edit_w, char *format, va_list *args);
Sets up a `DIALOGF_DIALOG *', which can be used by `dialogf_run()' to
open a dialog.
int dialogf_run(DIALOGF_DIALOG *dd);
Runs a dialog until the user closes it, but doesn't store any results or
free any memory. Returns 1 if the user OK'ed and 2 if he cancelled.
void dialogf_store_results(DIALOGF_DIALOG *dd);
Stores the data that the user entered in the dialog in the appropriate
output fields.
void dialogf_reset_dialog(DIALOGF_DIALOG *dd);
Resets all the dialog objects to reflect the default values as given by
the `va_list *args' arguments to `dialogf_start()'.
void dialogf_end(DIALOGF_DIALOG *dd);
Destroys all mallocated memory for the dialog.
DIALOG *_dime_dialog;
Pointer to the first object in the current dialog, in case any function
needs to access it.
Some of the built in formats (%line[] and %nothing[]) need to know the max width of the whole dialog. Naturally, this can not be known until all the objects have been created. Therefore, any `dialogf_create_<MyFormat>()' function that returns 1 will be called again after all other creation functions have been called. The return value is actually a flag field, where the zeroth and first bit may both be set or cleared, so the possible values are 0, 1, 2 and 3. If bit #1 is set, the `dialogf_create_<MyFormat>()' function will be called in a final pass, after all other creation routines have returned a number in which the first bit is cleared.