CONTROL(2)                                             CONTROL(2)

     NAME
          Control, Controlset, activate, closecontrol,
          closecontrolset, controlcalled, controlwire, createbox,
          createbutton, createentry, createkeyboard, createlabel,
          createmenu, createradiobutton, createscribble, createslider,
          createtext, createtextbutton, ctlerror, ctlmalloc,
          ctlrealloc, ctlstrdup, deactivate, freectlfont,
          freectlimage, initcontrols, namectlfont, namectlimage,
          newcontrolset, printctl, 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
          {
              char        *name;
              Rectangle   rect;   /* area on screen */
              Channel *event; /* chan(char*) to client */
              Channel *ctl;       /* chan(char*) from client */
              Channel *data;  /* chan(char*) to client */
              ...
          };

          struct Controlset
          {
              ...
              int clicktotype;
              ...
          };

          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)

     Page 1                       Plan 9             (printed 4/18/24)

     CONTROL(2)                                             CONTROL(2)

          int     namectlimage(Image *image, char *name)

          int     freectlimage(char *name)

          Control*    createbox(Controlset *cs, char *name)

          Control*    createbutton(Controlset *cs, char *name)

          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*    createscribble(Controlset *cs, char *name)

          Control*    createslider(Controlset *cs, char *name)

          Control*    createtext(Controlset *cs, char *name)

          Control*    createtextbutton(Controlset *cs, char *name)

          void        closecontrol(Control *c)

          int     printctl(Channel *c, char *fmt, ...)

          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 preliminary implementation of a set

     Page 2                       Plan 9             (printed 4/18/24)

     CONTROL(2)                                             CONTROL(2)

          of interactive controls for graphical displays: buttons,
          sliders, text entry boxes, and so on.  Each control runs as
          a separate thread in the program, which must therefore be
          linked with the thread library, thread(2). The controls are
          manipulated by reading and writing to its channels, as
          defined in thread(2). Each control has three channels: ctl
          accepts messages to configure and manage the control, while
          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 has no provision for automatic layout; the geom-
          etry of controls must be specified explicitly.

        Message format
          All messages are represented as UTF-8 text.  Numbers are
          formatted in decimal, and strings are transmitted in the
          quoted form of quote(2).

          Messages sent to a control are of the form,

               verb [argument ... ]

          For example, the initial field of a text entry control could
          be set by sending the message,

               value 'Hello, world!'

          to its ctl file.  This message contains the verb value and
          the single argument Hello, world!.

          Messages sent by a control on its event channel are of the
          form,

               sender: verb [argument ... ]

          The sender is the name of the control sending the message;
          the verb and arguments are control- and message-dependent.
          For example, when the user types a newline at a text entry
          control named entry, it sends on its event channel the mes-
          sage

               entry: value 'Hello again!'

          To make it easy to write messages, the function printctl
          formats its arguments in the manner of print(2) and sends
          the result to the channel c. The %q and %Q formats are con-
          venient for properly quoting string arguments, as in

               printctl(e->event, "value %q", "Don't touch!");

     Page 3                       Plan 9             (printed 4/18/24)

     CONTROL(2)                                             CONTROL(2)

          It is wise to use %q always instead of %s when sending mes-
          sages, and avoid dealing with the quoting explicitly.  In
          the other direction, tokenize (see getfields(2)) parses
          these messages and interprets the quotes correctly.

        Initialization and Control sets
          After initdraw (see graphics(2)) is called, the function
          initcontrols should be called to initialize the library.  It
          calls quotefmtinstall to install the %q and %Q formats; see
          quote(2).

          Each control is represented by a Control data structure and
          is associated with a Controlset that groups a set of con-
          trols sharing mouse, keyboard, and display.  Most applica-
          tions will need only one Controlset; only those with multi-
          ple 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 con-
          trols 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 only public element of a Controlset is the flag
          clicktotype, which 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.

          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.

        Fonts and images
          Fonts and images must be given names so they may be refer-
          enced in messages.  The functions namectlfont and
          namectlimage associate a (unique) name with the specified
          font or image.  The association is removed by freectlfont
          and freectlimage. The font or image is not freed by these
          functions, however.

          The function initcontrols establishes name bindings for all

     Page 4                       Plan 9             (printed 4/18/24)

     CONTROL(2)                                             CONTROL(2)

          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 vari-
          able set up by initdraw.

        Creation
          Each type of control has an associated creation function:
          createbutton, createentry, etc., whose arguments are the
          Controlset to attach it to and a globally unique name for
          it.  A control may be destroyed by calling closecontrol.

          The function controlcalled returns a pointer to the Control
          with the given name, or nil if no such control exists.

        Configuration
          After a control is created, it must be configured using the
          control-specific commands documented below.  Commands are
          sent to the ctl channel of the control.  Multiple commands
          may be sent in a single message; newline characters separate
          commands.  For an example, see the implementation of
          resizecontrolset in the EXAMPLES section.  Note that newline
          is a separator, not a terminator; the final command does not
          need a newline.

          The recipient of a message to its ctl file ignores the ini-
          tial 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
          When they are created, controls are disabled: they do not
          respond to user input.  Not all controls need to be respon-
          sive; for example, labels are static and a text display
          might show a log of messages but not be useful to edit.  But
          buttons, entry boxes, and other text displays should be
          active.

          To enable a control, call the activate function, which spec-
          ifies that the Control c should respond to mouse and key-
          board events; deactivate turns it off again.

          The function controlwire permits rearrangement of the chan-
          nels associated with a Control.  The channel cname (one of
          "ctl", "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 of
          a text display (after setting the format for the slider's
          messages to the appropriate syntax) to let the slider act as
          a scroll bar for the text without rerouting the messages
          explicitly.

     Page 5                       Plan 9             (printed 4/18/24)

     CONTROL(2)                                             CONTROL(2)

        Controls
          The following sections document the individual controls in
          alphabetical order.  The layout of each section is a brief
          description of the control's behavior, followed by the mes-
          sages it sends on event, followed by the messages it accepts
          on ctl.  The event messages are triggered only by mouse or
          keyboard action; messages to the ctl file do not cause
          events to be generated.

          All controls accept the following messages:

          rect minx miny maxx maxy
               Set the bounding rectangle for the control on the dis-
               play.  The syntax generated by the %R print format of
               the draw library is also acceptable for the coordi-
               nates.

          show Display the control on its screen.  Some actions will
               also cause the controls to show themselves automati-
               cally.  The details of how redisplay is handled in gen-
               eral are likely to change.

          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 pre-
          sented.

          align n
               Specify the alignment of (some part of) the control's
               display within its rectangle.  For textual controls,
               the alignment specifies where the text should appear.
               For multiline text, the alignment refers to each line
               within its box, and only the horizontal part is hon-
               ored.  For other controls, the alignment affects the
               appearance of the display in a reasonable way.  The
               valid alignments are words with obvious interpreta-
               tions: upperleft, uppercenter, upperright, centerleft,
               center, centerright, lowerleft, lowercenter, and
               lowerright.

          border n
               Inset the control within its rectangle by n pixels,
               default zero.

          bordercolor name
               Paint the border of the control with the named color,
               default black.

          focus n
               The control now has (if n is non-zero) or does not have
               ( if n is zero) focus.  Most controls ignore the mes-
               sage; there are plans to make them react.

     Page 6                       Plan 9             (printed 4/18/24)

     CONTROL(2)                                             CONTROL(2)

          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 controls such as buttons, and "%q: value 0x%x"
               for the keyboard and scribble controls.  The %q prints
               the name of the control; the rest the value.  Any sup-
               plied format string must be type-equivalent to the
               default for that control.

          image name

          light name

          mask name
               Many controls set a background image or color for dis-
               play.  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 unmodified.  The default image is white; mask
               opaque; light yellow.

          font name

          textcolor name
               These commands set the font and color for displaying
               text.  The defaults are the default font set up by the
               draw library, and black.

          value v
               Set the value of the control.  Textual images accept an
               arbitrary string; others an integral value.

        Box
          A box is a trivial control that does nothing more than pass
          keyboard, mouse, and focus messages back on its event chan-
          nel.  Keyboard characters are sent in the format

               boxname: key 0xnn

          where nn is the hexadecimal value of the character.  Mouse
          messages are sent in the format

               boxname: mouse [x y] but msec

          where x, y, but, and msec are the various fields of the
          Mouse structure.  The focus message is just

               boxname: focus n

          where n is 0 if the box has lost focus, 1 if it has acquired

     Page 7                       Plan 9             (printed 4/18/24)

     CONTROL(2)                                             CONTROL(2)

          it.

          The box displays within its rectangle an image, under mask,
          with specified alignment.  The control messages it accepts
          are:

          align a
               Controls the placement of the image in the rectangle
               (unimplemented).

          border b

          bordercolor name

          focus n

          image name

          rect minx miny maxx maxy

          show

        Button
          A button is a simple control that toggles its state when
          mouse button 1 is pressed on its rectangle.  Each state
          change triggers an event message:

               buttonname: value n

          The button displays an image (which may of course be a sim-
          ple color) and illuminates in the standard way when it is
          `on'.  The control messages it accepts are:

          align a
               Controls the placement of the image in the rectangle
               (unimplemented).

          border b

          bordercolor name

          focus n

          format fmt

          image name

          light name

          mask name

          rect minx miny maxx maxy

     Page 8                       Plan 9             (printed 4/18/24)

     CONTROL(2)                                             CONTROL(2)

          show

          value n
               Set the button to `on' (if n is non-zero) or `off' (if
               n is zero).

        Entry
          The entry control manages a single line of editable text.
          When the user hits a carriage return anywhere in the text,
          the control generates the event message,

               entryname: value s

          with s the complete text of the entry box.

          The cursor can be moved by clicking button 1; at the moment,
          there is no way to select characters, only a typing posi-
          tion.  Some control characters have special actions:
          control-H (backspace) deletes the character before the cur-
          sor; control-U clears the line; and control-V pastes the
          snarf buffer at the typing position.  Most important, car-
          riage return sends the text to the event channel.

          The control messages the entry control accepts are:

          align a
               Controls the placement of the text in the rectangle.

          border b

          bordercolor name

          data After receiving this message, the entry will send its
               value to its data channel as an unadorned, unquoted
               string.

          focus n
               When it receives focus, the entry box displays a typing
               cursor.  When it does not have focus, the cursor is not
               displayed.

          font name

          format fmt

          image name

          rect minx miny maxx maxy

          show

          textcolor name

     Page 9                       Plan 9             (printed 4/18/24)

     CONTROL(2)                                             CONTROL(2)

          value s
               Set the string displayed in the entry box.

        Keyboard
          The keyboard control implements a simulated keyboard useful
          on palmtop devices.  Keystrokes, generated by mouse button 1
          on the simulated keys, are sent as event messages:

               keyboardname: value 0xnn

          where nn is the hexadecimal Unicode value of the character.
          Shift, control, and caps lock are handled by the keyboard
          control itself; shift and control affect only the next regu-
          lar keystroke.  The Alt key is unimplemented; it will become
          equivalent to the standard Plan 9 key for synthesizing non-
          ASCII characters.

          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:

          border b

          bordercolor name

          focus n

          font name1 name2
               Sets the font for the keys.  If only one font is named,
               it is used for all keys.  If two are named, the second
               is used for key caps with special names such as Shift
               and Enter.  (Good choices on the Bitsy are
               /lib/font/bit/lucidasans/boldlatin1.6.font for the
               first and /lib/font/bit/lucidasans/unicode.6.font for
               the second argument.)  If neither is specified, both
               will be set to the default global font.

          format fmt

          image name

          light name

          mask name

          rect minx miny maxx maxy

     Page 10                      Plan 9             (printed 4/18/24)

     CONTROL(2)                                             CONTROL(2)

          show

        Label
          A label is like a textbutton (q.v.)  that does not react,
          but whose value is the text it displays.  The control mes-
          sages it accepts are:

          align a
               Controls the placement of the image in the rectangle.

          border b

          bordercolor name

          focus n

          font name

          image name

          rect minx miny maxx maxy

          show

          textcolor name

          value s
               The value is a string that can be modified only by
               sending this message to the ctl file.

        Menu
          A menu is a pop-up window containing a set of textual selec-
          tions.  When a selection is made, it removes itself from the
          screen and reports the selection by value:

               menuname: value n

          If no selection is made, no message is reported.  Because it
          creates a window, programs using a menu must have their
          screen variable (see graphics(2) and window(2)) set up to be
          refreshed properly.  The easiest way to do this is to call
          getwindow with refresh argument Refbackup (see graphics(2));
          most programs use Refnone.

          The control messages accepted by a menu are:

          add text
               Add a line of text to the end of the menu.

          align a
               Controls the left-right placement of the text in its
               rectangle.

     Page 11                      Plan 9             (printed 4/18/24)

     CONTROL(2)                                             CONTROL(2)

          border b

          bordercolor name

          focus n

          font name

          format fmt

          image name

          rect minx miny maxx maxy

     the appropriate size.
          Only the origin of the rectangle is significant; menus calculate

          selectcolor name
               Set the color in which to highlight selected lines;
               default yellow.

          selecttextcolor name
               Set the color in which to draw the text in selected
               lines; default black.

          show Display the menu. Not usually needed unless the menu is
               changed while visible; use window instead.

          window

          window n
               With no arguments, toggle the menu's visibility; other-
               wise make it visible (1) or invisible (0).  When the
               selection is made, the menu will remove its window
               automatically.

        Radiobutton
          The radiobutton assembles a group of buttons or textbuttons
          into a single control with a numeric value.  Its value is -1
          if none of the constituent buttons is pressed; otherwise it
          is the index, starting at zero, of the button that is
          pressed.  Only one button may be pressed; the radiobutton
          manipulates its buttons to guarantee this.  State changes
          trigger an event message:

               radiobuttonname: value n

          Buttons are added to the radio button using the add message;
          there is no way to remove them, although they may be turned
          off independently using deactivate. The index reported in
          the value is defined by the order in which the buttons are
          added.  The constituent buttons should be configured and

     Page 12                      Plan 9             (printed 4/18/24)

     CONTROL(2)                                             CONTROL(2)

          layed out in the usual way; the rectangle of the radiobutton
          is used only to `catch' mouse events and should almost
          always correspond to the bounding box of the constituent
          buttons.  In other words, the geometry is not maintained
          automatically.

          The control messages the radiobutton accepts are:

          add name
               Add the control with the specified name to the
               radiobutton.

          focus n

          format fmt

          rect minx miny maxx maxy

          show

          value n

        Scribble
          The scribble control provides a region in which strokes
          drawn with mouse button 1 are interpreted as characters in
          the manner of scribble(2). In most respects, including the
          format of its event messages, it is equivalent to a keyboard
          control.

          The control messages it accepts are:

          align a
               Controls the placement of the image in the rectangle
               (unimplemented).

          border b

          bordercolor name

          focus n

          font name
               Used to display the indicia.

          image name

          linecolor name
               The color in which to draw the strokes; default black.

          rect minx miny maxx maxy

          show

     Page 13                      Plan 9             (printed 4/18/24)

     CONTROL(2)                                             CONTROL(2)

        Slider
          A slider controls an integer value by dragging the mouse
          with a button.  Configured appropriately, it can serve as a
          scroll bar with the standard Plan 9 behavior.  When the
          value changes, an event message is sent:

               slidername: value n

          The slider is a good candidate for connecting to another
          control by setting its format and rewiring its event channel
          to the other's ctl channel.

          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 man-
          aging 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 por-
          tion of the controlled object.

          The control messages the slider accepts are:

          absolute n
               If n is zero, the slider behaves like a Plan 9 scroll
               bar: button 2 sets absolute position, button 1
               decreases the value, and button 3 increases it.  If n
               is non-zero, all buttons behave like button 2, setting
               the absolute value.

          border b

          bordercolor name

          clamp end n
               The end is either the word high or low; n sets whether
               that end is clamped or not.  If it is clamped, that end
               of the indicator is always at its supremum.  A standard
               scroll bar has neither end clamped; a volume slider
               would have its low end clamped.  If the low end is
               clamped, the value of the slider is represented by the
               high end of the indicator; otherwise it is represented
               by the low end.

          focus n

          format fmt

          image name

     Page 14                      Plan 9             (printed 4/18/24)

     CONTROL(2)                                             CONTROL(2)

          indicatorcolor name
               Set the color in which to draw the indicator; default
               black.

          max n
               Set the maximum value of the range covered by the
               slider.

          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

          show

          value n

          vis n
               Set the visible area shown by the indicator.

        Text
          A text control presents a set of lines of text.  The text
          cannot be edited with the keyboard, but can be changed by
          control messages.  (A more interactive text control will be
          created eventually.)  The mouse can be used to select lines
          of text.  The only event message reports a state change in
          the selection of a line:

               textname: select n s

          states that line n has changed its selection state to s,
          either 0 (unselected) or 1 (selected).

          The control messages the text control accepts are:

          accumulate s

          accumulate n s

          add s

          add n s
               With one argument, append the string s as a new last
               line of the control; if n is specified, add the line
               before the current line n, making the new line number
               n. The lines are zero indexed and n can be no greater
               than the current number of lines.  Add refreshes the
               display, but accumulate does not, to avoid n-squared
               behavior when assembling a piece of text.

     Page 15                      Plan 9             (printed 4/18/24)

     CONTROL(2)                                             CONTROL(2)

          align a
               Controls the placement of each line of text left-to-
               right in its rectangle.  Vertically, lines are tightly
               packed with separation set by the font's interline
               spacing.

          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.

          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
               Set the color in which to highlight selected lines;
               default yellow.

          selectmode s
               The string s is either single or multi.  If single, the
               default, only one line may be selected at a time; when
               a line is selected, other lines are unselected.  If
               multi, the selection state of individual lines can be
               toggled independently.

          textcolor name

          topline n
               Scroll the text so the top visible line is number n.

          show

     Page 16                      Plan 9             (printed 4/18/24)

     CONTROL(2)                                             CONTROL(2)

          value s
               Delete all the text in the control and then add the
               single line s.

        Textbutton
          A textbutton is a textual variant of a plain button.  Each
          state change triggers an event message:

               textbuttonname: value n

          Like a regular button, the value of a textbutton is an inte-
          ger; 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.

          border b

          bordercolor name

          focus n

          font name

          format fmt

          image name

          light name

          mask name

          pressedtextcolor name
               Set the color in which to display text when the
               textbutton is pressed.

          rect 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).

     Page 17                      Plan 9             (printed 4/18/24)

     CONTROL(2)                                             CONTROL(2)

        Helper functions
          The function ctlerror is called when the library encounters
          an error.  It prints the formatted message and exits the
          program.

          The functions ctlmalloc, ctlrealloc, ctlstrdup, and
          ctlrunestrdup are packagings of the corresponding C library
          functions.  They call ctlerror if they fail to allocate mem-
          ory, 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

               ctlerror("delete");

        Caveat
          This library is very new and is still missing a number of
          important features.  The details are all subject to change.
          Another level of library that handles geometry and has sen-
          sible default appearances for the controls would be useful.

          One unusual design goal of this library was to make the con-
          trols themselves easy to implement.  The reader is encour-
          aged to create new controls by adapting the source to exist-
          ing 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>
          #include <libc.h>
          #include <thread.h>
          #include <draw.h>
          #include <mouse.h>
          #include <keyboard.h>
          #include <control.h>

          Control *top;
          Control *bot;
          Controlset *cs;

          int ctldeletequits = 1;

          void
          resizecontrolset(Controlset*)
          {
              int i;
              Rectangle r, r1, r2;

     Page 18                      Plan 9             (printed 4/18/24)

     CONTROL(2)                                             CONTROL(2)

              if(getwindow(display, Refnone) < 0)
                  ctlerror("resize failed: %r");
              r = insetrect(screen->r, 10);
              r1 = r;
              r2 = r;
              r1.max.y = r1.min.y+1+font->height+1;
              r2.min.y = r1.max.y+10;
              r2.max.y = r2.min.y+1+font->height+1;
              printctl(top->ctl, "rect %R\nshow", r1);
              printctl(bot->ctl, "rect %R\nshow", r2);
          }

          void
          threadmain(int argc, char *argv[])
          {
              char *s, *args[3];
              Channel *c;
              int n;

              initdraw(0, 0, "example");
              initcontrols();
              cs = newcontrolset(screen, nil, nil, nil);
              cs->clicktotype = 1;

              top = createentry(cs, "top");
              printctl(top->ctl, "image paleyellow");
              printctl(top->ctl, "border 1");
              bot = createentry(cs, "bot");
              printctl(bot->ctl, "image paleyellow");
              printctl(bot->ctl, "border 1");

              c = chancreate(sizeof(char*), 0);
              controlwire(top, "event", c);
              controlwire(bot, "event", c);

              activate(top);
              activate(bot);
              resizecontrolset(cs);

              for(;;){
                  s = recvp(c);
                  n = tokenize(s, args, nelem(args));
                  if(n==3 && strcmp(args[1], "value")==0){
                      if(strcmp(args[0], "top:") == 0)
                          printctl(bot->ctl, "value %q", args[2]);
                      else
                          printctl(top->ctl, "value %q", args[2]);
                  }
              }
              threadexitsall(nil);
          }

     Page 19                      Plan 9             (printed 4/18/24)

     CONTROL(2)                                             CONTROL(2)

          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:

              bot = createslider(cs, "bot");
              printctl(bot->ctl, "border 1");
              printctl(bot->ctl, "image paleyellow");
              printctl(bot->ctl, "indicatorcolor red");
              printctl(bot->ctl, "max 100");
              printctl(bot->ctl, "clamp low 1");
              printctl(bot->ctl, "orient horizontal");

          The rest is the same.  Of course, the value of the entry box
          is only meaningful to the slider if it is also a decimal
          number.

          Finally, we can avoid processing events altogether by
          cross-coupling the controls.  Replace the rest of threadmain
          with this:

              controlwire(top, "event", bot->ctl);
              controlwire(bot, "event", top->ctl);

              activate(top);
              activate(bot);
              resizecontrolset(cs);

              for(;;)
                  yield();
              threadexitsall(nil);

     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.

     Page 20                      Plan 9             (printed 4/18/24)