Using dialogue boxes is, unfortunately, the most complicated part of writing a module. It's annoying in the beginning, but, after your first dialogue is done, you'll be able to scavenge code and re-use it at will. I've been doing the same!So, let's dive straight into it with some code to prepare and issue a dialogue box. We'll be issuing a dialogue with the following controls:
- An 80 character string field.
- A 30 character password field.
- A list selection field allowing `Yes', `No' and `Maybe' (5 characters maximum).
- A toggle control (3 characters, because these controls report `on' or `off' depending on their state.
- A button labeled `OK'.
- Another button, `Cancel'.
Here's the code:
int result; sprintf (inp_buffer,"%s\n%s\ns\n%s\nOK\nCancel\n", "First string field", "password", "Yes", "on"); result = dialog_run ("foo", FOOVT, FOOLT, inp_buffer, MAXINPLEN); if (result!=0) { error_log("Unable to run data entry subsystem"); return; }This code demonstrates quite a few things:
- Allocating space for the data. Here, we need space for: one 80-character field, one 30-character field, a list whose longest value is 5 characters long, and a toggle with 3 characters (`off' is the longest value). Add space needed for line feeds and we have 81+31+6+4 bytes. Add the "OK" button (3 bytes, including line feed) and the "Cancel" button (7 bytes, including line feed). Add enough space for the name of the longest button (7 bytes), which will be added by the data entry subsystem to tell you what button ended the session, and don't forget one byte for null termination. The grand total is 81+31+6+4+3+7+7+1=140. Brilliant stuff.
Alternatively, you could say the hell with it, figure out the system already has buffers much larger than this, and use them. I whole-heartedly recommend using inp_buffer from the input subsystem because you can re-use existing BBS functionality to parse the results. It's all right to clobber inp_buffer, assuming you've already parsed all of the user's input, which is highly likely. In fact, you shouldn't allow concatenated commands past a data entry session anyway.
- Specifying the default values. The sprintf() command takes care of that for us (if you're paranoid about overflows, you're welcome to use snprintf() instead). We put the value of each control on a line of its own, terminating lines with '\n'. Here's how to do it for all available types of controls:
- String and numerical fields
- Just write the default value you need. Make sure the value is within the specifications (e.g. length, min-max ranges for numbers) of the fields! There's no need to enclose strings in double quotes.
- Lists
- Write the string of one of the settings. In our yes/no/maybe example, we write "Yes". Note that we observe case. The string should be a perfect match with strcmp().
- Toggles
- Specify on or off to denote the obvious things. User lower case.
- Buttons
- Anything you write will be ignored, but do write something as a placeholder. The data entry subsystem will replace these placeholders with the actual labels of the respective buttons on exit.
- Executing the data entry subsystem.
The call to the data entry subsystem is nothing too complicated (and it's all explained in this part of the documentation). You need to give it the name of a message block, two prompts containing the dialogue templates for visual and menu-based (`linear') data entry, and the newly constructed string of default values. Don't forget to check the return value in case an error precluded the dialogue from running. In such a case, abort the current process and go back to the module's previous (or main) menu. No need to register a fatal error for this.