;-*- Mode:LISP; Package:TV; Base:8 -*- ;Questionnaires. ;A questionnaire frame is a frame containing a bunch of questionnaire elements, ;which are windows containing a label and often a "value". You can change the ;value with the mouse. This is intended for displaying options to complicated ;programs and the like; it is a generalization of menus. ; ;The elements have names in the usual constraint-frame fashion. ; ;The following messages are special to questionnaire frames: ;They work by sending to the questionnaire elements ; :ELEMENT-VALUE name ; :SET-ELEMENT-VALUE name value ; :ELEMENT-ACCENT name ; :SET-ELEMENT-ACCENT name value ; :BROADCAST message &rest args ; Sends message to all elements. This is useful ; for various forms of resetting. ; Broadcasting the :QUESTIONNAIRE-RESET message resets all the state ; :SEND-ELEMENT pane-name message args ; :FIND-PANE name (returns the pane [this doesn't belong here]) ; ;Note that since a questionnaire frame has a bit save array, and its component ;questionnaire element panes do not, you can update them if the frame is ;de-exposed and they will automatically update in the bit save array, ;which is the right thing to avoid gratuitous-looking redisplay. This also ;implies that all questionnaire panes need to know how to redisplay themselves ;without the aid of a bit-save array, e.g. when the pane configuration is changed. ;The ones in this file do so. ; ;If you want a function to get called when a questionnaire element is changed ;with the mouse, give it a :AFTER :MOUSE-BUTTONS method which looks at its ;VALUE and/or ACCENT instance variables. This will do exactly the right thing. (DEFFLAVOR QUESTIONNAIRE-FRAME-MIXIN () () (:INCLUDED-FLAVORS BASIC-CONSTRAINT-FRAME) (:DEFAULT-INIT-PLIST :SAVE-BITS T) (:DOCUMENTATION :MIXIN "Stuff specific to questionnaires")) (DEFMETHOD (QUESTIONNAIRE-FRAME-MIXIN :ELEMENT-VALUE) (ELEMENT-NAME) (LET ((PANE (CDR (ASSQ ELEMENT-NAME INTERNAL-PANES)))) (IF PANE (FUNCALL PANE ':VALUE) (FERROR NIL "No ~S element in ~S" ELEMENT-NAME SELF)))) (DEFMETHOD (QUESTIONNAIRE-FRAME-MIXIN :SET-ELEMENT-VALUE) (ELEMENT-NAME VALUE) (LET ((PANE (CDR (ASSQ ELEMENT-NAME INTERNAL-PANES)))) (IF PANE (FUNCALL PANE ':SET-VALUE VALUE) (FERROR NIL "No ~S element in ~S" ELEMENT-NAME SELF)))) (DEFMETHOD (QUESTIONNAIRE-FRAME-MIXIN :ELEMENT-ACCENT) (ELEMENT-NAME) (LET ((PANE (CDR (ASSQ ELEMENT-NAME INTERNAL-PANES)))) (IF PANE (FUNCALL PANE ':ACCENT) (FERROR NIL "No ~S element in ~S" ELEMENT-NAME SELF)))) (DEFMETHOD (QUESTIONNAIRE-FRAME-MIXIN :SET-ELEMENT-ACCENT) (ELEMENT-NAME ACCENT-P) (LET ((PANE (CDR (ASSQ ELEMENT-NAME INTERNAL-PANES)))) (IF PANE (FUNCALL PANE ':SET-ACCENT ACCENT-P) (FERROR NIL "No ~S element in ~S" ELEMENT-NAME SELF)))) ;This sends to all panes, not just the exposed ones (DEFMETHOD (QUESTIONNAIRE-FRAME-MIXIN :BROADCAST) (MESSAGE &REST ARGS) (DOLIST (X INTERNAL-PANES) (LEXPR-FUNCALL (CDR X) MESSAGE ARGS))) (DEFMETHOD (QUESTIONNAIRE-FRAME-MIXIN :FIND-PANE) (ELEMENT-NAME) (CDR (ASSQ ELEMENT-NAME INTERNAL-PANES))) (DEFMETHOD (QUESTIONNAIRE-FRAME-MIXIN :SEND-ELEMENT) (ELEMENT-NAME MESSAGE &REST ARGS) (LEXPR-FUNCALL (CDR (ASSQ ELEMENT-NAME INTERNAL-PANES)) MESSAGE ARGS)) ;Given a pane, this returns the name for that pane the user gave in his alist. ;NIL if for some reason it is not found. (DEFMETHOD (QUESTIONNAIRE-FRAME-MIXIN :NAME-FOR-PANE) (WINDOW) (DOLIST (X INTERNAL-PANES) (AND (EQ (CDR X) WINDOW) (RETURN (CAR X))))) ;Default kind of questionnaire frame has moby label and thick borders ;I may decide to change this later (DEFFLAVOR QUESTIONNAIRE-FRAME () (BORDERS-MIXIN TOP-CENTERED-LABEL-MIXIN DIVIDER-MIXIN QUESTIONNAIRE-FRAME-MIXIN BASIC-CONSTRAINT-FRAME BASIC-FRAME WINDOW) (:DEFAULT-INIT-PLIST :BORDERS 3 :DIVIDER 3 :LABEL FONTS:METS) (:DOCUMENTATION :COMBINATION "Something like a menu but with more-active elements")) ;;; Flavors I depend on which should perhaps be installed but aren't currently. (DEFFLAVOR TOP-CENTERED-LABEL-MIXIN () (TOP-LABEL-MIXIN) (:DOCUMENTATION :MIXIN "Puts the label at the top of the window and centered")) (DEFMETHOD (TOP-CENTERED-LABEL-MIXIN :DRAW-LABEL) (SPEC LEFT TOP RIGHT BOTTOM) (COND (SPEC (%DRAW-RECTANGLE (- RIGHT LEFT) (- BOTTOM TOP) LEFT TOP ERASE-ALUF SELF) (SHEET-DISPLAY-X-Y-CENTERED-STRING SELF (LABEL-STRING SPEC) (- LEFT (SHEET-INSIDE-LEFT)) (- TOP (SHEET-INSIDE-TOP)) (- RIGHT (SHEET-INSIDE-LEFT)) (- BOTTOM (SHEET-INSIDE-TOP)) (LABEL-FONT SPEC))))) ;This flavor provides a line between the label and the data, if you ;put it in your flavor list after the other borders stuff. ;I haven't bothered to make this provide a way to say that ;the label is at other than the top. The totally(?) ((well, slightly)) hairy way ;this works is necessary to make redefinition of the margins, ;which constraint frames always do, work right. ;The DIVIDER variable internally contains cons of Y-pos and thickness, ;or NIL to turn it off. Externally you may give NIL to turn it off ;or a number which is the thickness of the black part (default=1). ;There is also one raster line of white above and one below. (DEFFLAVOR DIVIDER-MIXIN ((DIVIDER 1)) (MARGIN-HACKER-MIXIN) (:INCLUDED-FLAVORS ESSENTIAL-WINDOW) (:INITABLE-INSTANCE-VARIABLES DIVIDER) (:DOCUMENTATION :MIXIN "Provides a line between the top-centered label and the body of the window")) (DEFMETHOD (DIVIDER-MIXIN :BEFORE :INIT) (INIT-PLIST) (ADJUST-MARGINS 'DIVIDER ':PARSE-DIVIDER-SPEC INIT-PLIST NIL)) (DEFMETHOD (DIVIDER-MIXIN :BEFORE :REDEFINE-MARGINS) (PLIST) (ADJUST-MARGINS 'DIVIDER ':PARSE-DIVIDER-SPEC PLIST ':DIVIDER)) (DEFMETHOD (DIVIDER-MIXIN :PARSE-DIVIDER-SPEC) (SPEC LM TM RM BM) (COND ((NULL SPEC)) ;NIL means no divider (T (OR (NUMBERP SPEC) (SETQ SPEC (CDR SPEC))) ;Get thickness number (PSETQ SPEC (CONS (1+ TM) SPEC) TM (+ TM SPEC 2)))) (PROG () (RETURN SPEC LM TM RM BM))) (DEFMETHOD (DIVIDER-MIXIN :AFTER :REFRESH-MARGINS) () (%DRAW-RECTANGLE WIDTH (CDR DIVIDER) 0 (CAR DIVIDER) CHAR-ALUF SELF)) ;;; Questionnaire panes ;There are two basic flavors for questionnaire panes. One for those with labels, ;and one for those without. The difference is mainly the :XOR-ACCENT message, ;which in one case XORs just the label area, while in the other case it XORs the ;whole window. ;This flavor is the real low-level questionnaire pane stuff. It is shared between ;the two basic kinds, and not to be used otherwise. (DEFFLAVOR ESSENTIAL-QUESTIONNAIRE-PANE () (PANE-MIXIN) (:DEFAULT-INIT-PLIST :SAVE-BITS NIL ;The frame takes care of it :MORE-P NIL ;Normally don't want more-processing :BLINKER-DESELECTED-VISIBILITY NIL ;nor blinker turd :BLINKER-P NIL ;nor a blinker at all ;You can turn the above back on in your own flavor if you like :BORDERS 1) (:REQUIRED-METHODS :XOR-ACCENT ;Highlight the window by XOR'ing over it :QUESTIONNAIRE-RESET) ;Broadcast to all panes for general reset (:METHOD-COMBINATION (:PROGN :BASE-FLAVOR-LAST :QUESTIONNAIRE-RESET)) (:DOCUMENTATION :LOWLEVEL-MIXIN "Lowest level of the questionnaire-pane family")) ;This is just here to get rid of a gratuitous error message I put in for ;not having any methods (DEFMETHOD (ESSENTIAL-QUESTIONNAIRE-PANE :DEFAULT :QUESTIONNAIRE-RESET) () NIL) ;The regular mouse-buttons method screws me over by trying to select the pane. ;Punt that, but still have it call the system menu for the right-hand button, ;and have the feature of exposing the frame if not exposed and you click the ;left button. There is a wrapper to prevent it calling the daemons if ;the mouse was just used in one of those ways. ;This gets rid of the ESSENTIAL-MOUSE method, which tries to select it, fails, and beeps (DEFMETHOD (ESSENTIAL-QUESTIONNAIRE-PANE :MOUSE-BUTTONS) (IGNORE IGNORE IGNORE) NIL) (DEFWRAPPER (ESSENTIAL-QUESTIONNAIRE-PANE :MOUSE-BUTTONS) ((BD IGNORE IGNORE) . BODY) `(COND ((BIT-TEST 4 BD) (MOUSE-CALL-SYSTEM-MENU)) ((NOT (SHEET-EXPOSED-P SUPERIOR)) (FUNCALL SUPERIOR ':EXPOSE)) (T . ,BODY))) (DEFFLAVOR QUESTIONNAIRE-PANE-WITHOUT-LABEL () (ESSENTIAL-QUESTIONNAIRE-PANE STREAM-MIXIN BORDERS-MIXIN MINIMUM-WINDOW) (:DOCUMENTATION :COMBINATION "Base flavor for unlabelled questionnaire panes")) ;; XOR over the whole interior of the window (DEFMETHOD (QUESTIONNAIRE-PANE-WITHOUT-LABEL :XOR-ACCENT) () (%DRAW-RECTANGLE (SHEET-INSIDE-WIDTH) (SHEET-INSIDE-HEIGHT) (SHEET-INSIDE-LEFT) (SHEET-INSIDE-TOP) ALU-XOR SELF)) (DEFFLAVOR QUESTIONNAIRE-PANE-WITH-LABEL () (ESSENTIAL-QUESTIONNAIRE-PANE STREAM-MIXIN BORDERS-MIXIN TOP-CENTERED-LABEL-MIXIN DIVIDER-MIXIN CHANGEABLE-NAME-MIXIN SELECT-MIXIN MINIMUM-WINDOW) (:DEFAULT-INIT-PLIST :INTEGRAL-P T ;Do I want this? :BORDERS 2) ;I suspect this wants thicker borders (:DOCUMENTATION :COMBINATION "Base flavor for labelled questionnaire panes")) ;; XOR over just the label (DEFMETHOD (QUESTIONNAIRE-PANE-WITH-LABEL :XOR-ACCENT) () (MULTIPLE-VALUE-BIND (LLEFT LTOP LRIGHT LBOTTOM) (COMPUTE-LABEL-POSITION) (%DRAW-RECTANGLE (- LRIGHT LLEFT) (- LBOTTOM LTOP) LLEFT LTOP ALU-XOR SELF))) ;; This is a type of questionnaire pane which sort of consists of just a label. ;; It isn't implemented that way because that turns out to be hard to do. ;; Instead it has no label and automatically displays its name. ;; It's called a "button" because it sort of looks like a big square pushbutton. (DEFFLAVOR QUESTIONNAIRE-BUTTON-PANE () (QUESTIONNAIRE-PANE-WITHOUT-LABEL) (:DEFAULT-INIT-PLIST :FONT-MAP (LIST FONTS:MEDFNT)) (:DOCUMENTATION :COMBINATION "A questionnaire pane consisting of just a box and its name")) (DEFMETHOD (QUESTIONNAIRE-BUTTON-PANE :AFTER :REFRESH) (&REST IGNORE) (OR RESTORED-BITS-P (SHEET-DISPLAY-X-Y-CENTERED-STRING SELF NAME))) ;;; *** I still need to figure out what are really the best default border thicknesses *** ;;; Mixins for questionnaire panes with additional features ;;; This flavor provides the gettable/settable ACCENT value, which puts ;;; inverse video on the window if it is non-NIL. ;;; The :XOR-ACCENT method is not defined here, but elsewhere since it ;;; depends on whether or not the window has separate label and text areas. (DEFFLAVOR QUESTIONNAIRE-ACCENT-MIXIN ((ACCENT NIL)) () (:GETTABLE-INSTANCE-VARIABLES ACCENT) ;Really settable, but auto method would screw me (:INCLUDED-FLAVORS ESSENTIAL-QUESTIONNAIRE-PANE ESSENTIAL-WINDOW) (:DOCUMENTATION :MIXIN "Provides the accenting feature for questionnaire panes")) (DEFMETHOD (QUESTIONNAIRE-ACCENT-MIXIN :SET-ACCENT) (ACCENT-P) (OR (EQ (NOT ACCENT-P) (NOT ACCENT)) ;If complementing accent, (SHEET-FORCE-ACCESS (SELF) ; update it on the display (FUNCALL-SELF ':XOR-ACCENT))) (SETQ ACCENT ACCENT-P)) (DEFMETHOD (QUESTIONNAIRE-ACCENT-MIXIN :QUESTIONNAIRE-RESET) () (FUNCALL-SELF ':SET-ACCENT NIL)) ;; This assumes this flavor comes earlier in the flavor list than the label, ;; so that the label is already refreshed before this accenting happens. ;; **** This needs to be hacked for REFRESH-MARGINS **** (DEFMETHOD (QUESTIONNAIRE-ACCENT-MIXIN :AFTER :REFRESH) (&OPTIONAL TYPE) (OR RESTORED-BITS-P (NOT ACCENT) (FUNCALL-SELF ':XOR-ACCENT))) ;;; This flavor provides for a function to be called when the user clicks ;;; the mouse on the pane. The FUNCTION instance variable is the function, ;;; which may be set to NIL to disable the feature, or :BEEP to just beep, ;;; or a function to be called with four arguments: ;;; 1. The questionnaire frame ;;; 2. The name of the pane ;;; 3. The buttons mask ;;; 4. What happened: ;;; If this pane has a value, this is the new value. ;;; Else if this pane has an accent, this is the current accent; thus NIL if ;;; the user thinks he turned it on, and T if he thinks he turned it off, ;;; if the function is going to complement the accent. ;;; Else just NIL. ;;; Note that the function is run in a separate process, not in the mouse process, ;;; so it's free to do what it likes without worrying about hanging the mouse process. ;;; Note that the function gets called even if the user clicks to change the value ;;; then punts by hitting rubout. (DEFFLAVOR QUESTIONNAIRE-FUNCTION-MIXIN ((FUNCTION NIL)) () (:SETTABLE-INSTANCE-VARIABLES FUNCTION) (:INCLUDED-FLAVORS ESSENTIAL-QUESTIONNAIRE-PANE ESSENTIAL-WINDOW) (:DOCUMENTATION :MIXIN "Provides the feature of calling a function when moused, for questionnaire panes")) (DECLARE-FLAVOR-INSTANCE-VARIABLES (QUESTIONNAIRE-VALUE-ELEMENT) ;A bit of a kludge I admit (DEFMETHOD (QUESTIONNAIRE-FUNCTION-MIXIN :AFTER :MOUSE-BUTTONS) (BUTTONS IGNORE IGNORE) (COND ((NULL FUNCTION) NIL) ((OR (EQ FUNCTION ':BEEP) (AND (SYMBOLP FUNCTION) (NOT (FBOUNDP FUNCTION)))) (BEEP)) (T (PROCESS-RUN-FUNCTION "Questionnaire" FUNCTION (SHEET-SUPERIOR SELF) (FUNCALL (SHEET-SUPERIOR SELF) ':NAME-FOR-PANE SELF) BUTTONS (COND ((TYPEP SELF 'QUESTIONNAIRE-VALUE-ELEMENT) VALUE) ((TYPEP SELF 'QUESTIONNAIRE-ACCENT-MIXIN) ACCENT))))))) ;;; NOTE: You probably don't want to use this. It causes extraneous flashing, ;;; which could be fixed, but it also seems to be obnoxious and doesn't ;;; really fit in with our ways of doing things. I'm keeping it "in ;;; storage for man's use". ;This flavor provides that the accent will complement ;when a mouse button is pushed with the mouse over the window, and moving ;the mouse out of the window before releasing the button will cause the ;button to take no effect. Note that it does not change the ACCENT instance ;variable, which represents the desired state, not the current state. ;Note that this flavor precludes the ability to do multiple clicks and to ;get to the system menu from this type of window. If that is a problem ;it could be changed so that the right button gets you to the system menu ;and only the left button is for these hacks. (DEFFLAVOR QUESTIONNAIRE-MOUSE-MIXIN () () (:INCLUDED-FLAVORS ESSENTIAL-QUESTIONNAIRE-PANE) (:DOCUMENTATION :MIXIN "Provides xerox-like mouse (active when button released) for questionnaire panes")) ;Before processing the mouse-buttons message, complement the accent ;to show the user that he is winning, then run a function to wait ;for the button to be raised or the mouse to be moved out of the ;window, and to decide if the rest of the mosue button processing ;should be performed or skipped. The unwind-protect guarantees ;that the complementing of the accent gets undone. It is done just ;the way it is so that if the mouse button processor changes the ;accent state, it gets restored properly. (DEFWRAPPER (QUESTIONNAIRE-MOUSE-MIXIN :MOUSE-BUTTONS) (IGNORE . BODY) `(PROGN (FUNCALL-SELF ':XOR-ACCENT) (UNWIND-PROTECT (COND ((QUESTIONNAIRE-MOUSE-HACK-BUTTONS) . ,BODY)) (FUNCALL-SELF ':XOR-ACCENT)))) (DECLARE-FLAVOR-INSTANCE-VARIABLES (QUESTIONNAIRE-MOUSE-MIXIN) (DEFUN QUESTIONNAIRE-MOUSE-HACK-BUTTONS () ;; Wait for the button to be lifted. Return NIL if it should be ignored, ;; T if it should go through. Don't bother about inferiors and scroll bars. (MULTIPLE-VALUE-BIND (WINDOW-X-OFFSET WINDOW-Y-OFFSET) (SHEET-CALCULATE-OFFSETS SELF MOUSE-SHEET) (DO ((MIN-X 0) (MIN-Y 0) (MAX-X (1- (SHEET-INSIDE-WIDTH MOUSE-SHEET))) (MAX-Y (1- (SHEET-INSIDE-HEIGHT MOUSE-SHEET))) (DX) (DY) (BU) (BD) (MOVE-METHOD (OR (GET-HANDLER-FOR SELF ':MOUSE-MOVES) #'MOUSE-SET-BLINKER-CURSORPOS))) (MOUSE-RECONSIDER NIL) ;; Wait for the mouse to do something. (MULTIPLE-VALUE (DX DY BD BU) (MOUSE-INPUT)) (AND MOUSE-RECONSIDER (RETURN NIL)) ;; If button was released, then we are done. If still inside the window ;; process the previous button depression. (OR (ZEROP BU) (RETURN (WINDOW-OWNS-MOUSE-P SELF))) ;; Update the position of the mouse (SETQ MOUSE-X (MAX MIN-X (MIN MAX-X (+ MOUSE-X DX))) MOUSE-Y (MAX MIN-Y (MIN MAX-Y (+ MOUSE-Y DY)))) (FUNCALL MOVE-METHOD ':MOUSE-MOVES (- MOUSE-X WINDOW-X-OFFSET) (- MOUSE-Y WINDOW-Y-OFFSET)) ;; We are also done if the mouse has moved out of the window (OR (WINDOW-OWNS-MOUSE-P SELF) (RETURN NIL)))))) ;Entering the window with a button held down should work just like pushing ;the button after entering it. This is different from the way other windows ;work but seems right for this. (DEFMETHOD (QUESTIONNAIRE-MOUSE-MIXIN :BEFORE :HANDLE-MOUSE) () (AND (PLUSP MOUSE-LAST-BUTTONS) (MULTIPLE-VALUE-BIND (WINDOW-X-OFFSET WINDOW-Y-OFFSET) (SHEET-CALCULATE-OFFSETS SELF MOUSE-SHEET) (FUNCALL-SELF ':MOUSE-BUTTONS MOUSE-LAST-BUTTONS (- MOUSE-X WINDOW-X-OFFSET) (- MOUSE-Y WINDOW-Y-OFFSET))))) ;;; A questionnaire element is a window designed to go inside a questionnaire frame. ;;; Its main purpose is to maintain a value which can be changed with the mouse. ;;; It also maintains a true/false "accent" state; accent is normally displayed ;;; as inverse video over the label. Typically accenting is used to tell the ;;; user what elements are important to the current operation. ;;; You want to specify in your init-plist :NAME "foo" to set the label. ;;; This type of questionnaire element has no value; if you ask for the value ;;; you get T or NIL depending on the accent. Clicking the mouse just complements ;;; the accent. The initial value is always NIL. ;;; You don't want to mix this with QUESTIONNAIRE-FUNCTION-MIXIN, since in that ;;; case the function should control the turning on and off of the accent. (DEFFLAVOR QUESTIONNAIRE-ONOFF-ELEMENT () (QUESTIONNAIRE-ACCENT-MIXIN QUESTIONNAIRE-BUTTON-PANE) (:DOCUMENTATION :COMBINATION "A questionnaire element with T//NIL value, complemented by mouse")) ;These three methods simulate the value with the accent. I don't seem to ;use that, but it sounds like it ought to be convenient. (DEFMETHOD (QUESTIONNAIRE-ONOFF-ELEMENT :VALUE) () ACCENT) (DEFMETHOD (QUESTIONNAIRE-ONOFF-ELEMENT :SET-VALUE) (NEW-VALUE) (FUNCALL-SELF ':SET-ACCENT NEW-VALUE)) (DEFMETHOD (QUESTIONNAIRE-ONOFF-ELEMENT :RESET-VALUE) () (FUNCALL-SELF ':SET-ACCENT NIL)) ;Clicking any mouse button complements the accent (value). (DEFMETHOD (QUESTIONNAIRE-ONOFF-ELEMENT :MOUSE-BUTTONS) (BUTTON-MASK X-POS Y-POS) BUTTON-MASK X-POS Y-POS ;Ignored (FUNCALL-SELF ':SET-ACCENT (NOT ACCENT))) ;;; This type of questionnaire element consists of a button which if you click ;;; on it calls a function. This turns out to be pretty convenient. ;;; It comes in two sizes, regular and the large inflated-economy size. ;;; The sizes of these do not default from the name you give them, since ;;; that would interfere with the ability to make an array of them all ;;; the same size. Instead they default to what I wanted for TRACE, ;;; which may turn out to be the right thing for others as well. (DEFFLAVOR QUESTIONNAIRE-FUNCTION-BUTTON () (QUESTIONNAIRE-FUNCTION-MIXIN QUESTIONNAIRE-ACCENT-MIXIN QUESTIONNAIRE-BUTTON-PANE) (:DEFAULT-INIT-PLIST :CHARACTER-HEIGHT 1 :CHARACTER-WIDTH 10.) (:DOCUMENTATION :COMBINATION "A questionnaire element which calls a function when moused")) (DEFFLAVOR QUESTIONNAIRE-BIG-FUNCTION-BUTTON () (QUESTIONNAIRE-FUNCTION-BUTTON) (:DEFAULT-INIT-PLIST :FONT-MAP (LIST FONTS:BIGFNT) :BORDERS 4 :CHARACTER-HEIGHT 2 :CHARACTER-WIDTH 10.) (:DOCUMENTATION :COMBINATION "A questionnaire element, of prominent size, which calls a function when moused")) ;;; Basic flavor for a questionnaire element that has a value which is displayed. ;;; The default-init-plist sets up a label at the top, a divider below the label, ;;; and borders all around with a width of 2. ;;; Special messages: ;;; :RESET-VALUE restore value to INITIAL-VALUE ;;; :NEW-VALUE-FROM-KEYBOARD So you can redefine this method ;;; Also the accent and value messages implied by questionnaire frame messages. (DEFFLAVOR QUESTIONNAIRE-VALUE-ELEMENT (VALUE (INITIAL-VALUE "")) (QUESTIONNAIRE-ACCENT-MIXIN QUESTIONNAIRE-PANE-WITH-LABEL) ;(:SETTABLE-INSTANCE-VARIABLES VALUE INITIAL-VALUE) ;commented due to auto method bug (:SETTABLE-INSTANCE-VARIABLES INITIAL-VALUE) (:GETTABLE-INSTANCE-VARIABLES VALUE) ;Settable but there is an explicit set method (:DEFAULT-INIT-PLIST :BLINKER-P T) ;I need a blinker when asking for input (:DOCUMENTATION :COMBINATION "A questionnaire element containing a displayed value, input from keyboard")) (DEFMETHOD (QUESTIONNAIRE-VALUE-ELEMENT :BEFORE :INIT) (IGNORE) (SETQ VALUE INITIAL-VALUE)) ;Value will be displayed later (DEFMETHOD (QUESTIONNAIRE-VALUE-ELEMENT :RESET-VALUE) () (FUNCALL-SELF ':SET-VALUE INITIAL-VALUE)) (DEFMETHOD (QUESTIONNAIRE-VALUE-ELEMENT :QUESTIONNAIRE-RESET) () (FUNCALL-SELF ':SET-VALUE INITIAL-VALUE)) (DEFMETHOD (QUESTIONNAIRE-VALUE-ELEMENT :SET-VALUE) (NEW-VALUE) (SETQ VALUE NEW-VALUE) (DISPLAY-QUESTIONNAIRE-VALUE)) (DEFMETHOD (QUESTIONNAIRE-VALUE-ELEMENT :AFTER :REFRESH) (&OPTIONAL IGNORE) (OR RESTORED-BITS-P (DISPLAY-QUESTIONNAIRE-VALUE))) (DECLARE-FLAVOR-INSTANCE-VARIABLES (QUESTIONNAIRE-VALUE-ELEMENT) (DEFUN DISPLAY-QUESTIONNAIRE-VALUE (&REST IGNORE) (FUNCALL-SELF ':CLEAR-SCREEN) (LET ((STRING (COND ((STRINGP VALUE) VALUE) ((SYMBOLP VALUE) (GET-PNAME VALUE)) (T (FORMAT NIL "~D" VALUE))))) (SHEET-DISPLAY-X-Y-CENTERED-STRING SELF STRING)))) ;Fix bugs in the system select and deselect (DEFMETHOD (QUESTIONNAIRE-VALUE-ELEMENT :AFTER :SELECT) (&REST IGNORE) (BLINKER-SET-VISIBILITY (FIRST (SHEET-BLINKER-LIST SELF)) ':BLINK)) (DEFMETHOD (QUESTIONNAIRE-VALUE-ELEMENT :AFTER :DESELECT) (&REST IGNORE) (BLINKER-SET-VISIBILITY (FIRST (SHEET-BLINKER-LIST SELF)) NIL)) ;Clicking any mouse button gets a new string value from the keyboard (DEFMETHOD (QUESTIONNAIRE-VALUE-ELEMENT :MOUSE-BUTTONS) (BUTTON-MASK X-POS Y-POS) BUTTON-MASK X-POS Y-POS ;Ignored (SHEET-HOME SELF) ;Blinker should not appear in random place (FUNCALL-SELF ':SELECT NIL) ;; Peek ahead at the first character so present value not immediately erased ;; Typing just a rubout leaves the present value alone (LET ((CH (FUNCALL-SELF ':TYI))) (COND ((NOT (= CH #\RUBOUT)) (FUNCALL-SELF ':UNTYI CH) (FUNCALL-SELF ':CLEAR-SCREEN) (SETQ VALUE (FUNCALL-SELF ':NEW-VALUE-FROM-KEYBOARD)) (DISPLAY-QUESTIONNAIRE-VALUE)))) (FUNCALL-SELF ':DESELECT NIL)) ;This method is the default, but typically gets replaced, for flavors with different syntax (DEFMETHOD (QUESTIONNAIRE-VALUE-ELEMENT :NEW-VALUE-FROM-KEYBOARD) () (READLINE SELF)) ;;; A questionnaire element whose value is constrained to be an integer. (DEFFLAVOR QUESTIONNAIRE-INTEGER-ELEMENT () (QUESTIONNAIRE-VALUE-ELEMENT) (:DOCUMENTATION :COMBINATION "A questionnaire value element constrained to be an integer")) (DEFMETHOD (QUESTIONNAIRE-INTEGER-ELEMENT :NEW-VALUE-FROM-KEYBOARD) () (LET ((STANDARD-INPUT SELF) (IBASE 10.)) (DO ((NUM)) (NIL) (SETQ NUM (READ-FOR-TOP-LEVEL)) (AND (FIXP NUM) (RETURN NUM)) (FUNCALL-SELF ':CLEAR-SCREEN) (FUNCALL-SELF ':STRING-OUT "Number: ")))) ;;; A questionnaire element whose value is an S-expression. Also remembers the ;;; package to work in. Input radix is decimal since output radix is. ;;; Perhaps that should be controllable? ;;; Note that PACKAGE is initialized to self rather than to unbound, because otherwise ;;; the who-line can see the unbound symbol. (DEFFLAVOR QUESTIONNAIRE-SEXP-ELEMENT ((PACKAGE PACKAGE)) (QUESTIONNAIRE-VALUE-ELEMENT) (:SETTABLE-INSTANCE-VARIABLES PACKAGE) (:DOCUMENTATION :COMBINATION "A questionnaire element whose displayed value is a Lisp S-expression")) (DEFMETHOD (QUESTIONNAIRE-SEXP-ELEMENT :NEW-VALUE-FROM-KEYBOARD) () (LET ((STANDARD-INPUT SELF) (IBASE 10.)) (READ-FOR-TOP-LEVEL))) ;;; One that takes from a set of choices, you could use TRUE and FALSE if you like. ;;; This one doesn't use the keyboard, but rotates around the set as you click with ;;; the mouse. (DEFFLAVOR QUESTIONNAIRE-CHOICES-ELEMENT (CHOICES) (QUESTIONNAIRE-VALUE-ELEMENT) (:SETTABLE-INSTANCE-VARIABLES CHOICES) (:DOCUMENTATION :COMBINATION "A questionnaire element with a fixed set of values")) ;If no initial value given, default to the first choice. You better ;give the choices in the init-plist! (DEFMETHOD (QUESTIONNAIRE-CHOICES-ELEMENT :BEFORE :INIT) (INIT-PLIST) (OR (GET INIT-PLIST ':INITIAL-VALUE) (SETQ INITIAL-VALUE (FIRST CHOICES)))) ;Clicking the mouse picks the next choice (DEFMETHOD (QUESTIONNAIRE-CHOICES-ELEMENT :MOUSE-BUTTONS) (IGNORE IGNORE IGNORE) (FUNCALL-SELF ':SET-VALUE (OR (CADR (MEMQ VALUE CHOICES)) (CAR CHOICES)))) ;;; Value elements that also call a function after the user changes the value (DEFFLAVOR QUESTIONNAIRE-VALUE-FUNCTION-ELEMENT () (QUESTIONNAIRE-FUNCTION-MIXIN QUESTIONNAIRE-VALUE-ELEMENT) (:DOCUMENTATION :COMBINATION "A questionnaire value element that calls a function when value changed")) (DEFFLAVOR QUESTIONNAIRE-INTEGER-FUNCTION-ELEMENT () (QUESTIONNAIRE-FUNCTION-MIXIN QUESTIONNAIRE-INTEGER-ELEMENT) (:DOCUMENTATION :COMBINATION "A questionnaire integer element that calls a function when value changed")) (DEFFLAVOR QUESTIONNAIRE-SEXP-FUNCTION-ELEMENT () (QUESTIONNAIRE-FUNCTION-MIXIN QUESTIONNAIRE-SEXP-ELEMENT) (:DOCUMENTATION :COMBINATION "A questionnaire sexp element that calls a function when value changed")) (DEFFLAVOR QUESTIONNAIRE-CHOICES-FUNCTION-ELEMENT () (QUESTIONNAIRE-FUNCTION-MIXIN QUESTIONNAIRE-CHOICES-ELEMENT) (:DOCUMENTATION :COMBINATION "A questionnaire choices element that calls a function when value changed")) ;;; This should come after all flavor definitions (COMPILE-FLAVOR-METHODS QUESTIONNAIRE-FRAME QUESTIONNAIRE-PANE-WITHOUT-LABEL QUESTIONNAIRE-PANE-WITH-LABEL QUESTIONNAIRE-BUTTON-PANE QUESTIONNAIRE-ONOFF-ELEMENT QUESTIONNAIRE-FUNCTION-BUTTON QUESTIONNAIRE-BIG-FUNCTION-BUTTON QUESTIONNAIRE-VALUE-ELEMENT QUESTIONNAIRE-INTEGER-ELEMENT QUESTIONNAIRE-SEXP-ELEMENT QUESTIONNAIRE-CHOICES-ELEMENT QUESTIONNAIRE-VALUE-FUNCTION-ELEMENT QUESTIONNAIRE-INTEGER-FUNCTION-ELEMENT QUESTIONNAIRE-SEXP-FUNCTION-ELEMENT QUESTIONNAIRE-CHOICES-FUNCTION-ELEMENT) ;Trace window. I am trying to get something which looks like this: ; ; TRACE ; Function ; Print ; Break When Conditional ; Step ; Argpdl Form ; Wherein ; CANCEL DO IT UNTRACE ; ;Most of these are function-button type elements. Function contains the name of the function ;to do. When lets you choose between Before, After, and Before&After. ;Conditional is usually a trace conditional, if you select Print or Break ;it becomes a conditional just for that, if you select argpdl or wherein it ;is renamed and used to read the argument to those. ;Form shows the trace form being built up. ;CANCEL normally cancels the whole thing, when lit it cancels just the current ;operation that is waiting for arguments. ;Should this be a resource? (DEFVAR TRACE-WINDOW) (DEFVAR TRACE-WINDOW-FORM) (DEFUN MAKE-TRACE-WINDOW () (SETQ TRACE-WINDOW (WINDOW-CREATE 'QUESTIONNAIRE-FRAME ':NAME "TRACE" ':LEFT 100 ':TOP 100 ':WIDTH 1000 ':HEIGHT 600 ':PANES '((PRINT QUESTIONNAIRE-FUNCTION-BUTTON :NAME "Print" :FUNCTION TRACE-WINDOW-PRINT-BUTTON) (BREAK QUESTIONNAIRE-FUNCTION-BUTTON :NAME "Break" :FUNCTION TRACE-WINDOW-BREAK-BUTTON) (STEP QUESTIONNAIRE-FUNCTION-BUTTON :NAME "Step" :FUNCTION TRACE-WINDOW-STEP-BUTTON) (ARGPDL QUESTIONNAIRE-FUNCTION-BUTTON :NAME "Arg pdl" :FUNCTION TRACE-WINDOW-ARGPDL-BUTTON) (WHEREIN QUESTIONNAIRE-FUNCTION-BUTTON :NAME "Wherein" :FUNCTION TRACE-WINDOW-WHEREIN-BUTTON) (UNDO QUESTIONNAIRE-FUNCTION-BUTTON :NAME "Undo" :FUNCTION TRACE-WINDOW-UNDO-BUTTON) (CANCEL QUESTIONNAIRE-BIG-FUNCTION-BUTTON :NAME "Cancel" :FUNCTION TRACE-WINDOW-CANCEL-BUTTON) (DO-IT QUESTIONNAIRE-BIG-FUNCTION-BUTTON :NAME "Do It" :FUNCTION TRACE-WINDOW-DO-IT-BUTTON) (UNTRACE QUESTIONNAIRE-BIG-FUNCTION-BUTTON :NAME "UnTrace" :FUNCTION TRACE-WINDOW-UNTRACE-BUTTON) (FUNCTION QUESTIONNAIRE-SEXP-FUNCTION-ELEMENT :NAME "Function" :CHARACTER-HEIGHT 2 :FUNCTION TRACE-WINDOW-FUNCTION-SPECIFIED) (WHEN QUESTIONNAIRE-CHOICES-ELEMENT :NAME "When" :CHOICES (BEFORE&AFTER BEFORE AFTER) :EDGES-FROM "BEFORE&AFTER ") (CONDITIONAL QUESTIONNAIRE-SEXP-FUNCTION-ELEMENT :NAME "Conditional" :CHARACTER-HEIGHT 2 :FUNCTION TRACE-WINDOW-CONDITIONAL-SPECIFIED) (FORM QUESTIONNAIRE-PANE-WITHOUT-LABEL)) ':CONSTRAINTS '((MAIN . ( (1DUMY) ((1DUMY :HORIZONTAL (:EVEN) (2DUMY) ((2DUMY INTERDIGITATED-WHITESPACE :WHITE :INCLUDE ;Vertical (:EVEN) (:EVEN) ;; We start with a vertical stack of the function name, ;; the bulk of the cruft, and the 3 big buttons at the bottom (FUNCTIONX 3DUMY 3-BIG-BUTTONS) ((FUNCTIONX INTERDIGITATED-WHITESPACE :WHITE :INCLUDE ;Hor (:ASK-WINDOW FUNCTION :PANE-HEIGHT) (:EVEN) (FUNCTION) ((FUNCTION 0.9))) (3-BIG-BUTTONS INTERDIGITATED-WHITESPACE :WHITE :INCLUDE ;Hor (:ASK-WINDOW CANCEL :PANE-HEIGHT) (:EVEN) (CANCEL DO-IT UNTRACE) ((CANCEL :ASK :PANE-WIDTH) (DO-IT :ASK :PANE-WIDTH) (UNTRACE :ASK :PANE-WIDTH)))) ((3DUMY INTERDIGITATED-WHITESPACE :WHITE :INCLUDE ;Horizontal (0.85) (:EVEN) ;; This consists of the function buttons in a column ;; on the left, and to the right of that the When ;; and Conditional above the Form. (SMALL-BUTTONS 4DUMY) ((SMALL-BUTTONS INTERDIGITATED-WHITESPACE :WHITE :EXCLUDE ;V (:ASK-WINDOW PRINT :PANE-WIDTH) (:EVEN) (PRINT BREAK STEP ARGPDL WHEREIN UNDO) ((PRINT :ASK :PANE-HEIGHT) (BREAK :ASK :PANE-HEIGHT) (STEP :ASK :PANE-HEIGHT) (ARGPDL :ASK :PANE-HEIGHT) (WHEREIN :ASK :PANE-HEIGHT) (UNDO :ASK :PANE-HEIGHT)))) ((4DUMY INTERDIGITATED-WHITESPACE :WHITE :EXCLUDE ;Vertical (0.9) (:EVEN) (5DUMY FORM) ((5DUMY INTERDIGITATED-WHITESPACE :WHITE :EXCLUDE ;Hor ;; I really just want the max of the two heights (:ASK-WINDOW CONDITIONAL :PANE-HEIGHT) (:EVEN) (WHEN CONDITIONAL) ((WHEN :ASK :PANE-WIDTH)) ((CONDITIONAL 0.9)))) ((FORM 0.9)))))))))))))))) (DEFUN CALL-TRACE-WINDOW (&OPTIONAL FUNCTION (PKG PACKAGE)) (OR (BOUNDP 'TRACE-WINDOW) (MAKE-TRACE-WINDOW)) (FUNCALL TRACE-WINDOW ':BROADCAST ':QUESTIONNAIRE-RESET) (FUNCALL TRACE-WINDOW ':SEND-ELEMENT 'CONDITIONAL ':SET-NAME "Conditional") (FUNCALL TRACE-WINDOW ':SEND-ELEMENT 'FUNCTION ':SET-PACKAGE PKG) (FUNCALL TRACE-WINDOW ':SEND-ELEMENT 'CONDITIONAL ':SET-PACKAGE PKG) (SETQ TRACE-WINDOW-FORM NIL) ;Should perhaps be some sort of instance variable? (IF FUNCTION (FUNCALL TRACE-WINDOW ':SET-ELEMENT-VALUE 'FUNCTION FUNCTION) (FUNCALL TRACE-WINDOW ':SET-ELEMENT-ACCENT 'FUNCTION T)) (IF FUNCTION (TRACE-WINDOW-FUNCTION-SPECIFIED TRACE-WINDOW 'FUNCTION 1 FUNCTION) (FUNCALL TRACE-WINDOW ':SEND-ELEMENT 'FORM ':CLEAR-SCREEN)) (FUNCALL TRACE-WINDOW ':SELECT T) T) ;Magic arguments are frame, pane-name, buttons, new-value or accent-state ;This is called when a new value has been specified in the function window. ;Initialize the trace form, but if there's already options in it retain them. (DEFUN TRACE-WINDOW-FUNCTION-SPECIFIED (W IGNORE IGNORE FUNCTION) (LET ((OPTIONS (COND ((NULL TRACE-WINDOW-FORM) NIL) ;Parse out current options ((EQ (CAADR TRACE-WINDOW-FORM) ':FUNCTION) (CDDADR TRACE-WINDOW-FORM)) (T (CDADR TRACE-WINDOW-FORM))))) (PUSH FUNCTION OPTIONS) ;Put function onto front of options list (AND (OR (LISTP FUNCTION) (EQ FUNCTION ':FUNCTION)) (PUSH ':FUNCTION OPTIONS)) (SETQ TRACE-WINDOW-FORM (LIST 'TRACE OPTIONS)) (FUNCALL W ':SET-ELEMENT-ACCENT 'FUNCTION NIL) (TRACE-WINDOW-REDISPLAY W))) ;CLAUSE is a list which is nconc'ed onto the end of the trace options (DEFUN TRACE-WINDOW-ADD-CLAUSE (W CLAUSE &OPTIONAL INHIBIT-REDISPLAY) (OR TRACE-WINDOW-FORM (SETQ TRACE-WINDOW-FORM (SUBST NIL NIL '(TRACE (:FUNCTION "not yet specified"))))) (DOLIST (PIECE CLAUSE) (NCONC (CADR TRACE-WINDOW-FORM) (NCONS PIECE))) (OR INHIBIT-REDISPLAY (TRACE-WINDOW-REDISPLAY W))) (DEFUN TRACE-WINDOW-REDISPLAY (W) (LET ((WW (FUNCALL W ':FIND-PANE 'FORM))) ;Redisplay the form (FUNCALL WW ':CLEAR-SCREEN) (GRIND-TOP-LEVEL TRACE-WINDOW-FORM (FUNCALL WW ':SIZE-IN-CHARACTERS) WW))) ;This is used to make function buttons light up while they are executing. ;Useful for making the display more busy, and confirmation that it is working. (DEFMACRO WITH-TEMPORARY-ACCENT ((FRAME PANE-NAME) . BODY) `(LET ((.OLD-ACCENT. (FUNCALL ,FRAME ':ELEMENT-ACCENT ,PANE-NAME))) (UNWIND-PROTECT (PROGN (FUNCALL ,FRAME ':SET-ELEMENT-ACCENT ,PANE-NAME (NOT .OLD-ACCENT.)) . ,BODY) (FUNCALL ,FRAME ':SET-ELEMENT-ACCENT ,PANE-NAME .OLD-ACCENT.)))) ;This is called when someone clicks on the Print button. Normally, it puts you ;into "print" mode, lighting Print, When, Cancel, and Form (over Conditional). ;But when lit, it completes Print mode, adding to the form. (DEFUN TRACE-WINDOW-PRINT-BUTTON (W IGNORE IGNORE MODE) (COND ((NOT MODE) ;Not lit (TRACE-WINDOW-CANCEL-BUTTON W NIL 0 T) ;Cancel special modes (FUNCALL W ':SET-ELEMENT-ACCENT 'PRINT T) ;Light appropriate frobs (FUNCALL W ':SET-ELEMENT-ACCENT 'WHEN T) (FUNCALL W ':SET-ELEMENT-ACCENT 'CANCEL T) (FUNCALL W ':SEND-ELEMENT 'CONDITIONAL ':SET-NAME "Form to print") (FUNCALL W ':SET-ELEMENT-ACCENT 'CONDITIONAL T)) (T ;Lit, set up a PRINT operation (LET ((FORM (FUNCALL W ':ELEMENT-VALUE 'CONDITIONAL)) (WHEN (FUNCALL W ':ELEMENT-VALUE 'WHEN))) (TRACE-WINDOW-ADD-CLAUSE W (LIST (SELECTQ WHEN (BEFORE ':ENTRYPRINT) (AFTER ':EXITPRINT) (OTHERWISE ':PRINT)) FORM)) (TRACE-WINDOW-CANCEL-BUTTON W NIL 0 T))))) ;Cancel special modes ;This is called when someone clicks on the Break button. Normally, it puts you ;into "break" mode, lighting Break, When, Cancel, and Conditional. ;But when lit, it completes Break mode, adding to the form. (DEFUN TRACE-WINDOW-BREAK-BUTTON (W IGNORE IGNORE MODE) (COND ((NOT MODE) ;Not lit (TRACE-WINDOW-CANCEL-BUTTON W NIL 0 T) ;Cancel special modes (FUNCALL W ':SET-ELEMENT-ACCENT 'BREAK T) ;Light appropriate frobs (FUNCALL W ':SET-ELEMENT-ACCENT 'WHEN T) (FUNCALL W ':SET-ELEMENT-ACCENT 'CANCEL T) (FUNCALL W ':SET-ELEMENT-ACCENT 'CONDITIONAL T)) (T ;Lit, set up a BREAK operation (LET ((COND (FUNCALL W ':ELEMENT-VALUE 'CONDITIONAL)) (WHEN (FUNCALL W ':ELEMENT-VALUE 'WHEN))) (AND (EQUAL COND "") (SETQ COND T)) ;Unspecified means always (superfluous code) (OR (EQ WHEN 'AFTER) (TRACE-WINDOW-ADD-CLAUSE W `(:BREAK ,COND) T)) (OR (EQ WHEN 'BEFORE) (TRACE-WINDOW-ADD-CLAUSE W `(:EXITBREAK ,COND))) (TRACE-WINDOW-CANCEL-BUTTON W NIL 0 T))))) ;Cancel special modes ;This is called when someone clicks on the Step button. It has no options. (DEFUN TRACE-WINDOW-STEP-BUTTON (W P IGNORE IGNORE) (WITH-TEMPORARY-ACCENT (W P) (TRACE-WINDOW-ADD-CLAUSE W '(:STEP)))) ;This is called when someone clicks on the Undo button. Remove the last ;option clause from the trace form. (DEFUN TRACE-WINDOW-UNDO-BUTTON (W P IGNORE IGNORE) (WITH-TEMPORARY-ACCENT (W P) (DO ((L (CADR TRACE-WINDOW-FORM) (CDR L)) ;Find the place where option list should end (LAST NIL)) ((NULL L) (IF (NULL LAST) (BEEP) (RPLACD LAST NIL))) ;; If a clause starts after here, remember here (AND (MEMQ (CADR L) '(:ENTRYPRINT :EXITPRINT :PRINT :BREAK :EXITBREAK :STEP :ARGPDL :WHEREIN :COND :ENTRYCOND :EXITCOND)) (SETQ LAST L))) (TRACE-WINDOW-REDISPLAY W))) ;This is called when someone clicks on the Argpdl button. Need to get an argument. (DEFUN TRACE-WINDOW-ARGPDL-BUTTON (W IGNORE IGNORE MODE) (COND ((NOT MODE) ;Not lit (TRACE-WINDOW-CANCEL-BUTTON W NIL 0 T) ;Cancel special modes (FUNCALL W ':SET-ELEMENT-ACCENT 'ARGPDL T) ;Light appropriate frobs (FUNCALL W ':SET-ELEMENT-ACCENT 'CANCEL T) (FUNCALL W ':SEND-ELEMENT 'CONDITIONAL ':SET-NAME "Argpdl variable") (FUNCALL W ':SET-ELEMENT-ACCENT 'CONDITIONAL T)) (T ;Lit, complete operation (LET ((VAR (FUNCALL W ':ELEMENT-VALUE 'CONDITIONAL))) (TRACE-WINDOW-ADD-CLAUSE W `(:ARGPDL ,VAR)) (TRACE-WINDOW-CANCEL-BUTTON W NIL 0 T))))) ;This is called when someone clicks on the Wherein button. Need to get an argument. (DEFUN TRACE-WINDOW-WHEREIN-BUTTON (W IGNORE IGNORE MODE) (COND ((NOT MODE) ;Not lit (TRACE-WINDOW-CANCEL-BUTTON W NIL 0 T) ;Cancel special modes (FUNCALL W ':SET-ELEMENT-ACCENT 'WHEREIN T) ;Light appropriate frobs (FUNCALL W ':SET-ELEMENT-ACCENT 'CANCEL T) (FUNCALL W ':SEND-ELEMENT 'CONDITIONAL ':SET-NAME "Wherein function") (FUNCALL W ':SET-ELEMENT-ACCENT 'CONDITIONAL T)) (T ;Lit, complete operation (LET ((FCN (FUNCALL W ':ELEMENT-VALUE 'CONDITIONAL))) (TRACE-WINDOW-ADD-CLAUSE W `(:WHEREIN ,FCN)) (TRACE-WINDOW-CANCEL-BUTTON W NIL 0 T))))) ;This is called when someone clicks on the Do It button. Call trace. (DEFUN TRACE-WINDOW-DO-IT-BUTTON (W IGNORE IGNORE IGNORE) (LET ((TERMINAL-IO (FUNCALL W ':FIND-PANE 'FORM)) (ERROR-OUTPUT SI:SYN-TERMINAL-IO)) (COND ((ERRSET (EVAL TRACE-WINDOW-FORM)) (FUNCALL W ':DESELECT T) (FUNCALL W ':DEACTIVATE))))) ;MODE is NIL if cancelling the whole thing, T ("when lit") if cancelling a special mode (DEFUN TRACE-WINDOW-CANCEL-BUTTON (W IGNORE IGNORE MODE) (COND (MODE ;When lit (DOLIST (X '(PRINT BREAK ARGPDL WHEREIN WHEN CANCEL CONDITIONAL)) (FUNCALL W ':SET-ELEMENT-ACCENT X NIL)) (FUNCALL W ':SEND-ELEMENT 'CONDITIONAL ':SET-NAME "Conditional") (FUNCALL W ':SET-ELEMENT-VALUE 'CONDITIONAL "")) (T (FUNCALL W ':DESELECT T) (FUNCALL W ':DEACTIVATE)))) ;Called when someone clicks on the conditional/utility pane. This can conditionalize ;the whole trace, provided it is not lit and not being used for something else. ;Otherwise, the value that was just entered will be picked up later by another function. (DEFUN TRACE-WINDOW-CONDITIONAL-SPECIFIED (W P IGNORE COND) (LET ((WW (FUNCALL W ':FIND-PANE P))) (COND ((AND (NULL (FUNCALL WW ':ACCENT)) (EQUAL (SHEET-NAME WW) "Conditional")) (LET ((WHEN (FUNCALL W ':ELEMENT-VALUE 'WHEN))) (TRACE-WINDOW-ADD-CLAUSE W (LIST (SELECTQ WHEN (BEFORE ':ENTRYCOND) (AFTER ':EXITCOND) (OTHERWISE ':COND)) COND))))))) ;******* To be done ******* ;The Untrace button. Wants to reformat and give a menu of guys to untrace, or "all". ;Refreshing the frame needs to refresh the form window. Good general mechanism?