/* TEACH RC_ASYNC_DEMO Aaron Sloman Oct 1999 Demonstrating asynchronous actions in RCLIB Added FASTER and SLOWER buttons 23 Jul 2002 CONTENTS -- Introduction -- Loading required libraries -- Running the demonstration -- Global variables used by the program -- The main procedure: async_go(), with control panel specification -- rc_restart(); -- do_delay(); -- multi_box -- multi_line -- multi_poly -- multi_square -- Colour control -- Introduction ------------------------------------------------------- This teach file, based on $poplocal/local/menu/teach/menu_demo.p, shows how to create a panel which can launch a program which is then controlled asynchronously by other panels. If you compile this file (ENTER l1) and then give Pop-11 the command async_go(); it will create a panel with several buttons. The STARTUP button will start a dynamic display. The next four buttons give options for selecting the drawing procedure to produce the display. The four drawing procedures are defined below: multi_box multi_line multi_poly multi_square The next button, labelled 'Changecolour*', where the asterisk is a reminder that this will create another panel, creates a new panel with a set of buttons most of which have colour names. There is also a button which enables you to pop up a text input panel which waits for you to type in a string with the name of a colour. Make sure you give only colours included in the file HELP XCOLOURS. The next few buttons have labels which should be obvious, including one to stop the display. If you click on STARTUP while a graphical panel already exists, the contents of the old one will be frozen and the dynamic display will be run in the new one. An possible exercise would be to change the program that if a panel already exists it is re-used. -- Loading required libraries ----------------------------------------- First load the required libraries. */ uses rclib uses rc_buttons uses rc_control_panel /* -- Running the demonstration ------------------------------------------ Load this file (ENTER l1) then run this command async_go(); On some terminals you may get a warning about unknown colours. Just refresh the screen afterwards (CTRL-L). Then try clicking on the various buttons and see what happens. After a while click on STOP and then read the rest of this file. The procedure async_go(), defined below, will create a control panel which you can use to start up a moving graphical display (based on lib rc_graphic), by clicking on the STARTUP button. You can change the display by clicking on the buttons on the panel while the display is actively changing. After playing a while, use the STOP button to stop the graphics. Then kill the graphic window, by clicking on KillGraphic. Then look at the definition of the control panel inside the procedure async_go() defined below. Try changing the definition, including changing the location, other controls, and specifying default foreground and background colours (See HELP * RC_CONTROL_PANEL, HELP * XCOLOURS). The procedure async_go(), includes the definition of a panel for controlling the graphical display. The comments include suggestions for redefining parts of the panel to try different colours, locations, etc. For more information see TEACH * RC_CONTROL_PANEL HELP * RC_BUTTONS HELP * RC_CONTROL_PANEL HELP RCLIB */ /* -- Global variables used by the program */ ;;; A procedure to create a control panel. It uses procedures defined ;;; below to produce the graphics global vars ;;; The main panel async_go_panel, ;;; The dynamic graphic panel async_graphic_panel, ;;; The colour control panel async_colour_panel, do_pause = false, ;;; used to control drawing loops do_stop = false, ;;; true if demo is to stop do_finish = false, ;;; true of panels are to be removed control_procedure, ;;; current drawing procedure ;;; procedures defined below procedure (rc_restart, multi_box, multi_line, multi_poly, multi_square, rc_restart, startup, make_colour_panel), ; /* -- The main procedure: async_go(), with control panel specification ;;; Compile the file then test it async_go(); */ define graphic_live() -> boole; ;;; utility procedure async_graphic_panel and rc_widget(async_graphic_panel) and xt_islivewindow(rc_widget(async_graphic_panel)) -> boole; enddefine; define rc_test_hide(panel); if isrc_window_object(panel) and rc_widget(panel) then rc_hide_window(panel); endif; enddefine; define async_go(); ;;; This does nothing more than set up the main control panel rc_control_panel("right", "top", [ {events [button]} ;;; restrict events handler {font '8x13bold'} ;;; font specification {bg 'black'} ;;; background black (try brown) {fg 'white'} ;;; foreground white (try yellow) ;;; try {cols 2} [TEXT : 'Change the' 'function'] ;;; Now button definitions. Use POPNOW for instant action. [ACTIONS {cols 1} ;;; orientation vertical, single column {bg 'grey20'}: ['STARTUP' startup] ['SLOWER' [POP11 do_delay_delay + 1 -> do_delay_delay]] ['FASTER' [POP11 max(0, do_delay_delay - 1) -> do_delay_delay]] [multi_box [POP11 restart(multi_box)]] [multi_line [POP11 restart(multi_line)]] [multi_poly [POP11 restart(multi_poly)]] [multi_square [POP11 restart(multi_square)]] ['ChangeColour*' [POP11 make_colour_panel()]] ;;; make this one happen immediately [STOP [POP11 true -> do_stop]] [KillGraphic [POP11 true -> do_stop; rc_test_hide(async_graphic_panel); ]] [DISMISS [POP11 true ->> do_stop -> do_finish; ;;; get rid of other panels rc_test_hide(async_graphic_panel); rc_test_hide(async_colour_panel); ;;; hide this panel rc_hide_panel(); ]] ] ], 'async_go') -> async_go_panel; enddefine; /* -- rc_restart(); ;;; test it rc_restart(); */ define rc_restart(); ;;; Clear the image. true -> do_pause; returnif(do_stop or not(graphic_live())); async_graphic_panel -> rc_current_window_object; rc_start(); false -> do_pause; enddefine; /* -- do_delay(); Try giving this different definitions to have different effects. on the speed of the display. */ ;;; delay is one tenth of a second global vars do_delay_delay = 0; define do_delay(); ;;; could be changed to use an argument set by a counter ;;; button unless do_pause or do_stop then syssleep(do_delay_delay); endunless; enddefine; /* -- multi_box ;;; test it multi_box(); */ define rc_draw_box(x,y,width, height); ;;; Draw a box ;;; Add a bit of random jitter. x-10+random(20) -> x; y-10+random(20) -> y; lvars xmax = x + width, ymax = y + height; ;;; returnif(do_stop or do_pause or not(graphic_live())); rc_drawline(x, y, xmax, y); ;;; returnif(do_stop or do_pause or not(graphic_live())); rc_drawline(xmax, y, xmax, ymax); ;;; returnif(do_stop or do_pause or not(graphic_live())); rc_drawline(xmax, ymax, x, ymax); ;;; returnif(do_stop or do_pause or not(graphic_live())); rc_drawline(x, ymax, x, y); enddefine; define multi_box(); ;;; Draw lots of boxes lvars x,y,height,width; rc_restart(); for x from -220 by 60 to 180 do for y from -220 by 70 to 190 do for width from 0 by 80 to 200 do for height from -100 by 30 to 100 do returnif(do_stop or do_pause or not(graphic_live())); unless rc_in_event_handler then dlocal rc_current_window_object = async_graphic_panel; rc_draw_box(x,y,width,height); endunless; endfor endfor endfor endfor; do_delay(); enddefine; /* -- multi_line ;;;test it multi_line(); */ define multi_line(); lvars x1,y1,x2,y2; rc_restart(); repeat 500 times random(600) - 300 -> x1; random(600) - 300 -> x2; random(600) - 300 -> y1; random(600) - 300 -> y2; returnif(do_stop or do_pause or not(graphic_live())); unless rc_in_event_handler then dlocal rc_current_window_object = async_graphic_panel; rc_drawline(x1, y1, x2, y2); endunless; endrepeat; do_delay(); enddefine; /* -- multi_poly ;;; test multi_poly(); */ define polyspi(side, inc, ang, num); ;;; Draw a polygonal spiral. Initial arm length is side. ;;; inc is added at each turn. ;;; The angle turned (to left) is ang (in degrees). ;;; The total number of sides is num. ;;; This is invoked by the operation -rc_poly- below dlocal popradians = false; 1 -> rc_xscale; -1 -> rc_yscale; rc_window_xsize >> 1 -> rc_xorigin; rc_window_ysize >> 1 -> rc_yorigin; rc_jumpto(0, 0); 45 -> rc_heading; ;;; move to a location and heading which will cause the centre of the ;;; spiral to be near centre of screen (very approximate). ;;; but first normalise ang to lie in range 0 to 359 until ang >= 0 do ang + 360 ->ang enduntil; until ang < 360 do ang - 360 ->ang enduntil; if ang > 0.5 then ang/2.0 -> rc_heading; rc_jump(min(side/(2.0*sin(ang/2.0)),side)); endif; rc_turn(90 + ang/2.0); repeat num times returnif(do_stop or do_pause or not(graphic_live())); unless rc_in_event_handler then dlocal rc_current_window_object = async_graphic_panel; rc_draw(side); rc_turn(ang); side+inc ->side; endunless endrepeat; do_delay(); enddefine; define multi_poly(); lvars side, inc, ang, num; rc_restart(); random(400)+ 200 -> side; random(4) - 8 -> inc; 180 - (720 / random(4) + 3) -> ang; if random(10) > 5 then -ang -> ang endif; random(300) + 300 -> num; polyspi(side,inc,ang,num); enddefine; /* -- multi_square ;;; test it multi_square(); */ define rc_demo_square(side); repeat 4 times unless rc_in_event_handler then dlocal rc_current_window_object = async_graphic_panel; rc_draw(side); rc_turn(90); endunless endrepeat; enddefine; define multi_square(); lvars side, angle; dlocal popradians = false; rc_restart(); oneof([46 -46]) -> angle; random(200) + 30 -> side; rc_jumpto(0, 0); 45 -> rc_heading; repeat 64 times returnif(do_stop or do_pause or not(async_graphic_panel)); rc_demo_square(side); rc_turn(angle); endrepeat; do_delay(); enddefine; global vars control_procedure = valof(oneof( [multi_box multi_line multi_poly multi_square ])); /* -- Colour control */ lvars current_colour = 'black'; define rc_set_colour(string); if isstring(string) then true -> do_pause; string -> current_colour; if isrc_window_object(async_graphic_panel) then ;;; in case current window object has been changed async_graphic_panel -> rc_current_window_object endif; endif; enddefine; define ask_colour(); ;;;; true -> do_pause; lvars new_colour = rc_getinput(250, 250, ['Please type a colour name'], 'black', [{width 80}{font '9x15'}{align centre}], 'Select Colour'); if new_colour then rc_set_colour(new_colour) endif; enddefine; define make_colour_panel(); ;;; set up a control panel to specify next colour dlocal rc_in_event_handler = true; rc_control_panel(20, 20, [ {bg 'white'} {fg 'black'} ;;; restrict events handler {events [button]} [TEXT : 'Choose next colour:'] ;;; Exercise: change the following to use RADIO buttons [ACTIONS {width 80} {cols 6}: ['Red' [POPNOW rc_set_colour('red')]] ['Orange' [POPNOW rc_set_colour('orange')]] ['Yellow' [POPNOW rc_set_colour('yellow')]] ['Green' [POPNOW rc_set_colour('green')]] ['Darkgreen' [POPNOW rc_set_colour('darkgreen')]] ['Blue' [POPNOW rc_set_colour('blue')]] ['Navy' [POPNOW rc_set_colour('navy')]] ['Brown' [POPNOW rc_set_colour('brown')]] ['Pink' [POPNOW rc_set_colour('pink')]] ['Grey' [POPNOW rc_set_colour('grey50')]] ;;; See HELP * POPUPTOOL for this ['AskUser*' ask_colour] [DISMISS rc_hide_panel] ] ], 'NEXT COLOUR') -> async_colour_panel; if isrc_window_object(async_graphic_panel) and rc_widget(async_graphic_panel) then async_graphic_panel -> rc_current_window_object; endif; enddefine; define startup(); ;;; Make sure the graphical display happens only in the intended ;;; window dlocal do_pause; ;;; Create a new window if necessary if isrc_window_object(async_graphic_panel) and xt_islivewindow(rc_widget(async_graphic_panel)) then async_graphic_panel -> rc_current_window_object; rc_show_window(async_graphic_panel); else rc_new_window_object(200,200,400,400, true,'async_graphic') -> async_graphic_panel; endif; ;;; The next variable can be made true by the STOP button dlocal do_stop = false, do_finish = false; until do_stop do rc_restart(); XpwSetColor(rc_window, current_colour) ->; ;;; Print the name on the graphic window control_procedure>< nullstring -> rc_window_title(async_graphic_panel); rc_window_sync(); ;;; if this is made true, central loop will exit false -> do_pause; recursive_valof(control_procedure)(); enduntil; if do_finish then if graphic_live() then rc_kill_window_object(async_graphic_panel); false -> async_graphic_panel; endif endif; enddefine; define restart(proc); true -> do_pause; proc -> control_procedure; enddefine; pr('\nplease type:\n async_go();\n'); /* ;;; Revised Sept 2000 to enable Dismiss and Kill ;;; buttons to be used while process is running. ;;; Some bugs fixed: 5 Sep 1999 ;;; fewer unwanted interactions ;;; changed rc_square to rc_demo_square, to prevent clash ;;; 11 Sep 2000 ;;; Changed to prevent interactions between mouse movement on ;;; control panel and other events. ;;; Changed to allow the graphical panel to be killed at the same ;;; time as dismissing everything else. ;;; 14 Sep 2000 ;;; Fixed DISMISS button if used before colour chooser created. --- $poplocal/local/rclib/teach/rc_async_demo --- Copyright University of Birmingham 2002. All rights reserved. ------ */