;;; -*- Mode:LISP; Package:TV; Base:8; Readtable:ZL -*- ;;; ** (c) Copyright 1980 Massachusetts Institute of Technology ** ;;; Superior that supports its inferiors as panes -- windows which are managed ;;; by the superior in some way ;;; Each window that is a pane (an inferior of a frame), should include ;;; the PANE-MIXIN flavor so as to interact correctly (DEFFLAVOR PANE-MIXIN () () (:INCLUDED-FLAVORS ESSENTIAL-WINDOW) (:DOCUMENTATION "No-op for compatibility")) (DEFFLAVOR PANE-NO-MOUSE-SELECT-MIXIN () (DONT-SELECT-WITH-MOUSE-MIXIN) :ALIAS-FLAVOR) (DEFFLAVOR WINDOW-PANE () (WINDOW) :ALIAS-FLAVOR) (DEFFLAVOR LISP-LISTENER-PANE () (LISP-LISTENER) :ALIAS-FLAVOR) (DEFFLAVOR COMMAND-MENU-PANE () (COMMAND-MENU) :ALIAS-FLAVOR) ;;; Basic frame contains methods that are used by most frames ;;; Recursion variable keeps track of whether or not we are performing an operation ;;; that will cause us to get notified. If RECURSION is set, the routine ;;; should ignore the notification and return immediatly a value of T. This ;;; will be the standard. (DEFFLAVOR BASIC-FRAME ((RECURSION NIL)) (ESSENTIAL-EXPOSE ESSENTIAL-ACTIVATE ESSENTIAL-SET-EDGES POP-UP-NOTIFICATION-MIXIN ESSENTIAL-WINDOW) (:REQUIRED-METHODS :INFERIOR-SET-EDGES) (:DEFAULT-INIT-PLIST :BLINKER-P NIL :MORE-P NIL) (:DOCUMENTATION "Pane handling messages used by most frames")) ;; Obsolete name. (DEFFLAVOR FRAME-DONT-SELECT-INFERIORS-WITH-MOUSE-MIXIN () (ALIAS-FOR-INFERIORS-MIXIN) (:REQUIRED-FLAVORS BASIC-FRAME) (:DOCUMENTATION "Don't list our panes in Select menu.")) (DEFMETHOD (FRAME-DONT-SELECT-INFERIORS-WITH-MOUSE-MIXIN :SELECTABLE-WINDOWS) (&AUX STRING) (AND (SETQ STRING (SEND SELF ':NAME-FOR-SELECTION)) (LIST (LIST STRING SELF)))) (DEFFLAVOR INFERIORS-NOT-IN-SELECT-MENU-MIXIN () (ALIAS-FOR-INFERIORS-MIXIN) (:REQUIRED-FLAVORS BASIC-FRAME) (:DOCUMENTATION "Don't list our panes in Select menu.")) (DEFMETHOD (INFERIORS-NOT-IN-SELECT-MENU-MIXIN :SELECTABLE-WINDOWS) (&AUX STRING) (AND (SETQ STRING (SEND SELF ':NAME-FOR-SELECTION)) (LIST (LIST STRING SELF)))) (DEFMETHOD (BASIC-FRAME :SELECTED-PANE) () SELECTION-SUBSTITUTE) ;This sets what pane should be selected if this window is selected. (DEFMETHOD (BASIC-FRAME :SELECT-PANE) (PANE) (OR (MEMQ PANE INFERIORS) (NULL PANE) (FERROR "Cannot select ~S, which is not a pane of ~S" PANE SELF)) (SEND SELF :SET-SELECTION-SUBSTITUTE PANE)) (DEFMETHOD (BASIC-FRAME :NAME-FOR-SELECTION) () (AND SELECTION-SUBSTITUTE (SEND SELECTION-SUBSTITUTE :NAME-FOR-SELECTION))) ;;This is a bad way to do things, and will get flushed ;;once the system is verified to work without it. (DEFCONST FLUSH-BASIC-FRAME-STATUS-METHOD NIL) (DEFWRAPPER (BASIC-FRAME :STATUS) (IGNORE . BODY) `(COND ((AND SELECTION-SUBSTITUTE (NOT FLUSH-BASIC-FRAME-STATUS-METHOD) (EQ (SEND SELECTION-SUBSTITUTE :STATUS) ':SELECTED)) ':SELECTED) (T . ,BODY))) (DEFMETHOD (BASIC-FRAME :AFTER :ACTIVATE) (&REST IGNORE) (DOLIST (I INFERIORS) ;; Give it a chance to put itself in previously-selected-windows. (SEND I ':ACTIVATE))) (DEFMETHOD (BASIC-FRAME :AFTER :DEACTIVATE) (&REST IGNORE) ;; Make sure that none of our inferiors are remembered as selectable (DOLIST (I INFERIORS) (REMOVE-FROM-PREVIOUSLY-SELECTED-WINDOWS I))) (DEFWRAPPER (BASIC-FRAME :PRINT-NOTIFICATION) (ARGS . BODY) `(IF SELECTION-SUBSTITUTE (LEXPR-SEND SELECTION-SUBSTITUTE :PRINT-NOTIFICATION ARGS) . ,BODY)) ;; Removing this should make nested frames win more. ;(DEFMETHOD (BASIC-FRAME :ALIAS-FOR-SELECTED-WINDOWS) () SELF) (DEFMETHOD (BASIC-FRAME :INFERIOR-SELECT) (PANE) (SETQ SELECTION-SUBSTITUTE PANE) T) ;;; Screen management et. al. (DEFMETHOD (BASIC-FRAME :SCREEN-MANAGE-RESTORE-AREA) (RECTS ARRAY-TO-DRAW-ON X Y ALU &AUX RS) (IF BIT-ARRAY (SCREEN-MANAGE-RESTORE-AREA RECTS ARRAY-TO-DRAW-ON X Y ALU T) (DOLIST (R RECTS) (COND ((EQ (CAR (RECT-SOURCE R)) SELF) (PUSH (LIST (LIST SELF 0 0) (- (RECT-LEFT R) X-OFFSET) (- (RECT-TOP R) Y-OFFSET) (- (RECT-RIGHT R) X-OFFSET) (- (RECT-BOTTOM R) Y-OFFSET)) RS) (SETQ RECTS (DELQ R RECTS))))) (SCREEN-MANAGE-SHEET SELF RS ARRAY-TO-DRAW-ON (+ X X-OFFSET) (+ Y Y-OFFSET) ALU) RECTS)) ;; I think these are no longer relevant. ;(DEFWRAPPER (BASIC-FRAME :EXPOSE) (IGNORE . BODY) ; `(LETF ((RECURSION T)) ; . ,BODY)) ;(DEFWRAPPER (BASIC-FRAME :DEEXPOSE) (IGNORE . BODY) ; `(LETF ((RECURSION T)) ; . ,BODY)) (DEFMETHOD (BASIC-FRAME :SCREEN-MANAGE-DEEXPOSED-VISIBILITY) () T) (DEFMETHOD (BASIC-FRAME :SCREEN-MANAGE-UNCOVERED-AREA) SCREEN-MANAGE-CLEAR-UNCOVERED-AREA) (DEFFLAVOR FRAME-FORWARDING-MIXIN () () (:INCLUDED-FLAVORS BASIC-FRAME) (:DOCUMENTATION "Used when forwarding of EXPOSE//DEEXPOSE//BURY messages from pane to frame is desired.")) (DEFMETHOD (FRAME-FORWARDING-MIXIN :INFERIOR-EXPOSE) (PANE) PANE (COND (RECURSION T) (T (SEND SELF ':EXPOSE) NIL))) (DEFMETHOD (FRAME-FORWARDING-MIXIN :INFERIOR-DEEXPOSE) (PANE) PANE (COND (RECURSION T) (T (SEND SELF ':DEEXPOSE) NIL))) (DEFMETHOD (FRAME-FORWARDING-MIXIN :INFERIOR-BURY) (PANE) PANE (COND (RECURSION T) (T (SEND SELF ':BURY) NIL))) (DEFMETHOD (FRAME-FORWARDING-MIXIN :INFERIOR-SET-EDGES) (PANE &REST ARGS) (IF RECURSION T (LETF ((RECURSION T)) ;; :SET-EDGES can deexpose and reexpose the pane; ;; avoid forwarding that to the frame. (LEXPR-SEND PANE ':SET-EDGES ARGS)))) (DEFWRAPPER (FRAME-FORWARDING-MIXIN :SCREEN-MANAGE-AUTOEXPOSE-INFERIORS) (IGNORE . BODY) `(LETF ((RECURSION T)) . ,BODY)) (DEFMETHOD (BASIC-FRAME :PANE-TYPES-ALIST) () NIL) ;;; Simple superior for split-screen (DEFFLAVOR SPLIT-SCREEN-FRAME () (scale-inferiors-mixin BASIC-FRAME)) (DEFMETHOD (SPLIT-SCREEN-FRAME :PANE-TYPES-ALIST) () DEFAULT-WINDOW-TYPES-ITEM-LIST) (DEFMETHOD (SPLIT-SCREEN-FRAME :NAME-FOR-SELECTION) () NAME) (DEFMETHOD (SPLIT-SCREEN-FRAME :AFTER :EXPOSE) (&REST IGNORE) (REMOVE-FROM-PREVIOUSLY-SELECTED-WINDOWS SELF)) (DEFMETHOD (SPLIT-SCREEN-FRAME :AFTER :ACTIVATE) (&REST IGNORE) (REMOVE-FROM-PREVIOUSLY-SELECTED-WINDOWS SELF)) (DEFMETHOD (SPLIT-SCREEN-FRAME :SELECT) (&REST ARGS) (SEND SELF ':SET-SELECTION-SUBSTITUTE (FIRST EXPOSED-INFERIORS)) (LEXPR-SEND (FIRST EXPOSED-INFERIORS) ':SELECT ARGS)) ;;; Constraint frames -- these frames maintain their panes based on a set ;;; of constraints. These frames are the right thing for most frame applications. ;PANES is the list describing the panes, specified by the user. ;INTERNAL-PANES is an alist mapping pane-names (as used in PANES and in constraints) ;to actual windows. ;EXPOSED-PANES is a list of panes used in the current configuration. ;CONSTRAINTS is, again, the list specified by the user. ;PARSED-CONSTRAINS is the result of crunching that. ;INTERNAL-CONSTRAINS contains the parsed constraints for this configuration. (DEFFLAVOR BASIC-CONSTRAINT-FRAME (PANES INTERNAL-PANES SELECTION-SUBSTITUTE (EXPOSED-PANES NIL) CONSTRAINTS PARSED-CONSTRAINTS INTERNAL-CONSTRAINTS (SUBSTITUTIONS NIL) (BLANK-RECTANGLES NIL) (CONFIGURATION NIL)) (BASIC-FRAME) (:INITABLE-INSTANCE-VARIABLES CONSTRAINTS PANES SUBSTITUTIONS SELECTION-SUBSTITUTE CONFIGURATION) (:GETTABLE-INSTANCE-VARIABLES CONSTRAINTS PANES CONFIGURATION) (:SETTABLE-INSTANCE-VARIABLES EXPOSED-PANES) (:DOCUMENTATION "Maintains panes according to specified constraints")) ;There used to be a definition of the :inferior-set-edges operation here. ;Let's see if there is any problem with this being the same as FRAME-FORWARDING-MIXIN ;before flushing the separate name. (DEFFLAVOR CONSTRAINT-FRAME-FORWARDING-MIXIN () (FRAME-FORWARDING-MIXIN)) (DEFFLAVOR CONSTRAINT-FRAME-NO-FORWARDING () (BASIC-CONSTRAINT-FRAME BASIC-FRAME) (:DOCUMENTATION "Constraint frame, but with no special handling of FORWARDed messages such as :EXPOSE.")) (DEFFLAVOR CONSTRAINT-FRAME () (BASIC-CONSTRAINT-FRAME CONSTRAINT-FRAME-FORWARDING-MIXIN BASIC-FRAME) (:DOCUMENTATION "Normal constraint frame")) (DEFFLAVOR BORDERED-CONSTRAINT-FRAME () (BASIC-CONSTRAINT-FRAME CONSTRAINT-FRAME-FORWARDING-MIXIN BORDERS-MIXIN BASIC-FRAME) (:DEFAULT-INIT-PLIST :BORDER-MARGIN-WIDTH 0) (:DOCUMENTATION "Maintains uniform borders around panes")) (DEFSTRUCT (CONSTRAINT-NODE :ARRAY) CONSTRAINT-NAME ;Name of this node (CONSTRAINT-MIN -1) ;Minimum limit (CONSTRAINT-MAX 1_20.) ;Maximum limit CONSTRAINT-CONSTRAINT ;The constraint as specified by the user CONSTRAINT-TYPE ;One of: :WINDOW, :STACKING, :IF, :BLANK CONSTRAINT-DATA ;If WINDOW: the window ;If SPECIAL: (ordering . inferiors) ;If IF: (conditional . inferiors) ;If BLANK: function to draw "whitespace" (CONSTRAINT-CW 0) ;Current position of this window (if a window) (CONSTRAINT-CH 0) (CONSTRAINT-CX 0) (CONSTRAINT-CY 0) (CONSTRAINT-PW 0) ;Proposed position (CONSTRAINT-PH 0) (CONSTRAINT-PX 0) (CONSTRAINT-PY 0)) (DEFUN CONSTRAINT-FRAME-PROCESS-CONSTRAINTS (&REST IGNORE) "CONSTRAINTS contains a list of unprocessed constraints. Process them. Entries look like: constraint := ({:LIMIT (min max {[:LINES | :CHARACTERS]})} [:ASK-WINDOW pane-name message . args | :ASK message . args | :FUNCALL function . args | :EVAL form | [:EVEN | fixnum | flonum] {[:LINES | :CHARACTERS]} | :FIXED ]) desc := (ordering desc-part) desc-part := (desc-group) {desc-part} desc-group := [ ('window name' . constraint) | ('special name' [:HORIZONTAL | :VERTICAL] constraint . desc) | ('special name' :IF [conditional | :ELSE] desc) ('special name' :BLANK [:WHITE | :BLACK] constraint) ] {desc-group} Fixnum - absolute number of pixels Flonum - percentage of available space :EVEN - divide remaining space evenly among all :EVEN constraints :EVEN's can only be in the last descriptor group, and must be by themselves (No other types of constraints allowed) :ASK, :ASK-WINDOW, :FUNCALL - sends the message to the pane with the args as shown below, and the specified args, and expects back the height or the width that the window wants to be. :ASK-WINDOW takes the name of a window as its first arg. :EVAL - evals the specified form :FIXED - Only for a window: never change the window's size For :FUNCALL the first arg is the node. For :EVAL, **CONSTRAINT-NODE** is bound to the node. The first five arguments given to the method are as follows: **CONSTRAINT-REMAINING-WIDTH** - The maximum width of the window (amount of space remaining for this window) **CONSTRAINT-REMAINING-HEIGHT** - The maximum height **CONSTRAINT-TOTAL-WIDTH** - The total width of the current section **CONSTRAINT-TOTAL-HEIGHT** - The total height of the current section **CONSTRAINT-CURRENT-STACKING** - :HORIZONTAL or :VERTICAL, depending upon which dimension is currently being hacked (In the case of :EVAL, these special variables are bound) A typical frame setup might be (dimension starts out as :HEIGHT): ((WA LISP-LISTENER) (WB MENU :ITEM-LIST (foo bar baz quux)) (WC MY-OWN-LISP-LISTENER) (WD SOME-OTHER-FUNNY-WINDOW :MY-INIT MY-ARG)) ((WA WB G0) ((WB :ASK :PANE-SIZE)) ((WA :LIMIT (3 NIL :LINES) :EVEN) (G0 :HORIZONTAL (:ASK-WINDOW WD :PANE-SIZE) (WD WC) ((WC :LIMIT (10. NIL :LINES) :EVEN) (WD :LIMIT (10. NIL :LINES) :EVEN)))))" (DECLARE (:SELF-FLAVOR BASIC-CONSTRAINT-FRAME)) ;; First turn constraint list into nodes (SETQ INTERNAL-PANES (LETF ((RECURSION T)) (CONSTRAINT-FRAME-WINDOWS PANES))) (SETQ PARSED-CONSTRAINTS NIL) (DOLIST (CONSTR CONSTRAINTS) (PUSH (CONS (CAR CONSTR) (CONSTRAINT-FRAME-PARSE-CONSTRAINTS (CDR CONSTR) INTERNAL-PANES)) PARSED-CONSTRAINTS)) (SETQ PARSED-CONSTRAINTS (NREVERSE PARSED-CONSTRAINTS))) (DEFMETHOD (BASIC-CONSTRAINT-FRAME :AFTER :INIT) (IGNORE) (CONSTRAINT-FRAME-PROCESS-CONSTRAINTS) (SETF `(,CONFIGURATION . ,INTERNAL-CONSTRAINTS) (IF CONFIGURATION (OR (ASSQ CONFIGURATION PARSED-CONSTRAINTS) (FERROR "Configuration ~S not found" CONFIGURATION)) (FIRST PARSED-CONSTRAINTS))) ;Default initial configuration (AND SELECTION-SUBSTITUTE (SYMBOLP SELECTION-SUBSTITUTE) (SETQ SELECTION-SUBSTITUTE (SEND SELF ':GET-PANE SELECTION-SUBSTITUTE))) (CONSTRAINT-FRAME-RECOMPUTE-CONFIGURATION)) (DEFUN CONSTRAINT-FRAME-DRAW-BLANK-SPACE (&OPTIONAL (CONSTRS INTERNAL-CONSTRAINTS)) "Map over the constraint data structure, and draw all blank area." (DECLARE (:SELF-FLAVOR BASIC-CONSTRAINT-FRAME)) (DOLIST (AENTRY (FIRST CONSTRS)) (LET ((NODE (CDR AENTRY))) (CASE (CONSTRAINT-TYPE NODE) (:BLANK (PREPARE-SHEET (SELF) (CONSTRAINT-FRAME-DRAW-A-BLANK (CONSTRAINT-DATA NODE) NODE (CONSTRAINT-CX NODE) (CONSTRAINT-CY NODE) (CONSTRAINT-CW NODE) (CONSTRAINT-CH NODE) SCREEN-ARRAY))) (:STACKING (CONSTRAINT-FRAME-DRAW-BLANK-SPACE (CONSTRAINT-DATA NODE))))))) (DEFMETHOD (BASIC-CONSTRAINT-FRAME :AFTER :REFRESH) (&OPTIONAL TYPE) (OR (AND RESTORED-BITS-P (NEQ TYPE ':SIZE-CHANGED)) (EQ TYPE ':MARGINS-ONLY) (CONSTRAINT-FRAME-DRAW-BLANK-SPACE))) (DEFMETHOD (BASIC-CONSTRAINT-FRAME :AFTER :CHANGE-OF-DEFAULT-FONT) (OLD-FONT NEW-FONT) ;; SHEET'S method got the INFERIORS -- get any panes that weren't got then. (DOLIST (ELT INTERNAL-PANES) (LET ((PANE (CDR ELT))) (OR (MEMQ PANE INFERIORS) (NOT (TYPEP PANE 'INSTANCE)) (SEND PANE :CHANGE-OF-DEFAULT-FONT OLD-FONT NEW-FONT))))) ;;; Stuff for dealing with panes by name (DEFMETHOD (BASIC-CONSTRAINT-FRAME :GET-PANE) (PANE-NAME) "Returns the pane with specified name or NIL if not found" (CDR (ASSQ PANE-NAME INTERNAL-PANES))) (DEFMETHOD (BASIC-CONSTRAINT-FRAME :SEND-PANE) (PANE-NAME MESSAGE &REST ARGS &AUX W) "Send a message to the pane with specified name (error if not found)" (IF (SETQ W (CDR (ASSQ PANE-NAME INTERNAL-PANES))) (LEXPR-SEND W MESSAGE ARGS) (FERROR "No pane named ~S in this frame" PANE-NAME))) (DEFMETHOD (BASIC-CONSTRAINT-FRAME :SEND-ALL-PANES) (MESSAGE &REST ARGS) "Send a message to all panes, including non-exposed ones" (DOLIST (X INTERNAL-PANES) (LEXPR-SEND (CDR X) MESSAGE ARGS))) (DEFMETHOD (BASIC-CONSTRAINT-FRAME :SEND-ALL-EXPOSED-PANES) (MESSAGE &REST ARGS) "Send a message to all exposed panes" (DOLIST (X INTERNAL-PANES) (AND (MEMQ (CDR X) EXPOSED-INFERIORS) (LEXPR-SEND (CDR X) MESSAGE ARGS)))) (DEFMETHOD (BASIC-CONSTRAINT-FRAME :PANE-NAME) (PANE) "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." (DOLIST (X INTERNAL-PANES) (AND (EQ (CDR X) PANE) (RETURN (CAR X))))) (DEFMETHOD (BASIC-CONSTRAINT-FRAME :GET-CONFIGURATION) (CONFIG-NAME) (CDR (ASSQ CONFIG-NAME PARSED-CONSTRAINTS))) (DEFMETHOD (BASIC-CONSTRAINT-FRAME :REDEFINE-CONFIGURATION) (CONFIG-NAME NEW-CONFIG &OPTIONAL (PARSED-P T)) (OR PARSED-P (SETQ NEW-CONFIG (CONSTRAINT-FRAME-PARSE-CONSTRAINTS NEW-CONFIG INTERNAL-PANES))) (LET ((CONFIG (ASSQ CONFIG-NAME PARSED-CONSTRAINTS))) (WITHOUT-INTERRUPTS (OR CONFIG (IF PARSED-CONSTRAINTS (RPLACD (LAST PARSED-CONSTRAINTS) (SETQ CONFIG (CONS CONFIG-NAME NIL))) (SETQ PARSED-CONSTRAINTS (SETQ CONFIG (CONS CONFIG-NAME NIL)))))) (RPLACD CONFIG NEW-CONFIG) NEW-CONFIG)) (DEFMETHOD (BASIC-CONSTRAINT-FRAME :SET-CONFIGURATION) (NEW-CONFIG-NAME) (LET ((CONFIG (ASSQ NEW-CONFIG-NAME PARSED-CONSTRAINTS))) (OR CONFIG (FERROR "Unknown configuration ~A" NEW-CONFIG-NAME)) (SETQ CONFIGURATION (CAR CONFIG) INTERNAL-CONSTRAINTS (CDR CONFIG) BLANK-RECTANGLES NIL)) (CONSTRAINT-FRAME-CLEAR-CURRENT-POSITION INTERNAL-CONSTRAINTS) (CONSTRAINT-FRAME-RECOMPUTE-CONFIGURATION)) (DEFUN CONSTRAINT-FRAME-CLEAR-CURRENT-POSITION (CONSTRS &AUX NODE) (DOLIST (AENTRY (FIRST CONSTRS)) (SETQ NODE (CDR AENTRY)) (CASE (CONSTRAINT-TYPE NODE) (:WINDOW (MULTIPLE-VALUE-BIND (LEFT TOP RIGHT BOTTOM) (SEND (CONSTRAINT-DATA NODE) :EDGES) (SETF (CONSTRAINT-CX NODE) LEFT) (SETF (CONSTRAINT-CY NODE) TOP) (SETF (CONSTRAINT-CW NODE) (- RIGHT LEFT)) (SETF (CONSTRAINT-CH NODE) (- BOTTOM TOP)))) (:STACKING (CONSTRAINT-FRAME-CLEAR-CURRENT-POSITION (CONSTRAINT-DATA NODE))) (:IF (FERROR ":IF node type not yet implemented")) (OTHERWISE (SETF (CONSTRAINT-CX NODE) 0) (SETF (CONSTRAINT-CY NODE) 0) (SETF (CONSTRAINT-CW NODE) 0) (SETF (CONSTRAINT-CH NODE) 0))))) (DEFMETHOD (BASIC-CONSTRAINT-FRAME :VERIFY-NEW-EDGES) (IGNORE IGNORE NEW-WIDTH NEW-HEIGHT) (COND ((VARIABLE-BOUNDP INTERNAL-CONSTRAINTS) (IF (NOT (CONSTRAINT-FRAME-DO-CONSTRAINTS SELF INTERNAL-CONSTRAINTS (- NEW-WIDTH LEFT-MARGIN-SIZE RIGHT-MARGIN-SIZE) (- NEW-HEIGHT TOP-MARGIN-SIZE BOTTOM-MARGIN-SIZE))) "Some constraint cannot be satisfied" ;; Change our size temporarily ;; so that panes will check their edges against the new size (WITHOUT-INTERRUPTS (LETF ((WIDTH NEW-WIDTH) (HEIGHT NEW-HEIGHT) (RECURSION T)) (COND ((CONSTRAINT-FRAME-SET-EDGES INTERNAL-CONSTRAINTS ':VERIFY) NIL) (T "Some pane refused to have its size set")))))))) (DEFUN CONSTRAINT-FRAME-RECOMPUTE-CONFIGURATION () (DECLARE (:SELF-FLAVOR BASIC-CONSTRAINT-FRAME)) (PRESERVE-SUBSTITUTE-STATUS SELF (LETF ((RECURSION T)) (SEND SELF :DEEXPOSE :DEFAULT :NOOP) (DOLIST (P EXPOSED-PANES) (SEND P :DEEXPOSE :DEFAULT :NOOP) ;; This assures that old panes won't gratuitously reappear if there is ;; blank space in the new configuration where a pane used to be. Note that ;; this is careful not to touch inferiors that aren't "panes" of this ;; constraint frame. (SEND P :DEACTIVATE)) (OR (CONSTRAINT-FRAME-DO-CONSTRAINTS SELF INTERNAL-CONSTRAINTS (SHEET-INSIDE-WIDTH) (SHEET-INSIDE-HEIGHT)) (FERROR "Some constraint could not be satisfied")) (CONSTRAINT-FRAME-SET-EDGES INTERNAL-CONSTRAINTS NIL) (DOLIST (P EXPOSED-PANES) (SEND P :EXPOSE)) (SETQ BLANK-RECTANGLES NIL) (SHEET-FORCE-ACCESS (SELF :NO-PREPARE) (CONSTRAINT-FRAME-DRAW-BLANK-SPACE)) (OR (MEMQ SELECTION-SUBSTITUTE EXPOSED-INFERIORS) (SETQ SELECTION-SUBSTITUTE NIL))))) ;;; When the inside-size changes, rethink the constraints and panes' edges (DEFMETHOD (BASIC-CONSTRAINT-FRAME :AFTER :CHANGE-OF-SIZE-OR-MARGINS) (&REST IGNORE) (CONSTRAINT-FRAME-RECOMPUTE-CONFIGURATION)) (DEFUN CONSTRAINT-FRAME-SCREEN-MANAGE-UNCOVERED-AREA (RECTS ARRAY X Y IGNORE) "If there is any blank area, it might be covered by some :BLANK type constraints. Check through the constraint list, and draw onto the array the appropriate swatches of 'blankness'" (DECLARE (:SELF-FLAVOR BASIC-CONSTRAINT-FRAME)) (OR BLANK-RECTANGLES ;; If haven't figured out the blank rectangles, compute them now (SETQ BLANK-RECTANGLES (OR (CONSTRAINT-FRAME-MAKE-BLANK-RECTANGLES INTERNAL-CONSTRAINTS) T))) (AND (NEQ BLANK-RECTANGLES T) (DOLIST (R RECTS) (COND ((EQ (CAR (RECT-SOURCE R)) SELF) ;; This is a blank area, hack appropriate portions of it (PROG DONE ((REMAINING-BLANK-RECTS (LIST R))) (DOLIST (BLANK-RECT BLANK-RECTANGLES) (DOLIST (REM-BLANK-RECT REMAINING-BLANK-RECTS) (COND ((RECT-NOT-OVERLAP-RECT-P BLANK-RECT REM-BLANK-RECT)) (T (LET ((NODE (FOURTH (RECT-SOURCE BLANK-RECT))) (LEFT) (TOP) (RIGHT) (BOTTOM)) ;; Draw the overlapping area (SETQ LEFT (MAX (RECT-LEFT BLANK-RECT) (RECT-LEFT REM-BLANK-RECT)) TOP (MAX (RECT-TOP BLANK-RECT) (RECT-TOP REM-BLANK-RECT)) RIGHT (MIN (RECT-RIGHT BLANK-RECT) (RECT-RIGHT REM-BLANK-RECT)) BOTTOM (MIN (RECT-BOTTOM BLANK-RECT) (RECT-BOTTOM REM-BLANK-RECT))) (CONSTRAINT-FRAME-DRAW-A-BLANK (CONSTRAINT-DATA NODE) NODE (+ X LEFT) (+ Y TOP) (- RIGHT LEFT) (- BOTTOM TOP) ARRAY)) (SETQ REMAINING-BLANK-RECTS (NCONC (RECTANGLE-NOT-INTERSECTION BLANK-RECT REM-BLANK-RECT) (DELQ REM-BLANK-RECT REMAINING-BLANK-RECTS))) (AND (NULL REMAINING-BLANK-RECTS) (RETURN-FROM DONE)))))) (SETQ RECTS (NCONC REMAINING-BLANK-RECTS RECTS))) (SETQ RECTS (DELQ R RECTS 1)))))) RECTS) (DEFWRAPPER (BASIC-CONSTRAINT-FRAME :SCREEN-MANAGE-UNCOVERED-AREA) ((RECTS ARRAY X Y ALU) . BODY) `(PROGN (SETF (SECOND SI::.DAEMON-CALLER-ARGS.) (CONSTRAINT-FRAME-SCREEN-MANAGE-UNCOVERED-AREA RECTS ARRAY X Y ALU)) . ,BODY)) (DEFUN CONSTRAINT-FRAME-MAKE-BLANK-RECTANGLES (CONSTR &AUX RECTS) (DOLIST (AENTRY (FIRST CONSTR)) (LET ((NODE (CDR AENTRY)) (X) (Y)) (CASE (CONSTRAINT-TYPE NODE) (:BLANK (PUSH (LIST (LIST SELF 0 0 NODE) (SETQ X (CONSTRAINT-CX NODE)) (SETQ Y (CONSTRAINT-CY NODE)) (+ X (CONSTRAINT-CW NODE)) (+ Y (CONSTRAINT-CH NODE))) RECTS)) (:STACKING (SETQ RECTS (NCONC RECTS (CONSTRAINT-FRAME-MAKE-BLANK-RECTANGLES (CONSTRAINT-DATA NODE)))))))) RECTS) (DEFVAR CONSTRAINT-FRAME-DEFAULT-STACKING ':VERTICAL) (DEFUN CONSTRAINT-FRAME-SET-EDGES (CONSTRS OPTION &AUX X Y R) "Loop over all panes and hack the edges as specified by the option." (NOT (DOLIST (AENTRY (FIRST CONSTRS)) (LET ((NODE (CDR AENTRY))) (CASE (CONSTRAINT-TYPE NODE) (:WINDOW (SETQ R (OR (AND (NEQ OPTION ':VERIFY) (= (CONSTRAINT-PX NODE) (CONSTRAINT-CX NODE)) (= (CONSTRAINT-PY NODE) (CONSTRAINT-CY NODE)) (= (CONSTRAINT-PW NODE) (CONSTRAINT-CW NODE)) (= (CONSTRAINT-PH NODE) (CONSTRAINT-CH NODE))) (SEND (CONSTRAINT-DATA NODE) :SET-EDGES (SETQ X (CONSTRAINT-PX NODE)) (SETQ Y (CONSTRAINT-PY NODE)) (+ X (CONSTRAINT-PW NODE)) (+ Y (CONSTRAINT-PH NODE)) OPTION)))) (:STACKING (SETQ R (CONSTRAINT-FRAME-SET-EDGES (CONSTRAINT-DATA NODE) OPTION))) (:IF (FERROR ":IF is unimplemented option")) (OTHERWISE (SETQ R T))) (IF (EQ OPTION ':VERIFY) ;; If verifying, return right away if didn't verify (OR R (RETURN T)) ;; If not verifying, proposed data is now current data (SETF (CONSTRAINT-CX NODE) (CONSTRAINT-PX NODE)) (SETF (CONSTRAINT-CY NODE) (CONSTRAINT-PY NODE)) (SETF (CONSTRAINT-CW NODE) (CONSTRAINT-PW NODE)) (SETF (CONSTRAINT-CH NODE) (CONSTRAINT-PH NODE))))))) (DEFUN CONSTRAINT-FRAME-WINDOWS (DESCS &AUX PARSED) (DOLIST (DESC DESCS) (PUSH (CONS (FIRST DESC) (IF (TYPEP (CDR DESC) 'SHEET) (CDR DESC) (LEXPR-SEND SELF ':CREATE-PANE DESC))) PARSED)) PARSED) (DEFMETHOD (BASIC-CONSTRAINT-FRAME :CREATE-PANE) (IGNORE FLAVOR &REST OPTIONS) (APPLY #'MAKE-INSTANCE FLAVOR :SUPERIOR SELF OPTIONS)) (DEFFLAVOR CONSTRAINT-FRAME-WITH-SHARED-IO-BUFFER ((IO-BUFFER NIL)) (BASIC-CONSTRAINT-FRAME) (:INITABLE-INSTANCE-VARIABLES IO-BUFFER) (:GETTABLE-INSTANCE-VARIABLES IO-BUFFER)) (DEFMETHOD (CONSTRAINT-FRAME-WITH-SHARED-IO-BUFFER :BEFORE :INIT) (IGNORE) (OR IO-BUFFER (SETQ IO-BUFFER (MAKE-DEFAULT-IO-BUFFER)))) (DEFMETHOD (CONSTRAINT-FRAME-WITH-SHARED-IO-BUFFER :CREATE-PANE) (IGNORE FLAVOR &REST OPTIONS) (APPLY #'MAKE-INSTANCE FLAVOR :SUPERIOR SELF :IO-BUFFER IO-BUFFER OPTIONS)) (DEFFLAVOR BORDERED-CONSTRAINT-FRAME-WITH-SHARED-IO-BUFFER () (CONSTRAINT-FRAME-WITH-SHARED-IO-BUFFER CONSTRAINT-FRAME-FORWARDING-MIXIN BORDERS-MIXIN BASIC-FRAME) (:DEFAULT-INIT-PLIST :BORDER-MARGIN-WIDTH 0)) (DEFUN CONSTRAINT-FRAME-SUBSTITUTION (DESC) (DECLARE (:SELF-FLAVOR BASIC-CONSTRAINT-FRAME)) (COND ((CONSP DESC) DESC) ((SYMBOLP DESC) (OR (CDR (ASSQ DESC SUBSTITUTIONS)) (FERROR "~A is a symbol where a list was expected (and it has no substitution)" DESC))) (T (FERROR "~A was found where a list (or a symbol with a substitution) was expected" DESC)))) (DEFUN CONSTRAINT-FRAME-PARSE-CONSTRAINTS (CONSTRAINTS PANES &OPTIONAL (STACKING CONSTRAINT-FRAME-DEFAULT-STACKING)) "Given a list of constraints, returns the internal format." (LET ((INTERNAL-ORDERING NIL) (ORDERING (CAR CONSTRAINTS)) (INTERNAL-DESCS NIL)) (OR (CONSP ORDERING) (FERROR "Constraint ~S does not start with an ordering" CONSTRAINTS)) (DO ((WNS ORDERING (CDR WNS)) (WS NIL) (WINDOW)) ((NULL WNS) (SETQ INTERNAL-ORDERING (NREVERSE WS))) (PUSH (CONS (CAR WNS) (IF (SETQ WINDOW (ASSQ (CAR WNS) PANES)) (CDR WINDOW) ;A window, include the window itself (CAR WNS))) ;Must be a special name, will fill it in later WS)) (DO ((DESC-GROUPS (CDR CONSTRAINTS) (CDR DESC-GROUPS)) (INTERNAL-DESC-GROUP NIL NIL) (EVEN-P NIL NIL) (LAST-GROUP-P)) ((NULL DESC-GROUPS)) ;; Process each descriptor group (SETQ LAST-GROUP-P (NULL (CDR DESC-GROUPS))) (DOLIST (DESC (CONSTRAINT-FRAME-SUBSTITUTION (CAR DESC-GROUPS))) REPARSE ;Yes, this is a GO tag! ;; For each descriptor, parse it (SETQ DESC (CONSTRAINT-FRAME-SUBSTITUTION DESC)) (LET ((NAME (CAR DESC)) (WOS) (AENTRY) (MACRO-P)) (OR (SETQ WOS (CDR (SETQ AENTRY (ASSQ NAME INTERNAL-ORDERING)))) (FERROR "~A is unspecified in the ordering" NAME)) (COND ((TYPEP WOS 'SHEET) ;; A window -- parse the constraint and make the node (MULTIPLE-VALUE-BIND (CONSTR MIN MAX TEM) (PARSE-CONSTRAINT (CDR DESC) PANES WOS LAST-GROUP-P EVEN-P) (SETQ EVEN-P TEM) (PUSH (MAKE-CONSTRAINT-NODE CONSTRAINT-NAME (GET-PNAME NAME) CONSTRAINT-TYPE ':WINDOW CONSTRAINT-CONSTRAINT CONSTR CONSTRAINT-DATA WOS CONSTRAINT-MIN MIN CONSTRAINT-MAX MAX) INTERNAL-DESC-GROUP))) ((NOT (SYMBOLP WOS)) (FERROR "~A is not a valid special name at this point" NAME)) ((MEMQ (SECOND DESC) '(:HORIZONTAL :VERTICAL)) (AND (EQ (SECOND DESC) STACKING) (FERROR "Current stacking (~A) same as new stacking" STACKING)) (MULTIPLE-VALUE-BIND (CONSTR MIN MAX TEM) (PARSE-CONSTRAINT (THIRD DESC) PANES NIL LAST-GROUP-P EVEN-P) (SETQ EVEN-P TEM) (PUSH (MAKE-CONSTRAINT-NODE CONSTRAINT-NAME (GET-PNAME NAME) CONSTRAINT-TYPE ':STACKING CONSTRAINT-CONSTRAINT CONSTR CONSTRAINT-DATA (CONSTRAINT-FRAME-PARSE-CONSTRAINTS (CDDDR DESC) PANES (SECOND DESC)) CONSTRAINT-MIN MIN CONSTRAINT-MAX MAX) INTERNAL-DESC-GROUP))) ((EQ (SECOND DESC) ':IF) (FERROR "Conditionals not currently supported")) ((EQ (SECOND DESC) ':BLANK) (MULTIPLE-VALUE-BIND (CONSTR MIN MAX TEM) (PARSE-CONSTRAINT (CDDDR DESC) PANES NIL LAST-GROUP-P EVEN-P) (SETQ EVEN-P TEM) (PUSH (MAKE-CONSTRAINT-NODE CONSTRAINT-NAME (GET-PNAME NAME) CONSTRAINT-TYPE ':BLANK CONSTRAINT-CONSTRAINT CONSTR CONSTRAINT-DATA (CASE (THIRD DESC) (:WHITE #'CONSTRAINT-FRAME-WHITE-BLANKING) (:BLACK #'CONSTRAINT-FRAME-BLACK-BLANKING) (OTHERWISE (THIRD DESC))) CONSTRAINT-MIN MIN CONSTRAINT-MAX MAX) INTERNAL-DESC-GROUP))) ((SETQ MACRO-P (GET (SECOND DESC) 'CONSTRAINT-MACRO)) ;; A macro: expand it and use its expansion in place of the current ;; description (SETQ DESC (CONS (CAR DESC) (FUNCALL MACRO-P DESC STACKING))) (GO REPARSE)) (T (FERROR "~A is unknown special keyword, perhaps ~A is missing from TV:PANES" (SECOND DESC) (FIRST DESC)))) (RPLACD AENTRY (CAR INTERNAL-DESC-GROUP)))) (PUSH (NREVERSE INTERNAL-DESC-GROUP) INTERNAL-DESCS)) (DOLIST (ORD INTERNAL-ORDERING) (AND (OR (TYPEP (CDR ORD) 'SHEET) (EQ (CAR ORD) (CDR ORD))) (FERROR "~A was specified in ordering, but not specified in any descriptor" (CAR ORD)))) (CONS INTERNAL-ORDERING (NREVERSE INTERNAL-DESCS)))) (DEFUNP PARSE-CONSTRAINT (CONSTR PANES WINDOW LG-P EVEN-P &AUX (MIN -1) (MAX 1_15.)) "Verify correctness of the specified constraint. Returns the constraint part of the constraint, as well as the limits if specified." (COND ((EQ (FIRST CONSTR) ':LIMIT) (LET ((LIMITS (SECOND CONSTR)) (ROUND) (OFFSET)) (COND ((> (LENGTH LIMITS) 2) (OR (SETQ WINDOW (OR (PARSE-CONSTRAINT-GET-PANE (FOURTH LIMITS) PANES) WINDOW)) (FERROR "Illegal format :LIMIT (no window specified)")) (CASE (THIRD LIMITS) (:CHARACTERS (SETQ ROUND (SHEET-CHAR-WIDTH WINDOW) OFFSET (+ (SHEET-LEFT-MARGIN-SIZE WINDOW) (SHEET-RIGHT-MARGIN-SIZE WINDOW)))) (:LINES (SETQ ROUND (SHEET-LINE-HEIGHT WINDOW) OFFSET (+ (SHEET-TOP-MARGIN-SIZE WINDOW) (SHEET-BOTTOM-MARGIN-SIZE WINDOW)))) (OTHERWISE (FERROR "~A is illegal rounding specification" (THIRD LIMITS)))))) (SETQ MIN (OR (FIRST LIMITS) MIN) MAX (OR (SECOND LIMITS) MAX)) (SETQ MIN (IF ROUND (+ (* MIN ROUND) OFFSET) MIN) MAX (IF ROUND (+ (* MAX ROUND) OFFSET) MAX))) (SETQ CONSTR (CDDR CONSTR)))) (COND ((OR (IF (NUMBERP (FIRST CONSTR)) (OR (NULL EVEN-P) (EQ EVEN-P ':NO) (FERROR "Cannot mix :EVEN constraints and other constraints")) NIL) (COND ((EQ (FIRST CONSTR) ':EVEN) (OR LG-P (FERROR ":EVEN not in last descriptor group")) ;;; This was causing incredible problems... looks useless -dg ; (OR (NULL EVEN-P) (EQ EVEN-P ':YES) ; (FERROR "Cannot mix :EVEN constraints and other constraints")) (SETQ EVEN-P ':YES) T))) (COND ((> (LENGTH CONSTR) 1) (LET ((W (PARSE-CONSTRAINT-GET-PANE (THIRD CONSTR) PANES))) (IF W (SETQ WINDOW W CONSTR (LIST (FIRST CONSTR) (SECOND CONSTR) W)) (OR WINDOW (FERROR "Illegal format constraint -- no window specified")))) (OR (MEMQ (SECOND CONSTR) '(:LINES :CHARACTERS)) (FERROR "Illegal rounding specifier ~A" (SECOND CONSTR))) (AND (FIXP (FIRST CONSTR)) (SETQ CONSTR (LIST (* (FIRST CONSTR) (CASE (SECOND CONSTR) (:LINES (SHEET-LINE-HEIGHT WINDOW)) (:CHARACTERS (SHEET-CHAR-WIDTH WINDOW)))) (SECOND CONSTR) WINDOW)))))) ((NOT (OR (NULL EVEN-P) (EQ EVEN-P ':NO))) (FERROR "Cannot mix :EVEN constraints and other constraints")) ((MEMQ (FIRST CONSTR) '(:ASK :FUNCALL :EVAL :FIXED))) ((EQ (FIRST CONSTR) ':ASK-WINDOW) (LET ((W (IF (EQ (SECOND CONSTR) 'SELF) SELF (CDR (ASSQ (SECOND CONSTR) PANES))))) (OR W (FERROR "Unknown pane ~A is :ASK-WINDOW constraint" (SECOND CONSTR))) (SETF (SECOND (SETQ CONSTR (COPYLIST CONSTR))) W)))) (RETURN (VALUES CONSTR MIN MAX (OR EVEN-P ':NO)))) (DEFUN PARSE-CONSTRAINT-GET-PANE (PANE-NAME PANES) (AND PANE-NAME (OR (CDR (ASSQ PANE-NAME PANES)) (FERROR "Unknown pane name ~A" PANE-NAME)))) (DEFUN CONSTRAINT-FRAME-DO-CONSTRAINTS (FRAME CONSTRS &OPTIONAL (W (SHEET-INSIDE-WIDTH FRAME)) (H (SHEET-INSIDE-HEIGHT FRAME))) (CATCH ':VERTICAL (CATCH ':HORIZONTAL (PROGN (CONSTRAINT-FRAME-DO-SIZES W H CONSTRS) (SEND FRAME :SET-EXPOSED-PANES (CONSTRAINT-FRAME-DO-POSITIONS CONSTRS CONSTRAINT-FRAME-DEFAULT-STACKING (SHEET-LEFT-MARGIN-SIZE FRAME) (SHEET-TOP-MARGIN-SIZE FRAME))) T)))) (DEFUN CONSTRAINT-FRAME-DO-SIZES (WIDTH HEIGHT CONSTRS &OPTIONAL (STACKING CONSTRAINT-FRAME-DEFAULT-STACKING)) "Given that the current width and height of the frame, calculate new values of position and size for each node. Constraints are assumed parsed and valid." ;;; **** Does not know about min's or max's yet! (LET ((DESC-GROUPS (CDR CONSTRS))) (DOLIST (DESC-GROUP DESC-GROUPS) ;; For each group, assign widths and heights (LET (WIDTH-USED HEIGHT-USED) (COND ((NOT (CATCH STACKING (PROGN (MULTIPLE-VALUE (WIDTH-USED HEIGHT-USED) (CONSTRAINT-FRAME-DO-SIZES-INTERNAL DESC-GROUP WIDTH HEIGHT WIDTH HEIGHT STACKING)) T))) ;; Some constraint couldn't be satisfied. Try only allowing each constraint ;; to take 1/Nth of the area, where N is the total number of constraints (MULTIPLE-VALUE (WIDTH-USED HEIGHT-USED) (CONSTRAINT-FRAME-DO-SIZES-INTERNAL DESC-GROUP WIDTH HEIGHT (IF (EQ STACKING ':HORIZONTAL) (TRUNCATE WIDTH (LENGTH DESC-GROUP)) WIDTH) (IF (EQ STACKING ':VERTICAL) (TRUNCATE HEIGHT (LENGTH DESC-GROUP)) HEIGHT) STACKING)))) (SETQ WIDTH (- WIDTH WIDTH-USED) HEIGHT (- HEIGHT HEIGHT-USED)) (AND (OR (< WIDTH 0) (< HEIGHT 0)) (THROW STACKING NIL)))))) (DEFUN CONSTRAINT-FRAME-DO-SIZES-INTERNAL (DESC-GROUP WIDTH HEIGHT AV-WIDTH AV-HEIGHT STACKING &AUX (WIDTH-USED 0) (HEIGHT-USED 0) W H) (DOLIST (NODE DESC-GROUP) ;; Amount of room available is the smaller of the total amount of room, or the maximum ;; allowed by the caller (SETQ AV-WIDTH (MIN (- WIDTH WIDTH-USED) AV-WIDTH) AV-HEIGHT (MIN (- HEIGHT HEIGHT-USED) AV-HEIGHT)) (CASE (CONSTRAINT-TYPE NODE) ;; Dispatch on node type ((:WINDOW :BLANK) ;; A real window, easy -- compute the new values, stick 'em in, and loop ;; Blanks get handled in same way (MULTIPLE-VALUE (W H) (CONSTRAINT-FRAME-DO-A-CONSTRAINT NODE AV-WIDTH AV-HEIGHT WIDTH HEIGHT STACKING DESC-GROUP))) (:STACKING ;; A special thing, some sort of descent needed. First fill in size (MULTIPLE-VALUE (W H) (CONSTRAINT-FRAME-DO-A-CONSTRAINT NODE AV-WIDTH AV-HEIGHT WIDTH HEIGHT STACKING DESC-GROUP)) ;; Then recurse with new values (CONSTRAINT-FRAME-DO-SIZES W H (CONSTRAINT-DATA NODE) (CASE STACKING (:VERTICAL ':HORIZONTAL) (:HORIZONTAL ':VERTICAL)))) (:IF (FERROR ":IF not yet supported")) (OTHERWISE (FERROR "Unknown node type ~A" (CONSTRAINT-TYPE NODE)))) (CASE STACKING (:VERTICAL (SETQ HEIGHT-USED (+ HEIGHT-USED H)) (AND (> HEIGHT-USED HEIGHT) ;; Ran out of room, try alternate algorithm (THROW ':VERTICAL NIL))) (:HORIZONTAL (SETQ WIDTH-USED (+ WIDTH-USED W)) (AND (> WIDTH-USED WIDTH) (THROW ':HORIZONTAL NIL))))) (VALUES WIDTH-USED HEIGHT-USED)) (DEFVAR **CONSTRAINT-NODE**) (DEFVAR **CONSTRAINT-REMAINING-WIDTH**) (DEFVAR **CONSTRAINT-REMAINING-HEIGHT**) (DEFVAR **CONSTRAINT-TOTAL-WIDTH**) (DEFVAR **CONSTRAINT-TOTAL-HEIGHT**) (DEFVAR **CONSTRAINT-CURRENT-STACKING**) (DEFUNP CONSTRAINT-FRAME-DO-A-CONSTRAINT (NODE AV-W AV-H W H STACKING DG &AUX AMOUNT CON) "Processes one constraint, setting the proposed width and height in the node to the ones specified by the constraint." (SETQ CON (CONSTRAINT-CONSTRAINT NODE)) (COND ;; Dispatch on type of constraint ((EQ (FIRST CON) ':ASK-WINDOW) (SETQ AMOUNT (MIN (CONSTRAINT-MAX NODE) (MAX (CONSTRAINT-MIN NODE) (LEXPR-SEND (SECOND CON) (THIRD CON) AV-W AV-H W H STACKING (CDDDR CON)))))) ((EQ (FIRST CON) ':ASK) (SETQ AMOUNT (MIN (CONSTRAINT-MAX NODE) (MAX (CONSTRAINT-MIN NODE) (LEXPR-SEND (CONSTRAINT-DATA NODE) (SECOND CON) AV-W AV-H W H STACKING (CDDR CON)))))) ((EQ (FIRST CON) ':FUNCALL) (SETQ AMOUNT (MIN (CONSTRAINT-MAX NODE) (MAX (CONSTRAINT-MIN NODE) (APPLY (SECOND CON) NODE AV-W AV-H W H STACKING (CDDR CON)))))) ((EQ (FIRST CON) ':EVAL) (LET ((**CONSTRAINT-NODE** NODE) (**CONSTRAINT-REMAINING-WIDTH** AV-W) (**CONSTRAINT-REMAINING-HEIGHT** AV-H) (**CONSTRAINT-TOTAL-WIDTH** W) (**CONSTRAINT-TOTAL-HEIGHT** H) (**CONSTRAINT-CURRENT-STACKING** STACKING)) (SETQ AMOUNT (MIN (CONSTRAINT-MAX NODE) (MAX (CONSTRAINT-MIN NODE) (EVAL (SECOND CON))))))) ((FIXP (FIRST CON)) (SETQ AMOUNT (CONSTRAINT-ROUND (FIRST CON) CON NODE))) ((FLOATP (FIRST CON)) (SETQ AMOUNT (CONSTRAINT-ROUND (* (FIRST CON) (CASE STACKING (:VERTICAL H) (:HORIZONTAL W))) CON NODE))) ((EQ (FIRST CON) ':EVEN) (SETQ AMOUNT (CONSTRAINT-ROUND (TRUNCATE (CASE STACKING (:HORIZONTAL AV-W) (:VERTICAL AV-H)) (- (LENGTH DG) (DO ((I 0 (1+ I)) (L DG (CDR L))) ((NULL L) (FERROR "Node not a node")) (AND (EQ (CAR L) NODE) (RETURN I))))) CON NODE))) ((EQ (FIRST CON) ':FIXED) (CASE STACKING (:VERTICAL (SETQ AMOUNT (SHEET-HEIGHT (CONSTRAINT-DATA NODE)) W (SHEET-WIDTH (CONSTRAINT-DATA NODE)))) (:HORIZONTAL (SETQ H (SHEET-HEIGHT (CONSTRAINT-DATA NODE)) AMOUNT (SHEET-WIDTH (CONSTRAINT-DATA NODE)))))) (T (FERROR "Unknown constraint type ~A" CON))) (CASE STACKING (:VERTICAL (SETF (CONSTRAINT-PW NODE) W) (SETF (CONSTRAINT-PH NODE) (SETQ H AMOUNT))) (:HORIZONTAL (SETF (CONSTRAINT-PW NODE) (SETQ W AMOUNT)) (SETF (CONSTRAINT-PH NODE) H)) (OTHERWISE (FERROR "Illegal value for stacking ~A" STACKING))) (RETURN (VALUES W H))) (DEFUN CONSTRAINT-ROUND (SIZE CON NODE &AUX TEM (WINDOW (CONSTRAINT-DATA NODE))) "Given a proposed size, a constraint, and the node, don't round, or round to lines or characters. Also enforces limits." (SETQ SIZE (FIX SIZE)) (MIN (CONSTRAINT-MAX NODE) (MAX (CONSTRAINT-MIN NODE) (COND ((OR (NUMBERP (FIRST CON)) (EQ (FIRST CON) ':EVEN)) (SETQ WINDOW (OR (THIRD CON) WINDOW)) (CASE (SECOND CON) (:LINES (+ (SHEET-TOP-MARGIN-SIZE WINDOW) (SHEET-BOTTOM-MARGIN-SIZE WINDOW) (* (SETQ TEM (SHEET-LINE-HEIGHT WINDOW)) (TRUNCATE SIZE TEM)))) (:CHARACTERS (+ (SHEET-LEFT-MARGIN-SIZE WINDOW) (SHEET-RIGHT-MARGIN-SIZE WINDOW) (* (SETQ TEM (SHEET-CHAR-WIDTH WINDOW)) (TRUNCATE SIZE TEM)))) (T SIZE))) (T SIZE))))) (DEFUN CONSTRAINT-FRAME-DO-POSITIONS (CONSTRS &OPTIONAL (STACKING CONSTRAINT-FRAME-DEFAULT-STACKING) (X 0) (Y 0) &AUX NODE PANES) "Given that proposed size has been set up, set up the proposed positions. Returns a list of all involved panes." (DOLIST (AENTRY (FIRST CONSTRS)) ;; Loop over windows in order, and assign positions (SETQ NODE (CDR AENTRY)) (SETF (CONSTRAINT-PX NODE) X) (SETF (CONSTRAINT-PY NODE) Y) (CASE (CONSTRAINT-TYPE NODE) (:WINDOW (PUSH (CONSTRAINT-DATA NODE) PANES)) (:STACKING (SETQ PANES (NCONC (CONSTRAINT-FRAME-DO-POSITIONS (CONSTRAINT-DATA NODE) (CASE STACKING (:VERTICAL ':HORIZONTAL) (:HORIZONTAL ':VERTICAL)) X Y) PANES))) (:IF (FERROR ":IF not yet supported")) (:BLANK) (OTHERWISE (FERROR "Unknown node type ~A" (CONSTRAINT-TYPE NODE)))) (CASE STACKING (:VERTICAL (SETQ Y (+ Y (CONSTRAINT-PH NODE)))) (:HORIZONTAL (SETQ X (+ X (CONSTRAINT-PW NODE)))))) PANES) (DEFUN CONSTRAINT-FRAME-WHITE-BLANKING (IGNORE X Y W H ARRAY) (DECLARE (:SELF-FLAVOR SHEET)) (BITBLT ERASE-ALUF W H BLANKING-ARRAY 0 0 ARRAY X Y)) (DEFUN CONSTRAINT-FRAME-BLACK-BLANKING (IGNORE X Y W H ARRAY) (DECLARE (:SELF-FLAVOR SHEET)) (BITBLT CHAR-ALUF W H BLANKING-ARRAY 0 0 ARRAY X Y)) (DEFUN CONSTRAINT-FRAME-STIPPLE-BLANKING (IGNORE X Y W H ARRAY GRAY-ARRAY) (DECLARE (:SELF-FLAVOR SHEET)) (BITBLT CHAR-ALUF W H GRAY-ARRAY (\ X (PIXEL-ARRAY-WIDTH GRAY-ARRAY)) (\ Y (PIXEL-ARRAY-HEIGHT GRAY-ARRAY)) ARRAY X Y)) (DEFUN CONSTRAINT-FRAME-DRAW-A-BLANK (BLANK-TYPE NODE X Y W H SCREEN-ARRAY) "Draw blanking of type BLANK-TYPE for constraint node NODE. We blank a rectangle of size W, H with upper left corner at X, Y. The drawing is done in SCREEN-ARRAY. BLANK-TYPE is either a function (which receives the rest of our args), a list of a function and some additional args to give it, or an array of stipple pattern to BITBLT from." (COND ((FUNCTIONP BLANK-TYPE) ;; An explicit drawing function (FUNCALL BLANK-TYPE NODE X Y W H SCREEN-ARRAY)) ((CONSP BLANK-TYPE) (APPLY (CAR BLANK-TYPE) NODE X Y W H SCREEN-ARRAY (CDR BLANK-TYPE))) ((ARRAYP BLANK-TYPE) ;; Stipple array -- draw in standard way (CONSTRAINT-FRAME-STIPPLE-BLANKING NODE X Y W H SCREEN-ARRAY BLANK-TYPE)) (T (FERROR "~S is an unknown type of blanking" BLANK-TYPE)))) (DEFVAR BLANKING-ARRAY (MAKE-PIXEL-ARRAY 32. 1 :ELEMENT-TYPE 'BIT :INITIAL-ELEMENT 1)) ;;; Constraint macros (DEFUN (FIXED-WITH-WHITESPACE CONSTRAINT-MACRO) (OLD-DESC STACKING) "A constraint-frame macro to take a window, and giving it the :FIXED attribute leave whitespace around it on all four sides. Format is: (name FIXED-WITH-WHITESPACE name-of-window color-of-border . constraint) " (LET ((SYM1 (GENSYM)) (SYM2 (GENSYM)) (SYM3 (GENSYM)) (SYM4 (GENSYM)) (SN (GENSYM)) (COB (FOURTH OLD-DESC))) `(,(CASE STACKING (:VERTICAL ':HORIZONTAL) (:HORIZONTAL ':VERTICAL)) ,(CDDDDR OLD-DESC) (,SYM1 ,SN ,SYM2) ((,SN ,STACKING (:ASK-WINDOW ,(THIRD OLD-DESC) :PANE-SIZE) (,SYM3 ,(THIRD OLD-DESC) ,SYM4) ((,(THIRD OLD-DESC) :FIXED)) ((,SYM3 :BLANK ,COB :EVEN) (,SYM4 :BLANK ,COB :EVEN)))) ((,SYM1 :BLANK ,COB :EVEN) (,SYM2 :BLANK ,COB :EVEN))))) (DEFUN (INTERDIGITATED-WHITESPACE CONSTRAINT-MACRO) (OLD-DESC STACKING) "Leave whitespace betweem all specified constraints (alternates stacking): (name INTERDIGITATED-WHITESPACE color :INCLUDE-or-:EXCLUDE our-constraint whitespace-constraint . ) :EXCLUDE means no whitespace before first and after last, :INCLUDE means include this whitespace." (LET ((COLOR (THIRD OLD-DESC)) (IOE (FOURTH OLD-DESC)) (WSPACECON (SIXTH OLD-DESC)) (INFS (SEVENTH OLD-DESC)) (WSPACE) (NINFS)) (OR (MEMQ IOE '(:INCLUDE :EXCLUDE)) (FERROR "~A must be either :INCLUDE or :EXCLUDE" IOE)) (DO ((I INFS (CDR I)) (GS)) (NIL) (COND ((AND (EQ IOE ':EXCLUDE) (OR (EQ I INFS) (NULL I)))) (T (SETQ GS (GENSYM)) (PUSH GS NINFS) (PUSH `(,GS :BLANK ,COLOR . ,WSPACECON) WSPACE))) (AND I (PUSH (CAR I) NINFS)) (AND (NULL I) (RETURN))) `(,(CASE STACKING (:VERTICAL ':HORIZONTAL) (:HORIZONTAL ':VERTICAL)) ,(FIFTH OLD-DESC) ,(NREVERSE NINFS) . ,(LET ((CONSTRS (COPYLIST (NTHCDR 7 OLD-DESC)))) (DO ((CS CONSTRS (CDR CS)) (SEEN-* NIL)) ((NULL CS) (OR SEEN-* (RPLACD (LAST CONSTRS) (NCONS WSPACE)))) (COND ((MEMQ '* (CAR CS)) (SETQ SEEN-* T) (RPLACA CS (APPEND (REMQ '* (CAR CS)) WSPACE))))) CONSTRS)))) ;;; Support from other flavors (DEFMETHOD (BASIC-MENU :PANE-SIZE) (REM-WIDTH REM-HEIGHT IGNORE IGNORE STACKING &OPTIONAL N-ROWS N-COLUMNS) (MULTIPLE-VALUE-BIND (IGNORE IGNORE NEW-WIDTH NEW-HEIGHT) (MENU-DEDUCE-PARAMETERS N-COLUMNS N-ROWS (IF (EQ STACKING ':VERTICAL) (- REM-WIDTH LEFT-MARGIN-SIZE RIGHT-MARGIN-SIZE) ':UNCONSTRAINED) (IF (EQ STACKING ':HORIZONTAL) (- REM-HEIGHT TOP-MARGIN-SIZE BOTTOM-MARGIN-SIZE) ':UNCONSTRAINED) (- REM-WIDTH LEFT-MARGIN-SIZE RIGHT-MARGIN-SIZE) (- REM-HEIGHT TOP-MARGIN-SIZE BOTTOM-MARGIN-SIZE)) (CASE STACKING (:VERTICAL (+ NEW-HEIGHT TOP-MARGIN-SIZE BOTTOM-MARGIN-SIZE)) (:HORIZONTAL (+ NEW-WIDTH LEFT-MARGIN-SIZE RIGHT-MARGIN-SIZE))))) (DEFMETHOD (ESSENTIAL-WINDOW :PANE-SIZE) (REM-WIDTH REM-HEIGHT IGNORE IGNORE STACKING) (CASE STACKING (:VERTICAL (MIN REM-HEIGHT HEIGHT)) (:HORIZONTAL (MIN REM-WIDTH WIDTH)))) (COMPILE-FLAVOR-METHODS BASIC-FRAME CONSTRAINT-FRAME-NO-FORWARDING CONSTRAINT-FRAME BORDERED-CONSTRAINT-FRAME CONSTRAINT-FRAME-WITH-SHARED-IO-BUFFER BORDERED-CONSTRAINT-FRAME-WITH-SHARED-IO-BUFFER)