(wiki-page (Header (title "bb")) (body (section 2 "bb " (toc) (section 3 "Description" (p "A very simple GUI toolkit based on " (link "http://www.fltk.org/" "FLTK") ". This extension library has been tested with FLTK versions 1.1.4 and 1.1.6.")) (section 3 "Author" (p (int-link "/users/felix winkelmann" "felix winkelmann"))) (section 3 "Requirements" (ul (li (int-link "silex")) (li (int-link "easyffi")))) (section 3 "Download" (p (link "http://www.call-with-current-continuation.org/eggs/bb.egg" "bb.egg"))) (section 3 "Documentation" (section 4 "Base interface" (section 5 "bb:init" (def (sig (procedure "(bb:init [SCHEME])")) (p "Initializes the toolkit. The optional argument " (tt "SCHEME") " may be a string naming a particular graphical scheme (possible values " (tt "\"none\"") " or " (tt "\"plastic\"") ") or " (tt "#f") " (meaning the default). Calling this procedure a subsequent time has no effect."))) (section 5 "bb:widget?" (def (sig (procedure "(bb:widget? X)")) (p "Returns " (tt "#t") " if " (tt "X") " is a widget, or " (tt "#f") " otherwise."))) (section 5 "bb:make-widget" (def (sig (procedure "(bb:make-widget TYPE [W H])") (procedure "(bb:make-widget TYPE X Y W H)")) (p "Creates and returns a widget of the type given by the symbol " (tt "TYPE") ". Possible widget types are:") (dl (dt "window") (dd "a normal top-level window") (dt "double-window") (dd "a double-buffered window") (dt "button") (dt "return-button") (dt "choice-button") (dt "menu-button") (dt "check-box") (dt "entry") (dd "a single-line text field") (dt "edit") (dd "a multiline text field") (dt "text-editor") (dd "a full text editor with scroll bars") (dt "int-entry") (dd "text field for editing integer numbers. Value is a string rather than number.") (dt "float-entry") (dd "text field for editing float numbers. Value is a string rather than number.") (dt "counter") (dd "a \"spin-box\" like widget") (dt "dial") (dd "a \"clock\"-type dial widget") (dt "clock") (dd "a proper clock") (dt "label") (dt "slider") (dt "adjuster") (dd "a widget for changing a value by dragging") (dt "roller") (dd "another adjuster-like widget") (dt "list") (dd "a vertical list of strings") (dt "radio-button") (dt "progress") (dt "tabs") (dd "a collection of tab widgets") (dt "tile") (dd "groups widgets with draggable boundaries") (dt "pack") (dd "packs widgets vertically or horizontally") (dt "group") (dd "a generic grouping widget") (dt "scroll") (dd "a group widget with scrollable contents") (dt "light-button") (dd "like a checkbox with a \"light\"") (dt "menu-bar") (dt "glwindow") (dd "a window that contains OpenGL graphics") (dt "live-image") (dd "an image that will be redrawn from a given pointer") (dt "tree") (dd "a tree control. Available only if bb was compiled with " (link "http://www.osc.edu/~jbryan/FLU" "FLU") " support.") (dt "table") (dd "a simple table widget") (dt "html-view") (dd "a simple html viewer")) (p "A top-level window created with " (tt "bb:make-widget") " will not automatically be shown until " (tt "bb:show") " has been called."))) (section 5 "bb:property" (def (sig (procedure "(bb:property WIDGET PROPERTY)") (setter "(set! (bb:property WIDGET PROPERTY) VALUE)")) (p "Gets or sets the properties given in " (tt "PROPERTY1 ...") " (which should be symbols). Values may also be lists, in that case the values are combined (this only applies to certain properties - see below).") (p ">Some properties may be set for individual items of the " (tt "tree") " and " (tt "table") " widgets. They are specified in the form " (tt "(list WIDGET ITEMID)") ". " (tt "ITEMID") " is either unique item id or one of the symbols:") (ul (li (tt "root")) (li (tt "connector")) (li (tt "leaf")) (li (tt "branch"))) (p "In this case the " (tt "VALUE") " will be applied either to root node, connector or all subsequent branches or leaves added to the tree.") (p (tt "width") " and " (tt "align") " properties can be applied to the " (tt "table") " widget's columns.") (p "Allowed widget properties are:") (dl (dt "x") (dt "y") (dt "width") (dt "height") (dd "Position and dimensions (integer). Positions are always relative to the container. " (tt "Width") " property may be set for " (tt "connector") " item of the " (tt "tree") " widget.") (dt "text") (dd "The text of a label, button, text-fields or " (tt "html-view") ". Also the title of a window. For the " (tt "tree") " widget the value is the label of the subitem. For the " (tt "table") " widget one can specify individual cells in the form " (tt "(list TABLEWIDGET ROW COLUMN)") ". The negative " (tt "ROW") " means column header.") (dt "value") (dd "The value of a \"range\" widget (" (tt "slider") ", " (tt "roller") ", " (tt "adjuster") ", " (tt "counter") " or " (tt "dial") "), in which case it should be a number. For " (tt "check-box") " and " (tt "radio-button") " widgets the value should be a boolean. For " (tt "list") " widgets, the value is the index of the highlighted item, starting from 1. The value of the " (tt "choice-button") " widget is the index of the selected item. For " (tt "tree") " widgets, the value is the unique id of the currently selected item. The value of the " (tt "html-view") " is a current file name.") (dt "box") (dd "The " (i "box type") ". A box type is one of the symbols")) (ul (li "no-box") (li "flat-box") (li "up-box") (li "down-box") (li "up-frame") (li "down-frame") (li "thin-up-box") (li "thin-down-box") (li "thin-up-frame") (li "thin-down-frame") (li "engraved-box") (li "embossed-box") (li "engraved-frame") (li "embossed-frame") (li "border-box")) (dl (dt "callback") (dd "The callback procedure that is invoked when the value of a widget changes. See the " (tt "when") " property for more information. For " (tt "tree") " widgets one can obtain additional information from properties " (tt "callback-reason") " and " (tt "callback-node") ".") (dt "image") (dd "An image that should be drawn into the widget. See " (tt "bb:image") " for how to load images. You can also set the value " (tt "image") " property to a string, which will load any image file with this name automatically. The value may also be a pointer object pointing to a data buffer for a " (tt "live-image") " widget. Images may be set for a " (tt "tree") " widget items. If subitem is the " (tt "branch") " or " (tt "connector") ", then " (tt "VALUE") " can specify pair of the images: for closed and open state respectively.") (dt "type") (dd "The " (i "type") " of a widget. The possible type symbols depend on what kind of widget it applies to:")) (p "scroll:") (ul (li "scroll-horizontal") (li "scroll-vertical") (li "scroll-both") (li "scroll-always-on") (li "scroll-horizontal-always") (li "scroll-vertical-always") (li "scroll-both-always")) (p "(may be combined)") (p "slider:") (ul (li "vertical-fill-slider") (li "horizontal-fill-slider") (li "vertical-nice-slider") (li "horizontal-nice-slider")) (p "dial:") (ul (li "normal-dial") (li "line-dial") (li "fill-dial") (li "resizable")) (dl (dt "modal") (dd "Whether a window is resizable and/or modal.") (dt "direction") (dd "The direction of a widget, which should be one of the symbols " (tt "horizontal") " or " (tt "vertical") ".") (dt "color") (dd "The background color of a widget. This can either be a value returned by " (tt "bb:rgb") " or one of the following symbols:")) (ul (li "gray0") (li "dark3") (li "dark2") (li "dark1") (li "light1") (li "light2") (li "light3") (li "gray") (li "black") (li "red") (li "green") (li "yellow") (li "blue") (li "magenta") (li "cyan") (li "dark-red") (li "dark-green") (li "dark-yellow") (li "dark-blue") (li "dark-magenta") (li "dark-cyan") (li "white")) (p "The color attribute of a " (tt "live-image") " widget designates the number of color channels (1-4). Also is applicable to the " (tt "connector") " subitem of the " (tt "tree") " widget.") (dl (dt "image-width") (dd "The width of a " (tt "live-image") " widget.") (dt "image-height") (dd "The height of a " (tt "live-image") " widget.") (dt "focus") (dd "Whether this widget has the input focus. Calling " (tt "bb:property") " for this property will always return 0 (but setting it will change the focus to the target widget).") (dt "spacing") (dd "The spacing inside group widgets (in pixels).") (dt "maximum") (dd "Maximum value for range widgets.") (dt "minimum") (dd "Minimum value for range widgets.") (dt "x-position") (dd "X-position for " (tt "scroll") " widgets.") (dt "y-position") (dd "Y-position for " (tt "scroll") " widgets.") (dt "text-color") (dd "Text color. Can also be applied to the " (tt "tree") " subitems.") (dt "text-size") (dd "Text size. Can also be applied to the " (tt "tree") " subitems.") (dt "text-font") (dd "Text font, which may be one of the following:")) (ul (li "helvetica") (li "helvetica-bold") (li "helvetica-italic") (li "helvetica-bold-italic") (li "courier") (li "courier-bold") (li "courier-italic") (li "courier-bold-italic") (li "times") (li "times-bold") (li "times-italic") (li "times-bold-italic") (li "symbol") (li "screen") (li "screen-bold")) (p "Can be specified for the " (tt "tree") " branches and leaves.") (dl (dt "label-color") (dd "Color of a label.") (dt "label-size") (dd "Size of a label.") (dt "label-font") (dd "Font of a label.") (dt "selection-color") (dd "The color of the selection in a text widget or the color of indicators in other widgets.") (dt "position") (dd "The position of the caret in an " (tt "entry") ", " (tt "edit") " or " (tt "text-editor") " widget. Setting the position to " (tt "-1") " will move the caret to the end of the current text.") (dt "mark") (dd "The position of the selection mark in an " (tt "entry") ", " (tt "edit") " or " (tt "text-editor") " widget. The text between the selection mark and the caret is the current selection.") (dt "selection") (dd "The currently selected text in an " (tt "entry") ", " (tt "edit") " or " (tt "text-editor") " widget. When set, the value should be a pair containing start and end position of the selection in the buffer.") (dt "tooltip") (dd "A string that should be displayed, when the mouse hovers over a widget.") (dt "visible") (dd "Whether a widget is visible or not.") (dt "resizable-widget") (dd "The widget in a group, which should be exclusively resizable.") (dt "valid-context") (dd "A flag indicating whether the GL context for a " (tt "glwindow") " is already initialized.") (dt "read-only") (dd "If true, an " (tt "edit") " or " (tt "entry") " widget can not be changed by the user.") (dt "align") (dd "The alignment of the widget label. May be combination of the following symbols:")) (ul (li "center") (li "top") (li "bottom") (li "left") (li "right") (li "inside") (li "text-over-image") (li "image-over-text") (li "clip") (li "wrap")) (dl (dt "when") (dd "An indicator when a widgets callback should be invoked. The default behaviour depends on the type of the widget. Possible settings are:")) (ul (li "never - never invoked the callback") (li "changed - when the widget's value changes") (li "released - when the button or key is released and the value changes") (li "enter - when the enter key is pressed and the value changes") (li "always - modifier for " (tt "released") " or " (tt "enter") ", that indicates the callback should be invoked, even if the value doesn't change")) (p "The default behaviour is to invoke the callback whenever the value of a widget changes, when a " (tt "window") " is closed, when " (tt "glwindow") " needs to be redrawn, or a " (tt "button") " or " (tt "list") " item has been clicked.") (dl (dt "handler") (dd "The callback procedure that is invoked when the event occurs. The event is passed in a")) (p "first (and only) argument to the handler. A event is one of the symbols:") (ul (li "no-event") (li "push") (li "release") (li "enter") (li "leave") (li "drag") (li "focus") (li "unfocus") (li "keydown") (li "keyup") (li "close") (li "move") (li "shortcut") (li "deactivate") (li "activate") (li "hide") (li "show") (li "paste") (li "selectionclear") (li "mousewheel") (li "dnd-enter") (li "dnd-drag") (li "dnd-leave") (li "dnd-release") (li "unknown")) (p "Additional information about event can be obtained with " (tt "bb:event") " procedure. Returning " (tt "#f") " from handler indicates that widget is not interested in handling this event. " (tt "#t") " means that event was successfully handled. Any other value leads to invoking default handler of this widget.") (p "The " (tt "html-view") " widget's " (tt "handler") " is invoked when user tries to follow the link (which URI is passed as an argument). " (tt "Handler") " should return either the name of the temporary file or " (tt "#f") " and set the " (tt "text") " property.") (dl (dt "callback-reason") (dd "The reason for callback. Available only for " (tt "tree") " widget. Valid values are:")) (ul (li "hilighted") (li "unhilighted") (li "selected") (li "unselected") (li "opened") (li "closed") (li "double-click") (li "widget-callback") (li "moved-node") (li "new-node") (li "nothing")) (dl (dt "callback-node") (dd "The unique id of the node that caused callback. Available only for " (tt "tree") " widget.")))) (section 5 "bb:event" (def (sig (procedure "(bb:event PROPERTY)") (setter "(set! (bb:event PROPERTY) VALUE)")) (p "Gets or sets the event properties given in " (tt "PROPERTY") " (which should be symbol). Only " (tt "click?") " and " (tt "clicks") " properties can be set.") (p "Allowed event properties are:") (ul (li "alt") (li "ctrl") (li "shift") (li "click?") (li "button1") (li "button2") (li "button3")) (p "Whether mouse or special keyboard button was pressed.") (ul (li "clicks")) (p "The number of clicks (" (tt "N - 1") " for " (tt "N") " clicks)") (ul (li "x") (li "y") (li "x-root") (li "y-root") (li "dx") (li "dy")) (p "Coordinates.") (ul (li "length") (li "text")) (p "The length and text.") (ul (li "key")) (p "Which key was pressed. Possible values are:") (ul (li "character")) (p "for ordinary keys") (ul (li "the pair of " (tt "character") " and " (tt "kp"))) (p "for keypad keys") (ul (li "backspace") (li "tab") (li "enter") (li "pause") (li "scroll-lock") (li "escape") (li "home") (li "left") (li "up") (li "right") (li "down") (li "page-up") (li "page-down") (li "end") (li "print") (li "insert") (li "menu") (li "help") (li "num-lock") (li "shift-l") (li "shift-r") (li "control-l") (li "control-r") (li "caps-lock") (li "meta-l") (li "meta-r") (li "alt-l") (li "alt-r") (li "delete") (li "F1...F24") (li "button1") (li "button2") (li "button3") (li "unknown")) (p "for special keys."))) (section 5 "bb:message" (def (sig (procedure "(bb:message MESSAGE)") (procedure "(bb:message TYPE MESSAGE [BUTTON1 [BUTTON2 [BUTTON3]]])")) (p "Shows a message box of type " (tt "TYPE") " with the string " (tt "MESSAGE") ". The optional " (tt "BUTTON") " arguments should be strings the specify the text of any extra buttons. Message types may be:") (dl (dt "message") (dd "information dialog with an \"OK\" button.") (dt "alert") (dd "alert box with an \"OK\" button.") (dt "ask") (dd "a \"yes/no\" request dialog.") (dt "choice") (dd "a request button with three choices.")))) (section 5 "bb:run" (def (sig (procedure "(bb:run [WAIT])")) (p "Processes events. If " (tt "WAIT") " is true or not specified, " (tt "bb:run") " does not return until the last window closes. If " (tt "WAIT") " is a number, then " (tt "bb:run") " returns after that many seconds, or earlier, if no events are queued."))) (section 5 "bb:add!" (def (sig (procedure "(bb:add! WIDGET ITEM [CALLBACK [SHORTCUT]])") (procedure "(bb:add! LISTWIDGET TEXT [POSITION])") (procedure "(bb:add! TREEWIDGET TEXT [PARENT [POSITION [SUBWIDGET]])") (procedure "(bb:add! TABLEWIDGET [CELLTEXT ...])") (procedure "(bb:add! TEXTEDITOR TEXT [REPLACE])")) (p "If " (tt "WIDGET") " is a " (tt "menu-bar") ", " (tt "choice-button") " or " (tt "menu-button") ", " (tt "bb:add!") " adds a new menu with the text " (tt "ITEM") " (a string), the keyboard-shortcut " (tt "SHORTCUT") " (another string) and the callback " (tt "CALLBACK") " (a procedure of no arguments).") (p "The string encoding the menu-item can include subitems, using the syntax " (tt "foo/bar/baz") ". As many levels as necessary are created.") (p "The shortcut can be " (tt "#f") " or a string describing the shortcut in one of two ways: " (tt "[#+^]ASCII") " or " (tt "[#+^]CHAR") " where a decimal value represents an ascii character (eg. 97 is the ascii for 'a'), and the optional prefixes enhance the value that follows. Multiple prefixes must appear in the above order.") (dl (dt (tt "#")) (dd "Alt") (dt (tt "{+")) (dd "Shift") (dt (tt "^")) (dd "Control")) (p "If " (tt "WIDGET") " is an " (tt "edit") ", " (tt "entry") " or " (tt "text-edit") " widget, " (tt "ITEM") " should be a string, which will be added to the end of the existing text. In case of a " (tt "text-editor") ", the optional boolean argument " (tt "REPLACE") " indicates whether the text should be inserted, or the current selection be replaced.") (p "If " (tt "WIDGET") " is a " (tt "list") ", the " (tt "ITEM") " should be a string, which will added to the list of existing lines. The string may be prefixed by a " (tt "@...") " sequence to enable special formatting:") (dl (dt (tt "@.")) (dd "Print rest of line, don't look for more '@' signs") (dt (tt "@@")) (dd "Print rest of line starting with '@'") (dt (tt "@l")) (dd "Use a large (24 point) font") (dt (tt "@m")) (dd "Use a medium large (18 point) font") (dt (tt "@s")) (dd "Use a small (11 point) font") (dt (tt "@b")) (dd "Use a bold font") (dt (tt "@i")) (dd "Use an italic font") (dt (tt "@f or @t")) (dd "Use a fixed-pitch font") (dt (tt "@c")) (dd "Center the line horizontally") (dt (tt "@r")) (dd "Right-justify the text") (dt (tt "@B0, @B1, ... @B255")) (dd "Fill the backgound with indexed color") (dt (tt "@C0, @C1, ... @C255")) (dd "Use indexed color to draw the text") (dt (tt "@F0, @F1, ...")) (dd "Use indexed font to draw the text") (dt (tt "@S1, @S2, ...")) (dd "Use point size n to draw the text") (dt (tt "@u or @_")) (dd "Underline the text.") (dt (tt "@-")) (dd "draw an engraved line through the middle.")) (p "If " (tt "WIDGET") " is a widget of any other type, then " (tt "ITEM") " should be a child widget, which will be added with " (tt "WIDGET") " as its parent.") (p "For " (tt "tree") " widget " (tt "TEXT") " can be either full path (items are separated with slash) or text label. If it is terminated with slash, the branch (rather than leaf) will be inserted. One can specify parent node id and position in it (default values are " (tt "-1") " for both). The " (tt "SUBWIDGET") " is a widget that will be inserted as a node. The procedure returns either the unique id of the freshly inserted node or " (tt "-1") " if failed.") (p "This procedure can be used to add either columns (if first " (tt "CELLTEXT") " is symbol " (tt "column") ") or cells to the " (tt "table") " widget."))) (section 5 "bb:image" (def (sig (procedure "(bb:image X)") (procedure "(bb:image PTR W H D)")) (p "If " (tt "X") " is a string, then " (tt "bb:image") " will load an image file (if its format is supported by FLTK). If " (tt "X") " is a pointer, then it is treated as a pointer to XPM data. The 4-argument form of " (tt "bb:image") " creates an RGB image from the data pointed to by the foreign pointer " (tt "PTR") ", with width " (tt "W") ", height " (tt "H") " and depth " (tt "D") ", where " (tt "D") " specifies the number of color channels (1-4)."))) (section 5 "bb:image-data" (def (sig (procedure "(bb:image-data IMAGE)")) (p "Returns four values: list of pointers to " (tt "IMAGE") " data (usually one element for all formats, except of pixmaps), width, height and depth of the " (tt "IMAGE") "."))) (section 5 "bb:remove!" (def (sig (procedure "(bb:remove! WIDGET [INDEX])")) (p "Removes the entry at the position " (tt "INDEX") " from the " (tt "list") " " (tt "WIDGET") ", or all items, if index is " (tt "#t") ". If " (tt "widget") " is an image pointer, the storage occupied by the image will be released. For " (tt "tree") " " (tt "WIDGET") " the node with id " (tt "INDEX") " will be removed. Destroys the widget."))) (section 5 "bb:set-menu-item-active!" (def (sig (procedure "(bb:set-menu-item-active! WIDGET INDEX FLAG)")) (p "Activates or deactivates the menu item with the index " (tt "INDEX") " in the menu-bar " (tt "WIDGET") ", depending on the boolean " (tt "FLAG") ". Counting menu-items starts with 0 and every sub-menu increases the count by one. Note that each sub-menu introduces an invisible extra menu-item that has to be counted in."))) (section 5 "bb:redraw" (def (sig (procedure "(bb:redraw WIDGET)")) (p "Redraws " (tt "WIDGET") "."))) (section 5 "bb:show" (def (sig (procedure "(bb:show WINDOW [ARG ...])")) (p "Shows " (tt "WINDOW") ". If " (tt "WINDOW") " is already visible, it will be raised to the top. " (tt "ARG") "s are the options to be parsed by FLTK. By default the name of the executable is passed. " (tt "#f") " doesn't pass any arguments."))) (section 5 "bb:select-file" (def (sig (procedure "(bb:select-file MESSAGE PATTERN [FILENAME])")) (p "Opens a file-dialog and returns the selected filename (or " (tt "#f") " if the file-selection has been canceled). " (tt "PATTERN") " is a file-pattern that is used to match filenames that can be selected. The following syntax is used by pattern:") (dl (dt (tt "*")) (dd "matches any sequence of 0 or more characters.") (dt (tt "?")) (dd "matches any single character") (dt (tt "[set]")) (dd "matches any character in the set. Set can contain any single characters, or " (tt "a-z") " to represent a range. To match " (tt "]") " or " (tt "-") " they must be the first characters. To match " (tt "^") " or " (tt "!") " they must not be the first characters.") (dt (tt "[^set]")) (dd "Matches any character not in the set.") (dt (tt "[!set]")) (dd "Matches any character not in the set.") (dt (tt "{X|Y|Z") "}") (dd "Matches any one of the subexpressions literally.") (dt (tt "{X,Y,Z") "}") (dd "Matches any one of the subexpressions literally.") (dt (tt "\\x")) (dd "Quotes the character " (tt "x") " so it has no special meaning.") (dt (tt "x")) (dd "All other characters must be matched exactly.")) (p (tt "FILENAME") " specifies the default filename, if given."))) (section 5 "bb:select-color" (def (sig (procedure "(bb:select-color [STRING])") (procedure "(bb:select-color COLOR [STRING])")) (p "Pops up a color-selection dialog. If " (tt "COLOR") " is an exact integer, or a symbol naming one of the default colors, then the user can select a color index, which will then be returned. If " (tt "COLOR") " is a three-element list or vector, then the user can select an RGB (or HSV) color. " (tt "bb:select-color") " either returns a color value (an integer, encoding a color index or a packed RGB value), or " (tt "#f") " if the selection dialog was closed or canceled."))) (section 5 "bb:rgb" (def (sig (procedure "(bb:rgb R [G B])")) (p "Transforms the red, green and blue components given in " (tt "R") ", " (tt "G") " and " (tt "B") " into a color value. All components should be integers in the range 0 - 255. If " (tt "G") " and " (tt "B") " are not given, " (tt "bb:rgb") " returns a list of the red, green and blue color components of the packed color value " (tt "R") "."))) (section 5 "bb:get-input" (def (sig (procedure "(bb:get-input LABEL [DEFAULT])")) (p "Pops up a dialog the requests an input string. " (tt "LABEL") " should be a string that will be shown in the dialog, " (tt "DEFAULT") " is the default text."))) (section 5 "bb:group" (def (sig (procedure "(bb:group WIDGET THUNK)")) (p "Invokes the zero-argument procedure " (tt "THUNK") " in a dynamic context in which all created widgets are added the group " (tt "WIDGET") " (which should be a " (tt "window") ", " (tt "group") ", " (tt "tabs") ", " (tt "tile") ", " (tt "pack") " or " (tt "scroll") ").")))) (section 4 "Keybindings" (p "The following is a list of keyboard and mouse shortcuts available in " (tt "entry") " and " (tt "edit") " widgets.") (dl (dt "Mouse button 1") (dd "Moves the cursor to this point. Drag selects characters. Double click selects words. Triple click selects all text. Shift+click extends the selection. When you select text it is automatically copied to the clipboard.") (dt "Mouse button 2") (dd "Insert the clipboard at the point clicked. You can also select a region and replace it with the clipboard by selecting the region with mouse button 2.") (dt "Mouse button 3") (dd "Currently acts like button 1.") (dt "Backspace") (dd "Deletes one character to the left, or deletes the selected region.") (dt "Enter") (dd "May cause the callback, see the " (tt "when") " property") (dt "^A or Home") (dd "Go to start of line.") (dt "^B or Left") (dd "Move left") (dt "^C") (dd "Copy the selection to the clipboard") (dt "^D or Delete") (dd "Deletes one character to the right or deletes the selected region.") (dt "^E or End") (dd "Go to the end of line.") (dt "^F or Right") (dd "Move right") (dt "^K") (dd "Delete to the end of line (next \\n character) or deletes a single \\n character. These deletions are all concatenated into the clipboard.") (dt "^N or Down") (dd "Move down (" (tt "edit") " widget only, otherwise it moves to the next input field).") (dt "^P or Up") (dd "Move up (for edit widgets only, otherwise it moves to the previous input field).") (dt "^U") (dd "Delete everything.") (dt "^V or ^Y") (dd "Paste the clipboard") (dt "^X or ^W") (dd "Copy the region to the clipboard and delete it.") (dt "^Z or ^_") (dd "Undo. This is a single-level undo mechanism, but all adjacent deletions and insertions are concatenated into a single \"undo\". Often this will undo a lot more than you expected.") (dt "Shift+move") (dd "Move the cursor but also extend the selection.") (dt "RightCtrl or Compose") (dd "Start a compose-character sequence.")) (p "With compose-character sequences, the next one or two keys typed define the character to insert (see " (int-link "#Character Composition Table" "the table") " that follows.)") (p "For instance, to type \"á\" type " (tt "[compose][a][']") " or " (tt "[compose]['][a]") ".") (p "The character \"nbsp\" (non-breaking space) is typed by using " (tt "[compose][space]") ".") (p "The single-character sequences may be followed by a space if necessary to remove ambiguity. For instance, if you really want to type \"ª~\" rather than \"ã\" you must type " (tt "[compose][a][space][~]") ".") (p "The same key may be used to \"quote\" control characters into the text. If you need a " (tt "^Q") " character you can get one by typing " (tt "[compose][Control+Q]") ".") (p "X may have a key on the keyboard defined as " (tt "XK_Multi_key") ". If so this key may be used as well as the right-hand control key. You can set this up with the program " (tt "xmodmap") ".") (p "If your keyboard is set to support a foreign language you should also be able to type \"dead key\" prefix characters. On X you will actually be able to see what dead key you typed, and if you then move the cursor without completing the sequence the accent will remain inserted.") (section 5 "Character Composition Table" (table (@ (border "1") (summary "Character Composition Table")) (tr " " (th "Keys") (th "Char") " " (th "Keys") (th "Char") " " (th "Keys") (th "Char") " " (th "Keys") (th "Char") " " (th "Keys") (th "Char") " " (th "Keys") (th "Char") " ") " " (tr " " (td (@ (align "center")) (tt "sp")) (td (@ (align "center")) (small "nbsp")) " " (td (@ (align "center")) (tt "*")) (td (@ (align "center")) "°") " " (td (@ (align "center")) (tt "` A")) (td (@ (align "center")) "À") " " (td (@ (align "center")) (tt "D -")) (td (@ (align "center")) "Ð") " " (td (@ (align "center")) (tt "` a")) (td (@ (align "center")) "à") " " (td (@ (align "center")) (tt "d -")) (td (@ (align "center")) "ð") " ") " " (tr " " (td (@ (align "center")) (tt "!")) (td (@ (align "center")) "¡") " " (td (@ (align "center")) (tt "+ -")) (td (@ (align "center")) "±") " " (td (@ (align "center")) (tt "' A")) (td (@ (align "center")) "Á") " " (td (@ (align "center")) (tt "~ N")) (td (@ (align "center")) "Ñ") " " (td (@ (align "center")) (tt "' a")) (td (@ (align "center")) "á") " " (td (@ (align "center")) (tt "~ n")) (td (@ (align "center")) "ñ") " ") " " (tr " " (td (@ (align "center")) (tt "%")) (td (@ (align "center")) "¢") " " (td (@ (align "center")) (tt "2")) (td (@ (align "center")) "²") " " (td (@ (align "center")) (tt "A ^")) (td (@ (align "center")) "Â") " " (td (@ (align "center")) (tt "` O")) (td (@ (align "center")) "Ò") " " (td (@ (align "center")) (tt "^ a")) (td (@ (align "center")) "â") " " (td (@ (align "center")) (tt "` o")) (td (@ (align "center")) "ò") " ") " " (tr " " (td (@ (align "center")) (tt "#")) (td (@ (align "center")) "£") " " (td (@ (align "center")) (tt "3")) (td (@ (align "center")) "³") " " (td (@ (align "center")) (tt "~ A")) (td (@ (align "center")) "Ã") " " (td (@ (align "center")) (tt "' O")) (td (@ (align "center")) "Ó") " " (td (@ (align "center")) (tt "~ a")) (td (@ (align "center")) "ã") " " (td (@ (align "center")) (tt "' o")) (td (@ (align "center")) "ó") " ") " " (tr " " (td (@ (align "center")) (tt "$")) (td (@ (align "center")) "¤") " " (td (@ (align "center")) (tt "'")) (td (@ (align "center")) "´") " " (td (@ (align "center")) (tt ": A")) (td (@ (align "center")) "Ä") " " (td (@ (align "center")) (tt "^ O")) (td (@ (align "center")) "Ô") " " (td (@ (align "center")) (tt ": a")) (td (@ (align "center")) "ä") " " (td (@ (align "center")) (tt "^ o")) (td (@ (align "center")) "ô") " ") " " (tr " " (td (@ (align "center")) (tt "y =")) (td (@ (align "center")) "¥") " " (td (@ (align "center")) (tt "u")) (td (@ (align "center")) "µ") " " (td (@ (align "center")) (tt "* A")) (td (@ (align "center")) "Å") " " (td (@ (align "center")) (tt "~ O")) (td (@ (align "center")) "Õ") " " (td (@ (align "center")) (tt "* a")) (td (@ (align "center")) "å") " " (td (@ (align "center")) (tt "~ o")) (td (@ (align "center")) "õ") " ") " " (tr " " (td (@ (align "center")) (tt "|")) (td (@ (align "center")) "¦") " " (td (@ (align "center")) (tt "p")) (td (@ (align "center")) "¶") " " (td (@ (align "center")) (tt "A E")) (td (@ (align "center")) "Æ") " " (td (@ (align "center")) (tt ": O")) (td (@ (align "center")) "Ö") " " (td (@ (align "center")) (tt "a e")) (td (@ (align "center")) "æ") " " (td (@ (align "center")) (tt ": o")) (td (@ (align "center")) "ö") " ") " " (tr " " (td (@ (align "center")) (tt "&")) (td (@ (align "center")) "§") " " (td (@ (align "center")) (tt ".")) (td (@ (align "center")) "·") " " (td (@ (align "center")) (tt ", C")) (td (@ (align "center")) "Ç") " " (td (@ (align "center")) (tt "x")) (td (@ (align "center")) "×") " " (td (@ (align "center")) (tt ", c")) (td (@ (align "center")) "ç") " " (td (@ (align "center")) (tt "- :")) (td (@ (align "center")) "÷") " ") " " (tr " " (td (@ (align "center")) (tt ":")) (td (@ (align "center")) "¨") " " (td (@ (align "center")) (tt ",")) (td (@ (align "center")) "¸") " " (td (@ (align "center")) (tt "E `")) (td (@ (align "center")) "È") " " (td (@ (align "center")) (tt "O /")) (td (@ (align "center")) "Ø") " " (td (@ (align "center")) (tt "` e")) (td (@ (align "center")) "è") " " (td (@ (align "center")) (tt "o /")) (td (@ (align "center")) "ø") " ") " " (tr " " (td (@ (align "center")) (tt "c")) (td (@ (align "center")) "©") " " (td (@ (align "center")) (tt "1")) (td (@ (align "center")) "¹") " " (td (@ (align "center")) (tt "' E")) (td (@ (align "center")) "É") " " (td (@ (align "center")) (tt "` U")) (td (@ (align "center")) "Ù") " " (td (@ (align "center")) (tt "' e")) (td (@ (align "center")) "é") " " (td (@ (align "center")) (tt "` u")) (td (@ (align "center")) "ù") " ") " " (tr " " (td (@ (align "center")) (tt "a")) (td (@ (align "center")) "ª") " " (td (@ (align "center")) (tt "o")) (td (@ (align "center")) "º") " " (td (@ (align "center")) (tt "^ E")) (td (@ (align "center")) "Ê") " " (td (@ (align "center")) (tt "' U")) (td (@ (align "center")) "Ú") " " (td (@ (align "center")) (tt "^ e")) (td (@ (align "center")) "ê") " " (td (@ (align "center")) (tt "' u")) (td (@ (align "center")) "ú") " ") " " (tr " " (td (@ (align "center")) (tt "< <")) (td (@ (align "center")) "«") " " (td (@ (align "center")) (tt "> >")) (td (@ (align "center")) "»") " " (td (@ (align "center")) (tt ": E")) (td (@ (align "center")) "Ë") " " (td (@ (align "center")) (tt "^ U")) (td (@ (align "center")) "Û") " " (td (@ (align "center")) (tt ": e")) (td (@ (align "center")) "ë") " " (td (@ (align "center")) (tt "^ u")) (td (@ (align "center")) "û") " ") " " (tr " " (td (@ (align "center")) (tt "~")) (td (@ (align "center")) "¬") " " (td (@ (align "center")) (tt "1 4")) (td (@ (align "center")) "¼") " " (td (@ (align "center")) (tt "` I")) (td (@ (align "center")) "Ì") " " (td (@ (align "center")) (tt ": U")) (td (@ (align "center")) "Ü") " " (td (@ (align "center")) (tt "` i")) (td (@ (align "center")) "ì") " " (td (@ (align "center")) (tt ": u")) (td (@ (align "center")) "ü") " ") " " (tr " " (td (@ (align "center")) (tt "-")) (td (@ (align "center")) "­") " " (td (@ (align "center")) (tt "1 2")) (td (@ (align "center")) "½") " " (td (@ (align "center")) (tt "' I")) (td (@ (align "center")) "Í") " " (td (@ (align "center")) (tt "' Y")) (td (@ (align "center")) "Ý") " " (td (@ (align "center")) (tt "' i")) (td (@ (align "center")) "í") " " (td (@ (align "center")) (tt "' y")) (td (@ (align "center")) "ý") " ") " " (tr " " (td (@ (align "center")) (tt "r")) (td (@ (align "center")) "®") " " (td (@ (align "center")) (tt "3 4")) (td (@ (align "center")) "¾") " " (td (@ (align "center")) (tt "^ I")) (td (@ (align "center")) "Î") " " (td (@ (align "center")) (tt "T H")) (td (@ (align "center")) "Þ") " " (td (@ (align "center")) (tt "^ i")) (td (@ (align "center")) "î") " " (td (@ (align "center")) (tt "t h")) (td (@ (align "center")) "þ") " ") " " (tr " " (td (@ (align "center")) (tt "_")) (td (@ (align "center")) "¯") " " (td (@ (align "center")) (tt "?")) (td (@ (align "center")) "¿") " " (td (@ (align "center")) (tt ": I")) (td (@ (align "center")) "Ï") " " (td (@ (align "center")) (tt "s s")) (td (@ (align "center")) "ß") " " (td (@ (align "center")) (tt ": i")) (td (@ (align "center")) "ï") " " (td (@ (align "center")) (tt ": y")) (td (@ (align "center")) "ÿ") " ")))) (section 4 "ASCII picture interface" (section 5 "bb:make-widgets" (def (sig (procedure "(bb:make-widgets SPEC WIDTH HEIGHT [CHARMAP])")) (p "Creates the widgets defined in the graphical representation string " (tt "SPEC") " in a window of the dimensions " (tt "WIDTH") " and " (tt "HEIGHT") ". The graphical representation string is an ASCII picture of the widget layout, with uppercase characters designating widget types:") (ul (li (tt "B") " - button") (li (tt "C") " - check-xbox") (li (tt "E") " - entry") (li (tt "I") " - edit") (li (tt "N") " - counter") (li (tt "M") " - menu-bar") (li (tt "D") " - dial") (li (tt "S") " - slider") (li (tt "A") " - adjuster") (li (tt "L") " - list") (li (tt "W") " - label") (li (tt "O") " - radio-button") (li (tt "P") " - progress") (li (tt "T") " - tabs") (li (tt "F") " - glwindow") (li (tt "X") " - tile") (li (tt "G") " - group") (li (tt "K") " - pack") (li (tt "Z") " - scroll") (li (tt "R") " - roller") (li (tt "J") " - clock") (li (tt "V") " - live-image") (li (tt "H") " - choice-button") (li (tt "<") " - return-button") (li (tt "%") " - int-entry") (li (tt "*") " - int-entry") (li (tt ">") " - menu-button") (li (tt "Y") " - tree")) (p "A widgets dimensions are computed by drawing a contguous line along the upper and left border, starting from the origin of the widget:") (pre " 01234567890123456789 .................... .....BBBBBBBBB...... .....BBBBBBBBB...... .....BBBBBBBBB...... ....................") (p "Here we would have a button at 5/1, with width 9 and height 3 (before adjusting the dimensions to the specified width and height of the complete layout).") (p (tt "bb:make-widgets") " returns an association list of the form " (tt "(TAG . WIDGET)") " which maps widget-tags to created widgets. If the optional argument " (tt "CHARMAP") " (an list of lists of the form " (tt "(ALIASCHAR CHAR TAG)") ") is given, then any occurrence of " (tt "ALIASCHAR") " in the picture is treated as " (tt "CHAR") ". The " (tt "TAG") " will be returned in the widget a-list. If " (tt "CHARMAP") " is not given, then the tag defaults to the usual widget type character.") (p "Specially delimited strings can be embedded in the widget pictures:") (pre " \"STRING\"") (p "Sets the " (tt "text") " property of the widget.") (pre " |STRING|") (p "Sets the direction, box type, slider type or color of the widget. Valid values for " (tt "STRING") " are:") (p "Direction:") (ul (li "v") (li "h")) (p "Slider type:") (ul (li "vfill") (li "hfill") (li "vnice") (li "hnice")) (p "box type :") (ul (li "no") (li "flat") (li "up") (li "down") (li "thinup") (li "thindown") (li "upframe") (li "downframe") (li "thinupframe") (li "thindownframe") (li "engraved") (li "embossed") (li "engravedframe") (li "embossedframe") (li "border")) (p "color:") (ul (li "gray") (li "black") (li "red") (li "green") (li "yellow") (li "blue") (li "magenta") (li "cyan") (li "darkred") (li "darkgreen") (li "darkyellow") (li "darkblue") (li "darkmagenta") (li "darkcyan") (li "white")) (pre " 'STRING, ...'") (p "Adds items to a " (tt "list") " widget.") (pre " #STRING#") (p (tt "STRING") " should be the name of an image file (as understood by " (tt "bb:image") ").") (pre " :STRING:") (p (tt "STRING") " should be the name of a global variable holding a callback, or an expression evaulating to a procedure or name.")))) (section 4 "SXML Interface" (section 5 "bb:render" (def (sig (procedure "(bb:render SXML)")) (p "Creates the widgets defined by the " (link "http://okmij.org/ftp/Scheme/xml.html" "SXML") " representation in " (tt "SXML") ". Each element represents a widget where the tag specifies a widget type (as in " (tt "bb:make-widget") "). Element attributes represent widget properties. Attribute-value strings are transformed according to the following mapping:") (pre " x y width height spacing maximum minimum x-position y-position text-size") (p "Numeric strings. " (tt "x") ", " (tt "y") ", " (tt "width") " and " (tt "height") " may also be specified as offsets given as strings prefixed with " (tt "+") " or " (tt "-") ", or percentages given as strings suffixed with " (tt "%") ".") (pre " color text-color selection-color") (p "A string of the form " (tt "#RRGGBB") " or a color name") (pre " resizable visible focus modal read-only valid-context") (p "Anything different from the string " (tt "no") " means true.") (pre " resizable-widget") (p "an element id.") (pre " when") (p "A comma-separated list of indicator-names") (p "Anything else is either treated as a numeric string or (if not a valid number) as a symbolic property value. Note that attribute values may also be of other types than strings. The content of an SXML element will be used as the " (tt "text") " property value of the created widget, if given.") (p "Elements may have any number of additional attributes. The attribute " (tt "id") " can be used to identify elements.") (p "A child widget will have the dimensions of it's parent, if no " (tt "width") " and/or " (tt "height") " attributes are given."))) (section 5 "bb:element?" (def (sig (procedure "(bb:element? X)")) (p "Returns " (tt "#t") " if " (tt "X") " is an element, or " (tt "#f") " otherwise."))) (section 5 "Element accessors" (def (sig (procedure "(bb:element-widget ELEMENT)") (procedure "(bb:element-parent ELEMENT)") (procedure "(bb:element-children ELEMENT)") (procedure "(bb:element-id ELEMENT)") (procedure "(bb:element-tag ELEMENT)") (procedure "(bb:element-content ELEMENT)") (procedure "(bb:element-attributes ELEMENT)")) (p "Accessor procedures for element slots. Parent is an element or " (tt "#f") " (if its the root element). Children is a list of child elements. Widget is the widget represented by this element. Id and tag are symbols. Attributes is a property list mapping attribute symbols to values. Content is a string."))) (section 5 "bb:find-element" (def (sig (procedure "(bb:find-element ID [ROOT])")) (p "Searches the element with the id " (tt "ID") ", starting from parent element " (tt "ROOT") ", or the value of " (tt "(bb:root-element)") " if not given. If no element with this id can be found " (tt "#f") " is returned."))) (section 5 "bb:find-widget" (def (sig (procedure "(bb:find-widget ID [ROOT])")) (p "Equivalent to " (tt "(bb:element-widget (bb:find-element ID ROOT))")))) (section 5 "bb:root-element" (def (sig (parameter "(bb:root-element [ELEMENT])")) (p "Parameter holding the current root element."))))) (section 3 "Examples" (highlight scheme "(use bb) (bb:init) (define w (bb:make-widget 'window 200 100)) (bb:group w (lambda () (let ([lbl (bb:make-widget 'label 200 100)]) (set! (bb:property lbl 'box) 'engraved-box) (set! (bb:property lbl 'text-size) 32) (set! (bb:property lbl 'text-font) 'times-bold-italic) (set! (bb:property lbl 'text) \"Hello, World\") ) ) ) (bb:show w) ;An alternative, simpler way of doing the above: ; ;(bb:render ; '(window (@ (width 200) (height 100)) ; (label (@ (box engraved-box) (text-size 32) (text-font times-bold-italic)) ; \"Hello, World\"))) (bb:run)") (p "A very simple shell:") (highlight scheme "(require-extension extras posix srfi-17 bb) (bb:init) (define width 300) (define height 150) (define w (bb:make-widget 'window width height)) (define str #< item 0) (let ([note (list-ref all-notes (sub1 item))]) (note-hidden?-set! note #f) (bb:show (note-window note)) ) ) ) ) (bb:render `(window (@ (width 200) (height 300) (resizable) (id w) (resizable-widget lst)) (menu-bar (@ (height 30) (id m))) (list (@ (y 30) (width 200) (height 270) (id lst) (callback switch-note))) ) ) (define item-list (bb:find-widget 'lst)) (define menu-bar (bb:find-widget 'm)) (define notes-window (bb:find-widget 'w)) (define default-color 'yellow) (define all-notes '()) (define-record note window edit title color hidden?) (define (note-hider note) (lambda () (note-hidden?-set! note #t) (set! (bb:property (note-window note) 'visible) #f) ) ) (define (add-note . title) (let* ([name (:optional title (->string (gensym 'note)))] [x (random 600)] [y (random 400)] [w (bb:make-widget 'window x y 200 150)] [e (bb:group w (lambda () (bb:make-widget 'edit 0 0 200 150)))] [note (make-note w e name default-color #f)] ) (set! (bb:property w 'resizable) #t) (set! (bb:property w 'resizable-widget) e) (set! (bb:property e 'color) default-color) (set! (bb:property w 'callback) (note-hider note)) (bb:show w) (bb:add! item-list (sprintf \"@.~A\" name)) (set! all-notes (append all-notes (list note))) ) ) (define (choose-color) (and-let* ([col (bb:select-color default-color)]) (set! default-color col) ) ) (define notesfile (make-pathname (getenv \"HOME\") \".bbnotes\")) (define (load-notes . file) (with-input-from-file (:optional file notesfile) (lambda () (match (read) [(x y w h) (set! (bb:property notes-window 'x) x) (set! (bb:property notes-window 'y) y) (set! (bb:property notes-window 'width) w) (set! (bb:property notes-window 'height) h) ] ) (let loop () (match (read) [(? eof-object?) #f] [(title color pos text hidden?) (let* ([w (apply bb:make-widget 'window pos)] [e (bb:group w (lambda () (apply bb:make-widget 'edit 0 0 (cddr pos))))] [note (make-note w e title color hidden?)] ) (set! (bb:property e 'color) color) (set! (bb:property w 'resizable) #t) (set! (bb:property w 'resizable-widget) e) (set! (bb:property w 'text) title) (set! (bb:property w 'callback) (note-hider note)) (bb:add! e text) (unless hidden? (bb:show w)) (set! all-notes (append all-notes (list note))) (bb:add! item-list (string-append \"@.\" title)) (loop) ) ] ) ) ) ) ) (define (save-notes . file) (with-output-to-file (:optional file notesfile) (lambda () (write (map (cut bb:property notes-window <>) '(x y width height))) (newline) (for-each (lambda (note) (let ([w (note-window note)] [e (note-edit note)] ) (write (list (note-title note) (note-color note) (list (bb:property w 'x) (bb:property w 'y) (bb:property w 'width) (bb:property w 'height)) (bb:property e 'text) (note-hidden? note) ) ) (newline) ) ) all-notes) ) ) ) (define (change-title) (let ([i (bb:property item-list 'value)]) (when (> i 0) (let* ([note (list-ref all-notes (sub1 i))] [title (bb:get-input \"Enter new title\" (note-title note))] ) (set! (bb:property (note-window note) 'text) title) (note-title-set! note title) (update-list) ) ) ) ) (define (update-list) (bb:remove! item-list #t) (for-each (lambda (note) (bb:add! item-list (string-append \"@.\" (note-title note)))) all-notes) ) (define (change-color) (let ([i (bb:property item-list 'value)]) (when (> i 0) (let* ([note (list-ref all-notes (sub1 i))] [col (bb:select-color (note-color note))] ) (set! (bb:property (note-edit note) 'color) col) (bb:redraw (note-edit note)) (note-color-set! note col) ) ) ) ) (define (fini) (save-notes) (exit) ) (set! (bb:property notes-window 'callback) fini) ; when ESC is pressed (bb:add! menu-bar \"File/Quit\" fini \"^q\") (bb:add! menu-bar \"Notes/New\" add-note \"^n\") (bb:add! menu-bar \"Notes/Set default color...\" choose-color) (bb:add! menu-bar \"Change/Title...\" change-title) (bb:add! menu-bar \"Change/Color...\" change-color) (bb:show notes-window) (when (file-exists? notesfile) (load-notes)) (bb:run)") (p "Event handlers usage:") (highlight scheme "(use srfi-17 bb) (bb:init) (define w (bb:make-widget 'window 200 100)) (define e (bb:make-widget 'edit 5 5 150 25)) (set! (bb:property e 'callback) (lambda () (display \"edit was changed\") (newline) ) ) (set! (bb:property e 'when) 'changed) (set! (bb:property e 'handler) (lambda (e) (case e [(move) (printf \"mouse was moved over edit at (~A, ~A)~%\" (bb:event 'x) (bb:event 'y)) #t] [(push) (printf \"mouse was clicked on edit, clicks = 1 + ~A~%\" (bb:event 'clicks)) (set! (bb:event 'clicks) 0) (printf \"clicks after setting: ~A~%\" (bb:event 'clicks)) #t] [(keydown) (printf \"key was pressed: ~A~%\" (bb:event 'key)) -1] [else -1] ) ; pass other events to the base class ) ) (bb:show w) (bb:run)")) (section 3 "Changelog" (ul (li "1.26 Added " (tt "bb:select-directory") " [contributed by Joerg Wittenberger]") (li "1.25 Changed widget_type macro to use cast to long [Thanks to Ignaz Peter Hochgemuth]") (li "1.24 Uses lowercase file extension for FLU header [Thanks to Juergen Lorenz]") (li "1.23 Setting properties could invoke callbacks and needed a " (tt "___safe") " marker [Thanks to Nico Amtsberg]") (li "1.22 Used proper extension for included FLTK headers [Thanks to Matthew Welland]") (li "1.21 Added missing " (tt "(use easyffi)") " [Thanks to Juergen Lorenz]") (li "1.20 Added proper check for FLTK installation [reported by Brandon Van Every]") (li "1.19 Adapted to externalized easyffi") (li "1.18 Removed \"_s\" suffix from references to library-files [Thanks to Markus Hülsmann]") (li "1.17 Added " (tt "label-color") ", " (tt "label-font") " and " (tt "label-size") " properties.") (li "1.16 Fixed several bugs in property-getting code [Thanks to John]; " (tt "bb:add!") " can replace current selection in text-editor widget") (li "1.15 Fixed bug in " (tt "bb:show") " [Thanks to Markus Hüsmann]") (li "1.14 The implicit-exit-handler didn't take previously installed exit-handlers into account (which could give problems when embedding); Fixed bug in " (tt "bb:show") " related to embedded use") (li "1.13 Invalid property values could result in unbound recursion") (li "1.12 The " (tt "selection") " property of a " (tt "text-editor") " widgets can be set, now; Some bugfixes in callback-removal") (li "1.11 " (tt "bb:remove!") " allows completely clearing a list widget by passing the index " (tt "#t") "; destroying widgets removes all registered callbacks from children as well.") (li "1.10 Fixed setting " (tt "text-color") " for the " (tt "tree") " widget. Added support for Windows.") (li "1.9 " (tt "bb:remove!") " allows destroying all types of widgets; " (tt "bb:show") " had to be marked as callback; fixed bugs in selection-retrieval and special key-event handling") (li "1.8 Sergey Khorev added the " (tt "table") " and " (tt "html-view") " widgets") (li "1.7 Added " (tt "text-editor") " widget") (li "1.6 Fixed bug in the setup script") (li "1.5 More widgets added by Sergey") (li "1.4 Sergey Khorev added support for custom event handlers") (li "1.3 Adapted to new FFI macro names") (li "1.2 Converted to new extension scheme; fixed a bug in " (tt "bb:get") " (Thanks to Daniel B. Faken)") (li "1.1 Added " (tt "bb:init") " and " (tt "bb:set-menu-item-active!") " and fixed a bug in " (tt "bb:property") ". It is now required to call " (tt "bb:init") " before using any other bb procedure.") (li "1.0"))))))