___ _ | \(_)_ __ ___ | |) | | ' \/ -_) |___/|_|_|_|_\___|

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.

What You Need To Write

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.

Helper Functions

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.

Registering The Format

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.

Advanced Stuff

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.