I've had to write one of these back in the early 2000's for the
company I work for (commercial software).
Some advice: I allowed stdin (or optionally, a file) to allow the user
to specify the form template, and also a separate file to allow the
defaults to be specified and saved (so that the next time the form opens,
the user's last settings could reappear in the form).
In my case the program is called 'input', so one could use a shell script
to bring up the interface with something like:
input -uifile - << EOF
First Name: ____________
Last Name: _______________________
Tel#: _______________________
Date: _______________________
Notes: _______________________________________________
_______________________________________________
_______________________________________________
<<CANCEL>> <<SUBMIT>>
EOF
..which would open a window with those field prompts, and includes
"cancel" and "submit" buttons. The ascii art defined the field
widths and layout placement.
It writes out the form's values as key/value pairs, where the key names
were the prompts with the spaces removed, e.g. "First Name:" would become
the keyname "FirstName", and the values were all strings.
Multiline values for fields were allowed too, by just repeating
the key name for each line in the multiline field, e.g.
Notes: value for line 1..
Notes: value for line 2..
Notes: value for line 3..
Afraid I can't release the source code, as the company owns this program,
but the docs are here, in case you're looking for ideas on what to do.
The following documents the more verbose 'command' technique to define
the window size, input fields, buttons, etc.
http://seriss.com/rush.103.00/input/index.html
I also later added an 'ascii art' way the user could define forms,
so that the vertical and horizontal arrangement could be defined
in a graphic way using ascii. So for example this 'ascii art':
---------------------------------------------------------------------------------------
Job Title: ______________ ?
Scene Path: ____________________________________________ ? Browse"*.{ma,mb}"
Project Path: ____________________________________________ ? Browse"<DIR>"
Renderer: "default,maya(sw),arnold(arnold),mentalray(mr),mentalray-standalone(mi),mi-gen(mi),hardware(hw),vector(vr),renderm
Threads: "1,2,3,4,all,_" ?
= Frames: ______________ ?
= Batch Frames: ______________ ? |= Batch Clip: "yes,no" ?
Max Time: "00:00:00,00:05:00,00:10:00,00:30:00,01:00:00,01:30:00,02:00:00,02:30:00,03:00:00,_" ?
MaxTimeState: "Que,Fail,Done,Hold" ?
Cpus: ___________________________________________________ ? <ShowCpus>
___________________________________________________
___________________________________________________
---------------------------------------------------------------------------------------
So basically the width of the underbar lines defines the width of the fields,
and the vertical arrangement defined the vertical position of the fields.
The above ascii art ends up creating an FLTK UI that looks like this:
http://seriss.com/rush.103.00/submit-maya/index.html
There's some meta tags not shown in the above to define e.g. the size
of the window, the title, and how to define different tabs for a form
with multiple pages.
For that meta data, I chose to use little angle brackets to set those values:
<<WINDOW WIDTH=720>>
<<PROMPT X=160 COLWIDTH=334>>
<<TITLE>> "Rush Maya Submit"
<<TAB>> "Main"
..ascii art form goes here..
<<ENDPAGE>>
<<TAB>> "Maya"
..ascii art form for this new tab goes here..
<<ENDPAGE>>
..etc..
So this all defined relatively complex input forms, in some cases
allowing the user to hit buttons in the form that updated the form,
invoking the same script that created it, in order to add some logic
to change values in the form procedurally, based on things the user
typed in so far. When the user hit this button, the form window would
remain open, but saved out the key/value pairs to a tmp file, and invoked
the script with a special -update flag, so the script would load the
key/value pairs, make changes to the file, and resave, and exit. The
main program would then load the changes, and update the form on the
screen.
This allowed for fairly complex behavior, much like callbacks.
Anyway, FYI, depending on how complicated you want to get with this thing.
I needed all these features for the multi platform product I was working on
(still used to this day), where the scripting languages built around it can
be anything from perl to python, or even sh/csh scripts.