HELP RC_BUTTONS Aaron Sloman, June 1997 Updated: 19 Feb 2004 Corrected table of contents 17 Feb 2004 For changes see HELP rclib_news Note: Sept 2002 rc_informant_value, rc_button_label and rc_real_contents are now distinct slots in radio and someof buttons rc_options_chosen returns a list of labels of selected buttons rc_options_chosen returns a list of 'real_contents' of selected buttons The three categories of action button types POPNOW, POP11 and INVED are all now collapsed into one: POP11 actions. Changes to the event handler have made the distinctions unnecessary. However DEFER actions remain a distinct category. For an overview of rclib see HELP RCLIB CONTENTS -- Overview -- Introduction -- Use of featurespec arguments -- Types of buttons and related facilities -- -- Asynchronous control buttons -- -- Input fields -- -- Buttons for popup menus -- -- Information display panels -- Making the buttons available -- Examples of individual buttons, using rc_create_button -- -- A button to print out a greeting -- -- Using a featurespec and an identifier record -- -- Using a three element vector with a type word -- -- Action buttons with blobs -- -- An action button invoking a Unix command -- -- An action to display a message panel -- -- Specifying button actions as {[proc arg1 arg2 arg3]} -- -- Specifying actions as {''} -- -- A button to kill a window -- -- Other action formats -- -- Global variable rc_selected_action_button -- -- Global variable rc_in_button_handler -- -- Global variables rc_action_button_x, rc_action_button_y; -- The "scale independence" of button creation commands -- Getting rid of spare windows -- The definition of create_rc_button -- -- Inputs for create_rc_button -- -- create_rc_button does the following. -- Where output goes: async_vedbuffer -- Making output go into a Ved buffer -- A column of buttons -- Counter buttons and toggle buttons -- -- Changing the appearance of toggle buttons and counter buttons -- Creating buttons with blobs -- Procedures for creating rows and columns of buttons -- Button specification formats in lists of buttons -- -- 1. A string. (ACTION button) -- -- 2. A word. (ACTION button) -- -- 3. A list of at least two elements. (VARIOUS types) -- -- 4. A vector of three or more elements. (VARIOUS types) -- -- 5. Adding a featurespec -- -- Examples of legal specifications for list elements -- -- Specifying an array of buttons -- Allowed abbreviations in featurespec vectors -- -- Adding a new abbreviation -- Specifying an action button or blob button -- Buttons with associated state -- -- Toggle buttons -- -- Counter buttons -- -- Option buttons, radio buttons, someof buttons -- WARNING: List expressions in POP11 (and similar) actions -- An example list of buttons -- Making a column: create_button_column -- -- Exercise -- Making horizontal rows of buttons: create_button_row -- Using create_button_columns -- -- An array of buttons in three columns -- -- Additional examples: 4 and 6 columns -- Buttons on popup menus: rc_popup_query -- -- Example invocations of selection menus -- -- Global variables for rc_popup_query -- "Popup" Messages without buttons: rc_message -- -- Global variables for rc_message -- Messages that persist: rc_poster -- A variant that waits: rc_message_wait -- Radio buttons and someof buttons -- Complete list of action specifications for action buttons -- Default values for global variables in LIB rc_buttons -- SUMMARY OVERVIEW -- -- The main mixins: rc_button, rc_display_button -- The main button classes: action, blob, toggle,etc. -- -- Option buttons and radio and someof subclasses -- Procedures for creating individual buttons or collections -- -- Procedures in LIB RC_BUTTONS -- -- Procedures in LIB RC_BUTTON_UTILS -- -- Summary contents of LIB RC_BUTTONS -- -- Additional facilities in LIB RC_POPUP_QUERY -- -- Facilities in LIB RC_INFORMANT -- -- Additional autoloadable library procedures: -- Getting from a button or button list to its container -- See also -- Revision notes -- Overview ----------------------------------------------------------- LIB * RC_BUTTONS is a library within the RCLIB package, providing facilities for creating buttons of various sorts on an RC_GRAPHIC window object. It can also create and automatically format multiple columns or rows of buttons of various kinds. It is used by the rc_control_panel utility which automatically formats control panels containing buttons, sliders, dials, text fields, graphic elements, etc. Besides the examples presented below, there are additional examples in TEACH * RCLIB_DEMO.P TEACH * POPCONTROL TEACH * RC_CONTROL_PANEL HELP * RC_CONTROL_PANEL TEACH * RC_CONSTRAINED_PANEL -- Introduction ------------------------------------------------------- This file gives an overview of the facilities for creating "active" buttons of various sorts, provided by LIB * RC_BUTTONS LIB * RC_BUTTON_UTILS and also the facilities provided in these files LIB * RC_POPUP_QUERY LIB * RC_MESSAGE LIB * RC_MESSAGE_WAIT These provide related functions, involving panels that are displayed with information and possibly questions to be answered or selections to be made (rc_message and rc_message_wait do not use buttons). LIB * RC_CONTROL_PANEL defines a procedure that creates panels containing sets of text fields, button fields, slider fields, graphic fields, and several other types, all automatically formatted. These facilities are described in more detail in HELP * RC_CONTROL_PANEL The files TEACH * RC_CONTROL_PANEL and TEACH * RCLIB_DEMO.P both illustrate the use of buttons related mechanisms. Further detailed examples can be found in LIB * RC_POLYPANEL. For many purposes the procedures described below which create individual buttons, i.e. create_rc_button, create_action_button create_blob_button create_option_button create_select_button will be found found less useful than the procedures which do automatic formatting of arrays of buttons i.e. the procedure for creating an array of buttons create_button_columns(x, y, width, height, spacing, columns, list, type, specs) -> buttons; or its more specialised variants: create_button_column(x, y, width, height, spacing, list, type, specs) -> buttons; create_radio_button_columns(x, y, width, height, spacing, columns, string, list, specs) -> buttons; create_someof_button_columns(x, y, width, height, spacing, columns, string, list, specs) -> buttons; create_button_row(x, y, width, height, spacing, list, type, specs) -> buttons; create_button_column(x, y, width, height, spacing, list, type, specs) -> buttons; Probably the most useful procedure of all is rc_control_panel(x, y, fields, title) -> panel; Described in HELP rc_control_panel -- Use of featurespec arguments --------------------------------------- Many of the procedures in the RCLIB package including button creation procedures allow permit a "specs" argument. This allows the default specifications for buttons to be overridden using the mechanisms described in HELP * FEATURESPEC. When a procedure is given a list of button specifications it is sometimes useful to make individual buttons look different and the notation described below also allows a shorthand for altering the defaults for individual buttons within a list of buttons. -- Types of buttons and related facilities ---------------------------- The main facilities related to buttons are described in several groups, as follows: -- -- Asynchronous control buttons o Action buttons. These cause some specified action to happen when pressed (no matter what else is going on) o Invisible action buttons. These are the same except that they do not have a visible border which changes colour when mouse button 1 is pressed. o Action buttons with blobs. These are like action buttons, but with a different appearance. o Toggle buttons. These display the value of a boolean variable and toggle the value when selected, displaying the new value thereafter. o Counter buttons. These have an associated numeric variable and an increment. When selected with mouse button 1 the button decreases the value of the variable by the increment. When selected with mouse button 3 it decrease the value. The new value is shown in the button. o Radio buttons. These come in groups displayed in a control panel. Only one can be selected at any time. Selecting a new one deselects the previous one. Each button has an associated select method and a deselect method. These are applied to the buttons when the selection changes. o Someof buttons. These come in groups displayed in a panel in a control panel. Any subset or none can be selected at any time. Each button has an associated select method and a deselect method. These are applied to the buttons when the selection changes. All of these allow a changed value to be automatically assigned to a specified pop-11 variable. -- -- Input fields o Text input buttons o Number input buttons. These may look like buttons but are used for inserting or modifying a text or number field. See HELP * RC_TEXT_INPUT These also allow a changed value to be automatically assigned to a specified pop-11 variable. -- -- Buttons for popup menus o Select buttons. These can be used in a popup menu which waits for the user to select one of the buttons. At that point the button label (or some other value associated with it, e.g. a number) is then returned by the menu procedure. (These are partly analogous to Radio buttons.) o Option buttons. These come in groups displayed in a panel in a popup menu which asks a question. Any subset or none can be selected to answer the question. An additional button has to be provided to indicate when the selection has been made, whereupon a list of the selected buttons is returned by the menu procedure. (These are partly analogous to Someof buttons.) Besides their use in popup menus these can also be used in control panels that include other sorts of buttons, sliders, etc. -- -- Information display panels o These panels, created using rc_message, are not strictly types of buttons, but are included here. There are two sorts, Asynchronous panels remain visible until the user dismisses them or the garbage collector gets rid of them. rc_message produces these. Synchronous display panels, wait for the user to dismiss the panel before processing can continue rc_message_wait produces these. NOTE: the examples below should work whether you are using Ved or Xved, except that if you are not using Xved some of the instructions to create a new Xved window will simply cause a new Ved buffer to be created. -- Making the buttons available --------------------------------------- To make the package available use these commands: uses rclib uses rc_buttons Some of the additional facilities described below are in this file uses rc_button_utils In order to create buttons you have to create an instance of rc_window_object, using rc_new_window with the newrc_button_window creation procedure. The first two numbers give screen location, the next two width and height of the window. See TEACH * RC_LINEPIC. uses rc_window_object vars win1 = rc_new_window_object( "right", "top", 300, 300, true, newrc_button_window, 'win1'); By default this new window will have an associated coordinate frame with its origin in the middle of the window, with x increasing to the right and y upwards. (See TEACH RC_GRAPHIC). The window object is created automatically when rc_control_panel is used for creating buttons. -- Examples of individual buttons, using rc_create_button ------------- -- -- A button to print out a greeting Here is one way to define an action button to print out a greeting when selected. The procedure create_rc_button can take arguments in several formats, including this: x, y, width, height, [^label ^action], "action", specs The first two numbers give the location of the top left corner of the button in the current rc_graphic coordinage frame. Any of width, height, and specs may be false, in which case defaults are used. The word "action" may be replaced buy "blob" to produce an action button with a blob on the left, or "invisible" to produce an action button which does not necessarily have visible components. To make it visible either give it a label other than nullstring or draw something in the desired location, e.g using rc_draw_blob. (Even if invisible, the action button will still have a "sensitive" area, depending on the rc_mouse_limit slot.) The label can be a string, or word, or number. The action can be a string (a VED ENTER command), a word (the name of a procedure to be run), an ident whose idval is a procedure, a procedure, or a list which is interpreted according to the first word of the list. Here's a possible action procedure: define print_greeting(); ;;; A procedure to be the action of a button. 'Hello everybody' => enddefine; The command given below will create and display a button that will invoke that action, using the current window object, held in rc_current_window_object. The arguments to create_rc_button may take various forms. Here we provide x, y, width, height, label and action specification, type, and false The false argument could be replaced by a featurespec giving further information, as explained below. uses rc_buttons vars button1 = create_rc_button( 0, 150, 100, 29, ['Press me' print_greeting], "action", false); You can now try "pressing" the button, using the mouse with left button (button 1). When you press it the border changes, but no action occurs till you release the button. If you first move the mouse pointer off the button picture then the action is not performed when you let go. If you are running Xved launched from an Xterm window the printing may appear in that window, so you'll have to open and uncover the window if it is obscured. If you are running ordinary Ved the printing will go straight to the terminal, and may mess up your Ved window. Press RETURN to fix that. In the button's action specification, we give the name of the procedure rather than the procedure itself, because that means you can edit and recompile the procedure without having to create the button. It would be acceptable to give the procedure itself, for instance to prevent problems about crossing section boundaries. If "invisible" had been used instead of "action" the button's border would not have been drawn, and by default the sensitive area would have been a rectangle of the same size and location for a visible button with a border of thickness 0. If the word "blob" had been used instead of "action", a button with a slightly different appearance would have been drawn, as illustrated below. -- -- Using a featurespec and an identifier record A featurespec is a structure specifying alternatives to the default configuration for an instance of a class. See HELP FEATURESPEC for full details. We here give an example of use of a featurespec vector to override the default font and colour specifications. ;;; Create a featurespec descriptor to override the defaults ;;; when the next button is created vars spec1 = {rc_button_font '10x20' rc_button_stringcolour 'yellow' rc_button_labelground 'brown'}; Such featurespec vectors using the full names of slots in objectclass instances can be very cumbersome. The RC_BUTTONS library supports abbreviations in featurespec vectors, as illustrated below in button4. We now create a button similar in function to the previous one, except that the new featurespec defines its appearance, and instead of the word "print_greeting" we give the corresponding identifier, so that the behaviour can work with file-local lvars or variables defined in a section: vars button2 = create_rc_button( 0, 120, 150, 29, ['Press me too' ^(ident print_greeting)], "action", spec1); -- -- Using a three element vector with a type word Another way to specify the button is to replace the action list with a three element vector starting with the keyword "action". In that case the type specifier given as the next argument to create_rc_button is ignored (e.g. it could be false). This can be used in a command to create a list of buttons of the same default type, where the default type is to be overridden in some of the buttons in the list, which are of a different type. Examples are given below. Meanwhile here are two illustrations of the vector format starting with a type word, and in the case of button4 we use an abbreviated featurespec to specify foreground and background colours: vars button3 = create_rc_button(0, 90, 120, 29, {action 'PressHere' ^print_greeting}, false, false); or vars button4 = create_rc_button(0, 60, 160, 30, {toggle 'GC Trace' popgctrace}, false, {font '10x20' textfg 'yellow' textbg 'blue'}); Clicking on the former button prints out a message. Clicking on the latter switches the value of popgctrace between true and false. See HELP POPGCTRACE. Note that a "toggle" button has a different sort of border. It also reacts immediately when the mouse button goes down. Type words available at present for use in the three element vector format for specifying active buttons are: "action", "blob", "counter", "option", "radio", "select", "toggle" "invisible" However, users will normally only need these: "action" "blob" "counter" "toggle" and perhaps "invisible" since the others are usually invoked in a different way, e.g. using rc_control_panel, or create_button_columns, illustrated below. -- -- Action buttons with blobs It is possible to make an action button have a blob on the left, either by using "blob" as the type argument before the featurespec argument, or by using the word "blob" as the first element of a three element vector, as in this example, where we provide no featurespec argument to create_rc_button, but put an extra specification as the last item in the button description vector: vars button5 = create_rc_button(0, 30, 120, 29, {blob 'PressHere' print_greeting {textbg 'yellow' textfg 'blue'}}, false, false); Note that the featurespec vector in the contents vector can use the same abbreviated notation as illustrated in button4, instead of using full names of the button slots. Alternatively we can specify a blob button using the word "blob" as the type argument for create_rc_button, and add a different blob colour to spec1, while putting a pop-11 command in a list to specify the button's action: vars button6 = create_rc_button(0, 0, 120, 29, ['No Here' [POP11 'blobby here' =>]], "blob", [^spec1 {blobcol 'ivory'}]); -- -- An action button invoking a Unix command This one invokes a Unix command with output read into a Ved buffer: vars button7 = create_rc_button(0, -30, 120, 29, ['Users' 'sh who'], "blob", [^spec1 {blobcol 'pink' textfg 'pink'}]); or, another way to specify the blob colour: vars button7 = create_rc_button(0, -30, 120, 29, {blob 'Users' 'sh who' {blobcol 'blue'}}, false, spec1); -- -- An action to display a message panel Here the action is a command to invoke the rc_message procedure described in more detail below: define showmessage(); rc_message(200, 200, ['This is a test message' 'using white on black.' 'Generated at' ^(sysdaytime())], 0, true, '12x24', 'black', 'white') -> enddefine; vars button8 = create_rc_button(0, -60, 120, 29, ['Message' showmessage {blobcol 'blue' textfg 'white'}], "blob", spec1); WARNING: Sometimes after interacting with another panel, it is necessary to reset the "current" window object before installing more buttons. You can do this either by clicking mouse button 1 on the desired window while holding the "Control" key down, or, equivalently, executing this assignment: win1 -> rc_current_window_object; Check the value: rc_current_window_object=> It should show that you are currently dealing with the panel called 'win1'. If rc_current_window_object points to the wrong window your button creation command may have unintended effects. If it is false, because a window has just been killed, the next button creation command will produce an error. -- -- Specifying button actions as {[proc arg1 arg2 arg3]} You can specify an action to be performed as a vector containing a list starting with a procedure or name of a procedure, followed by the arguments (i.e. the action arguments themselves, not words that have them as values): win1 -> rc_current_window_object; vars button9 = create_rc_button(0, -90, 120, 29, ;;; a button to edit the user's login file ['EditLogin' {[vededit '~/.login']}], "blob", [^spec1 {rc_button_blobcolour 'blue' rc_button_stringcolour 'pink'}]); -- -- Specifying actions as {''} An action can be a vector containing a string with program text, which will be compiled and run, e.g. this button containing the pop-11 instruction 999*9 => vars button10 = create_rc_button(0, -120, 120, 29, ['999*9' {'999*9=>'}], "action", false); -- -- A button to kill a window Try adding a button to kill the current window by invoking the library procedure rc_kill_panel. vars button11 = create_rc_button(-150, 150, 95, 29, ['KILL' rc_kill_panel], "blob", {textbg 'yellow' textfg 'blue' font '10x20'}); If you have to ensure that the KILL action is run asynchronously, no matter what else is going on, use a list starting with "POPNOW", followed by a procedure or procedure name, or a longer list containing Pop-11 instructions to be obeyed: vars button11 = create_rc_button(-150, 150, 95, 29, ['KILL' [POPNOW rc_kill_panel]], "blob", {textbg 'yellow' textfg 'blue' font '10x20'}); or vars button11 = create_rc_button(-150, 150, 95, 29, ['KILL' [POPNOW rc_kill_panel();]], "blob", {textbg 'yellow' textfg 'blue' font '10x20'}); As a last resort you can do rc_kill_window_object(win1); -- -- Other action formats Additional action formats are described below, in addition to actions specified in lists starting [POP11 ...] or [POPNOW ...], as illustrated above. Additional keywords can be used to indicate specific types of actions. Creating individual buttons and working out their locations as in the examples just given can be very tedious. More powerful mechanisms for automatically generating a layout for rows or columns of buttons are described below and in HELP RC_CONTROL_PANEL, which describes a tool which does automatic formatting. -- -- Global variable rc_selected_action_button rc_selected_action_button is false by default, but points to the currently selected button when mouse button 1 has been clicked on an action button. See the method definitions in LIB * RC_BUTTONS. -- -- Global variable rc_in_button_handler The variable rc_in_button_handler has the value false by default, but it is set true in the context where an action button is running, invoked by this method: rc_rcbutton_1_up(pic:rc_action_button, x, y, modifiers); Thus procedures which are sometimes invoked by a mouse button and sometimes called directly from Pop-11 programs can tell which is happening by means of this variable. -- -- Global variables rc_action_button_x, rc_action_button_y; These two variables are set in rc_rcbutton_1_up, but not locally. So deferred actions may be able to use them to refer to the occurrence of the last deferred event. -- The "scale independence" of button creation commands --------------- You can use rc_new_window to create a window which has its origin at location (10 50) with xscale = 2 and yscale = -2, and give the above commands with appropriate adjustments to the coordinates. The sizes of the buttons are not changed by the change of size of the window, unlike other picture objects, as shown in HELP rc_linked_pic, and illustrated below. vars win1 = rc_new_window_object( 650, 20, 300, 300, {10 50 2 -2}, newrc_button_window, 'win1'); ;;; Show the origin: note that the blob will be expanded because of the ;;; scale values 2, -2. I.e. the radius 10 will be displayed as 20. rc_draw_blob(0, 0, 10, 'red'); vars buttona = create_rc_button(55, 18, 120, 29, {blob 'PressHere' print_greeting}, false, false); vars buttonb = create_rc_button(-5, 25, 95, 29, ['KILL' [POPNOW rc_kill_panel]], "blob", false); vars buttonc = create_rc_button(55, -30, 120, 29, ;;; invoke procedure showmessage defined above ['Message' showmessage], "blob", [^spec1 {rc_button_blobcolour 'blue' rc_button_stringcolour 'pink'}]); -- Getting rid of spare windows --------------------------------------- NOTE: if you have a left over window without a functioning KILL button, e.g. because an error occurred while attempting to create the window, you can get rid of the window as follows: Hold down the "Control" and click in the window with mouse button 1 then Either, in Ved ENTER killwin Or, in Pop-11 ved_killwin(); Alternatively you can use the window manager's "delete" or "close" mouse action. (Beware the stronger "destroy" action available on some window managers, e.g. f.destroy in twm or ctwm, will kill the whole pop-11 process, not just the window.) -- The definition of create_rc_button --------------------------------- create_rc_button(x, y, w, h, contents, type, specs) -> button; create_rc_button(x, y, w, h, contents, type, specs, "nodraw") -> button; -- -- Inputs for create_rc_button x. y: location of top left corner of button (numbers) w, h: width and height of button (numbers) Can be false, in which case current defaults are used, determined by the values of global variables: rcbutton_width rcbutton_height unless overridden by specs contents: string, or word, or list, or vector. This will determine the button label, and possibly values of some other fields that may be required, In some cases the word or string will serve two purposes, e.g. being both the button label and also a specification of an action, e.g. when it is a Ved "enter" command. If it is a list it will usually have at least two elements, the label, and other information specifying slot values for the button, including possibly an action to be performed. If there are more than two elements the third will be a featurespec. If it is a vector, the first item will be a word specifying the type of button, overriding the type argument. The other elements will include the label for the button and other components, depending on the type of button. E.g. for action, blob, toggle and counter buttons the last item in the vector can be a featurespec vector using an abbreviated notation, as in button5 and button7 above. type: Word or class key specifying type of button, or possibly false. If it is false, the contents argument must be a vector whose first item is a word specifying the type. specs: This can be a primitive or compound feature specifier to override the default button features. See HELP * FEATURESPEC Example feature specs were given above, e.g. blob_specs. "nodraw": If this word is provided as the last argument, then the button is not drawn when created. This allows a button to be invisible, or allows a user procedure to modify the button after it is created and before it is drawn. -- -- create_rc_button does the following. 1. It creates a button instance of the required type using general mechanisms and sets its x, y, w, h values. 2. It uses interpret_specs and the specs argument to override any defaults (See HELP FEATURESPEC) 3. It runs the (user definable) method modify_instance(button, contents, type, specs); which can take additional action. The default version of this method extracts items from the contents list or vector and stores them in the appropriate slots of the new instance. For a blob button it computes the blob radius if the radius has not been changed from 0. The specs argument given to modify_instance is the featurespec extracted from the list or vector contents argument to create_rc_button. 4. Unless the "nodraw" argument is provided, it uses rc_draw_linepic to draw the button in the current window. For an "invisible" action button, this will draw only the label unless the specs argument has been used to provide appropriate contents for the rc_pic_lines and/or rc_pic_strings slots (as illustrated in TEACH RC_LINEPIC). To make an invisible button totally invisible use the empty string as label (nullstring). 5. It adds the button to rc_current_window_object using rc_add_pic_to_window(button, rc_current_window_object, true) so that the picture becomes mouse sensitive. -- Where output goes: async_vedbuffer --------------------------------- [This is provisional and may change later] If a button action does some printing, the output can be controlled by the variable async_vedbuffer, which can be given a string as value. In that case if there are any ved files open at all (vedbufferlist is not empty) then output is directed to a VED buffer with that name. The default value is 'output.p'. It will be a file in the current directory. Alternatively try something like this to make sure it always goes to the same output buffer. '~/output.p' -> async_vedbuffer; -- Making output go into a Ved buffer --------------------------------- You can define the procedure that is invoked by an action button so as to ensure that its output goes where you want it to, and the window does not take up too much space, and that it is non-writeable. The following definition will change the behaviour of the buttons previously created which use the procedure print_greeting. The difference is biggest where XVed is in use. define print_greeting(); ;;; Ensure print out goes to a file called 'OUT' ;;; If running Xved, control the size, font, etc. dlocal cucharout = veddiscout('OUT'), vedautowrite = false; ;;; The next bit will be ignored outside Xved dlocal %xved_value("nextWindow", [x y numRows numColumns font])% = (100,100,3,50,'9x15'), ; 'Hello there -- Press REDO to quit this file' => ;;; Make the output file non-writeable false -> vedwriteable; ;;; Prepare a Ved quit command vedputcommand('q'); vedrefreshstatus(); enddefine; To test it, create a window if there isn't one. vars win1 = rc_new_window_object( 650, 20, 300, 300, {10 50 2 -2}, newrc_button_window, 'win1'); Now create a button to invoke the above procedure: vars button_greet = create_rc_button(55, 18, 120, 29, {blob 'PressHere' print_greeting}, false, false); -- A column of buttons ------------------------------------------------ Destroy the previous window if necessary and start a new one. rc_kill_window_object(win1); uses rclib uses rc_window_object uses rc_buttons vars win1 = rc_new_window_object( 600, 20, 300, 300, true, newrc_button_window, 'win1'); Define some more procedures to be invoked by action buttons. Compile this, and test it: define fact(x); ;;; Compute the factorial of x if x == 0 then 1 else x*fact(x-1) endif enddefine; ;;; test it fact(hd(vedreadlinefrom('TYPE_A_NUMBER', false, false))) => In response to the readline prompt, type a number and press RETURN Now define a procedure that will 1. destroy the current window, 2. create a new one, of the same size and location 3. insert in it all the buttons previously known to the window (the datastructures survive the destruction of the window, and can be added to a new window). define do_restart(); lvars win = rc_active_window_object, (x, y, w, h) = rc_window_location(win), title = rc_window_title(win), frame = rc_window_origin(win), pics = rc_window_contents(rc_active_window_object); ;;; Kill the current window rc_kill_window_object(rc_active_window_object); ;;; Built a new one and assign it to a variable derived from the ;;; old one's title (a string). rc_new_window_object(x,y,w,h, frame, newrc_button_window, title) -> valof(consword(title)); ;;; Now redraw the old picture objects and add them to the window. lvars pic; for pic in pics do rc_draw_linepic(pic); rc_add_pic_to_window(pic, win1, false) endfor; enddefine; Now create a collection of buttons, one of which will be an action button which runs the above procedure. For some of the buttons false is used for height and/or width, which means the current defaults will be used, as specified by the values of rc_button_width_def rc_button_height_def The featurespec given to each of these buttons is the empty list, []. If you have already created win1, as above, then you should be able to mark and load all of the following down to the semicolon. The buttons will be created and you can then test them. (Beware, the "factorial" button may cause messy interaction with Ved.) vars sb0 = create_rc_button( -150, 150, 149, 35, ['Restart' do_restart {textbg 'yellow'}], "action", {}), sb1 = create_rc_button( -150, 110, 149, false, ['Memlim' ^(ident popmemlim) 10000 {borderwidth 6 bordercol 'red'}], "counter", {}), sb2 = create_rc_button( -150, 85, false, false, ['help strings' ^false], "action", {}), sb3 = create_rc_button( -150, 60, false, false, ['factorial' [POP11 fact(hd(vedreadlinefrom( 'TYPE_A_NUMBER', false, true)))=>]], "action", {}), ;;; use the vector notation for the next two sb4 = create_rc_button( -150, 35, false, false, {action 'Yes Press me' [POP11 'hello there'=>]}, false, {}), sb5 = create_rc_button( -150, 10, false, false, {action 'LockHeap' sys_lock_heap}, false, {}), sb6 = create_rc_button( -150, -15, false, false, ['UnlockHeap' sys_unlock_heap], "action", {}), sb7 = create_rc_button( -150, -40, false, false, ['GarbageCollect' sysgarbage], "action", {}), ;;; An action button to run a UNIX command, 'who' sb8 = create_rc_button( -150, -65, false, false, ['who' [UNIX 'who']], "action", {}), ;;; Use vector notation for toggle buttons sb9 = create_rc_button( -150, -90, false, false, {toggle 'Gctrace' ^(ident popgctrace) {borderwidth 6 bordercol 'red'}}, false, {}), sb10 = create_rc_button( -150, -115, false, false, {toggle popsyscall ^(ident popsyscall) {borderwidth 6 bordercol 'red'}}, false, {}), sb11 = create_rc_button(5, 150, 95, 35, {blob 'KILL' rc_kill_panel {textbg 'yellow'}}, false, false), ; Note that the toggle buttons and counter buttons, which control values of global variables, have a different appearance from the others. They have different borders and also when you click on them they immediately change to show the new value of the variable. The difference in appearance has been exaggerated here by making their borders thicker and yellow in colour. The action buttons (including blob buttons) do not perform their actions until you release the mouse button. For counter buttons use left mouse button to decrement, right mouse button to increment the numeric value (buttons 1 and 3). Try the various buttons. Try using the Gctrace toggle button to make popgctrace true, then click on the GarbageCollect button to invoke sysgarbage. Then try again with popgctrace false. (See HELP POPGCTRACE) If you press on Restart it should replace the window with a new one containing all the buttons. -- Counter buttons and toggle buttons --------------------------------- Some of the buttons in the above demonstration have different borders from the action buttons. E.g. the Memlim button is a counter button. It shows the current value of popmemlim and if you click with the right mouse button the value is incremented, and decremented if you use the left button. The amount of increase and decrease is 10000, the "increment" argument given to create_rc_button. There are also two toggle buttons, one showing the value of popgctrace and the other the value of popsyscall, both of which can be true or false. Clicking with the left mouse button changes the value and shows you the current value. -- -- Changing the appearance of toggle buttons and counter buttons You can change the appearance of a toggle button, by giving it two new strings to show for true and false values. Likewise the appearance of a counter button can be changed. E.g. create some buttons as before: rc_new_window_object( 600, 20, 300, 300, true, newrc_button_window, 'win1') -> win1; vars togglebutton = create_rc_button( -150, 150, 150,30, {toggle popsyscall ^(ident popsyscall)}, false, {}), counterbutton = create_rc_button( -150, 115, 150, 30, ['Memlim' ^(ident popmemlim) 10000], "counter", {}), killbutton = create_rc_button(5, 150, 95, 35, ['KILL' rc_kill_panel], "blob", false); Instead of the lists given to create_rc_button, the last two could have been created using vectors starting with the word "counter" and "blob" respectively. Now change the appearance of the togglebutton, so that it shows "+" or "-" instead of "T" or "F": {' [+]' ' [-]'} -> rc_toggle_labels(togglebutton); rc_draw_linepic(togglebutton); Now try clicking on the popsyscall button. Or try these two strings: {' [Yes]' ' [No]'} -> rc_toggle_labels(togglebutton); rc_draw_linepic(togglebutton); It is possible to change the brackets surrounding the number associated with a counter button. E.g. try this {'((' '))'} -> rc_counter_brackets(counterbutton); rc_draw_linepic(counterbutton); You can invent your own bracket pairs. E.g. this format could remind you which button increments and which decrements. {'-|' '|+'} -> rc_counter_brackets(counterbutton); The default strings used for the brackets are held in two global variables, with these default values: global vars rc_toggle_labels_def = {' (T)' ' (F)'}, rc_counter_brackets_def = {'[' ']'}; -- Creating buttons with blobs ---------------------------------------- To emphasise the importance of certain buttons or simply to provide a different style, the package defines action buttons in the sub class rc_blob_button which is like an action button but with two extra fields for a blobcolour and blobradius. If the blobradius is left at 0, the default, an appropriate radius is chosen automatically when the button is drawn. To give these buttons a different set of colours when they are drawn, we can define a new featurespec. (See HELP FEATURESPEC) to be used with the create procedures. Mark and load the following: ;;; Some new defaults for buttons with blobs on left. One of the ;;; buttons below overrides the font specified here. vars blob_specs = {rc_button_font '8x13' rc_button_stringcolour 'white' rc_button_bordercolour 'red' rc_button_labelground 'brown' rc_button_blobcolour 'ivory'}; rc_new_window_object( 600, 20, 300, 300, true, newrc_button_window, 'win1') -> win1; ;;; Create buttons with blobs visible on left vars ;;; a button to get a help file bb1 = create_rc_button (0, 135, 130, 22, ['help rclib' ^false], "blob", blob_specs), ;;; buttons to move up and down the VED buffer and load marked range bb2 = create_rc_button (0, 112, 130, 24, ['PageUP' vedprevscreen], "blob", blob_specs), bb3 = create_rc_button (0, 87, 130, 26, ['PageDown' vednextscreen], "blob", blob_specs), bb4 = create_rc_button (0, 60, 130, 35, ['LoadRange' ved_lmr], "blob", [^blob_specs {rc_button_font '*lucida*-r-*sans-14*'}]), ;;; a button to rotate ved buffers, with a very large blue blob bb5 = create_rc_button (0, 24, 130, 40, ['Next file' ved_rb {blobrad 12 blobcol 'blue'}], "blob", [^blob_specs {rc_button_font '*lucida*-r-*sans-14*'}]), ;;; Print out the value of PI bb6 = create_rc_button (0, -17, 130, 40, {blob 'PI' [POP11 pi =>]}, false, blob_specs), ;;; Change the number of decimal points printed. Use mouse buttons ;;; 1 and 3 to increment or decrement bb7= create_rc_button (0, -58, 130, 30, ['pr_places' pop_pr_places 1], "counter", {}); ; If you click on the 'PI' button it prints out the value of Pop-11's global variable pi. Notice how you can use the left and right mouse buttons on the pr_places counter button to change the number of decimal places printed out. See REF * POP_PR_PLACES Try redoing the above with different values in the blob_specs structure, different button locations, etc. Destroy the window. rc_kill_window_object(win1); -- Procedures for creating rows and columns of buttons ---------------- Several procedures are provided: create_button_columns: can display a list of buttons in a row, or in one or more columns. create_button_row: displays just one row. (Probably redundant.) create_button_column: displays just one column. (Probably redundant.) rc_popup_query: presents some text and one or more rows of buttons and waits until the user makes a selection, whereupon it returns with information about the selection. There are two forms: o the select form where only one option can be chosen o the options form where several options or none can be chosen. This form has two sorts of buttons: options buttons and action buttons to indicate that the selection is complete. In both cases strings are supplied which are displayed above the buttons explaining what the selection is about. In some cases the button labels are themselves words or strings indicating the options. In other case they are numbers corresponding to options described in the strings displayed. Examples of all the above are given below. -- Button specification formats in lists of buttons ------------------- There are various ways of specifying formats for buttons, some of which directly use the relevant Pop-11 (and objectclass) procedures and methods, whereas others use short-hand notations which are more convenient when specifying the appearance of a complex display panel. For examples see the button specification formats in this file and in TEACH * RC_CONTROL_PANEL HELP * RC_CONTROL_PANEL We need to be able to create a list of button specifications to give to the procedures that create rows or columns of buttons. In a list, each specification for a button requires one of the following forms to indicate the type and appearance of the button, and possibly also what information it contains or what action it performs when selected. -- -- 1. A string. (ACTION button) The string is used as label for the button and as a VED ENTER command to be obeyed if the button is selected. The button is an action button. If a string is given as the button specification it is also copied to the rc_informant_value field, so that procedures which examine the button find that as its current contents. (Note that this copying is not done for all button types. E.g. for radio and someof buttons the rc_informant_value value is a boolean. -- -- 2. A word. (ACTION button) This is used as label and possibly the name of a procedure to be obeyed if the button is selected, if the button is an action button. If a word is given as the button specification it is also copied to the rc_informant_value field, so that procedures which examine the button find that as its current contents. -- -- 3. A list of at least two elements. (VARIOUS types) Depending on the type of button this can be interpreted differently. E.g. if it is an action (or blob) button, the first element is taken as label and the second as action. Formats for action specification are described below. (If the first element is a word or string, the second can be false. This amounts to the same as case 1 or case 2). If it is a select button (of type rc_select_button, used in rc_popup_query) then a two-element list can be used to indicate the button label and the item to be the rc_informant_value value, capable of being returned by a menu selection procedure, for instance. (See LIB rc_popup_query). If it is a toggle button or a counter button additional information can be provided as explained below. If it is a radio button or a someof button, the first item will be the string displayed as a label on the button and the second item will be the value that is to be used if the button is selected. It will be stored in the rc_real_contents slot of the button. If only a string is given it is stored in both the rc_button_label and the rc_real_contents. -- -- 4. A vector of three or more elements. (VARIOUS types) The first element should be a word specifying the button type, e.g. "action", "blob", "counter", "toggle", etc. The remaining elements correspond to the elements of the list in case 3. In the case of a counter button the second, third and fourth items are o a string or word to be displayed o the word or identifier to be incremented o either an integer, specifying the amount of the increment or a vector of three items { } where is an integer, giving the amount of the increment, is either an integer specifying the minimum value the counter can have, or false meaning there is no minimum, and is an either an integer specifying the maximum value the counter can have, or false meaning there is no maximum. Where there is no maximum a two element vector can be used, to specify and o A fifth element can be a featurespec vector, using abbreviations. In the case of a toggle button the second and third items are o a string or word to be displayed o the word or identifier whose value is to be toggled. o A fourth element can be a featurespec vector, using abbreviations. Radio buttons and Someof buttons are handled differently, as illustrated in TEACH rclib_demo.p, and below. -- -- 5. Adding a featurespec A featurespec is an even length vector consisting of procedure value pairs which can be used to override defaults when a button instance is created. (See HELP * FEATURESPEC). It is possible to specify that a particular button should override current defaults without creating a special class for that button, by providing a featurespec as the final element of the list in case 3, or the final element of the vector in case 4. (In this context featurespec vectors allow abbreviations described below.) -- -- Examples of legal specifications for list elements Example legal button specifications which can occur in lists of buttons to be displayed in rows and/or columns will now be given. Where a word occurs on its own it will be used as the label of an action button and the name of a procedure to be invoked when the button is selected. Where a string occurs on its own it will be used both as the label and as a VED enter command to be invoked when the button is selected. Wherever a list occurs without a type specification it is taken to be an "action" button. Where a list or vector is used it is possible to add an extra item which is a featurespec vector, in which featurespec abbreviations can be used as summarised below. The examples follow: Example action buttons: "vedprevscreen" 'help rc_buttons' ['GetHelp' 'help rc_buttons'] {blob 'GetHelp' 'help rc_buttons' {blobrad 10}} ['GC' sysgarbage] ['Show Users' 'sh who'] ['Show Usage' [UNIX 'w']] ['Show files ' [UNIX 'ls -l']] ['Greet' [POP11 'hello there' =>]] ['Show Menu' [DEFER setupmenu(myoptions)]] ['Increment' [POPNOW counter + 1 -> counter]] ['KILL PANEL' rc_kill_panel] {action 'Show Usage' [UNIX 'w']} A toggle button {toggle 'GC trace' popgctrace {textbg 'blue' textfg 'yellow'}} Counter buttons {counter 'Memlim' popmemlim 10000} {counter 'Memlim' ^(ident popmemlim) ^(ident popmemliminc)} ;;; The fourth element in a counter button spec can be a vector ;;; of two or three numbers, as explained below. {counter pop_pr_radix ^pop_pr_radix {1 2 36}} {counter pop_prolog_lim ^pop_prolog_lim {10000 0}} {counter pop_pr_places ^pop_pr_places {1 0} {reactor reactproc}} NOTE 1: In the last example, the procedure reactproc should be a suitable reactor procedure for the counter. E.g. it may change a slider's value. Examples involving reactors are given in HELP * RC_CONTROL_PANEL TEACH * RC_CONSTRAINED_PANEL NOTE 2: the "DEFER" prefix is explained below. To illustrate the use of a featurespec vector this is how it might be specified that a button should have a pink background. Consider an action button which when selected kills the current window. This could be specified as ['KILL PANEL' rc_kill_panel] It would be possible to require this to have a pink background, no matter what the current default button background was, by using this format: ['KILL PANEL' rc_kill_panel {rc_button_labelground 'pink'}] or, using the abbreviation facility: ['KILL PANEL' rc_kill_panel {textbg 'pink'}] The third element of the list is a featurespec vector containing a button instance slot name (or an abbreviation for one), and a possible value. It is possible to include several slot value pairs, e.g. {rc_button_labelground 'pink' rc_button_font '10x20' rc_button_stringcolour 'brown'} which can be abbreviated as {textbg 'pink' font '10x20' textfg 'brown'} Apart from the abbreviations defined below, it is necessary to know the names of the slots (as defined in LIB * RC_BUTTONS and other files) to make full use of featurespec vectors. (Watch HELP * RCLIB_NEWS for information about new abbreviations). The variety of types of featurespecs and their uses is described at length in HELP * FEATURESPEC -- -- Specifying an array of buttons Several different button specifications can be assembled in a list and given to the create_button_columns procedure, or included in field specification lists to rc_control_panel. They can also be used with other procedures, as illustrated below. In addition to these specifications, procedures for creating buttons will need information about location, width, height, various colour specifications, etc. However some of these can be derived from defaults, or provided via featurespecs, as shown below. In the case of the procedures for creating columns of buttons, or control panels, the locations of buttons are computed automatically depending on the required spacing, the height and width of the buttons, how many rows and columns there are, whether they are to be centred or not, etc. For more information and examples see TEACH * RC_CONTROL_PANEL TEACH * RCLIB_DEMO.P HELP * RC_CONTROL_PANEL LIB * RC_POLYPANEL -- Allowed abbreviations in featurespec vectors ----------------------- The abbreviations allowed in featurespec vectors given within a button description list or vector are held in the property rc_button_spectrans which by default has the following mappings: [height rc_button_height] [width rc_button_width] [font rc_button_font] [borderwidth rc_button_border] [textfg rc_button_stringcolour] [bordercol rc_button_bordercolour] [textbg rc_button_labelground] [blobrad rc_button_blobrad] [blobcol rc_button_blobcolour] [labels rc_toggle_labels] [constrain rc_constrain_contents] [ident rc_informant_ident] [reactor rc_informant_reactor] -- -- Adding a new abbreviation To allow the word "bg" to be used instead of "textbg" as an abbreviation for rc_button_labelground, do rc_button_labelground -> rc_button_spectrans("bg"); Note: these abbreviations can be used in lists of ACTION buttons in connection with rc_control_panel. But they are not necessarily the same as the abbreviations allowed in panel property specifications or field property specifications. See HELP RC_CONTROL_PANEL -- Specifying an action button or blob button ------------------------- The following comments apply also to invisible action buttons. As illustrated in the above examples, action buttons and blob buttons (which are a species of action button) need an action specification which can be any of the following: 1. A string to be given to veddo: i.e. a string which could be a Ved ENTER command. 2. A word or procedure or ident. If it is a word or ident, its valof or idval should be a procedure. 3. A list consisting of a keyword following by additional information. How this is interpreted depends on the keyword. 3.a. Keyword "UNIX" should be followed by a string, e.g. 'ls -lt' which will be treated as a unix shell command. The command is run and any output read into a Ved buffer. (Examples were given above.) 3.b. Keyword "POP11" means interpret the rest of the list as a pop11 command to be run. It will be run with the environment set by default so that any drawing actions will apply to the window in which the command is given. The command is run as a procedure given to external_defer_apply, so it is safe to use with complex procedures which may cause garbage collections, etc. (See REF external_defer_apply) 3.c. Keyword "POPNOW" causes the rest of the list to be interpreted as an action to be performed immediately, without using external_defer_apply. This means it is not safe for actions which can invoke memory management operations or other complex events that should not happen within a callback. It is safe to use for simple assignments of constants to variables. 3.d. Keyword "DEFER" (optionally followed by "POP11") causes the action to be run in a context in which the global variables rc_current_window_object, rc_window, rc_xorigin etc., etc. are no longer set to correspond to the window object in which the event occurred. I.e. they are set back to whatever values they had before the event occurred. This sort of action can be used to assign to rc_current_window_object. It causes the action to be run via rc_defer_apply, defined in LIB * rc_mousepic. See HELP * RC_LINEPIC/rc_defer_apply 3.4. Keyword "INVED" is analogous to "POP11" except that instead of the action procedure simply being given to external_defer_apply, the procedure vedinput is applied to it, if XVed is running. NB: Since 6 Sep 2002 this is no longer needed, since the test for whether XVed is running and whether it is suspended or active is now performed at a lower level in the procedure rc_handle_event, as described in HELP RC_EVENTS (Using vedinput means that the action will be put in XVed's input stream. Unless this is done, actions which interact with XVed may not perform as expected, especially if they read input from a Ved buffer.) NOTE: if the list specifying an action button starts with one of these keywords: "POP11" "DEFER" "POPNOW" "INVED" then the procedure to be run is compiled when the button is created, not each time the button is activated. If the latter is desired, the POP-11 action can include a call of pop11_compile. -- Buttons with associated state -------------------------------------- There are four kinds of buttons with associated state: Toggle buttons: These have a value true or false, which is changed by a mouse click. Counter buttons: These have an associated number wnich can be made to go up or down by a mouse click Radio buttons: Like toggle buttons these have an associated boolean value which can be changed by a mouse click. However only one of an array of Radio buttons can be true at a time. Someof buttons: Like radio buttons except that any subset of an array of radio buttons can be true. -- -- Toggle buttons For a toggle button, a string or word (the label) and a boolean variable (or ident) to be toggled must be provided. A toggle button is specified by a three or four element vector containing: o the word "toggle" o a string or word (the label), o a variable (word or ident) whose value is to be toggled. AND OPTIONALLY a featurespec vector, possibly using abbreviations. E.g. {toggle 'GC trace' popgctrace} {toggle 'Full Doing List' popsyscall} ;;; See REF * popgctrace, * popsyscall Additional featurespec information can be provided. -- -- Counter buttons A counter button has an associated variable with a numeric value which is incremented when mouse button 3 is used on the counter button, and decremented when mouse button 1 is used. A counter button is specified by a four or five element vector containing: o the word "counter" o a string or word (the label), o a variable (word or ident) to be incremented or decremented, AND ONE OF THE FOLLOWING: o a number specifying the amount by which to increment or decrement. o a variable or identifier holding as its value the amount by which to increment or decrement (so that the amount can be varied dynamically, or it may be a two or three element vector. o a three element vector { } where specifies the amount by which to increment or decrement, is the lowest value allowed for the associated variable, is the highest value allowed. o a two element vector { } where and are as above, and there is no maximum. and can either be numbers or false. In the latter case there is no minimum or maximum value. AND OPTIONALLY a featurespec vector. Examples of counter button specifications are: {counter 'Memlim' popmemlim 10000} {counter 'Memlim' ^(ident popmemlim) ^(ident popmemliminc)} {counter 'Memlim' popmemlim {10000 0 ^false}} {counter pop_pr_radix ^pop_pr_radix {1 2 36}} {counter pop_prolog_lim ^pop_prolog_lim {10000 0}} {counter pop_pr_places ^pop_pr_places {1 0}} {counter pop_pr_places ^pop_pr_places {1 0} {reactor reactproc textbg 'pink' height 40}} Instead of a vector starting with the word "counter" a list can be used without the word, provided that the type argument "counter" is given in an appropriate way to the the procedure creating the buttons. -- -- Option buttons, radio buttons, someof buttons These are created by For an options button or a select button only a word or string or number need be provided. The same applies to radio buttons and someof buttons. For examples see TEACH * RCLIB_DEMO.P/'Radio buttons and someof buttons' TEACH * RC_CONTROL_PANEL/'[RADIO' TEACH * RC_CONTROL_PANEL/'[SOMEOF' -- WARNING: List expressions in POP11 (and similar) actions ------------ If an action button specification includes a list starting with one of these words: "POP11", "INVED", "POPNOW" or "DEFER" it is compiled to form a POP11 procedure, which is run later when the button is activated (possibly using external_defer_apply, or vedinput). When the procedure is created during button creation, the list specifying its action has already been created. Therefore the use of expressions of the form [% ... %] in [POP11 ...] instructions will not have the desired effect, since the expression between the "%" symbols is executed when the list is created, NOT later on when the panel is created, nor when the button action is invoked. The same applies to the use of "^" and "^^" in expressions creating lists and vectors. This means that if you want a procedure to use such constructs it is necessary to define the procedure in advance, and then in the button specification list simply invoke the procedure, instead of putting the instructions inline in the action specification. -- An example list of buttons ----------------------------------------- ;;; The examples in this section work at Birmingham where the rcmenu ;;; library is available. It can be fetched from ;;; http://www.cs.bham.ac.uk/research/poplog/rcmenu.tar.gz ;;; Some of the buttons will work without this. All will display ;;; in the panel, and the ones with missing library procedures will ;;; complain only when selected. ;;; Load the extra library uses rcmenulib uses rclib uses rc_scratchpad ;;; explained below uses rc_message ;;; Explained below ;;; create the list of button specifications. We shall display buttons ;;; in various numbers of rows and columns. vars buttonlist = [ ['TEACH' 'teach rc_linepic'] ['PageUP' vedprevscreen {textbg 'yellow'}] ['PageDown' vednextscreen {textbg 'pink'}] ['GoSection' 'g'] ['QuitFile' 'q'] [Swapfiles vedswapfiles] ['MachineUse' [UNIX 'w']] 'dired' 'dired -lt' 'dired -d' [999 [POP11 rc_message( 300,300, sysdaytime() :: ['Hello Hello' 'I want to report' 'an emergency'],0, true, '9x15', false, false)->; ] {textbg 'blue' textfg 'yellow'}] ;;; The next four use LIB * RC_SCRATCHPAD ;;; Use RCSCRATCH to draw a blob on the scratchpad ;;; NB the semi colon is essential after RCSCRATCH ['DRAW BLOB' [POP11 RCSCRATCH rc_draw_blob( 200 - random(400), 200 - random(400), 5 + random(60), oneof(['red' 'green' 'blue' 'white']));]] ;;; Start up the scratchpad blank ['SCRATCHPAD' [DEFER POP11 rc_scratch_window -> rc_current_window_object]] ;;; This saves (tears off) the previous scratchpad and starts ;;; a new one ['TEAROFF' rc_tearoff] ;;; this kills all the saved tearoffs ['KILL TEAROFFS' rc_kill_tearoffs] ;;; This hides the current scratchpad window ['HIDE PAD' [DEFER POP11 false -> rc_scratch_window ]] {counter Dpoints pop_pr_places 1} ['Editor...' [MENU editor]] ['Mail...' [MENU mail]] ;;; For the next one one see REF * POP_UI/pop_ui_edittool ['EditFile*' {[pop_ui_edittool ^false ^false '*' ^false]}] ['FastChoose*' menu_choosefile2] ['Autosave*' [ENTER 'autosave 5' ['Get VED to save all files, e.g. every 5 minutes' 'See HELP VED_AUTOSAVE']]] ['PurgeFiles*' [ENTER 'purgefiles *-' ['To delete all files matching a pattern, give the command' 'below with a pattern. Edit the pattern if necessary' 'After pressing Do, you will get a request for confirmation' 'of the form: "OK?(n=NO,RETURN=yes,s=show)"' 'Type s to show the files before deciding whether to delete.']]] ['ENTER' [INVED vedenter(); ]] {blob 'DISMISS' rc_hide_menu} {invisible 'KILL' rc_kill_panel} ]; This list is used below. /* Additional examples are in TEACH * RC_CONTROL_PANEL -- Making a column: create_button_column ------------------------------ */ uses rclib uses rc_buttons uses rc_button_utils ;;; NB the last command is needed to make available the extra ;;; procedures used below, e.g. for creating rows and columns ;;; of specific sorts of buttons. ;;; create a tall narrow window vars win2 = rc_new_window_object( 800, 20, 120, 650, {0 0 1 1}, newrc_button_window, 'win2'); ;;; We specify the default buttonwidth (false), and a buttonheight of 24 ;;; The default width should be 120, as above. vars colbuttons = create_button_column(0, 0, false, 24, 1, buttonlist, "action", false); Compile and mark all that. It should create a vertical column of buttons. Experiment on them (using left mouse button) to find out what they do. E.g. try the 999 button, which uses rc_message to display a message. Note the effect on the following variables after pressing various buttons: false -> rc_current_window_object; false -> rc_active_window_object; rc_current_window_object => rc_active_window_object => Try replacing one of the occurrences of "blob" with "invisible". The sensitive area for the invisible button will correspond to the height and width specified, i.e. roughly where it would have been if it were not invisible. The Dpoints button as before controls the number of decimal points shown in printing. It can be increased or decreased using left and right mouse buttons. The 'DRAW BLOB' button creates a new "scratchpad" window and draws a random blob in it. If you click on the DISMISS blob button it runs the procedure rc_hide_menu() which will remove the window and its buttons from view. It can be shown again with the command: rc_show_window(win2); If you click on KILL it runs the procedure rc_kill_panel which destroys the current window, after which rc_show_window will not work. If you have not destroyed the window, you can also relocate it if you wish, e.g.: 20,20,false,false -> rc_window_location(win2); (The third and fourth arguments should be false as they otherwise alter the width and height. See HELP * RC_WINDOW_OBJECTS ;;; Get rid of the window if necessary. rc_kill_window_object(win2); ;;; Try the above create_button_column command again, with a negative ;;; scale for y specified in the vector argument. It should still work vars win2 = rc_new_window_object( 800, 20, 120, 650, {0 0 1 -1}, newrc_button_window, 'win2'); vars colbuttons = create_button_column(0, 0, false, 24, 1, buttonlist, "action", false); ;;; Get rid of the window if necessary. rc_kill_window_object(win2); -- -- Exercise Copy and edit the above to create a window that uses the scratchpad facilities, plus a number of buttons to assign values to a variable holding a colour name (See HELP * XCOLOURS), and a counter button to set the radius of a blob, and then a button to draw a blob using the selected colour and the current radius. -- Making horizontal rows of buttons: create_button_row --------------- Create a new wide window. Make the fifth argument a "setframe" vector specifying that the origin of the window is the top left corner (0,0) and that rc_xscale and rc_yscale are both 1, so that x increases to the right and y downwards. uses rclib uses rc_buttons uses rc_button_utils vars win2 = rc_new_window_object( 20, 20, 1055, 51, {0 0 1 1}, newrc_button_window, 'win2'); Use the buttonlist from the previous section: ;;; We need the length of the list to shorten the list and split ;;; it in two. vars buttonlen = length(buttonlist); ;;; get the 22 last buttons, to make two rows of 11 vars newlist = allbutfirst(length(buttonlist) - 22, buttonlist); vars buttonlen = length(newlist); vars list1 = allbutlast(round(buttonlen/2 ), newlist), list2 = allbutfirst(intof(buttonlen/2 ), newlist), ; ;;; Now create the buttons and display them. Some of them may be a ;;; bit short for the text. If so increase the window width and the ;;; third argument of create_button_row: vars rowbuttons1 = create_button_row( 0,0,95,25,1, list1, "action", false), rowbuttons2 = create_button_row(0,26,95,25,1, list2, "action", false), ; ;;; After experimenting, destroy the window, using the KILL button or: rc_kill_window_object(win2); ;;; Now try the above on a window with origin near botton left and y ;;; going up (rc_yscale = -1) vars win2 = rc_new_window_object( 20, 20, 1055, 70, {0 70 1 -1}, newrc_button_window, 'win2'); vars rowbuttons1 = create_button_row( 0,70,95,25,1, list1, "action", false), rowbuttons2 = create_button_row(0,40,95,25,1, list2, "action", false); Note how each row is drawn as before, even though rc_yscale is now -1. If you click on the dismiss button to hide the window, bring it back with rc_show_window(win2); You can clear the current window with rc_start(); And then redraw it with rc_redraw_window_object(win2); Now destroy it. rc_kill_window_object(win2); -- Using create_button_columns ---------------------------------------- -- -- An array of buttons in three columns We now show how to use the more powerful procedure create_button_columns, which can create an array of several columns of buttons. For a change, we'll use different colours. Create a featurespec vector to be used in the drawing procedures below. Experiment with different versions of the featurespec. (See HELP * FEATURESPEC) vars array_specs= {rc_button_font '*lucida*-r-*sans-12*' ;;; Other possibilities '9x15'; '8x13', rc_button_stringcolour 'yellow' ;;; colour of label rc_button_bordercolour 'grey60' rc_button_labelground 'NavyBlue' rc_button_blobcolour 'ivory' rc_button_pressedcolour 'grey85' ;;; Alternatives might be ;;;'lightsalmon'; ;;; 'linen' ; ;;;'LightGrey'; }; Create a new window vars win2 = rc_new_window_object( 600, 20, 400, 360, {10 10 -4 -4}, newrc_button_window, 'win2'); ;;; an amount by which popmemlim can be incremented or decremented vars popmemliminc = 10000; ;;; Some of the actions here use facilities in the Birmingham ;;; menulib package. Replace actions that don't work with others ;;; of your choice. vars buttonarray = create_button_columns(0,0,125,30,5,3, [ 'sh who' 'dired' 'dired -l' 'dired -lt' 'dired -d' 'dired -dcd' 'qdired' sysgarbage {counter 'Mlim' ^(ident popmemlim) ^(ident popmemliminc) {bordercol 'yellow'}} {counter 'Dplaces' ^(ident pop_pr_places) 1} ['Print PI' [POP11 pi =>]] ['PageUP' vedprevscreen] ['PageDown' vednextscreen] ['GoSection' 'g'] ['MarkLo' vedmarklo] ['MarkHi' vedmarkhi] ['Editor(Ved)...' [MENU editor]] ['Mail...' [MENU mail]] {toggle 'Gctrace' popgctrace {borderwidth 8 bordercol 'orange'}} {toggle popsyscall popsyscall {borderwidth 8 bordercol 'orange'}} ['EditFile*' [ENTER 'ved ' 'Editing a new file - insert the name on right.']] ['Choosefile*' menu_choosefile1] ['FastChoose*' menu_choosefile2] ['Autosave*' [ENTER 'autosave 5' ['Get VED to save all files, e.g. every 5 minutes' 'See HELP VED_AUTOSAVE']]] ['PurgeFiles*' [ENTER 'purgefiles *-' ['To delete all files matching a pattern, give the command' 'below with a pattern. Edit the pattern if necessary' 'After pressing Do, you will get a request for confirmation' 'of the form: "OK?(n=NO,RETURN=yes,s=show)"' 'Type s to show the files before deciding whether to delete.' ]]] {blob 'ENTER' [POP11 vedenter(); vedrefreshstatus()]} {blob 'TopMenu...' [MENU toplevel]} {blob 'Dismiss' rc_hide_menu} {blob 'Kill' rc_kill_panel {rc_button_labelground 'brown'}} ], "action", array_specs); Because the array_specs featurespec vector is given separately as an argument to create_button_columns it cannot use the abbreviations. Notice that you can change the value assigned to the variable popmemliminc, and that will affect the amount by which the Mlim button changes when you click on it. ;;; You can examine the buttons buttonarray ==> rc_kill_window_object(win2); -- -- Additional examples: 4 and 6 columns ;;; Try 4 columns, without the featurespec above. ;;; Kill the previous window if necessary rc_kill_window_object(win2); vars win2 = rc_new_window_object( 650, 20, 121*4, 25*7, {0 0 1 1}, newrc_button_window, 'win2'); vars buttons = create_button_columns( 0, 0, 120, 24, 1, 4, buttonlist, "action", false); ;;; Try 6 columns rc_kill_window_object(win2); vars win2 = rc_new_window_object( 400, 20,121*6, 26*5, {0 0 1 1}, newrc_button_window, 'win2'); ;;; Now make a panel with 6 columns vars buttons = create_button_columns(1,1,120,25,1,6, buttonlist, "action", false); rc_kill_window_object(win2); -- Buttons on popup menus: rc_popup_query ----------------------------- To make the following facilities available, give the following commands uses rclib uses rc_popup_query The format is as follows: rc_popup_query( x,y, strings, answers, centre, columns, buttonwidth, buttonheight, font, bgcol, fgcol, specs, options) -> selection; This creates a window at location x, y on the screen. The window has a set of strings at the top, centred if the "centre" argument is true, and a row of answer buttons showing the elements of the answers list. It may have additional action buttons. If answers is the word "numbers", then the buttons will have automatically generated numbers, and the strings will be shown preceded by numbers. If it is the word "NUMBERS" and it is not a someof query (i.e. the last argument is not true) then an additional answer "None" is added to the list of numerical answers. The centre argument can be any of false (align the strings on left) true (centre the strings) "right" (align the strings on right) anything else counts as true. The font, bgcol, fgcol and specs arguments can influence the appearance. The final argument (options) determines whether the program waits for a COLLECTION of answers to be selected or only ONE answer. In the former case it is a "someof" query, in the latter a "oneof" query. If options is true, there will be an additional row of buttons at the bottom for the user to indicate that the selection is complete, or that all or none of the options is wanted. If the options argument is false, the program wants for you to select one of the answers, whose label is then returned. If it is true, then after the panel appears, you can turn answers on and off by clicking on buttons (which will change their colour to indicate whether they are on or off). Then you indicate that your selection is complete by selecting one of the three control buttons, labelled "ACCEPT", "ALL", and "NONE". A list of answers will be returned, namely a (possibly empty) list of labels of the selected buttons. If the process is interrupted (e.g. CTRL C) before the selection is made then rc_popup_query returns false. rc_popup_query uses the user-definable procedure rc_warp_to(win, x, y) to warp the mouse pointer to the centre of the new panel. Like rc_message-wait, it locally sets rc_sole_active_widget to hold the current widget so that all events in other widgets are disabled until this one is dismissed. -- -- Example invocations of selection menus First some sets of strings to be displayed at the tops of the menu panels. First some silly instruction and question strings, and lists of possible answers. vars strings= ['Now is the time' 'for all good men and women' 'to stand up' 'and be counted.' 'What is your answer?'], strings2 = ['yes please' 'no thanks' 'sometimes' 'never'], answers1 = [yes no maybe thanks], answers2 = [Apple Banana Carrot Dog], answers3 = [ 1 2 3 4], answers4 = [one two three four five six seven eight nine ten eleven twelve], ;;; Sometimes when a string is given as the label for a button ;;; you will want a word or number to be returned when the ;;; selection is made, as in these two examples answers5 = [['yes please' yes] ['no thanks' no] sometimes never], answers6 = [['yes please' 1] ['no thanks' 2] [sometimes 3] [never 4]], ; ;;; Try some additional specs which can change the appearance of buttons vars button_specs = {rc_button_font '8x13' rc_button_stringcolour 'yellow' rc_button_bordercolour 'red' rc_button_labelground 'brown' rc_chosen_background 'grey20'}; ;;; Try each of these, using mouse button 1 to select your answers ;;; Note that when the final argument is true, you will be shown a set ;;; of option buttons which can be turned on or off, as well as three ;;; buttons (Accept, All or None), to indicate that your selection is ;;; done. rc_popup_query( 300,30, strings, answers1, true, false, 80, 25, '9x15', 'pink', 'black', false, false) => ;;; Using "numbers" as the "answers" parameter makes the program offer ;;; numbered options corresponding to the strings ;;; Try with the button_specs featurespec vector to get different ;;; colours, etc. rc_popup_query( 500,300, strings2, "numbers", false, 2, 40, 25, '9x15', 'navyblue', 'yellow', button_specs, false) => ;;; The same again, but use "right" for the centre argument, to make ;;; the strings right justified (looks a bit silly) rc_popup_query( 500,300, strings2, "numbers", "right", 2, 40, 25, '9x15', 'navyblue', 'yellow', button_specs, false) => ;;; This is similar, but an extra optional answer is given because ;;; "NUMBERS" is in upper case. The extra option is "None" ;;; Use 5 columns rc_popup_query( 500,300, strings2, "NUMBERS", false, 5, 60, 25, '9x15', 'navyblue', 'yellow', button_specs, false) => ;;; Now try with the button_specs featurespec vector. This returns ;;; a list of words selected from answers1 rc_popup_query( 200,300, strings, answers1, true, 2, 80, 25, '10x20', 'black', 'white', button_specs, true) => ;;; This one always returns a list of words, from answers5 rc_popup_query( 200,300, strings, answers5, true, 2, 100, 25, '10x20', 'black', 'white', button_specs, true) => ;;; This returns a list of numbers, from answers6 rc_popup_query( 200,300, strings, answers6, true, 2, 100, 25, '10x20', 'black', 'white', button_specs, true) => ;;; This returns ONE item from answers6 rc_popup_query( 200,300, strings, answers6, true, 2, 100, 25, '10x20', 'black', 'white', button_specs, false) => rc_popup_query( 300,30, answers2, "numbers", false, 4, 40, 25, '8x13', 'black', 'pink', button_specs, true) => ;;; For a "someof" query, using "NUMBERS" is the same as "numbers" rc_popup_query( 300,30, answers2, "NUMBERS", false, 4, 40, 25, '8x13', 'black', 'pink', button_specs, true) => rc_popup_query( 300,30, strings, answers4, true, 2, 80, 25, '9x15', 'pink', 'black', button_specs, true) => rc_popup_query( 300,30, strings, answers4, true, 3, 80, 25, '12x24', 'black', 'pink', false, true) => rc_popup_query( 300,30, strings, answers4, true, 3, 80, 25, '9x15', 'gold', 'black', false, false) => rc_popup_query(300,30, strings, answers1, true, false, 80, 25, '8x13bold', 'pink', 'black', button_specs, true) => rc_popup_query( 300,30, strings, answers1, true, false, 80, 25, '9x15', 'pink', 'black', button_specs, true) => rc_popup_query( 300,300, strings, answers2, true, false, 100, 24, '9x15', false, false, false, true) => rc_popup_query( 300,300, strings, answers2, true, 2, 100, 24, '6x13', false, false, false, true) => rc_popup_query( 300,30,strings, answers1, true, false, 80, 24, '10x20', 'darkslategrey', 'yellow', false, false) => rc_popup_query( 300,30,strings, answers1, true, false, 80, 24, '10x20', 'darkslategrey', 'yellow', false, true) => ;;; Change the instructions at the top of menus '[[[PLEASE ANSWER TRUTHFULLY]]]' -> rc_popup_query_instruct; rc_popup_query( 300,300,strings,answers3, true, false, 40, 30, '*lucida*-r-*sans-14*', 'yellow', 'blue', false, false) => rc_popup_query( 10,300,answers2, "numbers", false, false, 40, 30, '*lucida*-r-*sans-14*', 'yellow', 'blue', false, false) => ;;; Change the instructions at the top, and the "action" buttons '[[INDICATE YOUR PREFERENCES]]' -> rc_popup_options_instruct; ['OK' 'The lot' 'Zilch'] -> rc_options_labels; rc_popup_query( 300,300,strings,answers3, true, 2, 40, 30, '*lucida*-r-*sans-14*', 'yellow', 'blue', false, true) => ;;; remove the instructions for select menus false -> rc_popup_query_instruct; ;;; Try new "instructions" rc_popup_query( 600,100,['What do you think?'],answers1, true, false, 80,30, '*lucida*-r-*sans-14*', 'yellow','blue', button_specs, false)=> rc_popup_query( 600,100,['Hi there'],answers1, true, 1, 80,30, '*lucida*-r-*sans-14*', 'yellow', 'blue', false, true) => -- -- Global variables for rc_popup_query rc_current_query This variable, accessible from button actions while rc_pop_query is running, holds the current window object containing the menu. rc_kill_window_object is applied to it on exit. rc_popup_query_instruct This holds false or the instruction string to be displayed at the top of the panel for a select menu. The default is '[SELECT ONE ANSWER]', rc_popup_options_instruct This holds false or the instruction string to be displayed at the top of the panel for an options menu. The default is '[SELECT OPTIONS]' rc_options_button_width rc_options_button_height These two variables control the size of the control buttons used at the bottom of an options panel. rc_options_labels This three element list of words or strings holds labels for the action buttons on an options menu, used to indicate that selection of options is complete. The default is [ACCEPT ALL NONE] If this list is changed then it may be necessary to redefine the following procedure, unless the new list has three words or strings with the same interpretation as these three words. define vars rc_getoptions(answer, buttons) -> options; ;;; get all the labels of buttons in buttons that have been selected lvars button, (accept, all, none) = explode(rc_someof_labels); if answer == none then [] elseif answer == all then maplist(buttons, rc_informant_value) else ;;; answer was accept rc_options_chosen(buttons) endif -> options enddefine; -- "Popup" Messages without buttons: rc_message ----------------------- rc_message(x,y, strings, spacing, centre, font, bgcol, fgcol) -> win; The procedure rc_message can be used to put up a message consisting of a lot of strings, using a specified font, font colour and background colour. The message stays up until you click on the window with mouse button 1, or press a key while the mouse pointer is in the window. As before the centre argument can be false, true or "right" rc_message returns the window_object as its result. If this is not saved then it is possible for the garbage collector to remove the window before you dismiss it. Examples follow: uses rclib uses rc_message ;;; First some strings to be displayed in messages. vars strings= ['Now is the time''for all good men and women''to stand up' 'and be counted,' 'for the price of freedom' 'is eternal vigilance']; ;;; Now display some message panels, then later dismiss them using ;;; mouse button 1 or pressing a key while the pointer is in the window. ;;; rc_message(x,y, strings, spacing, centre, font, bgcol, fgcol) -> win; rc_message(300,300,strings, 0, false, '9x15', false, false)->; rc_message(300,300,strings, 0, true, '9x15', false, false)->; rc_message(300,300,strings, 0, "right", '9x15', false, false)->; rc_message(200,300,strings,20, true, '9x15', 'pink', false)->; rc_message(300,300,strings,5, true, '9x15', 'orange', false)->; rc_message(300,200,strings <> strings,0, true, '8x13bold', false, false)->; rc_message(300,200,strings,0, true, '10x20', 'darkslategrey', 'yellow')->; rc_message( 300,300,strings<>strings ,0, true, '*lucida*-r-*sans-14*', 'yellow', 'blue')->; rc_message( 600,100,['Hi there'],0, true, '12x24', 'yellow', 'blue')->; rc_message(20,20, [% 'Hi there - this is a very long one line message from ' <> ' your friendly over confident computer', 'OK?' %], 0, true, '10x20', 'yellow', 'blue')->; -- -- Global variables for rc_message vars rc_message_instruct = '[CLICK TO DISMISS]', This string is automatically put at the front of the list of messages, followed by an empty string. Change this if you wish to have different instructions. If it is made false, the instructions are omitted. -- Messages that persist: rc_poster ----------------------- rc_poster( x,y, strings, spacing, centre, font, bgcol, fgcol) -> win_obj; The procedure rc_poster, like rc_message, can be used to put up a message consisting of a lot of strings, using a specified font, font colour and background colour. However, whereas the rc_message window is mouse sensitive the rc_poster window is not. So it remains until explicitly removed using rc_kill_window_object. rc_poster returns the window_object as its result. If this is not saved then it is possible for the garbage collector to remove the window eventually. As before the centre argument can be false, true or "right" Examples follow: uses rclib uses rc_poster ;;; First some strings to be displayed in messages. vars strings= ['Now is the time''for all good men and women''to stand up' 'and be counted,' 'for the price of freedom' 'is eternal vigilance']; ;;;rc_poster(x,y, strings, spacing, centre, font, bgcol, fgcol) -> win; vars posters = [% rc_poster(30,20,strings,0, false, '9x15', false, false), rc_poster(200,20,strings,20, true, '9x15', 'pink', false), rc_poster(30,300,strings,5, "right", '9x15', 'orange', false), rc_poster(250,200,strings <> strings,0, true, '8x13bold', false, false), rc_poster(800,20,strings,0, true, '10x20', 'darkslategrey', 'yellow'), rc_poster(300,300,strings<>strings ,0, true, '*lucida*-r-*sans-14*', 'yellow', 'blue'), rc_poster(600,100,['Hi there'],0, true, '12x24', 'yellow', 'blue'), rc_poster(20,150, [% 'Hi there - this is a very long one line message from ' <> ' your friendly over confident computer', 'OK?' %], 0, true, '10x20', 'yellow', 'blue') %]; Because the poster windows are not mouse sensitive they can only be got rid off via rc_kill_window_object. applist(posters, rc_kill_window_object); -- A variant that waits: rc_message_wait ------------------------------ rc_message_wait(x,y, strings, spacing, centre, font, bgcol, fgcol); The procedure rc_message_wait is like rc_message in the arguments it takes, but it does not return any result, and the procedure does not return unless you click on the window, or press a key, or invoke interrupt. It also uses rc_warp_to to make the mouse pointer move to the window. It locally sets rc_sole_active_widget to hold the current widget so that all events in other widgets are disabled until this one is dismissed. The centre argument can be false, true or "right" uses rclib uses rc_message_wait ;;; First some strings to be displayed in messages. vars strings= ['You are now seeing' 'a demonstration of the' 'rc_message_wait procedure.' 'It will not continue' 'until you dismiss this window']; ;;; Now display some message panels, then dismiss them using ;;; mouse button 1 or pressing a key while the pointer is in the window. ;;;rc-message_wait(x,y, strings, spacing, centre, font, bgcol, fgcol); rc_message_wait(300,300,strings,0, true, '9x15', false, false); rc_message_wait(300,300,strings,0, false, '9x15', false, false); rc_message_wait(300,300,strings,0, "right", '9x15', false, false); rc_message_wait(200,300,strings,20, true, '9x15', 'pink', false); rc_message_wait(300,200,strings,0, true, '10x20', 'darkslategrey', 'yellow'); rc_message_wait( 600,100,['Hi there'],0, true, '12x24', 'yellow', 'blue'); rc_message_wait(20,20, [% 'Hi there - this is a very long one line message from ' <> ' your friendly over confident computer', 'OK?' %], 0, true, '10x20', 'yellow', 'blue'); The global variable rc_message_wait_instruct should hold false or a string to be used to specify instructions at the top of the panel. If it is made false, the instructions are omitted. Previously rc_message_wait could not be invoked from a control panel produced by rc_control_panel, or arbitrary action buttons. This has now been fixed. -- Radio buttons and someof buttons ----------------------------------- This section shows how to create a panel which includes o radio buttons, which allow only one item to be selected at a time, o someof buttons, which allow any subset to be selected or deselected. Appropriate actions are performed when individual buttons are selected or deselected. For the radio buttons we'll have a message panel put up displaying the selected colour. For the oneof buttons we have text messages printed out as the individual buttons are selected or deselected. The examples shown here can be used to create a panel of radio buttons or of someof buttons at a specified location in a window which contains other things. For a generic facility for creating control panels including these buttons see HELP * RC_CONTROL_PANEL, with illustrations in TEACH * RC_CONTROL_PANEL and LIB * RC_POLYPANEL. In general using rc_control panel is easier. A simpler example is provided in TEACH * RCLIB_DEMO.P ;;; When you experiment with the buttons with colour names. Note what ;;; happens if you click twice on one of the "someof" buttons. uses rclib uses rc_button_utils uses rc_message ;;; Radio buttons allow you to select one at a time only. ;;; Someof buttons allow any any subset to be on or off ;;; Use this to record previous message put up, in case it needs to be ;;; removed vars last_message = false; define show_selected(button); ;;; When a radio button has been selected with a colour name, put ;;; up a message using the colour as the background. dlocal rc_message_instruct = '[FOR INFORMAION]'; lvars label = rc_button_label(button), content = rc_real_contents(button), strings = ['The selected item is now' ^label %' i.e. ' >< content% '' 'Thank you']; if last_message then rc_kill_window_object(last_message); false -> last_message; endif; content => rc_message(300,300, strings, 0, true, '10x20', content, 'black') -> last_message; enddefine; define selecting_someof(button); ;;; Report selection of a someof button [selecting ^(rc_button_label(button)) : ^(rc_real_contents(button)) ] => enddefine; define deselecting_someof(button); ;;; Report deselection of a someof button [Deselecting ^(rc_button_label(button)) : ^(rc_real_contents(button)) ] => enddefine; ;;; We make a list of labels for the radio buttons and the someof ;;; buttons created below. Each item is a two element list, where ;;; the first element is the string to be displayed on the button ;;; and the second is the item to be stored in the rc_real_contents ;;; slot of the button. (If we used only a list of strings, then ;;; each button would use its string both as its label and as its ;;; real contents.) vars radio_labels = [['Y' 'yellow'] ['P' 'pink'] ['O' 'orange'] ['Go' 'gold'] ['I' 'ivory'] ['Gr' 'green'] ['B' 'blue'] ['C' 'cyan']]; ;;; Create a window large enough to hold the two arrays of buttons and a ;;; cancel button, with origin in top left corner and y axis going down. vars panel = rc_new_window_object( 650, 20,71*4, 26*7, {0 0 1 1}, newrc_button_window, 'panel'); ;;; Now create the two lots of buttons, using featurespecs to set the ;;; actions. vars radio_buttons = create_radio_button_columns( 0,0,70,25,1,4, 'Choose your colour (only one)', radio_labels, {rc_radio_select_action ^show_selected }), someof_buttons = create_someof_button_columns( 0,75,70,25,1,4, 'Select/deselect some colours (any number)', radio_labels, {rc_radio_select_action ^selecting_someof rc_radio_deselect_action ^deselecting_someof rc_button_bordercolour 'black' }); ;;; add a cancel button panel -> rc_current_window_object; create_rc_button( 0, 150, 75, 22, ['Cancel' rc_kill_panel], "blob", false); /* -- -- Accessing and changing the state of radio and someof buttons */ We have created these buttons radio_buttons ==> someof_buttons ==> There are many procedures available for operating on them, defined in HELP RC_BUTTONS HELP RC_CONTROL_PANEL Try this before and after clicking on the first radio button. It prints a boolean value: rc_button_value(radio_buttons(1)) => This returns the label, a string, of the currently selected radio button or a list of the labels of selected someof buttons. rc_options_chosen(radio_buttons) => rc_options_chosen(someof_buttons) => This returns the rc_real_contents of the currently selected radio button or a list of the contents of selected someof buttons. rc_values_chosen(radio_buttons) => rc_values_chosen(someof_buttons) => This can be changed by program commands also: rc_set_radio_buttons('B', radio_buttons); rc_set_radio_buttons('C', radio_buttons); rc_options_chosen(radio_buttons) => rc_values_chosen(radio_buttons) => rc_set_radio_buttons('B', radio_buttons); It is also possible to do a selection by running the button 1 down event handler for the selected button, rc_rcbutton_1_down. But this requires rc_current window_object to be set, so do this: SETWINDOW panel; Turn on radio button 1 then turn it off by turning on radio button 3, and after each operation examine the settings: rc_rcbutton_1_down(radio_buttons(1), 0, 0, nullstring); rc_rcbutton_1_down(radio_buttons(3), 0, 0, nullstring); rc_button_value(radio_buttons(1)) => rc_button_value(radio_buttons(3)) => rc_options_chosen(radio_buttons) => rc_informant_value(radio_buttons(1)) => rc_informant_value(radio_buttons(3)) => rc_values_chosen(radio_buttons) => Note that here the rc_button_value result is a boolean whereas the result of rc_informant_value is the string that is the label of the button. Similar things can be done with the someof buttons. Try turning the first and third buttons on and off, and check the following commands: rc_button_value(someof_buttons(1)) => rc_button_value(someof_buttons(3)) => The following now returns a (possibly empty) list of label strings, not just a single label: rc_options_chosen(someof_buttons) => rc_values_chosen(someof_buttons) => Try changing the selection among the someof buttons and running that command. The selections among the someof buttons can be altered using the procedure rc_set_someof_buttons as follows: rc_set_someof_buttons(['P' 'Go' 'B'], someof_buttons); rc_options_chosen(someof_buttons) => rc_values_chosen(someof_buttons) => rc_set_someof_buttons([], someof_buttons); rc_set_someof_buttons("none", someof_buttons); rc_set_someof_buttons("all", someof_buttons); rc_options_chosen(someof_buttons) => Run this one twice: It toggles the corresponding values rc_change_someof_buttons(['P' 'Go' 'B'], someof_buttons); Or, alternatively: ;;; Doing the following repeatedly causes the state to ;;; change back and forth SETWINDOW panel; rc_rcbutton_1_down(someof_buttons(1), 0, 0, nullstring); ;;; This gives the string that is the label of the button. rc_button_label(someof_buttons(1)) => ;;; Compare rc_real_contents(someof_buttons(1)) => rc_button_value(someof_buttons(1)) => rc_informant_value(someof_buttons(1)) => We can get at the containing window from the button rc_button_container(someof_buttons(1)) => -- Complete list of action specifications for action buttons ---------- See LIB * RC_BUTTONS/rc_do_button_action This is what happens by default) when you click on an action button, expressed in Pop-11 for now (in the method define :method rc_do_button_action(pic:rc_action_button); ;;; Action to be performed when mouse pic is released. ;;; action will determine the action ;;; Re-enable events. Is this safe ? dlocal rc_in_event_handler = false; lvars real_action, action = rc_button_action(pic); ;;; in case it is a word or identifier, get its valof recursive_valof(action) -> action; if isident(action) then idval(action) -> action endif; if isclosure(action) and pdpart(action) == rc_defer_apply then action(); ;;;process_defer_list(); return; elseif isprocedure(action) then ;;; Includes closures ;;; Do it in "defer" mode ;;; rc_active_window_object=> rc_async_apply(action, false); elseif islist(action) then if front(action) == "POPNOW" then ;;; should no longer arise: 'POPNOW action not expected '>< action => back(action) -> action; procedure(); dlocal vedediting = vedinvedprocess and isstring(rc_charout_buffer); lvars proc = recursive_valof(front(action)); if isprocedure(proc) then ;;; do it without deferring rc_async_apply(proc, false); else ;;; This is generally unsafe with POPNOW! async_interpret_action(action) endif; endprocedure(); else rc_async_apply(async_interpret_action(%action%), false) endif elseif isvector(action) and isstring(action(1) ->> real_action) then ;;; vector containing string: treat as pop11 instruction to be ;;; compiled and run rc_async_apply(pop11_compile(%stringin(real_action)%), false) elseif isvector(action) and islist(action(1) ->> real_action) then ;;; treat list as procedure (or procedure name) plus args rc_async_apply( recursive_valof(front(real_action))(% explode(back(real_action))%), false) elseif isstring(action) then ;;; treat as ved command rc_async_apply(veddo(%action,true%), false) else mishap('UNKNOWN ACTION TYPE IN ', [^action ^rc_active_picture_object]) endif; if vedusewindows == "x" and not(vedinvedprocess) then ;;; The next one sometimes causes an error ;;; vedinput(rc_flush_everything); XptSetXtWakeup(); else rc_flush_everything(); endif; enddefine; -- Default values for global variables in LIB rc_buttons -------------- This was the situation as of 28 Jul 2002 define :rc_defaults; ;;; total height of button rc_button_height_def = 24; ;;; total length of button rc_button_width_def = 120; ;;; default border width rc_button_border_def = 3; ;;; standard font for label rc_button_font_def = '-adobe-helvetica-bold-r-normal-*-10-*-*-*-p-*-*-*'; ;;; Other possibilities '9x15'; '8x13'; ;;; '*lucida*-r-*sans-10*'; ;;; colour of text label rc_button_stringcolour_def = 'black'; ;;; make this non-zero to get a blob on action button rc_button_blobrad_def = 0; ;;; If there's a blob to left of label use this colour rc_button_blobcolour_def = 'grey50'; ;;; This is "blob" size for "display" buttons, e.g. ;;; e.g. toggle, counter, radio, someof buttons rc_button_default_blobrad = 5; ;;; colour of border rc_button_bordercolour_def = 'grey60'; ;;; colour of border of action button when pressed rc_button_pressedcolour_def = 'grey75'; ;;;'lightsalmon'; ;;; 'linen' ; ;;;'LightGrey'; ;;; colour of background to label rc_button_labelground_def = 'white'; ;;; background colour for option button when pressed rc_button_chosenground_def = 'grey75'; ;;; Toggle button shows true or false using one of these labels ;;; can easily be replaced with another pair of strings. rc_toggle_labels_def = {' (T)' ' (F)'}; ;;; Counter buttons show the number between brackets. Use ;;; these as default rc_counter_brackets_def = {'[' ']'}; ;;; Make this false to prevent attempts to redirect output ;;; when action buttons cause printing async_vedbuffer = 'output.p'; enddefine; -- SUMMARY OVERVIEW The following information was consistent with LIB RC_BUTTONS on 30 Jul 2002. Since the code libraries may change look in that file if necessary, to get the latest correct information. -- -- The main mixins: rc_button, rc_display_button define :mixin vars rc_button; is rc_linepic, rc_selectable, rc_informant; slot rc_button_label = '??Label??'; slot rc_button_height = rc_button_height_def; slot rc_button_width = rc_button_width_def; slot rc_button_border = rc_button_border_def ; slot rc_button_font = rc_button_font_def ; slot rc_button_stringcolour = rc_button_stringcolour_def; slot rc_button_bordercolour = rc_button_bordercolour_def; slot rc_button_labelground = rc_button_labelground_def; slot rc_button_blobrad = 0; ;;; Not needed. Inherits from rc_informant ;;; slot rc_informant_value ;;; Sensitivity rectangle for buttons ;;; This needs to be kept consistent with height and width of button slot rc_mouse_limit = {%rc_button_border_def/rc_xscale, rc_button_border_def/rc_yscale, (rc_button_width_def-rc_button_border_def)/rc_xscale, (rc_button_height_def-rc_button_border_def)/rc_yscale%}; ;;; This specifies the drawing procedure to be used slot rc_pic_lines == "rc_draw_button"; slot rc_button_up_handlers = { rc_rcbutton_1_up rc_button_do_nothing rc_button_do_nothing}; slot rc_button_down_handlers = { rc_rcbutton_1_down rc_button_do_nothing rc_button_do_nothing}; slot rc_drag_handlers = {rc_button_do_no_drag rc_button_do_no_drag rc_button_do_no_drag }; slot rc_move_handler = "rc_button_do_nothing"; slot rc_button_container == undef; enddefine; ;;; This is used for toggle, counter, radio and someof buttons define :mixin vars rc_display_button; ;;; No longer has a border: has a square or blob to left of label ;;; square for counter and toggle buttons. ;;; blob for someof and radio buttons slot rc_button_labelground = 'grey95'; slot rc_button_blobcolour = rc_button_blobcolour_def; slot rc_button_blobrad = rc_button_default_blobrad; enddefine; -- The main button classes: action, blob, toggle,etc. define :class vars rc_action_button; is rc_button; slot rc_button_action = identfn; slot rc_button_pressedcolour = rc_button_pressedcolour_def; enddefine; define :class vars rc_invisible_action_button; is rc_action_button; ;;; This needs to be kept consistent with height and width ;;; Default box below and to right of button location. slot rc_mouse_limit = {0 0 20 -20}; slot rc_drag_handlers = {rc_drag_invisible ^false ^false}; enddefine; define :class vars rc_blob_button; is rc_action_button; ;;; for action buttons with blob on left. slot rc_button_blobcolour = rc_button_blobcolour_def; slot rc_button_blobrad = rc_button_blobrad_def; enddefine; define :class vars rc_toggle_button; is rc_display_button rc_button; ;;; These are buttons with an extra boolean field slot RC_informant_value = false; ;;; NB the same vector is shared by all instances. ;;; So make a copy if some are to have different toggle_labels. slot rc_toggle_labels = rc_toggle_labels_def; enddefine; define :class vars rc_counter_button; is rc_display_button rc_button; ;;; These are buttons with a number and an increment. ;;; Clicking with button 1 increases the number by the increment. ;;; Clicking with button 3 decreases it. ;;; Removed rc_counter_value 29 Mar 1999 slot rc_counter_inc = undef; slot rc_counter_min = false; slot rc_counter_max = false; ;;; the number will be printed inside these values slot rc_counter_brackets = rc_counter_brackets_def; slot rc_button_down_handlers == { rc_rcbutton_1_down rc_button_do_nothing rc_rcbutton_3_down }; slot rc_original_label = false; enddefine; -- -- Option buttons and radio and someof subclasses The top level class here is rc_option_button, for which rc_radio button and rc_someof_button are descendants. The design for these was altered around September 2002 to give them a clearer structure. Since these inherit from rc_informant, they also have an rc_informant_value slot (previously called rc_informant_contents). This value is normally a boolean, true for a button when it is in the selected state, otherwise false. In addition each has a label, rc_button_label, which normally does not change, though it could change. Finally each can have an additional value associated with it in the slot rc_real_contents. So for example a button may have as its rc_button_label the string 'My papers', and have as its rc_real_contents a string which is a file name, or some other object. In the standard specification for a button of one of these types the label can be specified as a string, whereas it it is a two element list, the first element is the string to be used as label and the second element is held in the rc_real_contents slot. define :class vars rc_option_button; is rc_display_button rc_button; ;;; These are buttons to be used in an array of options, where ;;; any subset of the options can be selected or unselected slot RC_informant_value == false; slot rc_real_contents == false; slot rc_chosen_background = rc_button_chosenground_def; enddefine; define :class vars rc_radio_button; is rc_option_button; ;;; These are buttons to be used in an array of options, where ;;; choosing one option undoes the choice of a different option slot rc_radio_list = []; ;;; list of sibling buttons slot rc_radio_select_action = erase; slot rc_radio_deselect_action = erase; enddefine; define :class vars rc_someof_button; is rc_radio_button; ;;; Allow any number in the list to be turned on ;;; will have slightly different methods enddefine; -- Procedures for creating individual buttons or collections ---------- -- -- Procedures in LIB RC_BUTTONS create_rc_button(x, y, width, height, contents, type, specs) -> button; Create an individual button, of whatever type create_button_columns(x, y, width, height, spacing, columns, list, type, specs) -> buttons; Display a list of buttons in a row, or in one or more columns, in an array with top left corner at location x, y. -- -- Procedures in LIB RC_BUTTON_UTILS These procedures are all subsumed by create_rc_button and create_button_columns. The command uses rc_button_utils will load all these. Alternatively they can be autoloaded, as they all have files linked to rclib/lib/rc_button_utils create_action_button(x, y, width, height, label, action, specs) -> button; create_blob_button(x, y, width, height, label, action, specs) -> button; create_option_button(x, y, width, height, label, specs) -> button; create_select_button(x, y, width, height, label, specs) -> button; create_radio_button_columns( x, y, width, height, spacing, columns, string, list, specs) -> buttons; Create and display a set of radio buttons, with a message given by string create_someof_button_columns( x, y, width, height, spacing, columns, string, list, specs) -> buttons; Create and display a set of someof buttons, with a message given by string create_button_row( x, y, width, height, spacing, list, type, specs) -> buttons; create_button_column( x, y, width, height, spacing, list, type, specs) -> buttons; Create and displays just one column of buttons -- Summary contents of LIB RC_BUTTONS --------------------------------- -- -- New class of window object (rc_button_window) define :class vars rc_button_window; is rc_window_object; define :method rc_realize_window_object(win_obj:rc_button_window); -- -- Globals holding default values for button appearance define :rc_defaults; -- -- rc_button and rc_display_button mixins define :mixin vars rc_button; define :mixin vars rc_display_button; To examine the available slots see LIB * RC_INFORMANT/':mixin' LIB * RC_BUTTONS/':mixin rc_button' LIB * RC_BUTTONS/':mixin rc_display_button' -- -- The main button classes: action, blob, toggle,etc. See LIB * RC_BUTTONS/':class rc_action_button' define :class vars rc_action_button; is rc_button; define :class vars rc_invisible_action_button; is rc_action_button; define :class vars rc_blob_button; is rc_action_button; define :class vars rc_toggle_button; is rc_display_button rc_button; define :class vars rc_counter_button; is rc_display_button rc_button; define :class vars rc_option_button; is rc_display_button rc_button; define :class vars rc_radio_button; is rc_option_button; define :class vars rc_someof_button; is rc_radio_button; -- -- Utility methods define :method rc_move_to(pic:rc_button, x, y, trail); -- -- Generic button methods for values/contents, etc. define lconstant DEREF(item) -> item; define :method rc_button_value(pic:rc_display_button) -> val; define :method updaterof rc_button_value(val, pic:rc_display_button); define :method updaterof rc_button_value(val, pic:rc_radio_button); define :method rc_toggle_value(pic:rc_toggle_button); define :method updaterof rc_toggle_value(val, pic:rc_toggle_button); define :method rc_counter_value(pic:rc_counter_button); define :method updaterof rc_counter_value(val, pic:rc_counter_button); define :method rc_option_chosen(pic:rc_option_button); define :method updaterof rc_option_chosen(val, pic:rc_option_button); define :method updaterof rc_informant_value(val, button:rc_display_button); define :method updaterof rc_informant_value(val, button:rc_counter_button); -- -- Some dummy methods for buttons with missing slots (for harmless use in spec vectors). These all have updaters that just pick up the item and do nothing. define :method updaterof rc_button_pressedcolour(x, pic:rc_button); define :method updaterof rc_button_blobcolour(x, pic:rc_button); define :method updaterof rc_button_blobrad(x, pic:rc_button); define :method updaterof rc_counter_brackets(x, pic:rc_button); define :method updaterof rc_toggle_labels(x, pic:rc_button); define :method updaterof rc_chosen_background(x, pic:rc_button); define :method updaterof rc_radio_select_action(x, pic:rc_button); define :method updaterof rc_radio_deselect_action(x, pic:rc_button); -- -- Utility methods and procedures define :method print_instance(pic:rc_button); define :method print_instance(pic:rc_display_button); define :method print_instance(pic:rc_counter_button); define :method print_instance(pic:rc_toggle_button); define :method print_instance(pic:rc_radio_button); define :method print_instance(pic:rc_someof_button); define :method print_instance(pic:rc_action_button); -- -- Drawing methods and procedures for buttons define lconstant DRAW_OB(x, y, xinc, yinc, width, height, border, radius, colour); define :method rc_draw_border_shape(pic:rc_button, x, y, width, height, border, halfborder, colour); define :method rc_draw_border(pic:rc_button, colour); define :method rc_draw_border(pic:rc_invisible_action_button, colour); define :method rc_setframe_draw_border(pic:rc_button, colour); define :method rc_setframe_draw_border(pic:rc_invisible_action_button, colour); define :method rc_draw_button_type(pic:rc_display_button, blobrad, height, colour); define :method rc_draw_button_type(pic:rc_radio_button, blobrad, height, colour); define :method rc_draw_button_type(pic:rc_someof_button, blobrad, height, colour); define :method rc_offset_print_button_label(pic:rc_button, stringx, stringy, label); define :method rc_offset_print_button_label(pic:rc_display_button, stringx, stringy, label); define :method rc_offset_print_button_label(pic:rc_invisible_action_button, stringx, stringy, label); define :method rc_string_offset(pic:rc_button, border, blob_rad) -> offset; define :method rc_string_offset(pic:rc_display_button, border, blob_rad) -> offset; define :method rc_draw_button_string(pic:rc_button, blob_rad, border, width, height); define :method rc_draw_border_or_blob(pic:rc_button); define :method rc_draw_button_blob(pic:rc_display_button); define :method rc_draw_border_or_blob(pic:rc_display_button); define :method draw_action_blob(pic:rc_button, mid, border, blob_rad); define :method rc_draw_button_background(pic:rc_button, mid, border, blob_rad, width, height); define :method rc_draw_button_background(pic:rc_display_button, mid, border, blob_rad, width, height); define :method rc_draw_button(pic:rc_button); This is the default procedure associated with the rc_pic_lines slot of button instances. It draws a button by drawing its background, then the border, then the label string. It uses: rc_draw_button_background(pic, mid, border, blob_rad, width, height); rc_draw_border_or_blob(pic); rc_draw_button_string(pic, blob_rad, border, width, height); define :method rc_draw_button(pic:rc_invisible_action_button); define :method rc_draw_button(pic:rc_toggle_button); define vars rc_DRAWBUTTON(pic); -- -- Undrawing methods for buttons define :method rc_undraw_button_background(pic:rc_button, mid, border, blob_rad, width, height); define :method rc_undraw_button(pic:rc_button); define :method rc_undraw_linepic(pic:rc_button); -- -- Mouse and motion methods for windows and buttons define :method rc_button_1_up(win_obj:rc_button_window, x, y, modifiers); define :method rc_mouse_exit(win_obj:rc_button_window, x, y, modifiers); define :method rc_button_do_nothing(pic:rc_button, x, y, modifiers); define :method rc_button_do_no_drag(pic:rc_button, x, y, modifiers); define :method rc_drag_invisible(pic:rc_invisible_action_button, x, y, modifiers); define :method rc_rcbutton_1_down(pic:rc_button, x, y, modifiers); define :method rc_rcbutton_1_up(pic:rc_button, x, y, modifiers); -- -- Facilities for action buttons define rc_async_apply(proc, deferring); This is the default procedure that runs actions associated with action buttons (when the mouse button is released). The button procedure may be run immediately or deferred. This is designed to support actions manipulating Ved files, e.g. opening new files, rotating or swapping files, etc. But does not warp the Xved context. It is a long and complex procedure defined in LIB rc_buttons. Some of the complications to be dealt with are discussed in HELP RC_EVENTS define :method rc_async_apply_action(pic:rc_button, action_type); ;;; handle the action in an appropriate context, e.g. to ensure that ;;; printing goes to the right place. ;;; This method could be redefined for some types of buttons to avoid ;;; the use of rc_async_apply define :method rc_do_button_action(pic:rc_action_button); The main action method for buttons. Invoked when the button is released. See full definition above. define :method rc_rcbutton_1_down(pic:rc_action_button, x, y, modifiers); define :method rc_rcbutton_1_down(pic:rc_invisible_action_button, x, y, modifiers); When mouse button 1 is depressed in an action button, pic -> rc_selected_action_button; and this method is invoked: rc_setframe_draw_border(pic, rc_button_pressedcolour(pic)); I.e. the button appearance is changed to show that the button has been selected and the mouse button is still held down. define vars do_rcbutton_1_up(pic, x, y, modifiers); define :method rc_rcbutton_1_up(pic:rc_action_button, x, y, modifiers); define :method rc_rcbutton_1_up(pic:rc_invisible_action_button, x, y, modifiers); If the mouse button is released with the mouse pointer within the button limits, the action will be performed, otherwise the action will not be performed. When the button is released (whether the action is performed or not) this redraws the border to its normal appearance: rc_setframe_draw_border(pic, rc_button_bordercolour(pic)); -- -- Facilities for display buttons define :method switch_rc_toggle_value(pic:rc_toggle_button); define :method rc_rcbutton_1_down(pic:rc_toggle_button, x, y, modifiers); define :method rc_rcbutton_1_up(pic:rc_toggle_button, x, y, modifiers); -- -- Facilities for counter buttons define lconstant procedure stack_chars_from(item); define :method rc_draw_button(pic:rc_counter_button); define lconstant restrict_to_range(val, minval, maxval) -> val; define :method rc_increment_counter(pic:rc_counter_button, up); define :method rc_rcbutton_1_down(pic:rc_counter_button, x, y, modifiers); define :method rc_rcbutton_1_up(pic:rc_counter_button, x, y, modifiers); define :method rc_rcbutton_3_down(pic:rc_counter_button, x, y, modifiers); -- -- Facilities for option buttons define :method rc_draw_button(pic:rc_option_button); define :method rc_rcbutton_1_down(pic:rc_option_button, x, y, modifiers); define rc_button_with_label(item, buttonlist) -> button; Check that item, usually a string, is one of the labels of the buttons in the list. Return the button or false. Used in rc_button_in_field_in_panel described in HELP RCLIB define rc_options_chosen_for(buttons, procedure proc) -> options; This is partially applied to eithe rc_button_label or rc_real_contents, to get the next two procedures. define rc_options_chosen(buttons) -> options; The argument is a list of radio or someof buttons. Return a list of all labels of the chosen options. Stop after first if it's a radio button. If they are radio buttons and nothing is found return false. If they are someof buttons return a list. define rc_values_chosen(buttons) -> options; As for rc_options_chosen, except that instead of returning the button label or labels it returns the rc_real_contents of the buttons that are selected. For examples of use see above, and also TEACH * RCLIB_DEMO.P/rc_values_chosen TEACH * RC_CONTROL_PANEL/rc_options_chosen, HELP * RC_CONTROL_PANEL/rc_options_chosen, There is also an updater: define updaterof rc_options_chosen(options, buttons); This uses rc_set_button_defaults, defined above. Note the warning. -- -- Facilities for radio buttons define :method rc_rcbutton_1_down(pic:rc_radio_button, x, y, modifiers); define rc_set_radio_buttons(item, buttons); Item is a button label, usually a string. Set the button with that label to be on, and the others off. For examples see HELP rc_control_panel define rc_set_button_defaults(buttons, wid, def, buttontype); Set the default button or buttons either on the basis of the associated word or identifier wid, if set or the default def, which may come from from a field in rc_control_panel Let wid have the priority unless the value is undef, or an undef instance. buttontype is one of "radio" and "someof" Warning: rc_current_window_object must have been set -- -- Facilities for someof buttons define :method rc_rcbutton_1_down(pic:rc_someof_button, x, y, modifiers); define set_or_unset_someof_buttons_to(list, buttons, setting); ;;; List is either empty, which means deselect all the buttons, ;;; or a list of labels of buttons (usually strings). Select all the ;;; buttons in list, leaving any others that were previously selected ;;; still selected. If list is the world "all", then select every one. ;;; If it is "none" unset all For examples see HELP rc_control_panel define rc_set_someof_buttons = set_or_unset_someof_buttons_to(%true%) define rc_unset_someof_buttons = set_or_unset_someof_buttons_to(%false%) define rc_change_someof_buttons = set_or_unset_someof_buttons_to(%undef%) -- -- Abbreviations for feature spec items define procedure rc_button_spectrans = newproperty( define expand_button_spec_abbreviations(spec) -> spec; -- -- Utilities for modifying buttons during creation define vars rc_update_button_mouse_limit(button, oldborder, oldheight, oldwidth); define :method modify_instance(button:rc_button, contents, type); define :method modify_instance(button:rc_action_button, contents, type); define :method modify_instance(button:rc_invisible_action_button, contents, type); define :method modify_instance(button:rc_display_button, contents, type); define :method modify_instance(button:rc_toggle_button, contents, type); define :method modify_instance(button:rc_counter_button, contents, type); define :method modify_instance(button:rc_option_button, contents, type); -- -- Utilities for creating new buttons ;;; User extendable property for abbreviating button types define procedure rc_button_type_key = newproperty( define rc_button_key_of_type(type) -> key; ;;; if the type is a word, find the corresponding key. If it is already ;;; a key, return it define create_rc_button(x, y, width, height, contents, type, specs) -> button; ;;; Type is either a recognised word, e.g. "toggle", "counter", "action" ;;; or a class key. The location of the button is at x, y. ;;; The specs can be used to override default slots. It is false ;;; or a vector of form {field val field val field val....}, ;;; as described in REF * OBJECTCLASS/create_instance, * OBJECTCLASS/set_slots ;;; or a list of such vectors, or a list of lists, etc. -- -- Procedures for creating rows, columns and arrays of buttons define create_button_columns(x, y, width, height, spacing, columns, list, type, specs) -> buttons; This is used heavily in rc_control_panel. It is perhaps the most flexible procedure for creating button arrays. define rc_inform_button_siblings(buttons); Used when a collection of related buttons is created. It informs each of them about all the others, so that if any button is selected it can invoke an appropriate action involving any or all of the others, e.g. in radio buttons. -- -- Additional facilities in LIB RC_POPUP_QUERY define :class rc_select_button; is rc_option_button; define :method rc_draw_button_type(pic:rc_select_button, offset, height, colour); -- -- Facilities for select buttons See LIB * RC_POPUP_QUERY/'rc_select_button' define :method rc_rcbutton_1_down(pic:rc_select_button, x, y, modifiers); define :method rc_rcbutton_1_up(pic:rc_select_button, x, y, modifiers); define :method rc_undo_selected(win_obj:rc_selectable, x, y, modifiers); define lconstant trynumber(numbers_wanted, answer) -> answer; define vars rc_getoptions(answer, buttons) -> options; define rc_popup_query(x,y, strings, answers, centre, columns, buttonW, buttonH, font, bgcol, fgcol, specs, options) -> selection; -- -- Facilities in LIB RC_INFORMANT A method inherited from rc_informant, by all these button classes, is rc_informant_value, which can be used by application procedures to access or store information used by event handlers. For more details see HELP RCLIB/rc_informant The use of constraints and reactors is illustrated in TEACH rc_constrained_panel -- -- Additional autoloadable library procedures: The following may be usefully invoked from action buttons. define rc_hide_panel(); define rc_kill_panel(); define rc_redraw_this_panel(); -- Getting from a button or button list to its container -------------- If button is added directly to a window, then the slot method rc_button_container(button) will return the window object. For example vars win1 = rc_new_window_object( "right", "top", 240, 100, true, newrc_button_window, 'win1'); Add a kill button: vars kill_button = create_rc_button(-90, 40, 95, 29, ['KILL ME' rc_kill_panel], "action", [{font '12x24'}]); This will print out the container. rc_button_container(kill_button) => We can add a row of three buttons: vars buttonrow = create_button_columns(-95,0,65,20,4,3, [ 'sh who' ['PageUP' vedprevscreen] ['PageDown' vednextscreen] ], "action", []); To find the container of the list, select its first element and get the container of that: rc_button_container(hd(buttonrow)) => This should again be the window object win1. However, if we get a button list out of a panel created by rc_control_panel, then the container of each button will be a field in the control panel, and that will in turn have the window_object as its container. Create a simple example vars buttonpanel = rc_control_panel(500, 20, [ [ACTIONS {label demo} {width 90} {height 30} {cols 3} : ['DISMISS' rc_kill_panel] ['PageUP' vedprevscreen] ['PageDown' vednextscreen] ] ] , 'Container Demo'); Because the set of ACTIONS buttons is in a control panel, the container of the first button will be the action button field. We can use the fact that the button field has a label "demo" in order to get access to that field. vars buttons = rc_fieldcontents_of(buttonpanel, "demo"); ;;; Print the list of buttons. buttons ==> ;;; extract the first one: vars button = hd(buttons); button ==> rc_button_container(button) => ** ** So starting from a button, or button list it is possible to get to the containinng window, e.g. in order to hide it or re-size it, etc. This may sometimes be done in one step using rc_button_container, where a button was added directly to a window, or in two steps using rc_button_container and rc_field_container, where the button is part of a panel produced by rc_control_panel. A program that operates on a button and which needs to change what is displayed by the button (e.g. its colour) can use this mechanism to get at the window object in order to ensure that drawing commands are done in the right context, using something like this construct: dlocal rc_current_window_object = container; -- See also ----------------------------------------------------------- HELP * RCLIB HELP * RC_LINEPIC Explains event handlers and top level mixins and methods TEACH * POPCONTROL TEACH * RC_ASYNC_DEMO TEACH * RCLIB_DEMO.P TEACH * RC_LINEPIC TEACH * RC_CONSTRAINED_PANEL TEACH * RC_CONTROL_PANEL HELP * RC_CONTROL_PANEL LIB * RC_CONTROL_PANEL LIB * RC_POLYPANEL LIB * RC_BUTTONS LIB * RC_BUTTON_UTILS LIB * RC_POPUP_QUERY -- Revision notes ----------------------------------------------------- NOTE (18 Feb 2004) Various changes in Sept 2002 and more recently recorded in help RCLIB_NEWS NOTE: (16 Jun 2000) LIB RC_BUTTONS has been completely reorganised, and many details changed. Most programs should run as before. However, there may be slight differences in the appearance of some files, and some bugs were fixed. A few procedures are withdrawn (e.g. rc_DRAWBUTTON) and some have had their paramaters changed. See HELP RCLIB_NEWS NOTE (28 Feb 2000): The [DEFER ...] format has been changed to invoke rc_defer_apply, defined in LIB * rc_mousepic. This enables actions to change the value of rc_current_window_object, etc. All other actions triggered by action buttons, including all specified as [POP11 ...] actions, are handled via external_defer_apply, unless they use the [POPNOW ...] format. [POPNOW ... ] actions are invoked immediately by the event handler, and programmers must make sure that such actions do not do anything complex (in particular anything that could trigger a garbage collection) except via external_defer_apply. NOTE (18th April 1999) The facilities for specifying properties of buttons on an individual basis were extended, by defining abbreviations for featurespec vectors included with button descriptions. This uses the property: rc_button_type_key and the procedure rc_button_key_of_type(type) (not exported for users till July 2002. NOTE (8th Nov 1997) LIB RC_BUTTONS was altered so as to ensure that all buttons, button rows, button columns took location coordinates to refer to the top left corner of the button or button array, no matter what the current values of rc_xscale and rc_yscale. Similarly, specifications of button border with, button length and button height are not affected by the current picture scales. --- $poplocal/local/rclib/help/rc_buttons --- Copyright University of Birmingham 2004. All rights reserved. ------