The Function of WC_RESET% in Window Processing (TB#81) (Functions/Subroutines/Programs)
Created at 14 NOV 1996 01:54PM
The Function of WC_RESET% in Window Processing
A hurdle for programmers new to the Advanced Revelation window processor is trying to decide which WINDOW_COMMON% variables to use in which circumstances, particularly, the variable WC_RESET%. It can take one of 6 values and which value it takes depends on where it is used. Furthermore, other variables, for example WC_DISPLAY_ACTION%, seem to need WC_RESET% in some places and not others.
This Technical Bulletin explains how the window processor uses WC_RESET% to affect window processing.
To understand WC_RESET% you must first understand that the window processor is basically a loop. The window starts, then the first prompt is processed. The second prompt is processed and then the third and so on until all prompts have been processed. In fact, Window consists of loops within loops.
The Basic LOOP…UNTIL
R/BASIC supports several looping structures. FOR…NEXT is one, LOOP…UNTIL…REPEAT is another. LOOP…UNTIL is the structure used by Window.
The syntax of LOOP…UNTIL is:
LOOP
UNTIL condition is met
REPEAT
This syntax is very flexible. Additional processing statements can be placed anywhere inside the LOOP…REPEAT block. For example:
LOOP
do some processing
do more processing
UNTIL
condition is met keep on working
don't stop
REPEAT
In this example the entire loop keeps on looping until some condition is realized. When that condition is realized control jumps straight to the REPEAT statement, skipping everything between the UNTIL and the REPEAT.
Using this knowledge, a basic window loop might look like:
LOOP
process prompt
UNTIL reset
do between prompt work
REPEAT
Advanced LOOP…UNTIL
LOOP…UNTIL permits multiple exit points. For example:
LOOP
do work
UNTIL condition is met
do more work
UNTIL another condition is met
do still more work
REPEAT
This feature helps the window loop exit more gracefully. Notice that in the basic window loop above that if the between prompt work indicates that the window should quit, one more prompt must be processed before exiting the loop. If you change the loop structure you can avoid the extra processing.
LOOP
process prompt
UNTIL reset
do between prompt work
UNTIL reset
REPEAT
Now there are two ways out of the loop. In fact you are not limited to just two exit points. You can have as many as you want.
Hypothetical Window Loop
The loop for a hypothetical window processor might look like this:
LOOP
process prompt
UNTIL reset
if perpetual process
do perpetual process
end
UNTIL reset
if save flag set then
do save process
end
UNTIL reset
if delete flag set
do delete process
end
UNTIL reset
if display then
do display process
end
REPEAT
The loop quits anytime reset is true. This loop allows multiple processes the opportunity to set reset. Reset is being used as a flag to indicate that a process (the window) should stop. How can the same feature be used to stop another process? Take, for example, the save process.
Resetting a Save Process
The save process (in the hypothetical window loop) should allow for a presave process. If the user wants to avoid the save they should set reset. One way to implement this is like this:
save process:
if presave process then
do presave process
if reset else
do save
end
end else
do save
end
This is cumbersome for two reasons. First, the actual save routine is duplicated. Second, if the save is cancelled so is the window because reset is never set back to false. What you need is a way to indicate that the save process should be cancelled, but not the window. You also need a way to indicate that both the save process and the window should be cancelled.
A simple approach would be to say, "1 means cancel the save, 2 means cancel the save and the window". This approach is too simple and it makes extension of the use of reset difficult. It makes all of the checks in the main loop look for a particular value. It also does not help the save process avoid duplicating code.
If you change the way you use the code it gets easier. For example:
save process:
if presave process then
do presave process
end
if reset then
if reset ⇐ 1 then
reset = ""
end else
reset -= 1
end
end else
do save
end
This approach uses the same value for reset as originally outlined, but makes it easier to write clean code. The presave process is completely encapsulated inside one IF…THEN block and the save code is not duplicated. Walking through the if reset section will show that the reset values produce the required results:
_ If reset is non-null (true) the then branch is taken. Otherwise the else branch is taken. It is only in the else branch that the save code is executed, so setting reset to 1 or 2 will prevent the save, which is what was intended.
_ In the then branch the value of reset is checked. If it is less than or equal to 1 reset is set to null. This means that when control returns to the main loop reset is not true and the window is not cancelled. If, on the other hand, reset is greater than 1, (in this case 2) subtract 1 from reset. When control returns to the main loop reset is true and the window is cancelled.
Prompt Processing
Prompt processing, unlike the save process examined above, is itself a loop. In the hypothetical window it would be desirable to have the same editor used in all conditions and to have some fancy features like popups and softkeys. All of this can be done by using a loop.
The simple solution is to call an editor until the editor is done and then pass control back to the main loop. For example:
LOOP
call editor
UNTIL done
REPEAT
This structure is both too complex and too simple. It assumes that the editor will handle all the desired features (like popups and softkeys). If that is the case then the editor should be called for the prompt and no loop is needed for when it returns control the prompt has been processed and the main loop can continue.
This is not a bad strategy if you don't mind burdening the editor with window specific functions. However, you might want to use the editor outside the window as well. A better strategy would be to define special keystrokes that the editor would recognize mean "give control back to the window processor". The window processor could then examine which key was pressed and act accordingly. With this strategy the prompt loop might look like this:
LOOP
editor(exitkeys, lastkey)
process lastkey
UNTIL reset
REPEAT
In this loop the process lastkey routine is like the save process above it can set reset. But this loop has the same failing as the original save process, if reset is set, the window is cancelled. There is also no preprompt processing. A better prompt processing loop looks like:
process prompt:
if preprompt then
perform preprompt
if reset then
if reset ⇐ reset_edit$ then
reset = ""
end else
reset -= 1
end
end
end
if reset else
loop
editor(exitkeys, lastkey)
process lastkey
until reset
repeat
if reset ⇐ reset_edit$ then
reset = ""
end else
reset -= 1
end
end
Notice how the same strategy is used here to deal with the reset codes as was used in the save process.
Summary
Refer to the original window loop, above. Note that the display action is evaluated at a specific point in the loop (the actual point is somewhat different in the real Window). In order to get the display action evaluated you must get to that point. If a prompt is being processed how do you get there? You must set reset to a value high enough to get control out of the prompt processing loop.
To set reset you need to invoke a special keystroke. Maybe [F2] or a softkey; any keystroke that the editor recognizes as significant so it returns control to the window processor. If your program doesn't set reset high enough the edit loop is not exited. Note that there is no need to set reset if control is passing out of the prompt normally.
Window
How does this hypothetical window processor compare to Window? Figure 1 is pseudo code that shows the flow of the main window loop, emphasizing the role of WC_RESET%. Figure 2 is the pseudo code for I/O processing, while Figure 3 shows prompt processing.
WC_RESET% can take the values in the following table. Use these values as you trace through the pseudo code.
Value Mnemonic
1 CLEAN.UP.LINE$
2 CLEAN.UP.EDIT$
3 RESET.EDIT$
4 RESET.PROMPT$
5 RESET.RECORD$
6 RESET.WINDOW$
Window Flow
As Figure 1 shows, if WC_RESET% is still set after the prompt is processed the perpetual process is not executed. Since most windows do not have a perpetual process there is usually no practical difference between setting WC_RESET% to RESET.PROMPT$ or setting it to RESET.RECORD$ from a prompt process.
Notice that after every possible "hook" the system checks for WC_RESET%. This means that setting WC_RESET% to RESET.WINDOW$ from any process will quickly cancel the window.
The window processor also checks for WC_DISPLAY_ACTION% after all hooks, making it easy for you to affect window display.
I/O Processing
Figure 2 shows the basic flow followed by read, write, and delete processing. Note that all WC_RESET% values less than RESET.RECORD$ have the same effect on window flow. To have an impact on window flow from an I/O process you must use RESET.RECORD$ or, to leave your window, RESET.WINDOW$.
Prompt Flow
Figure 3 shows the flow of control through a prompt. Careful study of the pseudo code will show that from a preprompt process you must set WC_RESET% to at least RESET.PROMPT$ to force the system to leave the prompt.
From the Options key or from Softkeys you must set WC_RESET% to at least RESET.EDIT$ to force the system to leave the prompt. Note that if you set WC_RESET% to CLEAN.UP.LINE$ or CLEAN.UP.EDIT$ you do not leave the prompt.
CLEAN.UP.LINE$ and CLEAN.UP.EDIT$ are used by the window processor to ensure that edit checks are done. Using these values in your programs will have no effect.
Edit Checks As you can see in Figure 3, one of the parameters passed to SCRIBE is the edit patterns used by the prompt (WC_SI%<VINP>). SCRIBE will, in turn, call IN.VALUE to validate your input. This processing is important in two ways.
First, it explains why your custom edit checks will find the input data in @ANS. SCRIBE and IN.VALUE are independent routines. They are not window specific and cannot use the window common variables. In order to pass data to your routine, @ANS, and not WC_IS% must be used.
Second, because SCRIBE can be interrupted before the edit checks have been done, there must be a way to call SCRIBE and tell it to process the data through the edit checks. This is the function of CLEAN.UP.LINE$ and CLEAN.UP.EDIT$.
Depending on when processing was interrupted and whether there are edit checks, the system will use WC_RESET% to set flags in WC_SCRIBE_FLAGS%. These flags will be used by SCRIBE when it is called again to determine what action to take.
Figure 1
LOOP
process prompt
IF WC_RESET% THEN
WC_RESET% -= 1
END ELSE
do perpetual process
END
UNTIL WC_RESET%
IF WC_AMV_ACTION% THEN do amv process
IF WC_JOINED_KEYS% THEN do join process
IF WC_DISPLAY_ACTION% THEN do display process
IF WC_SAVE_REC% THEN
do save process
IF WC_DISPLAY_ACTION% THEN do display process
END
UNTIL WC_RESET%
IF WC_DELETE_REC% THEN
do delete process
IF WC_DISPLAY_ACTION% THEN do display process
END
UNTIL WC_RESET%
IF WC_MV_NEXT% THEN adjust position in amv
IF WC_NEW_DATAFILE% THEN do new datafile process
IF WC_NEW_BROWSE% THEN do new browse list process
IF WC_RING_NEXT% THEN adjust browse list pointer
IF WC_NEW_ID% THEN
do read process
IF WC_DISPLAY_ACTION% THEN do display process
END
UNTIL WC_RESET%
IF WC_WI_NEXT% THEN adjust prompt cursor is on
IF WC_WINDOW_ACTION% THEN pan/resize/move
REPEAT
Figure 2
IF preprocess THEN
do preprocess
IF WC_RESET% ⇐ RESET.PROMPT$ THEN
WC_RESET% = ""
END ELSE
WC_RESET% -= RESET.PROMPT$
END
END
IF WC_RESET% THEN
WC_RESET% -= 1
END ELSE
IF replace process THEN
do replace process
IF WC_RESET% ⇐ RESET.PROMPT$ THEN
WC_RESET% = ""
END ELSE
WC_RESET -= RESET.PROMPT$
END
END ELSE
do i/o
END
IF WC_RESET% THEN
WC_RESET% -= 1
END ELSE
IF postprocess THEN
do postprocess
IF WC_RESET% ⇐ RESET.PROMPT$ THEN
WC_RESET% = ""
END ELSE
WC_RESET% -= RESET.PROMPT$
END
END
IF WC_RESET% THEN
WC_RESET -= 1
END ELSE
do work
END
END
END
Figure 3
prompt:
IF WC_SI%<PRE.CODE> THEN
do preprompt process
IF WC_RESET% ⇐ RESET.EDIT$ THEN
WC_RESET% = ""
END ELSE
WC_RESET% -= 1
END
END
IF WC_RESET% ELSE
LOOP
WC_VALID% = TRUE$
LOOP
LOOP
SCRIBE(WC_IS%, WC_WEXIT_KEYS%, WC_WC%, WC_SI%<VINP>……..)
UNTIL WC_RESET% ;* clean.up.line$
WHILE WC_WC%
IF WC_DISPLAY_ACTION% THEN
do display action
END
check wc_wc% ;* process popups, softkeys etc
UNTIL WC_RESET% ;* clean.up.line$
REPEAT
IF WC_WC% THEN
IF WC_RESET% THEN
WC_RESET% -= 1
IF WC_RESET% > 1 THEN
WC_RESET% -= 1
END ELSE
adjust scribe state so edit check gets done
END
END
END ELSE
WC_RESET% = 1
END
UNTIL WC_RESET% ;* clean.up.edit$
REPEAT
WC_RESET% -= 1
UNTIL WC_RESET% ;* reset.prompt$
IF WC_SI%<POST.CODE> THEN
do postprompt process
IF WC_RESET% ⇐ RESET.EDIT$ THEN
WC_RESET% = ""
END ELSE
WC_RESET% -= RESET.EDIT$
END
END
UNTIL WC_VALID%
UNTIL WC_RESET%
REPEAT
END
IF WC_RESET% THEN
WC_RESET% -= 1
WC_IS% = WC_IS_ORIG%
END
RETURN