home *** CD-ROM | disk | FTP | other *** search
- (****************************************************************
- *
- * Name: WASHER
- *
- * Function: Emulate a washing machine control panel.
- *
- * Shows how to: 1. construct complex menus (dialogues) including
- * select, input, output, and inactive fields.
- * 2. change field types dynamically.
- * 3. implement "radio button" select fields.
- * 4. use a timer object to measure time intervals.
- * 5. use an objectq to wait for multiple events.
- *
- ****************************************************************)
-
- program Washer;
-
- uses DVAPI;
-
- const
-
- (* minimum API version required *)
- REQUIRED = $201;
-
- (* possible values of the "temperature" variable *)
- HOT = 0;
- WARM = 1;
- COLD = 2;
-
- (* possible values of the "state" variable *)
- IDLE = 0;
- WASHING = 1;
- FIRST_RINSE = 2;
- FIRST_SPIN = 3;
- FINAL_RINSE = 4;
- FINAL_SPIN = 5;
-
- (* panel library filename in ASCIIZ string format *)
- lib : string = 'examples.plb'#$00;
-
- (* name of panel within panel library *)
- name : string = 'washer';
-
- var
-
- (* actual API version number *)
- version : integer;
-
- (* object handles *)
- winme,pan,win,kbd,tim,obj : ULONG;
-
- type
-
- (* keyboard buffer definition *)
- KEYBUF = array [0..4] of byte;
-
- var
-
- (* variables used when reading from the menu *)
- kptr,kend : pointer;
- kbufptr : ^KEYBUF;
- field,kstatus : byte;
- klng,fsize,err : integer;
- field1 : string[2];
-
- (* variables set according to menu input *)
- wash_time,temperature : integer;
- second_rinse,bell : boolean;
-
- (* state related variables *)
- state,indicator : integer;
- done : boolean;
-
- (* variables for saving the cursor position *)
- row,col : integer;
-
- (* unused function results *)
- status : integer;
-
- (* TFDD text files *)
- tfdme,tfd : text;
-
- const
-
- (* boolean values *)
- ON = True;
- OFF = False;
-
-
- (**********************************************************************
- * stop_cycle - stops the current timer, if any. Changes field 1 back
- * to an input field, enables the start button, and
- * disables the stop button.
- ***********************************************************************)
-
- procedure stop_cycle;
- begin
-
- tim_erase (tim);
- fld_type (win,1,FLT_INPUT);
- fld_type (win,7,FLT_DESELECT);
- fld_type (win,8,FLT_INACTIVE);
-
- end;
-
-
- (**********************************************************************
- * change_state - changes the current state of the wash cycle and
- * lights the specified indicator. The previously
- * lighted indicator, if any, is turned off.
- ***********************************************************************)
-
- procedure change_state (newstate, field : integer);
- begin
-
- (* log new state *)
- state := newstate;
-
- (* if an indicator is ON, turn it OFF *)
- if (indicator <> 0) then
- fld_attr (win,indicator,1);
-
- (* turn ON the requested indicator and remember it *)
- if (field <> 0) then
- fld_attr (win,field,5);
- indicator := field;
-
- end;
-
-
- (**********************************************************************
- * radio_button - select a specified field and deselect all others in
- * the given range.
- ***********************************************************************)
-
- procedure radio_button (win : ULONG; first,last,chosen : integer);
- var
- i : integer;
-
- begin
-
- (* loop for each field in range "first" through "last" *)
- for i := first to last do
-
- (* change "chosen" field type to SELECTed, others to DESELECTed *)
- if (i = chosen) then
- fld_type (win,i,FLT_SELECT)
- else
- fld_type (win,i,FLT_DESELECT);
-
- end;
-
-
- (**********************************************************************
- * process_timer_event - process timer expiration
- ***********************************************************************)
-
- procedure process_timer_event;
- var
- time : longint;
-
- begin
-
- (* read the timer object to clear the event *)
- time := tim_read(tim);
-
- (* save cursor position. Decrement time remaining and display. *)
- wash_time := wash_time - 1;
- qry_cursor (win,row,col);
- fld_cursor (win,1);
- write (tfd,wash_time:2);
-
- (* if the clock has expired, dispatch based on current state. *)
- (* In each case, switch to the next state and light the appropriate *)
- (* indicator. *)
- if (wash_time = 0) then
- begin
- case (state) of
- WASHING :
- if (second_rinse) then
- change_state (FIRST_RINSE,11)
- else
- change_state (FINAL_RINSE,11);
- FIRST_RINSE :
- change_state (FIRST_SPIN,12);
- FIRST_SPIN :
- change_state (FINAL_RINSE,11);
- FINAL_RINSE :
- change_state (FINAL_SPIN,12);
- FINAL_SPIN : (* Cycle complete - switch to IDLE state, beep if
- requested. Restore original field types. *)
- begin
- change_state (IDLE,0);
- if (bell) then
- api_sound (2000,18);
- stop_cycle;
- end;
- end;
-
- (* unless we are now IDLE, we need to start a rinse or spin cycle. *)
- (* do so by setting the clock to 3 seconds and setting the timer to *)
- (* expire in 1 second. *)
- if (state <> IDLE) then
- begin
- wash_time := 3;
- tim_addto (tim,100)
- end
- end
-
- (* if clock is still counting, simply set timer for another second *)
- else
- tim_addto (tim,100);
-
- (* restore cursor to its original position *)
- win_cursor (win,row,col);
-
- end;
-
-
-
- (**********************************************************************
- * process_menu_event - process data returned from the menu.
- ***********************************************************************)
-
- procedure process_menu_event;
- begin
-
- (* get menu data and determine what event caused data to be returned *)
- key_read (kbd,kptr,klng);
- kbufptr := kptr;
- kstatus := key_status (kbd);
-
- (* beep and return if anything but a field selection *)
- if (kstatus <> 1) then
- begin
- api_sound (1000,5);
- exit;
- end;
-
- (* point just past returned data. Save current cursor position. *)
- kend := @kbufptr^[klng];
- qry_cursor (win,row,col);
-
- (* loop once for each field returned *)
- while (kbufptr <> kend) do
- begin
-
- (* get field # and length. Log field info to task window. *)
- field := kbufptr^[0];
- fsize := kbufptr^[1] + (kbufptr^[2] * 256);
- write (tfdme,'field = ',field,' length = ',fsize,' contents = ');
- win_write (winme,@kbufptr^[3],fsize);
- writeln (tfdme);
-
- (* dispatch based on field number *)
- case (field) of
-
- 1 : (* wash time changed *)
- begin
-
- (* copy returned data to two character string variable *)
- field1 := ' ';
- move (kbufptr^[3],field1[1],2);
-
- (* convert to integer, clip at zero, and set state to IDLE *)
- val (field1,wash_time,err);
- if (wash_time < 0) then
- wash_time := 0;
- change_state (IDLE,0);
-
- end;
-
- 2 : (* Hot water selected - Select field 2. Deselect fields
- 3 and 4. Log temperature. *)
- begin
- radio_button (win,2,4,2);
- temperature := HOT;
- end;
-
- 3 : (* Warm water selected - Select field 3. Deselect fields
- 2 and 4. Log temperature. *)
- begin
- radio_button (win,2,4,3);
- temperature := WARM;
- end;
-
- 4 : (* Cold water selected - Select field 4. Deselect fields
- 2 and 3. Log temperature. *)
- begin
- radio_button (win,2,4,4);
- temperature := COLD;
- end;
-
- 5 : (* Second rinse - if the field data is "Y", the field is
- selected. Otherwise, the data will be "N". *)
- second_rinse := (chr(kbufptr^[3]) = 'Y');
-
- 6 : (* Beep when done - if the field data is "Y", the field is
- selected. Otherwise, the data will be "N". *)
- bell := (chr(kbufptr^[3]) = 'Y');
-
- 7 : (* Start button *)
- begin
-
- (* deselect field so it does not remain highlighted *)
- fld_type (win,7,FLT_DESELECT);
-
- (* ignore if no wash time has been selected. Otherwise ... *)
- if (wash_time <> 0) then
- begin
-
- (* convert field 1 to an output field. Disable the start button
- and enable the stop button *)
- fld_type (win,1,FLT_OUTPUT);
- fld_type (win,7,FLT_INACTIVE);
- fld_type (win,8,FLT_DESELECT);
-
- (* set timer to run 1 second. If IDLE, set state to WASHING. *)
- tim_addto (tim,100);
- if (state = IDLE) then
- change_state (WASHING,10);
- end;
- end;
-
- 8 : (* Stop button - stop cycle and reset field types. *)
- stop_cycle;
-
- 9 : (* Exit button - stop cycle, reset fields, and set "done". *)
- begin
- stop_cycle;
- done := True;
- end;
-
- else (* unknown field number - should never happen. *)
- begin
- writeln (tfdme,'impossible!');
- end;
-
- end;
-
- (* bump pointer to next field and loop *)
- kbufptr := @kbufptr^[fsize + 3];
-
- end;
-
- (* restore original cursor position *)
- win_cursor (win,row,col);
-
- end;
-
-
- (**********************************************************************
- * program_body - initialize application and loop processing events.
- ***********************************************************************)
-
- procedure program_body;
- begin
-
- (* get task window handle and open objectq *)
- winme := win_me;
- obq_open;
-
- (* create timer object *)
- tim := tim_new;
-
- (* create and open panel object, and associate it with panel library *)
- pan := pan_new;
- status := pan_sopen (pan,lib);
-
- (* apply named panel, and return window & keyboard handles *)
- status := pan_sapply (pan,winme,name,win,kbd);
-
- (* open TFDDs and assign to windows *)
- tfd_open (tfdme,winme);
- tfd_open (tfd,win);
-
- (* preselect "hot water". Jump cursor to field 1. Set "state" to idle *)
- radio_button (win,2,4,2);
- fld_cursor (win,1);
- change_state (IDLE,0);
- done := False;
-
- (* initialize to default variables set according to menu input *)
- wash_time := 0;
- temperature := HOT;
- second_rinse := False;
- bell := False;
-
- (* show panel window *)
- win_top (win);
-
- (* loop until "done" becomes TRUE *)
- while (not done) do
- begin
-
- (* wait for input from any open object and return its handle *)
- obj := obq_read;
-
- (* determine which object it is and process accordingly *)
- if (obj = kbd) then
- process_menu_event
- else
- if (obj = tim) then
- process_timer_event;
-
- end;
-
- (* close TFDDs *)
- tfd_close (tfd);
- tfd_close (tfdme);
-
- (* free all allocated objects and return *)
- key_free (kbd);
- win_free (win);
- pan_free (pan);
- tim_free (tim);
-
- end;
-
-
- (**********************************************************************
- * main - check for DESQview present and enable required extensions.
- ***********************************************************************)
-
- begin
-
- (* initialize Pascal interfaces and get API version number *)
- version := api_init;
-
- (* if DESQview is not running or version is too low, display a message *)
- if (version < REQUIRED) then
- writeln ('This program requires DESQview version ',REQUIRED div 256,
- '.',(REQUIRED mod 256) div 16,(REQUIRED mod 256) mod 16,' or later.')
-
- (* tell DESQview what extensions to enable and start application *)
- else
- begin
- api_level (REQUIRED);
- program_body;
- end;
-
- (* disable Pascal interfaces and return from program *)
- api_exit;
-
- end.