NAME
Control, Controlset, activate, closecontrol, closecontrolset,
controlcalled, controlwire, createbox, createboxbox, createbutton,
createcolumn, createentry, createkeyboard, createlabel, createmenu,
createradiobutton, createrow, createscribble, createslider, createstack,
createtab, createtext, createtextbutton, ctlerror,
ctlmalloc, ctlrealloc, ctlstrdup, ctlprint, deactivate, freectlfont,
freectlimage, initcontrols, namectlfont, namectlimage, newcontrolset,
resizecontrolset – interactive graphical controls |
SYNOPSIS
#include <u.h> #include <libc.h> #include <draw.h> #include <thread.h> #include <keyboard.h> #include <mouse.h> #include <control.h> typedef struct Control Control; typedef struct Controlset Controlset; struct Control {
struct Controlset {
void initcontrols(void) Controlset* newcontrolset(Image *i, Channel *kc, Channel *mc, Channel *rc) void closecontrolset(Controlset *cs) int namectlfont(Font *font, char *name) int freectlfont(char *name) int namectlimage(Image *image, char *name) int freectlimage(char *name) Control* createbox(Controlset *cs, char *name) Control* createboxbox(Controlset *cs, char *name) Control* createbutton(Controlset *cs, char *name) Control* createcolumn(Controlset*, char*) Control* createentry(Controlset *cs, char *name) Control* createkeyboard(Controlset *cs, char *name) Control* createlabel(Controlset *cs, char *name) Control* createmenu(Controlset *cs, char *name) Control* createradiobutton(Controlset *cs, char *name) Control* createrow(Controlset*, char*) Control* createscribble(Controlset *cs, char *name) Control* createslider(Controlset *cs, char *name) Control* createstack(Controlset*, char*) Control* createtab(Controlset*, char *) Control* createtext(Controlset *cs, char *name) Control* createtextbutton(Controlset *cs, char *name) void closecontrol(Control *c) int ctlprint(Control*, char*, ...); void ctlerror(char *fmt, ...) Control* controlcalled(char *name) void controlwire(Control *c, char *cname, Channel *ch) void activate(Control *c) void deactivate(Control *c) void resizecontrolset(Controlset *cs) void* ctlmalloc(uint n) void* ctlrealloc(void *p, uint n) char* ctlstrdup(char *s) int ctldeletequits; |
DESCRIPTION
This library provides a set of interactive controls for graphical
displays: buttons, sliders, text entry boxes, and so on. It also
provides aggregator Controls: boxes, columns, rows and stacks
of Controls. A stack is a collection of co–located Controls, of
which one is normally visible. A Controlset collects a
group of Controls that share mouse and keyboard. Each Controlset
has a separate thread of control that processes keyboard and mouse
events as well as commands to be passed on to the Controls. Since
each Controlset uses a thread, programs using the control library
must be linked with the thread
library, thread(2). Controls are manipulated by reading and writing to the control channel, ctl, of their Controlset. Channels are defined in thread(2). Each Control has two output channels: Event delivers messages about actions within the control (such as a button press) and data delivers (if requested by an appropriate write to ctl) control–specific data such as the contents of a field.
The library provides a simple mechanism for automatic layout:
the minimum and maximum sizes of each simple control can be specified.
Boxbox, row, column and stack Controls then use these sizes to
lay out their constituent Controls when called upon to do so.
See the description of these grouping
Controls for further details. Message format
Messages sent to a Controlset are of the form,
To make it easy to write messages, the function chanprint (see thread(2)) can be used to print formatted text to a Controlset's channel.
The %q and %Q formats are convenient for properly quoting string
arguments, as in
The destination of a message can be a named control, or a set
of controls identified by name or type. The command
Note that we are still experimenting with destination names. One proposal is that a destination of the form "`name1 name2 ⋯ type1 type2 ⋯' selects all controls of the named types in the control hierarchies (of columns, rows and stacks) whose names precede the types.
Messages sent by a control on its event channel are of the form
Initialization and Control sets Each control is represented by a Control data structure and is associated with a Controlset that groups a set of controls sharing mouse, keyboard, and display. Most applications will need only one Controlset; only those with multiple windows or unusual configurations will need more than one. The function newcontrolset creates a Controlset. Its arguments are the image (usually a window) on which its controls will appear, typically the screen variable in the draw library, and three channels: kc, a channel of Runes from the keyboard; mc, a channel of Mouse structures from the mouse; and rc, a channel of int that indicates when the window has been resized. Any of the channels may be nil, in which case newcontrolset will call initkeyboard and/or initmouse (see keyboard(2) and mouse(2)) to initialize the keyboard and mouse and connect them to the control set. The mouse and resize channels must both be nil or both be non–nil. The function closecontrolset frees all the controls in the control set and tears down all the associated threads. It does not close the mouse and keyboard. The public elements of a Controlset are the flag clicktotype, and the ctl and data channels. Clicktotype is zero by default. If it is set to non–zero, the controls in the set will acquire `focus' by the click–to–type paradigm. Otherwise, focus is always given to the control under the mouse. Commands for controls are sent through the Controlset's ctl channel. One special command is recognized by the Controlset itself: Sending the string sync to the ctl channel causes tha string to be echoed to the Controlset's data channel when all commands up to the sync command have been processed. The string is allocated and must be freed (see malloc(2)). Synchronization is necessary between sending a command, for example, to resize all controls, and using their rect fields. The function resizecontrolset must be provided by the user. When the associated window is resized, the library will call resizecontrolset with the affected Controlset; the function should reconnect to and redraw the window.
If all windows are organized in a hierachy of boxboxes, columns,
rows and stacks, and minimum and maximum sizes have already been
supplied, only the top control needs to be resized (see the rect
command below). Fonts and images
The function initcontrols establishes name bindings for all the
colors mentioned in <draw.h>, such as black, white, red, yellow,
etc., as well as masks transparent and opaque. It also sets the
name font to refer to the default font variable set up by initdraw. Creation
The function controlcalled returns a pointer to the Control with
the given name, or nil if no such control exists. Configuration Messages sent to the ctl channel are delivered to all controls that match the destination field. This field is a set of names separated by spaces, tabs or newlines. A control matches the destination if its name or its type is among the set.
The recipient of a message ignores the initial sender: field of
the message, if present, making it possible to send messages generated
on an event channel directly to another control's ctl channel. Activation To enable a control, call the activate function, which specifies that the Control c should respond to mouse and keyboard events; deactivate turns it off again. Controls can be either revealed (default) or hidden. When a control is hidden, it will not receive mouse or keyboard events and state changes or show commands will be ignored until the control is once again revealed. Control hiding is particularly useful when different controls are overlayed, revealing only the `top' one.
The function controlwire permits rearrangement of the channels
associated with a Control. The channel cname (one of "data" or "event")
of Control c is reassigned to the channel ch. There are several
uses for this operation: one may reassign all the event channels
to a single channel, in effect
multiplexing all the events onto a single channel; or connect
the event channel of a slider to the ctl channel for delivery
to a text display (after setting the format for the slider's messages
to name the destination control and the appropriate syntax for
the rest of the command) to let the slider act as a scroll bar
for the
text without rerouting the messages explicitly. Controls
All controls accept the following messages:
reveal This is the opposite of hide: the Control is displayed and mouse and keyboard operations resume. Grouping Controls (column, row, and stack) pass the request down to their constituent Controls. The reveal command for stacks takes an optional argument naming the Control to be revealed;
Many messages are common between multiple Controls. Such messages
are described in detail here to avoid repetition. In the individual
descriptions, only the syntax is presented.
bordercolor name
format fmt Set the format of `value' messages sent on the event channel. By default, the format is "%q: value %q" for string–valued Controls, "%q: value %d" for integer–valued Control s such as buttons, and "%q: value 0x%x" for the keyboard and scribble Controls. The %q prints the
light name mask name Many controls set a background image or color for display. The image message sets the image. The mask and light images together specify how the Control shows it is enabled: the light is printed through the mask when the state is `on' or `pressed'. Otherwise, the image appears
textcolor name
Box
The box displays within its rectangle an image, under mask, with
specified alignment. The control messages it accepts are: Boxbox
show This command is passed on to the member controls. Show also (re)displays background and borders. size minΔx minΔy maxΔx maxΔy Button
align a Controls the placement of the image in the rectangle (unimplemented). border b bordercolor name focus n format fmt hide image name light name mask name rect minx miny maxx maxy reveal show size minΔx minΔy maxΔx maxΔy value n Set the button to `on' (if n is non–zero) or `off' (if n is zero). Column
rect minx miny maxx maxy
size [ minΔx minΔy maxΔx maxΔy ]
Entry
The cursor can be moved by clicking button 1; at the moment, there is no way to select characters, only a typing position. Some control characters have special actions: control–H (backspace) deletes the character before the cursor; control–U clears the line; and control–V pastes the snarf buffer at the typing position. Most important, carriage return sends the text to the event channel. To enter passwords and other secret text without displaying the contents, set the font to one in which all characters are the same. The easiest way to do this is to make a font containing only one character, at position 0 (NUL), since that position is used to render all characters not otherwise defined in the font (see draw(2)). The file /lib/font/bit/lucm/passwd.9.font defines such a font.
The control messages the entry control accepts are: Keyboard
There are two special keys, Scrib and Menu, which return values 0x10000 and 0x10001. The image, mask, light rules are used to indicate that a key is pressed, but to aid clumsy fingers the keystroke is not generated until the key is released, so it is possible to slide the pointer to a different key to correct for bad aim.
The control messages the keyboard accepts are:
hide image name light name mask name rect minx miny maxx maxy reveal show size minx miny maxx maxy Label Menu
The control messages accepted by a menu are:
window window n With no arguments, toggle the menu's visibility; otherwise make it visible (1) or invisible (0). When the selection is made, the menu will remove its window automatically. Radiobutton
The control messages the radiobutton accepts are: Row
The control messages it accepts are: Scribble
The control messages it accepts are: Stack
The control messages it accepts are:
Slider
The geometry of the slider is defined by three numbers: max is a number representing the range of the slider; vis is a number representing how much of what is being controlled is visible; and value is a number representing the value of the slider within its range. For example, if the slider is managing a textual display of 1000 lines, with 18 visible, and the first visible line (numbered starting form 0) is 304, max will be 1000, vis will be 18, and value will be 304. The indicator is the visual representation of the vis portion of the controlled object.
The control messages the slider accepts are:
format fmt hide image name indicatorcolor name
orient dir The string dir begins either hor or ver to specify the orientation of the slider. The default is vertical. The value always increases to the right for horizontal sliders and downwards for vertical sliders. rect minx miny maxx maxy reveal size minx miny maxx maxy show value n vis n Set the visible area shown by the indicator. Tab
Control messages are
bordercolor color focus n format fmt When a format string is defined, the tab control reports which tab is selected using the format string (which must print a char* and an int). image color Color between member controls. separation nSpacing between buttons in the radiobutton and between the row of buttons and the stack below it. rect n n n n hide reveal size n n n n show value n Value must be an integer indicating which tab to bring to the top. Text
The control messages the text control accepts are:
border b bordercolor name clear Delete all text. delete n Delete line n. focus n font name image name rect minx miny maxx maxy replace n s Replace line n by the string s. reveal scroll n If n is non–zero, the text will automatically scroll so the last line is always visible when new text is added. select n m Set the selection state of line n to m. selectcolor name
size minx miny maxx maxy show textcolor name topline n Scroll the text so the top visible line is number n. value s Delete all the text in the control and then add the single line s. Textbutton
Like a regular button, the value of a textbutton is an integer;
the text is the string that appears in the button. It uses the
image, light, mask method of indicating its state; moreover, the
color of the text can be set to change when the button is pressed.
The control messages it accepts are:
align a Controls the placement of the text in the rectangle.
reveal size minx miny maxx maxy show text s Set the text displayed in the button. textcolor name value n Set the button to `on' (if n is non–zero) or `off' (if n is zero). Helper functions The functions ctlmalloc, ctlrealloc, ctlstrdup, and ctlrunestrdup are packagings of the corresponding C library functions. They call ctlerror if they fail to allocate memory, and ctlmalloc zeros the memory it returns.
Finally, for debugging, if the global variable ctldeletequits
is set to a non–zero value, typing a DEL will cause the program
to call
Caveat
One unusual design goal of this library was to make the controls
themselves easy to implement. The reader is encouraged to create
new controls by adapting the source to existing ones. |
EXAMPLES
This example creates two entry boxes, top and bot, and copies
the contents of one to the other whenever a newline is typed.
#include <u.h> A richer variant couples a text entry box to a slider. Since the value of a slider is its numerical setting, as a decimal number, all that needs changing is the setup of bot:
Finally, we can avoid processing events altogether by cross–coupling the controls. Replace the rest of threadmain with this:
|
SOURCE
/sys/src/libcontrol |
SEE ALSO
draw(2), frame(2), graphics(2), quote(2), thread(2) |
BUGS
The library is strict about matters of formatting, argument count
in messages, etc., and calls ctlerror in situations where it may
be fine to ignore the error and continue. |