[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
It is often required to obtain textual input from the user, e.g., a file name, some fields in a database, etc. To this end input fields exist in the Forms Library. An input field is a field that can be edited by the user using the keyboard.
18.1 Adding Input Objects | ||
18.2 Input Types | ||
18.3 Input Interaction | ||
18.4 Other Input Routines | ||
18.5 Input Attributes | ||
18.6 Remarks |
Adding an object To add an input field to a form you use the routine
FL_OBJECT *fl_add_input(int type, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, const char *label) |
The meaning of the parameters is as usual. The label is by default placed in front of the input field.
The following types of input fields exist:
FL_NORMAL_INPUT
Any type of text can be typed into this field.
FL_FLOAT_INPUT
Only a floating point numbers can be typed in (e.g., -23.2e12). The
resulting string will be accepted by strtod()
in its entirety
(but may be too big to be represented by an int
or
long
).
FL_INT_INPUT
Only an integers can be typed in (e.g., -86). The resulting string will
be accepted by strtol()
in its entirety (but may be too big to
be represented by an float
or double
).
FL_DATE_INPUT
Only a date (MM/DD/YY or DD/MM/YY) can be typed in (and limited per default to 10 characters).
FL_MULTILINE_INPUT
An input field allowing for multiple lines.
FL_SECRET_INPUT
A normal input field that does not show the text (and limited per default to a maximum length of 16 characters).
FL_HIDDEN_INPUT
A normal input field but invisible.
A normal input field can contain one line of text, to be typed in by the user. A float input field can only contain a float number. If the user tries to type in something else than a float, it is not shown and the bell is sounded. Similarly, an int input field can only contain an integer number and a date input field can only contain a valid date (see below). A multi-line input field can contain multiple lines of text. A secret input field works like a normal input field but the text is not shown (or scrambled). Only the cursor is shown which does move while text is being entered. This can for example be used for getting passwords. Finally, a hidden input field is not shown at all but does collect text for the application program to use.
Whenever the user presses the mouse inside an input field a cursor
will appear in it (and the field will change color to indicate that it
received the input focus). Further input will be directed into this
field. The user can use the following keys (as in emacs(1)
) to
edit or move around inside the input field:
<Backspace>
, <Ctrl>h
<Delete>
<Ctrl><Backspace>
<Ctrl><Delete>
<Ctrl>k
<Meta>h
<Ctrl>a
<Ctrl>e
<Ctrl>b
<Ctrl>f
<Ctrl>n
, <Down>
<Ctrl>p
, <Up>
<Meta>b
<Meta>f
<Home>
<End>
<Ctrl>u
<Ctrl>y
It is possible to remap the the bindings, see below for details.
A single click into the input field positions the cursor at the position of the mouse click.
There are three ways to select part of the input field. Dragging,
double-click and triple-click. A double-click selects the word the
mouse is on and a triple-click selects the entire line the mouse is
on. The selected part of the input field is removed when the user
types the <Backspace>
or <Delete>
key or replaced by
what the user types in.
One additional property of selecting part of the text field is that if
the selection is done with the left mouse button the selected part
becomes the primary (XA PRIMARY
) selection of the X Selection
mechanism, thus other applications, e.g., xterm
, can request
this selection. Conversely, the cut-buffers from other applications
can be pasted into the input field. Use the middle mouse button for
pasting. Note that <Ctrl>y
only pastes the cut-buffer generated
by <Ctrl>k
and is not related to the X Selection mechanism,
thus it only works within the same application. When the user presses
the <Tab>
key the input field is returned to the application
program and the input focus is directed to the next input field. This
also happens when the user presses the <Return>
key but only if
the form does not contain a return button. The order which input
fields get the focus when the <Tab>
is pressed is the same as
the order the input fields were added to the form. From within Form
Designer, using the raising function you can arrange (re-arrange) the
focus order, see Raising and Lowering, in Part II for details. If
the <Shift>
key is pressed down when the <Tab>
is
pressed, the focus is directed to the previous input field.
Leaving an input field using the <Return>
) key does not work for
multi-line input fields since the <Return>
key is used to start
a new line.
Per default the input object gets returned to the application (or the callback set for the input object is invoked) when the input field is left and has been changed. Depending on the application, other options might be useful. To change the precise condition for the object to be returned (or its callback to become invoked), the following function can be used:
void fl_set_input_return(FL_OBJECT *obj, int when); |
Where when
can take one of the following values:
FL_RETURN_NONE
Never return or invoke callback
FL_RETURN_END_CHANGED
Default, object is returned or callback is called at the end if the field had been modified.
FL_RETURN_CHANGED
Return or invoke the callback function whenever the field had been changed.
FL_RETURN_END
Return or invoke the callback function at the end regardless if the field was modified or not.
FL_RETURN_ALWAYS
Return or invoke the callback function upon each keystroke and at the end (regardless if the field was changed or not)
See demo `objreturn.c' for an example use of this.
A few additional notes: when you read "the fields has been changed" this includes the case that the user e.g., deleted a character and then added it back again. Also this case is reported as a "change" (a delete alone isn't) so the term "changed" does not necessarily mean that the content of the field has changed but that the user made changes (but which still might result in the exact same content as before).
Another term that may be understood differently is "end". In the
versions since 1.0.91 it means that the users either hits the
<Tab>
or the <Return>
key (except for multi-line
inputs) or that she clicks onto some other object that in principle
allows user interaction. These events are interpreted as an
indication the user is done editing the input field and thus are
reported back to the program, either by returning the input object
or invoking its callback. But unless the user goes to a different
input object the input field edited retains the focus.
Up to version 1.0.90 this was handled a bit differently: an "end of edit" event was not reported back to the program when the user clicked on a non-input object, i.e., changed to a different input object. This let to some problems when the interaction with the clicked-on non-input object dependet on the new content of the input object, just having been edited, but which hadn't been been reported back to the caller. On the other hand, some programs rely on the "old" behaviour. These programs can switch back to the traditional behaviour by calling the new function (available since 1.0.93)
fl_input_end_return_handling(int type); |
where type
can be either
FL_INPUT_END_EVENT_ALWAYS
, which is now the default, or
FL_INPUT_END_EVENT_CLASSIC
, which switches back to the type
of handing used in versions up and including to 1.0.90. The function
can be used at any time to change between the two possible types of
behaviour. The function returns the previous setting.
There is a routine that can be used to limit the number of characters
per line for input fields of type FL_NORMAL_INPUT
void fl_set_input_maxchars(FL_OBJECT *obj, int maxchars); |
To reset the limit to unlimited, set maxchars
to 0. Note that
input objects of type FL_DATE_INPUT
are limited to 10
characters per default and those of type FL_SECRET_INPUT
to 16.
Although an input of type FL_RETURN_ALWAYS
can be used in
combination with the callback function to check the validity of
characters that are entered into the input field, use of the following
method may simplify this task considerably:
typedef int (*FL_INPUTVALIDATOR)(FL_OBJECT *obj, const char *old, const char *cur, int c); FL_INPUTVALIDATOR fl_set_input_filter(FL_OBJECT *obj, FL_INPUTVALIDATOR filter); |
The function filter()
is called whenever a new (regular)
character is entered. old
is the string in the input field
before the newly typed character c
was added to form the new
string cur
. If the new character is not an acceptable character
for the input field, the filter function should return
FL_INVALID
otherwise
FL_VALID
. If FL_INVALID
is returned, the new character
is discarded and the input field remains unmodified. The function
returns the old filter. While the built-in filters also sound the
keyboard bell, this don't happpens if a custom filter only returns
FL_INVALID
. To also sound the keyboard bell logically or it
with
FL_INVALID | FL_RINGBELL
.
This still leaves the possibility that the input is valid for every
character entered, but the string is invalid for the field because it
is incomplete. For example, 12.0e is valid for a float input field for
every character typed, but the final string is not a valid floating
point number. To guard against this, the filter function is also called
just prior to returning the object with the argument c
(for the
newly entered character) set to zero. If the validator returns
FL_INVALID
the object is not returned to the application
program, but input focus can change to the next input field. If the
return value FL_INVALID | FL_RINGBELL
, the keyboard bell is
sound and the object is not returned to the application program and
the input focus remains in the object.
To facilitate specialized input fields using validators, the following validator dependent routines are available
void fl_set_input_format(FL_OBJECT *obj, int attrib1, int attrib2); void fl_get_input_format(FL_OBJECT *obj, int *attrib1, int *attrib2); |
These two routines more or less provide a means for the validator to
store and retrieve some information about user preference or other
state dependent information. attrib1
and attrib2
can be
any validator defined variables. For the built-in class, only the one
of type FL_DATE_INPUT
utilizes these to store the date format:
for attrib1
, it can take
FL_INPUT_MMDD
or
FL_INPUT_DDMM
and attrib2
is the separator between month
and day. For example, to set the date format to dd/mm
, use
fl_set_input_format(obj, FL_INPUT_DDMM, '/'); |
For the built-in type FL_DATE_INPUT
the default is
FL_INPUT_MMDD
and the separator is '/'
. There is no
limit on the year other than it must be an integer and appear after
month and day.
int fl_validate_input(FL_OBJECT *obj); |
can be used to test if the value in an input field is valid. It
returns FL_VALID
if the value is valid or if there is no
validator function set for the input, otherwise
FL_INVALID
.
There are two slightly different input modes for input objects. In the
"normal" mode, when the input field is entered not using the mouse
(e.g., by using of the <Tab> key) the cursor is placed again at the
position it was when the field was left (or at the end of a possibly
existing string when it's entered for the first time). When an input
object has a maximum number of allowed characters set (via the
fl_set_input_maxchars()
function) and there's no room
left no new input is accepted until at least one character has been
deleted.
As an alternative there's an input mode that is similar to the way things were handle in DOS forms etc. Here, when the field is entered by any means but clicking into it with the mouse, the cursor is placed at the start of the text. And for fields with a maximum capacity, that contain already as many characters as possible, the character at the end of the field are removed when a new one is entered.
To switch between the two modes use the function
int fl_set_input_mode( int mode ); |
where mode
is one of
FL_NORMAL_INPUT_MODE
FL_DOS_INPUT_MODE
For selecting the DOS-like input mode
The function returns the previous setting. Note that the function changes the input mode for all input fields in your application.
Note that the label is not the default text in the input field. To set the contents of the input field use one of these routines:
void fl_set_input(FL_OBJECT *obj, const char *str); void fl_set_input_f(FL_OBJECT *obj, const char *fmt, ...); |
The first one takes a simple string while the second expects a format
string with format specifiers just like printf()
etc. and as
many (appropriate) arguments as there are format specifiers.
Only a limited check on the string passed to the function is done in
that only printable characters (according to the isprint()
function) and, in the case of FL_MULTILINE_INPUT
objects,
new-lines ('\n'
) are accepted (i.e., all that don't fit are
skipped). Use an empty string (or a NULL
pointer as the second
argument) to clear an input field.
Setting the content of an input field does not trigger an object
event, i.e., the object callback is not called. In some situations
you might want to have the callback invoked. For this, you may use
the function fl_call_object_callback()
.
To obtain the string in the field (when the user has changed it) use:
const char *fl_get_input(FL_OBJECT *obj); |
This function returns a char pointer for all input types. Thus for
numerical input types e.g., strtol(3)
, atoi(3)
,
strtod(3)
, atof(3)
or sscanf(3)
should be used to
convert the string to the proper data type you need. For multiline
input, the returned pointer points to the entire content with possibly
embedded newlines. The application may not modify the content pointed
to by the returned pointer, it points to the internal buffer.
To select or deselect the current input or part of it, the following two routines can be used
void fl_set_input_selected(FL_OBJECT *obj, int flag); void fl_set_input_selected_range(FL_OBJECT *obj, int start, int end); |
where start
and end
are measured in characters. When
start
is 0 and end
equals the number of characters in
the string, fl_set_input_selected()
makes the entire
input field selected. However, there is a subtle difference between
this routine and fl_set_input_selected()
when called with
flag
set to 1: fl_set_input_selected()
always
places the cursor at the end of the string while
fl_set_input_selected_range()q
places the cursor at the
beginning of the selection.
To obtain the currently selected range, either selected by the application or by the user, use the following routine
const char *fl_get_input_selected_range(FL_OBJECT *obj, int *start, int *end); |
where start
and end
, if not NULL
, are set to the
begining and end position of the selected range, measured in
characters. For example, if start
is 5 after the function
returned and end
is 7, it means the selection starts at
character 6 (str[5]
) and ends before character 8
(str[7]
), so a total of two characters are selected (i.e.,
character 6 and 7). The function returns the selected string (which
may not be modified). If there is currently no selection, the function
returns NULL
and both start
and end
are set to
-1. Note that the char
pointer returned by the function points
to (kind of) a static buffer, and will be overwritten by the next
call.
It is possible to obtain the cursor position using the following routine
int fl_get_input_cursorpos(FL_OBJECT *obj, int *xpos, int *ypos); |
The function returns the cursor position measured in number of
characters (including newline characters) in front of the cursor. If
the input field does not have input focus (thus does not have a
cursor), the function returns -1. Upon function return, ypos
is
set to the number of the line (starting from 1) the cursor is on, and
xpos
set to the number of characters in front of the cursor
measured from the beginning of the current line as indicated by
ypos
. If the input field does not have input focus the
xpos
is set to -1.
It is possible to move the cursor within the input field programmatically using the following routine
void fl_set_input_cursorpos(FL_OBJECT *obj, int xpos, int ypos); |
where xpos
and ypos
are measured in characters (lines).
E.g., given the input field "an arbitrary string"
the call
fl_set_input_cursorpos(ob, 4, 1); |
places the the cursor after the first character of the word
"arbitrary"
, i.e., directly after the first a
.
By default, if an input field of type FL_MULTILINE_INPUT
contains more text than can be shown, scrollbars will appear with
which the user can scroll the text around horizontally or vertically.
To change this default, use the following routines
void fl_set_input_hscrollbar(FL_OBJECT *obj, int how); void fl_set_input_vscrollbar(FL_OBJECT *obj, int how); |
where how
can be one of the following values
FL_AUTO
FL_ON
FL_OFF
Never show scrollbar.
Note however that turning off scrollbars for an input field does not turn off scrolling, the user can still scroll the field using cursor and other keys.
To completely turn off scrolling for an input field (for both
multiline and single line input field), use the following routine with
a false value for yes_no
void fl_set_input_scroll(FL_OBJECT *obj, int yes_no); |
There are also routines that can scroll the input field
programmatically. To scroll vertically (for input fields of type
FL_MULTILINE_INPUT
only), use
void fl_set_input_topline(FL_OBJECT *obj, int line); |
where line
is the new top line (starting from 1) in the input
field. To programmatically scroll horizontally, use the following routine
void fl_set_input_xoffset(FL_OBJECT *obj, int pixels); |
where pixels
, which must be a positive number, indicates how
many pixels to scroll to the left relative to the nominal position of
the text lines.
To obtain the current xoffset, use
int fl_get_input_xoffset(FL_OBJECT *obj); |
It is possible to turn off the cursor of the input field using the
following routine with a false value for yes_no
:
void fl_set_input_cursor_visible(FL_OBJECT *obj, int yes_no); |
To obtain the number of lines in the input field, call
int fl_get_input_numberoflines(FL_OBJECT *obj); |
To obtain the current topline in the input field, use
int fl_get_input_topline(FL_OBJECT *obj); |
To obtain the number of lines that fit inside the input box, use
int fl_get_input_screenlines(FL_OBJECT *obj); |
For secret input field, the default is to draw the text using spaces. To change the character used to draw the text, the following function can be used
int fl_set_input_fieldchar(FL_OBJECT *obj, int field_char); |
The function returns the old field char.
Never use FL_NO_BOX
as the boxtype.
The first color argument (col1
) to
fl_set_object_color()
controls the color of the input
field when it is not selected and the second (col2
) is the
color when selected.
To change the color of the input text or the cursor use
void fl_set_input_color(FL_OBJECT *obj, FL_COLOR tcol, FL_COLOR ccol); |
Here tcol
indicates the color of the text and ccol
is
the color of the cursor.
If you want to know the colors of the text and cursor use
void fl_get_input_color(FL_OBJECT *obj, FL_COLOR *tcol, FL_COLOR *ccol); |
By default, the scrollbar size is dependent on the initial size of the input box. To change the size of the scrollbars, use the following routine
void fl_set_input_scrollbarsize(FL_OBJECT *obj, int hh, int vw); |
where hh
is the horizontal scrollbar height and vw
is
the vertical scrollbar width in pixels.
To determine the current settings for the horizontal scrollbar height and the vertical scrollbar width use
void fl_get_input_scrollbarsize(FL_OBJECT *obj, int *hh, int *vw); |
The default scrollbar types are FL_HOR_THIN_SCROLLBAR
and
FL_VERT_THIN_SCROLLBAR
. There are two ways you can change
the default. One way is to use fl_set_defaults()
or
fl_set_scrollbar_type()
to set the application wide
default (preferred); another way is to use
fl_get_object_component()
to get the object handle to the
scrollbars and change the the object type forcibly. Although the
second method of changing the scrollbar type is not recommended, the
object handle obtained can be useful in changing the scrollbar colors
etc.
As mentioned earlier, it is possible for the application program to
change the default edit keymaps. The editing key assignment is held in
a structure of type
FL_EditKeymap
defined as follows:
typedef struct { long del_prev_char; /* delete previous char */ long del_next_char; /* delete next char */ long del_prev_word; /* delete previous word */ long del_next_word; /* delete next word */ long del_to_eol; /* delete from cursor to end of line */ long del_to_bol; /* delete from cursor to begin of line */ long clear_field; /* delete all */ long del_to_eos; /* not implemented */ long backspace; /* alternative for del_prev_char */ long moveto_prev_line; /* one line up */ long moveto_next_line; /* one line down */ long moveto_prev_char; /* one char left */ long moveto_next_char; /* one char right */ long moveto_prev_word; /* one word left */ long moveto_next_word; /* one word right */ long moveto_prev_page; /* one page up */ long moveto_next_page; /* one page down */ long moveto_bol; /* move to begining of line */ long moveto_eol; /* move to end of line */ long moveto_bof; /* move to begin of file */ long moveto_eof; /* move to end of file */ long transpose; /* switch two char positions*/ long paste; /* paste the edit buffer */ } FL_EditKeymap; |
To change the default edit keymaps, the following routine is available:
void fl_set_input_editkeymap(const FL_EditKeymap *km); |
with a filled or partially filled FL_EditKeymap
structure. The unfilled members must be set to 0 so the default
mapping is retained. Change of edit keymap is global and affects all
input field within the application.
Calling fl_set_input_editkeymap()
with km
set to
NULL
restores the default. All cursor keys (<Left>
,
<Home>
etc.) are reserved and their meanings hard-coded, thus
can't be used in the mapping. For example, if you try to set
del_prev_char
to <Home>
, pressing the <Home>
key
will not delete the previous character.
To obtain the current map of the edit keys use the function
void fl_get_input_editkeymap(FL_EditKeymap *km); |
with the km
argument pointing of a user supplied structure
which after the call will be set up with the current settings for
the edit keys.
In filling the keymap structure, ASCII characters (i.e., characters
with values below 128, including the control characters with values
below 32) should be specified by their ASCII codes (<Ctrl> C
is 3 etc.), while all others by their Keysym
s (XK_F1
etc.). Control and special character combinations can be obtained by adding
FL_CONTROL_MASK
to the Keysym
. To specify Meta
add
FL_ALT_MASK
to the key value.
FL_EditKeymap ekm; memset(&ekm, 0, sizeof ekm); /* zero struct */ ekm.del_prev_char = 8; /* <Backspace> */ ekm.del_prev_word = 8 | FL_CONTROL_MASK; /* <Ctrl><Backspace> */ ekm.del_next_char = 127; /* <Delete> */ ekm.del_prev_word = 'h' | FL_ALT_MASK; /* <Meta>h */ ekm.del_next_word = 127 | FL_ALT_MASK; /* <Meta><Delete> */ ekm.moveto_bof = XK_F1; /* <F1> */ ekm.moveto_eof = XK_F1 | FL_CONTROL_MASK; /* <Ctrl><F1> */ fl_set_input_editkeymap(&ekm); |
Note: In earlier versions of XForms (all version before 1.2) the
default behaviour of the edit keys was slightly different which
doesn't fit modern user expectations, as was the way the way the
edit keymap was to be set up. If you use XForms for some older
application that makes massive use of the "classical" behaviour
you can compile XForms to use the old behaviour by using the
--enable-classic-editkeys
option when configuring the
library for compilation.
Always make sure that the input field is high enough to contain a single line of text. If the field is not high enough, the text may get clipped, i.e., become unreadable.
See the program `demo06.c' for an example of the use of input fields. See `minput.c' for multi-line input fields. See `secretinput.c' for secret input fields and `inputall.c' for all input fields.
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated by Build Daemon on October 16, 2020 using texi2html 1.82.