(DEFINE-FILE-INFO :PACKAGE "INTERLISP" :READTABLE "INTERLISP" :BASE 10)

(FILECREATED "29-Jul-2026 13:33:45" {MEDLEY}<library>tedit>TEDIT-PAGE.;301 127278 

      :EDIT-BY rmk

      :CHANGES-TO (FNS TEDIT.TO.IMAGEFILE)

      :PREVIOUS-DATE "29-Jul-2026 13:26:14" {MEDLEY}<library>tedit>TEDIT-PAGE.;299)


(PRETTYCOMPRINT TEDIT-PAGECOMS)

(RPAQQ TEDIT-PAGECOMS
       ((DECLARE%: EVAL@COMPILE DONTCOPY (RECORDS TEDITPAPERSIZE)
               (EXPORT (RECORDS PAGEFORMATTINGSTATE PAGEREGION)
                      (MACROS GETPFS SETPFS))
               (MACROS \FIRST-COLUMN-START)
               
               (* ;; "Replaces CL:MULTIPLE-VALUE-SETQ, to avoid CL:VALUES")

               (EXPORT (MACROS TEDIT.SETQS TEDIT.VALUES)))
        (INITRECORDS PAGEFORMATTINGSTATE PAGEREGION)
        [COMS 
              (* ;; "Page-numbering font specification/default.  ")

              
              (* ;; "(Must come before calls to TEDIT.SINGLE.PAGEFORMAT below.)")

              (GLOBALVARS TEDIT.DEFAULT.FOLIO.LOOKS)
              (INITVARS (TEDIT.DEFAULT.FOLIO.LOOKS (\TEDIT.CHARLOOKS.FROM.FONT
                                                    (FONTCOPY NIL
                                                           '(FAMILY MODERN SIZE 10 WEIGHT MEDIUM 
                                                                   SLOPE REGULAR]
        (VARS (MAXPAGE# 65535)
              (MINPAGE# 1))
        (COMS 
              (* ;; "Creation, GET, and PUT of page frames.")

              (FNS \TEDIT.PARSE.PAGEFRAMES \TEDIT.PUT.PAGEFRAMES \TEDIT.UNPARSE.PAGEFRAMES))
        [COMS 
              (* ;; "Public functions for setting up page layouts")

              (FNS TEDIT.SINGLE.PAGEFORMAT TEDIT.COMPOUND.PAGEFORMAT TEDIT.PAGEFORMAT 
                   TEDIT.GET.PAGEFORMAT)
              (INITVARS (TEDIT.PAGE.FRAMES (TEDIT.COMPOUND.PAGEFORMAT (TEDIT.SINGLE.PAGEFORMAT NIL 
                                                                             NIL NIL NIL NIL 72 72 72
                                                                             72 NIL 1)
                                                  (TEDIT.SINGLE.PAGEFORMAT T 72 756 NIL 'LEFT 72 72 
                                                         72 72 NIL 1)
                                                  (TEDIT.SINGLE.PAGEFORMAT T 540 756 NIL 'RIGHT 72 72
                                                         72 72 NIL 1]
        (FNS TEDIT.TO.IMAGEFILE)
        [P (DEFAULT.IMAGETYPE.CONVERSIONS '(TEDIT TEDIT.TO.IMAGEFILE]
        (COMS 
              (* ;; "Perform page layout, based on a regular expression of typed regions.")

              (FNS \TEDIT.FORMATBOX \TEDIT.FORMAT.PAGE \TEDIT.FORMAT.TEXT \TEDIT.FORMAT.FOLIO 
                   \TEDIT.HARDCOPY.PRINTBOX \TEDIT.FORMAT.COLUMNEND)
              (FNS \TEDIT.FORMAT.HEADING \TEDIT.FORMAT.HEADING.NEXTCHNO)
              (FNS \TEDIT.FORMAT.FOOTNOTE.LINES \TEDIT.FORMAT.FOOTNOTE.REMNANTS 
                   \TEDIT.FORMAT.TEXTBOX.FOOTNOTE))
        [COMS 
              (* ;; "Handle varying paper sizes")

              (FNS SCALEPAGEUNITS SCALEPAGEXUNITS SCALEPAGEYUNITS \TEDIT.PAPERHEIGHT 
                   \TEDIT.PAPERWIDTH)
              (GLOBALVARS TEDIT.PAPER.SIZES)
              (VARS (TEDIT.PAPER.SIZES '((A0 2384 3370)
                                         (A1 1684 2384)
                                         (A2 1191 1684)
                                         (A3 842 1191)
                                         (A4 595 842)
                                         (A5 420 595)
                                         (B0 2835 4008)
                                         (B1 2004 2835)
                                         (B2 1417 2004)
                                         (B3 1001 1417)
                                         (B4 709 1001)
                                         (B5 499 709]
        (COMS                                                (* ; "Page numbering option support")
              (FNS \TEDIT.PAGENO.PARAGRAPH ROMANNUMERALS))
        (COMS                                                (* ; "Page number image obj")
              (FNS TEDIT.PAGENO.CREATE \TEDIT.PAGENO.OBJINIT \TEDIT.PAGENO.BUTTONEVENTINFN 
                   \TEDIT.PAGENO.IMAGEBOXFN \TEDIT.PAGENO.DISPLAYFN \TEDIT.PAGENO.GETFN 
                   \TEDIT.PAGENO.PUTFN)
              (P (\TEDIT.PAGENO.OBJINIT)))
        (COMS 
              (* ;; "Foot note support")

              (FNS \TEDIT.FORMAT.FOOTNOTE))))
(DECLARE%: EVAL@COMPILE DONTCOPY 
(DECLARE%: EVAL@COMPILE

(RECORD TEDITPAPERSIZE (
                        (* ;; 
                        "Describe the size of a sheet of paper (in points), given a paper size-name.")

                        TPSNAME                              (* ; "The name, as a litatom")
                        TPSWIDTH                             (* ; "Paper width, in points")
                        TPSHEIGHT                            (* ; "Paper Height, in points")
                        TPSLANDSCAPE?                        (* ; 
                                         "T if we have to rotate things to print them on this paper.")
                        ))
)

(* "FOLLOWING DEFINITIONS EXPORTED")(DECLARE%: EVAL@COMPILE

(DATATYPE PAGEFORMATTINGSTATE (
                               (* ;; "Contains page-formatting information that carries over from page to page.  This includes, for example, the content of page headings (whether or not they will be output on a given page) and footnote remnants, but it doesn't include specialxy paragraphs--they are printed on the page where they are encountered, and don't persist.")

                               (PAGENUM WORD)                (* ; 
                                                           "The current page number.  Counted from 1")
                               (MINPAGE# WORD)               (* ; 
                                                 "The page # of the first page to be printed, or NIL")
                               (MAXPAGE# WORD)               (* ; 
                                                  "The page # of the last page to be printed, or NIL")
                               (PAGECOUNT WORD)              (* ; 
                                                        "The number of pages we've formatted so far.")
                               STATE                         (* ; "One of FORMATTING or SEARCHING.")
                               (FIRSTPAGE FLAG)

                               (* ;; "T if the current page is the 'first page' .  Is set initially, and can be set again by the user at will.  Gets reset after each page image is printed.")

                               (PAGEISRECTO FLAG)            (* ; 
                                      "T if this is a recto/odd page, NIL if it's a verso/even page.")
                               REQUIREDREGIONTYPE            (* ; "If STATE is SEARCHING, the kind of box we're looking for.  If STATE is :SEARCHING-FOR-EQUIVALENT-PAGE, this is the page count for the matching page.")
                               CHNO                          (* ; "Our position in that stream")
                               PRESSREGION                   (* ; "The press code's REGION info.")
                               PAGEHEADINGS                  (* ; 
                                       "An alist of current heading charnos, indexed by heading type")
                               PAGEFOOTNOTELINES             (* ; 
                         "A list of extant footnote lines that should appear at the next opportunity")
                               PAGEFLOATINGTOPLINES          (* ; "A list of lines that should float to the top of the next available place.  RMK:  Probably a never-implemented feature: original Tedit code doesn't reference this.")
                               PAGELINECACHE                 (* ; "A cache for pre-created LINEDESCRIPTOR/THISLINE pairs, to avoid the overhead of re-allocating them all the time")
                               NEWPAGELAYOUT                 (* ; "If we switch page layouts in mid-document, this is where the new layout gets cached until we get started again.")
                               PAGE#GENERATOR                (* ; "List of page numbers;  later, maybe, a function to generate page numbers.  Used to fill in PAGE#TEXT, below")
                               PAGE#TEXT                     (* ; "If special page numbers are in use, this is the place to take them from.  PAGE# is still used for recto/verso decisions &c")
                               ))

(DATATYPE PAGEREGION (
                      (* ;; 
            "Describe a part of a page for page formatting.  Can be made into compound descriptions.")

                      REGIONFILLMETHOD                       (* ; 
                                    "What kind of a region this is -- TEXT, FOLIO, PAGEHEADING, etc.")
                      REGIONSPEC                             (* ; 
                                                             "The page-relative region this occupies")
                      REGIONLOCALINFO                        (* ; "A PLIST for local information")
                      (REGIONPARENT FULLXPOINTER)            (* ; 
                                                        "The parent node for this box, for sub-boxes")
                      REGIONSUBBOXES                         (* ; "The sub-regions of this region")
                      REGIONTYPE                             (* ; "A user-settable region type")
                      ))
)

(/DECLAREDATATYPE 'PAGEFORMATTINGSTATE
       '(WORD WORD WORD WORD POINTER FLAG FLAG POINTER POINTER POINTER POINTER POINTER POINTER 
              POINTER POINTER POINTER POINTER)
       '((PAGEFORMATTINGSTATE 0 (BITS . 15))
         (PAGEFORMATTINGSTATE 1 (BITS . 15))
         (PAGEFORMATTINGSTATE 2 (BITS . 15))
         (PAGEFORMATTINGSTATE 3 (BITS . 15))
         (PAGEFORMATTINGSTATE 4 POINTER)
         (PAGEFORMATTINGSTATE 4 (FLAGBITS . 0))
         (PAGEFORMATTINGSTATE 4 (FLAGBITS . 16))
         (PAGEFORMATTINGSTATE 6 POINTER)
         (PAGEFORMATTINGSTATE 8 POINTER)
         (PAGEFORMATTINGSTATE 10 POINTER)
         (PAGEFORMATTINGSTATE 12 POINTER)
         (PAGEFORMATTINGSTATE 14 POINTER)
         (PAGEFORMATTINGSTATE 16 POINTER)
         (PAGEFORMATTINGSTATE 18 POINTER)
         (PAGEFORMATTINGSTATE 20 POINTER)
         (PAGEFORMATTINGSTATE 22 POINTER)
         (PAGEFORMATTINGSTATE 24 POINTER))
       '26)

(/DECLAREDATATYPE 'PAGEREGION '(POINTER POINTER POINTER FULLXPOINTER POINTER POINTER)
       '((PAGEREGION 0 POINTER)
         (PAGEREGION 2 POINTER)
         (PAGEREGION 4 POINTER)
         (PAGEREGION 6 FULLXPOINTER)
         (PAGEREGION 8 POINTER)
         (PAGEREGION 10 POINTER))
       '12)
(DECLARE%: EVAL@COMPILE 

(PUTPROPS GETPFS MACRO ((FS FIELD)
                        (fetch (PAGEFORMATTINGSTATE FIELD) of FS)))

(PUTPROPS SETPFS MACRO ((FS FIELD NEWVALUE)
                        (replace (PAGEFORMATTINGSTATE FIELD) of FS with NEWVALUE)))
)

(* "END EXPORTED DEFINITIONS")


(DECLARE%: EVAL@COMPILE 

(PUTPROPS \FIRST-COLUMN-START MACRO [(LINE PARALOOKS)
                                     (AND (FGETLD LINE 1STLN)
                                          (EQ 'FIRST (FGETPLOOKS PARALOOKS FMTCOLUMN])
)

(* "FOLLOWING DEFINITIONS EXPORTED")(DECLARE%: EVAL@COMPILE 

(PUTPROPS TEDIT.SETQS MACRO
          [ARGS `(LET [($$VALUES ,(CADR ARGS]
                      (DECLARE (LOCALVARS $$VALUES))
                      (PROG1 (CAR $$VALUES)
                          ,@[FOR V IN (CAR ARGS) collect (COND
                                                            [V `(SETQ ,V (POP $$VALUES]
                                                            (T `(SETQ $$VALUES (CDR $$VALUES])])

(PUTPROPS TEDIT.VALUES MACRO [ARGS `(LIST ,@ARGS])
)

(* "END EXPORTED DEFINITIONS")

)

(/DECLAREDATATYPE 'PAGEFORMATTINGSTATE
       '(WORD WORD WORD WORD POINTER FLAG FLAG POINTER POINTER POINTER POINTER POINTER POINTER 
              POINTER POINTER POINTER POINTER)
       '((PAGEFORMATTINGSTATE 0 (BITS . 15))
         (PAGEFORMATTINGSTATE 1 (BITS . 15))
         (PAGEFORMATTINGSTATE 2 (BITS . 15))
         (PAGEFORMATTINGSTATE 3 (BITS . 15))
         (PAGEFORMATTINGSTATE 4 POINTER)
         (PAGEFORMATTINGSTATE 4 (FLAGBITS . 0))
         (PAGEFORMATTINGSTATE 4 (FLAGBITS . 16))
         (PAGEFORMATTINGSTATE 6 POINTER)
         (PAGEFORMATTINGSTATE 8 POINTER)
         (PAGEFORMATTINGSTATE 10 POINTER)
         (PAGEFORMATTINGSTATE 12 POINTER)
         (PAGEFORMATTINGSTATE 14 POINTER)
         (PAGEFORMATTINGSTATE 16 POINTER)
         (PAGEFORMATTINGSTATE 18 POINTER)
         (PAGEFORMATTINGSTATE 20 POINTER)
         (PAGEFORMATTINGSTATE 22 POINTER)
         (PAGEFORMATTINGSTATE 24 POINTER))
       '26)

(/DECLAREDATATYPE 'PAGEREGION '(POINTER POINTER POINTER FULLXPOINTER POINTER POINTER)
       '((PAGEREGION 0 POINTER)
         (PAGEREGION 2 POINTER)
         (PAGEREGION 4 POINTER)
         (PAGEREGION 6 FULLXPOINTER)
         (PAGEREGION 8 POINTER)
         (PAGEREGION 10 POINTER))
       '12)



(* ;; "Page-numbering font specification/default.  ")




(* ;; "(Must come before calls to TEDIT.SINGLE.PAGEFORMAT below.)")

(DECLARE%: DOEVAL@COMPILE DONTCOPY

(GLOBALVARS TEDIT.DEFAULT.FOLIO.LOOKS)
)

(RPAQ? TEDIT.DEFAULT.FOLIO.LOOKS [\TEDIT.CHARLOOKS.FROM.FONT (FONTCOPY NIL
                                                                    '(FAMILY MODERN SIZE 10 WEIGHT 
                                                                            MEDIUM SLOPE REGULAR])

(RPAQQ MAXPAGE# 65535)

(RPAQQ MINPAGE# 1)



(* ;; "Creation, GET, and PUT of page frames.")

(DEFINEQ

(\TEDIT.PARSE.PAGEFRAMES
  [LAMBDA (PAGELIST PARENT)                                  (* ; "Edited 30-Aug-2024 15:40 by rmk")
                                                             (* ; "Edited 13-Nov-2023 00:14 by rmk")
                                                             (* ; "Edited  4-Oct-2022 16:57 by rmk")
                                                             (* jds "31-Jul-84 15:30")

    (* ;; "Internalize an external pageframe.")

    (* ;; "Exactly like TEDIT.PARSE.PAGEFRAMES1, except this doesn't scale the region specs")

    (LET (FRAMETYPE PAGEFRAME)
         (COND
            ((type? PAGEREGION PAGELIST)
             PAGELIST)
            ((NEQ 'LIST (SETQ FRAMETYPE (pop PAGELIST)))
             [SETQ PAGEFRAME (create PAGEREGION
                                    REGIONFILLMETHOD _ FRAMETYPE
                                    REGIONTYPE _ (pop PAGELIST)
                                    REGIONLOCALINFO _ (pop PAGELIST)
                                    REGIONSPEC _ (OR (pop PAGELIST)
                                                     (LIST 0 0 0 0]
             (replace REGIONSUBBOXES of PAGEFRAME with (for ALIST in (pop PAGELIST)
                                                          collect (\TEDIT.PARSE.PAGEFRAMES ALIST 
                                                                         PAGEFRAME)))
             PAGEFRAME)
            (T (SETQ PAGELIST (CAR PAGELIST))
               (TEDIT.COMPOUND.PAGEFORMAT (\TEDIT.PARSE.PAGEFRAMES (pop PAGELIST))
                      (\TEDIT.PARSE.PAGEFRAMES (pop PAGELIST))
                      (\TEDIT.PARSE.PAGEFRAMES (pop PAGELIST])

(\TEDIT.PUT.PAGEFRAMES
  [LAMBDA (LOOKSFILE PAGEFRAMES)                             (* ; "Edited 22-Dec-2023 09:03 by rmk")
                                                             (* ; "Edited 19-Dec-2023 10:25 by rmk")
                                                             (* ; "Edited 26-Aug-2023 08:29 by rmk")
                                                             (* jds "13-Nov-86 20:10")

    (* ;; "Put out a description of a set of page-layout frames")

    (\DWOUT LOOKSFILE 0)                                     (* ; "The length of this run of looks")
    (\WOUT LOOKSFILE \PieceDescriptorPAGEFRAME)              (* ; "Mark this as a set of page frames")
    (PRIN4 (\TEDIT.UNPARSE.PAGEFRAMES PAGEFRAMES)
           LOOKSFILE *TEDIT-FILE-READTABLE*])

(\TEDIT.UNPARSE.PAGEFRAMES
  [LAMBDA (PAGEFRAME)                                        (* ; "Edited 22-Dec-2023 09:04 by rmk")
                                                             (* jds "31-Jul-84 15:00")

    (* ;; "Take an internal page frame, and create an equivalent list structure.")

    (COND
       [(LISTP PAGEFRAME)
        (LIST 'LIST (for FRAME in PAGEFRAME collect (\TEDIT.UNPARSE.PAGEFRAMES FRAME]
       (T (LIST (fetch REGIONFILLMETHOD of PAGEFRAME)
                (fetch REGIONTYPE of PAGEFRAME)
                (fetch REGIONLOCALINFO of PAGEFRAME)
                (fetch REGIONSPEC of PAGEFRAME)
                (for SUBREGION in (fetch REGIONSUBBOXES of PAGEFRAME) collect (
                                                                            \TEDIT.UNPARSE.PAGEFRAMES
                                                                               SUBREGION])
)



(* ;; "Public functions for setting up page layouts")

(DEFINEQ

(TEDIT.SINGLE.PAGEFORMAT
  [LAMBDA (PAGE#S? PX PY PFONT PQUAD LEFT RIGHT TOP BOTTOM COLS COLWIDTH INTERCOL HEADINGS UNITS 
                 PAGEPROPS PAPERSIZE)                        (* ; "Edited 27-Jan-2026 10:30 by rmk")
                                                             (* ; "Edited 11-May-2025 14:59 by rmk")
                                                             (* ; "Edited 10-Jan-2025 11:41 by rmk")
                                                             (* ; "Edited 24-Dec-2024 21:20 by rmk")
                                                             (* ; "Edited 15-Aug-2024 23:01 by rmk")
                                                             (* ; "Edited  6-Aug-2024 12:06 by rmk")
                                                             (* ; "Edited 13-Nov-2023 08:59 by rmk")
                                                             (* ; "Edited 10-Aug-2023 08:14 by rmk")
                                                             (* ; "Edited 17-Dec-87 14:54 by jds")

    (* ;; "Given a description in the args, create a pageframe to describe a single kind of page. This is a documented user entry, and the user gets to decide the units of the various specified parameters.  But internally everything is stored as points, and oddly, the page layout menu doesn't reflect the original units, only picas.")

    (LET* ((LANDSCAPE? (LISTGET PAGEPROPS 'LANDSCAPE?))
           (PAPERWIDTH (\TEDIT.PAPERWIDTH PAPERSIZE LANDSCAPE?))
           (PAPERHEIGHT (\TEDIT.PAPERHEIGHT PAPERSIZE LANDSCAPE?))
           [PAGEREGION (create PAGEREGION
                              REGIONFILLMETHOD _ 'PAGE
                              REGIONSPEC _
                              (create REGION
                                     LEFT _ 0
                                     BOTTOM _ 0
                                     WIDTH _ PAPERWIDTH
                                     HEIGHT _ PAPERHEIGHT)
                              REGIONLOCALINFO _ (CONS 'PAPERSIZE (CONS PAPERSIZE PAGEPROPS]
           PAGEWIDTH SUBREGIONS FOLIOLEFT SCALEFACTOR HEADINGREGIONS)
          (SETQ SCALEFACTOR (SELECTQ UNITS
                                ((POINTS NIL)                (* ; 
                                        "If units are in printers points, the default, do no scaling")
                                     1)
                                (PICAS PTSPERPICA)
                                (INCHES PTSPERINCH)
                                (MICAS PTSPERMICA)
                                (CM PTSPERCM)
                                (\ILLEGAL.ARG UNITS)))
          (SETQ PX (SCALEPAGEXUNITS PX SCALEFACTOR PAPERSIZE LANDSCAPE?))
          (SETQ PY (SCALEPAGEYUNITS PY SCALEFACTOR PAPERSIZE LANDSCAPE?))
          (AND LEFT (SETQ LEFT (HCSCALE SCALEFACTOR LEFT)))
          (AND RIGHT (SETQ RIGHT (HCSCALE SCALEFACTOR RIGHT)))
          (AND TOP (SETQ TOP (HCSCALE SCALEFACTOR TOP)))
          (AND BOTTOM (SETQ BOTTOM (HCSCALE SCALEFACTOR BOTTOM)))
          (AND COLWIDTH (SETQ COLWIDTH (HCSCALE SCALEFACTOR COLWIDTH)))
          (AND INTERCOL (SETQ INTERCOL (HCSCALE SCALEFACTOR INTERCOL)))
          (SETQ PAGEWIDTH (IDIFFERENCE (IDIFFERENCE PAPERWIDTH RIGHT)
                                 LEFT))
          (CL:WHEN (MEMB (L-CASE PAGE#S? T)
                         '(T Yes))

              (* ;; "This asserts that the page number's region is 4 inches wide.  Why?  What if the pretext/posttext is longer?")

              (SELECTQ (U-CASE PQUAD)
                  (LEFT                                      (* ; 
                   "If the page number is flush left, set up the region to start where he specified.")
                        (SETQ FOLIOLEFT PX))
                  (RIGHT                                     (* ; 
                                                "If it's flush right, set up the region to END there")
                         (SETQ FOLIOLEFT (IDIFFERENCE PX (ITIMES 4 PTSPERINCH))))
                  ((CENTERED CENTER NIL)                     (* ; 
                                    "Otherwise, center the page number around the point he specifies")
                       (SETQ FOLIOLEFT (IDIFFERENCE PX (ITIMES 2 PTSPERINCH))))
                  (ERROR "Invalid  page number alignment" PQUAD))

              (* ;; "Note that the folio charlooks is a charlooks spec-list, not a CHARLOOKS.  The parse/unparse is just to get the priority union of PFONT with  the defaults.")

              (* ;; "RMK:   Very odd to default here 4 inches and 1/2 for the folio region.  ")

              (* ;; "PY is described as the baseline of the page numbers, measured from the bottom of the page.  So the page numbers and pre/posttext sit above.")

              [SETQ SUBREGIONS (LIST (create PAGEREGION
                                            REGIONFILLMETHOD _ 'FOLIO
                                            REGIONSPEC _
                                            (create REGION
                                                   LEFT _ FOLIOLEFT
                                                   BOTTOM _ PY
                                                   WIDTH _ (ITIMES 4 PTSPERINCH)
                                                   HEIGHT _ (IQUOTIENT PTSPERINCH 2))
                                            REGIONLOCALINFO _
                                            `(PARALOOKS [QUAD ,(OR PQUAD 'CENTERED]
                                                    CHARLOOKS
                                                    ,(\TEDIT.UNPARSE.CHARLOOKS.LIST (
                                                                          \TEDIT.PARSE.CHARLOOKS.LIST
                                                                                     PFONT 
                                                                            TEDIT.DEFAULT.FOLIO.LOOKS
                                                                                     ))
                                                    FORMATINFO
                                                    ,(LISTGET PAGEPROPS 'FOLIOINFO])
          (CL:WHEN HEADINGS
              [SETQ HEADINGREGIONS
               (for HDG LEFT in HEADINGS when (CAR HDG)
                  collect 

                        (* ;; "Run thru the list of headings, building a box for each.  By default the heading's width runs up to the right margin on the page.  X/LEFT is the left end of the top line, Y is the %"position of the top line%"--it's YTOP, baseline, or YBOT?  But SPECIALX and SPECIALY are described as %"the distances from the lower-left corner of the paper:  the lower-left corner of the paragraph's top line is placed at the specified position, so this suggests YBOT.")

                        (if (AND (NUMBERP (CADR HDG))
                                 (NUMBERP (CADDR HDG)))
                            then (SETQ LEFT (SCALEPAGEXUNITS (CADR HDG)
                                                   SCALEFACTOR PAPERSIZE LANDSCAPE?))
                                 (create PAGEREGION
                                        REGIONFILLMETHOD _ 'HEADING
                                        REGIONSPEC _ (create REGION
                                                            LEFT _ LEFT
                                                            BOTTOM _ (SCALEPAGEYUNITS (CADDR HDG)
                                                                            SCALEFACTOR PAPERSIZE 
                                                                            LANDSCAPE?)
                                                            WIDTH _ (IMAX (IDIFFERENCE PAPERWIDTH 
                                                                                 LEFT)
                                                                          PTSPERINCH)
                                                            HEIGHT _ (IQUOTIENT PTSPERINCH 2))
                                        REGIONLOCALINFO _ (LIST 'HEADINGTYPE (CAR HDG)))
                          else (ERROR (CONCAT "Invalid  X/Y position for heading-type " (CAR HDG]
              (SETQ SUBREGIONS (APPEND SUBREGIONS HEADINGREGIONS)))
          [COND
             [(OR (NULL COLS)
                  (EQ COLS 1))                               (* ; 
         "There is a single column, so treat it as just one text region bounded by the page margins.")
              (SETQ SUBREGIONS
               (NCONC1 SUBREGIONS
                      (create PAGEREGION
                             REGIONFILLMETHOD _ 'TEXT
                             REGIONSPEC _
                             (create REGION
                                    LEFT _ LEFT
                                    BOTTOM _ BOTTOM
                                    WIDTH _ PAGEWIDTH
                                    HEIGHT _ (IDIFFERENCE (IDIFFERENCE PAPERHEIGHT TOP)
                                                    BOTTOM]
             (T                                              (* ; 
                             "There are several columns.  We need to create a text box for each col.")
                (CL:UNLESS (OR COLWIDTH INTERCOL)
                       (ERROR "Can't default both Col width and spacing"))
                [COND
                   [(NULL COLWIDTH)                          (* ; 
                    "He wants us to fill in the column width, given margins and intercolumn spacing.")
                    (SETQ COLWIDTH (FIXR (FQUOTIENT (IDIFFERENCE PAGEWIDTH (ITIMES INTERCOL
                                                                                  (SUB1 COLS)))
                                                COLS]
                   ((NULL INTERCOL)                          (* ; 
                       "Or else he wants to give us just the col width and have us calc the spacing.")
                    (SETQ INTERCOL (FIXR (FQUOTIENT (IDIFFERENCE PAGEWIDTH (ITIMES COLWIDTH COLS))
                                                (SUB1 COLS]
                (SETQ SUBREGIONS
                 (NCONC SUBREGIONS
                        (for COL from 1 to COLS as CLEFT from LEFT by (IPLUS COLWIDTH INTERCOL)
                           collect (create PAGEREGION
                                          REGIONFILLMETHOD _ 'TEXT
                                          REGIONSPEC _
                                          (create REGION
                                                 LEFT _ CLEFT
                                                 BOTTOM _ BOTTOM
                                                 WIDTH _ COLWIDTH
                                                 HEIGHT _ (IDIFFERENCE (IDIFFERENCE PAPERHEIGHT TOP)
                                                                 BOTTOM]
          (replace REGIONSUBBOXES of PAGEREGION with SUBREGIONS)
          PAGEREGION])

(TEDIT.COMPOUND.PAGEFORMAT
  [LAMBDA (FIRST LEFT RIGHT)                                 (* ; "Edited  5-Jul-2026 12:27 by rmk")
                                                             (* ; "Edited 20-Jan-2024 12:07 by rmk")
                                                             (* ; "Edited 16-Jan-2024 14:24 by rmk")
                                                             (* jds "27-Jul-84 10:15")

    (* ;; "This creates a 2-element SEQUENCE pageformat consisting of FIRST followed by an ALTERNATE pageformat containing LEFT and RIGHT")

    (CL:UNLESS LEFT (SETQ LEFT FIRST))
    (CL:UNLESS RIGHT (SETQ RIGHT LEFT))
    (create PAGEREGION
           REGIONFILLMETHOD _ 'SEQUENCE
           REGIONSUBBOXES _ (LIST FIRST (create PAGEREGION
                                               REGIONFILLMETHOD _ 'ALTERNATE
                                               REGIONSUBBOXES _ (LIST LEFT RIGHT)
                                               REGIONSPEC _ (LIST 0 0 0 0)))
           REGIONSPEC _ (LIST 0 0 0 0])

(TEDIT.PAGEFORMAT
  [LAMBDA (TSTREAM FORMAT PAGEID)                            (* ; "Edited 22-Sep-2024 18:45 by rmk")
                                                             (* ; "Edited  3-Sep-2024 22:35 by rmk")
                                                             (* ; "Edited 30-Aug-2024 23:33 by rmk")
                                                             (* ; "Edited 12-Aug-2024 01:10 by rmk")
                                                             (* ; "Edited  4-Feb-2024 22:10 by rmk")
                                                             (* ; "Edited 16-Jan-2024 14:25 by rmk")
                                                             (* ; "Edited 21-Dec-2023 12:32 by rmk")
                                                            (* ; "Edited 12-Jun-90 19:13 by mitani")

    (* ;; "Programmatic interface for page formatting. If FORMAT is a single page format, it is applied only to PAGETYPE if not NIL.  If NIL, it becomes the FIRST/DEFAULT, overriding any LEFT or RIGHT that may already be there. If FORMAT is a composite, then PAGETYPE must be NIL.")

    (* ;; "PAGETYPE argument was not documented. But this preserves the original semantics: a single format with no PAGETYPE is taken as the first and default, wipes out whatever else that might have been there.")

    (* ;; "Original code allowed (undocumented) list of 3 items to be passed around")

    (* ;; "FORMAT can also be another textstream, in which case its format is take as FORMAT--essentially the copy case.")

    (SETQ TSTREAM (TEXTSTREAM TSTREAM))

    (* ;; "Note that PAGETYPE and the textstream-format case are extensions, not in the original documentation.")

    (LET* ((TEXTOBJ (FGETTSTR TSTREAM TEXTOBJ))
           (OLDPAGEREGION (FGETTOBJ TEXTOBJ TXTPAGEFRAMES))
           (OLDFIRST (TEDIT.GET.PAGEFORMAT OLDPAGEREGION '|FIRST(&DEFAULT)|))
           OLDLEFT OLDRIGHT NEWPAGEREGION SUBBOXES)
          (CL:WHEN (TEXTSTREAM FORMAT T)                     (* ; "Get it from somewhere else")
              (SETQ FORMAT (GETTOBJ (TEXTOBJ FORMAT)
                                  TXTPAGEFRAMES)))
          (CL:UNLESS (type? PAGEREGION FORMAT)
                 (\ILLEGAL.ARG FORMAT))
          (SETQ NEWPAGEREGION (SELECTQ (fetch (PAGEREGION REGIONFILLMETHOD) of FORMAT)
                                  (PAGE (SELECTQ PAGEID
                                            (|FIRST(&DEFAULT)| 
                                                             (* ; 
                                                  "Try to maintain EQ for defaults; use NIL instead?")
                                                 (SETQ OLDLEFT (TEDIT.GET.PAGEFORMAT OLDPAGEREGION
                                                                      'LEFT))
                                                 (SETQ OLDRIGHT (TEDIT.GET.PAGEFORMAT OLDPAGEREGION
                                                                       'RIGHT))
                                                 (TEDIT.COMPOUND.PAGEFORMAT FORMAT
                                                        (CL:IF (EQ OLDFIRST OLDLEFT)
                                                            FORMAT
                                                            OLDLEFT)
                                                        (CL:IF (EQ OLDFIRST OLDRIGHT)
                                                            FORMAT
                                                            OLDRIGHT)))
                                            (OTHER% LEFT (TEDIT.COMPOUND.PAGEFORMAT
                                                          OLDFIRST FORMAT (TEDIT.GET.PAGEFORMAT
                                                                           OLDPAGEREGION
                                                                           'RIGHT)))
                                            (OTHER% RIGHT (TEDIT.COMPOUND.PAGEFORMAT
                                                           OLDFIRST
                                                           (TEDIT.GET.PAGEFORMAT OLDPAGEREGION
                                                                  'LEFT)
                                                           FORMAT))
                                            (NIL 
                                                 (* ;; 
                                     "Both LEFT and RIGHT default to FIRST, as indicated by EQ tests")

                                                 (TEDIT.COMPOUND.PAGEFORMAT FORMAT FORMAT FORMAT))
                                            (\ILLEGAL.ARG)))
                                  (SEQUENCE                  (* ; 
                    "TEDIT.COMPOUND.PAGEFORMAT produces this complicated arrangement, don't know why")
                                            (SETQ SUBBOXES (fetch (PAGEREGION REGIONSUBBOXES)
                                                              of FORMAT))
                                            (CL:UNLESS
                                             [AND (EQ 'PAGE (fetch (PAGEREGION REGIONFILLMETHOD)
                                                               of (CAR SUBBOXES)))
                                                  (EQ 'ALTERNATE (fetch (PAGEREGION REGIONFILLMETHOD)
                                                                    of (CADR SUBBOXES)))
                                                  [EQ 'PAGE (fetch (PAGEREGION REGIONFILLMETHOD)
                                                               of (CAR (fetch (PAGEREGION 
                                                                                     REGIONSUBBOXES)
                                                                          of (CADR SUBBOXES]
                                                  (EQ 'PAGE (fetch (PAGEREGION REGIONFILLMETHOD)
                                                               of (CADR (fetch (PAGEREGION 
                                                                                      REGIONSUBBOXES)
                                                                           of (CADR SUBBOXES]
                                             (\ILLEGAL.ARG NEWPAGEREGION))
                                            FORMAT)
                                  (\ILLEGAL.ARG FORMAT)))

          (* ;; 
          "NEWPAGEREGION is now a compound PAGEREGION with defautls installed, ready to install. .")

          (CL:UNLESS (EQUALALL NEWPAGEREGION OLDPAGEREGION)  (* ; 
                         "This doesn't catch the default relations, which are based on EQ to first. ")
              (SETTOBJ TEXTOBJ TXTPAGEFRAMES NEWPAGEREGION)  (* ; 
                              "If NIL, this must be the call from OPENTEXTSTREAM, no history or dirt")
              (CL:WHEN OLDPAGEREGION
                  (\TEDIT.HISTORYADD TEXTOBJ (\TEDIT.HISTORY.EVENT TEXTOBJ :PageFormat NIL NIL NIL 
                                                    NIL OLDPAGEREGION))
                  (SETTOBJ TEXTOBJ \DIRTY T)))
          TSTREAM])

(TEDIT.GET.PAGEFORMAT
  [LAMBDA (TSTREAM PAGETYPE NOERROR)                         (* ; "Edited 24-Jul-2026 08:41 by rmk")
                                                             (* ; "Edited 30-Aug-2024 15:19 by rmk")

    (* ;; "Returns a single PAGEREGION for PAGETYPE in TSTREAM.  Essentially unravels the components that are slapped together by TEDIT.COMPOUND.PAGEFORMAT. To get the whole compound format, use GETTEXTPROP.")

    (* ;; "This also decodes a list of 3 single pageregions.")

    (CL:WHEN TSTREAM
        [LET ((PAGEREGION (if (type? PAGEREGION TSTREAM)
                              then TSTREAM
                            elseif (AND (TEXTSTREAM TSTREAM T)
                                        (FGETTOBJ (TEXTOBJ TSTREAM)
                                               TXTPAGEFRAMES))
                            elseif (LISTP TSTREAM)
                            else (TEXTSTREAM TSTREAM)))
              REST)
             (if (LISTP PAGEREGION)
                 then                                        (* ; "Maybe this should be deprecated.")
                      (SELECTQ PAGETYPE
                          ((FIRST DEFAULT |FIRST(&DEFAULT)| FIRST/DEFAULT) 
                               (CAR PAGEREGION))
                          ((OTHER% LEFT LEFT) 
                               (TEDIT.COMPOUND.PAGEFORMAT NIL PAGEREGION NIL)
                               (CADR PAGEREGION))
                          ((OTHER% RIGHT RIGHT) 
                               (CADDR PAGEREGION))
                          (CL:UNLESS NOERROR (\ILLEGAL.ARG PAGETYPE)))
               elseif (AND (type? PAGEREGION PAGEREGION)
                           (EQ 'SEQUENCE (fetch (PAGEREGION REGIONFILLMETHOD) of PAGEREGION)))
                 then (SETQ REST (CADR (fetch (PAGEREGION REGIONSUBBOXES) of PAGEREGION)))
                      (SELECTQ PAGETYPE
                          ((FIRST DEFAULT |FIRST(&DEFAULT)| FIRST/DEFAULT) 
                               (CAR (fetch (PAGEREGION REGIONSUBBOXES) of PAGEREGION)))
                          ((OTHER% LEFT LEFT EVEN VERSO) 
                               (CAR (CL:IF (EQ 'ALTERNATE (fetch (PAGEREGION REGIONFILLMETHOD)
                                                             of REST))
                                        (fetch (PAGEREGION REGIONSUBBOXES) of REST)
                                        REST)))
                          ((OTHER% RIGHT RIGHT ODD RECTO) 
                               (CADR (CL:IF (EQ 'ALTERNATE (fetch (PAGEREGION REGIONFILLMETHOD)
                                                              of REST))
                                         (fetch (PAGEREGION REGIONSUBBOXES) of REST)
                                         REST)))
                          (CL:UNLESS NOERROR (\ILLEGAL.ARG PAGETYPE)))
               elseif PAGEREGION
                 then (CL:UNLESS NOERROR (\ILLEGAL.ARG PAGETYPE])])
)

(RPAQ? TEDIT.PAGE.FRAMES
       (TEDIT.COMPOUND.PAGEFORMAT (TEDIT.SINGLE.PAGEFORMAT NIL NIL NIL NIL NIL 72 72 72 72 NIL 1)
              (TEDIT.SINGLE.PAGEFORMAT T 72 756 NIL 'LEFT 72 72 72 72 NIL 1)
              (TEDIT.SINGLE.PAGEFORMAT T 540 756 NIL 'RIGHT 72 72 72 72 NIL 1)))
(DEFINEQ

(TEDIT.TO.IMAGEFILE
  [LAMBDA (TSTREAM IMAGEFILE IMAGETYPE OPTIONS)              (* ; "Edited 29-Jul-2026 13:33 by rmk")
                                                             (* ; "Edited 26-Jul-2026 12:47 by rmk")
                                                             (* ; "Edited 24-Jul-2026 11:07 by rmk")
                                                             (* ; "Edited 20-Jul-2026 00:12 by rmk")
                                                             (* ; "Edited  6-May-2026 22:16 by rmk")
                                                             (* ; "Edited 17-Jan-2026 11:59 by rmk")
                                                             (* ; "Edited 15-Jan-2026 08:46 by rmk")
                                                             (* ; "Edited 25-Dec-2025 15:07 by rmk")
                                                             (* ; "Edited 20-Dec-2025 23:03 by rmk")
                                                             (* ; "Edited 14-Dec-2025 17:38 by rmk")
                                                             (* ; "Edited 27-Sep-2025 14:05 by rmk")
                                                             (* ; "Edited 19-Sep-2025 22:08 by rmk")

    (* ;; "Format a document for hardcopy.  Returns the number of pages printed (not the final page number!).  Returns NIL if the before-print-fn said not to print.")

    (* ;; "TSTREAM is either already a textstream or somehow denotes a tedit-formatted file, otherwise an error. ")

    (RESETLST
        (SETQ TSTREAM (if (TEXTSTREAM TSTREAM T)
                        else [RESETSAVE (SETQ TSTREAM (OPENTEXTSTREAM TSTREAM))
                                    `(PROGN (CLOSEF? OLDVALUE]
                             TSTREAM))
        (CL:WHEN (GETTEXTPROP TSTREAM 'MENUFLG)
            (SETQ TSTREAM (TEXTSTREAM (\TEDIT.MAINW TSTREAM))))
        (CL:UNLESS (EQ 'DON'T (APPLY* (OR (GETTEXTPROP TSTREAM 'BEFOREHARDCOPYFN)
                                          (FUNCTION NILL))
                                     TSTREAM))
            (CL:UNLESS IMAGEFILE
                [SETQ IMAGEFILE (if (GETTEXTPROP TSTREAM 'FILENAME)
                                    then (PACKFILENAME 'VERSION NIL 'EXTENSION (CAR (
                                                                         EXTENSIONS.FOR.IMAGEFILETYPE
                                                                                     IMAGETYPE))
                                                'BODY
                                                (GETTEXTPROP TSTREAM 'FILENAME))
                                  else (UNIX-TMP-FILE-NAME 'tedit (CAR (EXTENSIONS.FOR.IMAGEFILETYPE
                                                                        IMAGETYPE])

            (* ;; "RMK:  PAGE#GEENRATOR and PAGE#TEXT are overloaded on the FIRSTPG# option, providing a list instead of an actual page number or NIL=1.  But the field FIRSTPAGE# has to be filled by a fixp, can't be NIL, hence the FIXP test.  Not clear why STATE is also the FIRSTPG# option.  A mess of undocumented features.")

            (* ;; 
          "As a minimum PAGE#TEXT and PAGE#GENERATORS should be different OPTIONS, maybe STATE also.")

            (LET* ((TEXTOBJ (FTEXTOBJ TSTREAM))
                   (PAGENUMGOPTION (LISTGET OPTIONS 'FIRSTPG#))
                   (FIRSTPG# (OR (FIXP PAGENUMGOPTION)
                                 1))
                   [FORMATTINGSTATE (create PAGEFORMATTINGSTATE
                                           PAGENUM _ FIRSTPG#
                                           FIRSTPAGE _ T
                                           STATE _ FIRSTPG#
                                           MINPAGE# _ FIRSTPG#
                                           MAXPAGE# _ (OR (LISTGET OPTIONS 'ENDPG)
                                                          MAX.SMALLP)
                                           CHNO _ 1
                                           PRESSREGION _ TEDIT.DEFAULTPAGEREGION
                                           PAGE#TEXT _ (CAR (LISTP PAGENUMGOPTION))
                                           PAGE#GENERATOR _ (CDR (LISTP PAGENUMGOPTION]
                   IMAGESTREAM PAGEREGION)
                  [RESETSAVE (\TEDIT.MARKACTIVE TEXTOBJ "Image file")
                         '(PROGN (\TEDIT.MARKINACTIVE OLDVALUE]
                  (SETQ PAGEREGION (FGETTOBJ TEXTOBJ TXTPAGEFRAMES))

                  (* ;; "TEDIT puts its own headings on the page")

                  [SETQ IMAGESTREAM (OPENIMAGESTREAM IMAGEFILE IMAGETYPE `(HEADING NIL ,@OPTIONS]

                  (* ;; "The right margin must be big enough to prevent line wrap on landscaped 14 inch paper, with Postscript's scaling of .01-point increments. (~ 101,000).  This will cause a performance hit.  Sigh.  JDS 9/5/89")

                  (DSPRIGHTMARGIN 131072 IMAGESTREAM)
                  (while (ILEQ (GETPFS FORMATTINGSTATE CHNO)
                               (FGETTOBJ TEXTOBJ TEXTLEN))
                     do 
                        (* ;; "Format pages according to the existing layout.  This always starts out with a SEQUENCE page region that leads to a first-page region followed by an ALTERNATE  of even/odd page-regions that loops, as created by TEDIT.COMPOUND.PAGEFORMAT.  Not clear that sequence and alternate are ever used in any other context, why pretend?  Could just do the calls for the first and the even/odd looping here, with direct calls to \TEDIT.FORMATPAGE")

                        (\TEDIT.FORMATBOX TSTREAM IMAGESTREAM (GETPFS FORMATTINGSTATE CHNO)
                               PAGEREGION FORMATTINGSTATE IMAGETYPE)
                        (CL:WHEN (EQ (GETPFS FORMATTINGSTATE STATE)
                                     :NEW-PAGE-LAYOUT)

                            (* ;; "New page layout got specified.  Prepare to re-enter the formatting code and skip to the equivalent page in the new format.")

                            (SETQ PAGEREGION (GETPFS FORMATTINGSTATE NEWPAGELAYOUT))

                            (* ;; "Set up the formatting state so code knows we're looking for an equivalent page, and which page it is. (The SUB1 is because we counted an extra page for the page on which the new payout was detected.)")

                            (SETPFS FORMATTINGSTATE REQUIREDREGIONTYPE (SUB1 (GETPFS FORMATTINGSTATE
                                                                                    PAGECOUNT)))
                            (SETPFS FORMATTINGSTATE PAGECOUNT 0)
                            (SETPFS FORMATTINGSTATE STATE :SEARCHING-FOR-EQUIVALENT-PAGE)))
                  (APPLY* (OR (GETTEXTPROP TEXTOBJ 'AFTERHARDCOPYFN)
                              (FUNCTION NILL))
                         TSTREAM)

                  (* ;; "So caller can formulate a prompt message TEDIT.IMAGEFILE.MESSAGE")

                  (PUTTEXTPROP TSTREAM 'LASTIMAGEFILE (LIST (GETPFS FORMATTINGSTATE PAGECOUNT)
                                                            (FULLNAME IMAGESTREAM)
                                                            (PRINTERNAME IMAGESTREAM)))
                  (TEDIT.IMAGEFILE.MESSAGE TSTREAM)
                  (CLOSEF IMAGESTREAM))))])
)

(DEFAULT.IMAGETYPE.CONVERSIONS '(TEDIT TEDIT.TO.IMAGEFILE))



(* ;; "Perform page layout, based on a regular expression of typed regions.")

(DEFINEQ

(\TEDIT.FORMATBOX
  [LAMBDA (TSTREAM IMAGESTREAM STARTINGCHNO PAGEREGION FORMATTINGSTATE HEADINGS?)
                                                             (* ; "Edited 29-Jul-2026 05:55 by rmk")
                                                             (* ; "Edited 26-Jul-2026 00:15 by rmk")
                                                             (* ; "Edited 22-Jul-2026 10:16 by rmk")
                                                             (* ; "Edited 21-Apr-2025 18:50 by rmk")
                                                             (* ; "Edited 20-Nov-2024 12:37 by rmk")
                                                             (* ; "Edited 17-Nov-2024 19:10 by rmk")
                                                             (* ; "Edited 21-Oct-2024 00:33 by rmk")
                                                             (* ; "Edited 13-Mar-2024 17:09 by rmk")
                                                             (* ; "Edited 20-Jan-2024 12:16 by rmk")
                                                             (* ; "Edited 28-Jun-2023 15:54 by rmk")
                                                             (* ; "Edited 22-Jun-2023 21:50 by rmk")
                                                             (* ; "Edited  9-May-2023 18:22 by rmk")
                                                             (* ; "Edited 15-Feb-2023 23:47 by rmk")
                                                             (* ; "Edited 30-May-91 12:51 by jds")

    (* ;; "Grab text from the TSTREAM, starting with STARTINGCHNO, and use it to fill REGION on a page.  Return a list of line descriptors which, taken together, fill the region.")

    (* ;; "This updates the CHNO field of the  PAGEFORMATTINGSTATE")

    (LET* ((TEXTOBJ (FTEXTOBJ TSTREAM))
           (REGION (fetch (PAGEREGION REGIONSPEC) of PAGEREGION))
           (TEXTLEN (TEXTLEN TEXTOBJ))
           CHNO LINES LAST-CHNO SUBREGIONSPEC)
          (SELECTQ (fetch REGIONFILLMETHOD of PAGEREGION)
              (TEXT                                          (* ; 
                                  "A normal text region.  Fill it with text formatted the usual way.")
                    (CL:UNLESS HEADINGS?
                        (SETQ LINES (\TEDIT.FORMAT.TEXT TSTREAM IMAGESTREAM STARTINGCHNO PAGEREGION 
                                           FORMATTINGSTATE))))
              (FOLIO                                         (* ; 
                                           "A Page Number.  Fill it in according to the instructions")
                     (\TEDIT.FORMAT.FOLIO TEXTOBJ IMAGESTREAM FORMATTINGSTATE PAGEREGION))
              (HEADING                                       (* ; 
                          "A Page heading.  Fill it in from a text source we saved for the occasion.")
                       (CL:WHEN HEADINGS?
                           (SETQ LINES (\TEDIT.FORMAT.HEADING TSTREAM IMAGESTREAM FORMATTINGSTATE 
                                              PAGEREGION))))
              (PAGE 
                    (* ;; "This box is really a PAGE FRAME, no lines here.  Fill it in and do whatever other processing is needful for end of page.")

                    (\TEDIT.FORMAT.PAGE TSTREAM IMAGESTREAM STARTINGCHNO PAGEREGION FORMATTINGSTATE))
              ((RECURSIVE SEQUENCE ALTERNATE SELECTION REPEAT) 
                                                             (* ; 
                                                    "This box is really a list of boxes.  Fill them.")
                   (SELECTQ (fetch REGIONFILLMETHOD of PAGEREGION)
                       ((SEQUENCE RECURSIVE)                 (* ; 
                                                   "Just run thru filling in the sub-boxes in order.")
                            (for SUBREGION SUBREGIONSPEC in (fetch (PAGEREGION REGIONSUBBOXES)
                                                               of PAGEREGION)
                               while (AND (ILEQ (GETPFS FORMATTINGSTATE CHNO)
                                                TEXTLEN)
                                          (NEQ (GETPFS FORMATTINGSTATE STATE)
                                               :NEW-PAGE-LAYOUT))
                               unless (AND (GETPFS FORMATTINGSTATE PAGENUM)
                                           (GETPFS FORMATTINGSTATE MAXPAGE#)
                                           (IGREATERP (GETPFS FORMATTINGSTATE PAGENUM)
                                                  (GETPFS FORMATTINGSTATE MAXPAGE#)))
                               do ([SETQ SUBREGIONSPEC (create REGION
                                                          using (fetch REGIONSPEC of SUBREGION)
                                                                LEFT _
                                                                (IPLUS (fetch (REGION LEFT)
                                                                          of (fetch REGIONSPEC
                                                                                of SUBREGION))
                                                                       (fetch (REGION LEFT)
                                                                          of REGION))
                                                                BOTTOM _
                                                                (IPLUS (fetch (REGION BOTTOM)
                                                                          of (fetch REGIONSPEC
                                                                                of SUBREGION))
                                                                       (fetch (REGION BOTTOM)
                                                                          of REGION]
                                   (\TEDIT.FORMATBOX TSTREAM IMAGESTREAM (GETPFS FORMATTINGSTATE CHNO
                                                                                )
                                          (create PAGEREGION using SUBREGION REGIONSPEC _ 
                                                                   SUBREGIONSPEC)
                                          FORMATTINGSTATE HEADINGS?))))
                       (ALTERNATE                            (* ; 
                                                  "Run through the sub-boxes repeatedly in sequence.")
                                  (while (AND (ILEQ (GETPFS FORMATTINGSTATE CHNO)
                                                    TEXTLEN)
                                              (NEQ :NEW-PAGE-LAYOUT (GETPFS FORMATTINGSTATE STATE)))
                                     do (for SUBREGION SUBREGIONSPEC in (fetch (PAGEREGION 
                                                                                      REGIONSUBBOXES)
                                                                           of PAGEREGION)
                                           while (ILEQ (GETPFS FORMATTINGSTATE CHNO)
                                                       TEXTLEN) unless (EQ (GETPFS FORMATTINGSTATE 
                                                                                  STATE)
                                                                           :NEW-PAGE-LAYOUT)
                                           do [SETQ SUBREGIONSPEC
                                               (create REGION
                                                  using (fetch REGIONSPEC of SUBREGION)
                                                        LEFT _ (IPLUS (fetch (REGION LEFT)
                                                                         of (fetch REGIONSPEC
                                                                               of SUBREGION))
                                                                      (fetch (REGION LEFT)
                                                                         of REGION))
                                                        BOTTOM _ (IPLUS (fetch (REGION BOTTOM)
                                                                           of (fetch REGIONSPEC
                                                                                 of SUBREGION))
                                                                        (fetch (REGION BOTTOM)
                                                                           of REGION]
                                              (\TEDIT.FORMATBOX TSTREAM IMAGESTREAM (GETPFS 
                                                                                      FORMATTINGSTATE
                                                                                           CHNO)
                                                     (create PAGEREGION using SUBREGION REGIONSPEC _
                                                                              SUBREGIONSPEC)
                                                     FORMATTINGSTATE HEADINGS?))))
                       (SELECTION                            (* ; 
                                                "Do one or another box, depending on some criterion."))
                       (\TEDIT.THELP)))
              NIL)

          (* ;; "We now have the list of lines to be printed in this box")

          (\TEDIT.HARDCOPY.PRINTBOX LINES TSTREAM IMAGESTREAM PAGEREGION FORMATTINGSTATE])

(\TEDIT.FORMAT.PAGE
  [LAMBDA (TSTREAM IMAGESTREAM CHNO PAGEREGION FORMATTINGSTATE)
                                                             (* ; "Edited 28-Jul-2026 00:19 by rmk")
                                                             (* ; "Edited 25-Jul-2026 00:34 by rmk")
                                                             (* ; "Edited 22-Jul-2026 10:08 by rmk")
                                                             (* ; "Edited 20-Jul-2026 00:46 by rmk")
                                                             (* ; "Edited 21-Apr-2025 22:41 by rmk")
                                                             (* ; "Edited 19-Feb-2025 13:32 by rmk")
                                                             (* ; "Edited 11-Dec-2024 22:39 by rmk")
                                                             (* ; "Edited 17-Mar-2024 00:24 by rmk")
                                                             (* ; "Edited 19-Jan-2024 23:10 by rmk")
                                                             (* ; "Edited 11-Dec-2023 22:02 by rmk")
                                                             (* ; "Edited 13-Nov-2023 00:15 by rmk")
                                                             (* ; "Edited 22-Sep-2023 20:37 by rmk")
                                                             (* ; "Edited 15-Jul-2023 22:22 by rmk")
                                                             (* ; "Edited  8-Mar-2023 18:20 by rmk")
                                                             (* ; "Edited  9-Oct-2022 17:24 by rmk")
                                                             (* ; 
                                                        "Edited  4-Jul-93 00:29 by sybalskY:MV:ENVOS")

    (* ;; "In the simplest case the lines just fill the text boxes of the page (one for each column) until the box's region overflows.  The LX1 and YBASE of each linedescriptor are calculated to determine where the line will appear on the page. The LCHARLIM of the last line of the last text box is the starting CHNO for the next page.  Note that the starting and ending character numbers may be in the middle of paragraphs.")

    (* ;; "The positions of lines in some paragraphs are calculated in different ways, and those paragraphs are held out when the text box is being filled.")

    (* ;; "Lines in special x/y paragraphs are positioned according to the page-relative X and Y positions of the paragraphs first line.")

    (* ;; "Paragraphs for running headings are saved in the formattingstate so that they can be reformatted and repositioned for each page whose pageregion calls them out and specifies their page-relative coordinates (reformatted because the instances on different pages may vary if the heading contains context-sensitive image objects).  Headings may be encountered in the middle of a column, but they scope at the page level.")

    (* ;; "(Footnote paragraphs (if implemented?) position up from the bottom of a text region until they meet the text coming down...and there may be remnant lines that pass over to the next text region.)")

    (* ;; "")

    (* ;; "The implementation is complicated by the fact that a recursive traversal through the text subboxes of a page is needed to recognize and save the heading paragraphs, but a separate traversal is required to determine whether and where a particular heading (identified on this page or a previous one) is to be placed on this page.  For example, the content for an even-page heading may appear in the middle of the text of a preceding odd page.  So the box traversal is called twice.  The flag argument HEADINGS? is false on the first call, and text boxes are filled, heading boxes are ignored, but heading paragraphs are recognized and saved.  The HEADINGS? argument is true on the second call.   In that case the text boxes are skipped, but headings are positioned according to the heading-box regions and filled from the current heading entries saved on the formattingstate.  ")

    [PROG* ((TEXTOBJ (FTEXTOBJ TSTREAM))
            (PAGE# (GETPFS FORMATTINGSTATE PAGENUM))
            (MAXPAGE# (GETPFS FORMATTINGSTATE MAXPAGE#))
            (MINPAGE# (GETPFS FORMATTINGSTATE MINPAGE#))
            (PAGEPROPS (fetch (PAGEREGION REGIONLOCALINFO) of PAGEREGION))
            (REGION (\TEDIT.SCALEREGION IMAGESTREAM (fetch (PAGEREGION REGIONSPEC) of PAGEREGION)))
            (END-OF-PAGE-FN (GETTEXTPROP TSTREAM 'END-OF-PAGE-FN))
            (PRE-EXISTING-FONT (DSPFONT NIL IMAGESTREAM))
            (TEXTLEN (TEXTLEN TEXTOBJ))
            END-OF-PAGE-MARKER PC NEWPARALOOKS)

     (* ;; "For real page independence, we need to reset the font to where it was as of the beginning of the page before calling DSPNEWPAGE.  This avoids font creation in a page prolog, which might get missed otherwise.")
                                                             (* ; 
                                                             "Print in the usual region on the page")
           (CL:UNLESS (ILEQ CHNO TEXTLEN)
                  (RETURN))
           (SETQ PC (\TEDIT.ALIGNEDPIECE CHNO TEXTOBJ))
           (SETQ NEWPARALOOKS (\TEDIT.APPLY.PARASTYLES (PPARALOOKS PC)
                                     PC TEXTOBJ))
           (CL:WHEN (EQ :NEW-PAGE-LAYOUT (GETPLOOKS NEWPARALOOKS FMTPARATYPE))

               (* ;; "The first paragraph on this page starts a new page layout.")

               (SETPFS FORMATTINGSTATE STATE :NEW-PAGE-LAYOUT)

               (* ;; "The first character of the paragraph after the one containing PC:")

               [SETPFS FORMATTINGSTATE CHNO (ADD1 (CAR (\TEDIT.PARA.LAST TEXTOBJ PC]
               [SETPFS FORMATTINGSTATE NEWPAGELAYOUT (\TEDIT.PARSE.PAGEFRAMES (LISTGET (GETPLOOKS
                                                                                        NEWPARALOOKS
                                                                                        FMTUSERINFO)
                                                                                     'NEWPAGELAYOUT]
               (RETURN))

     (* ;; "")

           (CL:UNLESS PAGE#

               (* ;; "If this page template specifies a starting page number, use it.")

               (SETQ PAGE# (OR (LISTGET PAGEPROPS 'STARTINGPAGE#)
                               1))
               (SETPFS FORMATTINGSTATE PAGENUM PAGE#))
           (CL:WHEN (LISTGET PAGEPROPS 'LANDSCAPE?)          (* ; "This is a landscape page.")
               (STREAMPROP IMAGESTREAM 'PRINTERMODE 'LANDSCAPE)
                                                             (* ; "Put the info. into stream ")
               (DSPPUSHSTATE IMAGESTREAM)
               (DSPROTATE 90 IMAGESTREAM)
               (DSPTRANSLATE 0 (IMINUS (ffetch (REGION HEIGHT) of REGION))
                      IMAGESTREAM))
           (DSPCLIPPINGREGION REGION IMAGESTREAM)            (* ; "Clip to the whole sheet.")
           (DSPRIGHTMARGIN (fetch (REGION WIDTH) of REGION)
                  IMAGESTREAM)

     (* ;; "")

     (* ;; "Fill up the next complete page, finding and recording headings, but not applying them")

           (SETPFS FORMATTINGSTATE CHNO CHNO)
           (for SUBREGION in (fetch (PAGEREGION REGIONSUBBOXES) of PAGEREGION)
              while (ILEQ CHNO TEXTLEN) do 
                                           (* ;; 
                 "Now format the subregions of the page. The CHNO field may be updated by each call.")

                                           (\TEDIT.FORMATBOX TSTREAM IMAGESTREAM CHNO SUBREGION 
                                                  FORMATTINGSTATE)
                                           (SETQ CHNO (GETPFS FORMATTINGSTATE CHNO)))

     (* ;; "Now applying the headings appropriate to this page.")

           (for SUBREGION in (fetch (PAGEREGION REGIONSUBBOXES) of PAGEREGION)
              do (\TEDIT.FORMATBOX TSTREAM IMAGESTREAM CHNO SUBREGION FORMATTINGSTATE T))

     (* ;; "")

           (DSPFONT PRE-EXISTING-FONT IMAGESTREAM)
           (CL:WHEN (LISTGET PAGEPROPS 'LANDSCAPE?)          (* ; "This is a landscape page.")
               (STREAMPROP IMAGESTREAM 'PRINTERMODE NIL)
               (DSPTRANSLATE 0 (ffetch (REGION HEIGHT) of REGION)
                      IMAGESTREAM)
               (DSPROTATE 0 IMAGESTREAM)
               (DSPPOPSTATE IMAGESTREAM))
           (if (AND (ILEQ (GETPFS FORMATTINGSTATE CHNO)
                          TEXTLEN)
                    [NOT (AND END-OF-PAGE-FN (EQ 'DON'T (SETQ END-OF-PAGE-MARKER
                                                         (APPLY* END-OF-PAGE-FN TEXTOBJ 
                                                                FORMATTINGSTATE]
                    (<= MINPAGE# PAGE# MAXPAGE#))
               then 
                    (* ;; "There is more to print, force a new page")

                    (DSPNEWPAGE IMAGESTREAM)
             elseif (OR (IGREATERP PAGE# MAXPAGE#)
                        (EQ END-OF-PAGE-MARKER 'DON'T))
               then                                          (* ; 
                                  "We've run past the last page to be formatted or were told to stop")
                    (SETPFS FORMATTINGSTATE CHNO (ADD1 TEXTLEN)))
           (SETPFS FORMATTINGSTATE PAGENUM (ADD1 PAGE#))
           (SETPFS FORMATTINGSTATE FIRSTPAGE NIL)
           (SETPFS FORMATTINGSTATE PAGE#TEXT (pop (GETPFS FORMATTINGSTATE PAGE#GENERATOR]

    (* ;; "Some things happen regardless of whether we're searching or not:  Need to count pages we pass over to find an equivalent page in the new layout:")

    (add (GETPFS FORMATTINGSTATE PAGECOUNT)
         1])

(\TEDIT.FORMAT.TEXT
  [LAMBDA (TSTREAM IMAGESTREAM CHNO PAGEREGION FORMATTINGSTATE)
                                                             (* ; "Edited 28-Jul-2026 21:47 by rmk")
                                                             (* ; "Edited 26-Jul-2026 16:21 by rmk")
                                                             (* ; "Edited 23-Jul-2026 22:35 by rmk")
                                                             (* ; "Edited 21-Jul-2026 22:15 by rmk")
                                                             (* ; "Edited 20-Jul-2026 01:32 by rmk")
                                                             (* ; "Edited  7-Jul-2026 16:48 by rmk")
                                                             (* ; "Edited 15-Jun-2026 13:40 by rmk")
                                                             (* ; "Edited 21-Apr-2025 14:05 by rmk")
                                                             (* ; "Edited  8-Feb-2025 23:39 by rmk")
                                                             (* ; "Edited 11-Dec-2024 22:37 by rmk")
                                                             (* ; "Edited 17-Nov-2024 19:16 by rmk")
                                                             (* ; "Edited 13-Jun-2024 17:15 by rmk")
                                                             (* ; "Edited 15-Mar-2024 19:24 by rmk")
                                                             (* ; "Edited 19-Jan-2024 23:37 by rmk")
                                                             (* ; "Edited  2-Jul-2023 20:49 by rmk")
                                                             (* ; "Edited  1-Jun-2023 15:32 by rmk")
                                                             (* ; "Edited 30-Sep-2022 10:06 by rmk")
                                                             (* ; "Edited 24-Aug-2022 11:45 by rmk")
                                                             (* ; 
                                                        "Edited  3-Jul-93 22:14 by sybalskY:MV:ENVOS")

    (* ;; "Note that the headings and specialxy are here recognized and saved in the formattingstate as they are encountered in the line-loop.  But whether and (and for the headings) where they are actual put on the page is dependent on the pageframe specification--they may be recognized and held but never actually displayed.  ")

    (* ;; "Note that footnotes are a special complication, can't be simply separated out like the headings and specialxy overlays.")

    (* ;; "Also, it matters that lines are measured in the right order, to figure out where they go on the page and how they compete with other lines.  But once formatted, the order of lines in the box's list is immaterial, since each line carries its own display position.")

    (LET* ((TEXTOBJ (FTEXTOBJ TSTREAM))
           (REGION (SCALEREGION IMAGESTREAM (ffetch (PAGEREGION REGIONSPEC) of PAGEREGION)))
           COLUMNBOTTOM PRIOR-COLUMN-YBOT ALLFOOTNOTELINES FORCENEXTPAGE LINES ORPHAN)

          (* ;; "Account for footnote lines carried over from prior columns.  They act as if they were first encountered as a footnote at the top of this page, but they require special treatment because we won't trip over them as we loop through the text lines and their lines have already been formatted (but not yet y-positioned).")

          (* ;; "f they don't all fit, the new remnants will be carried over to the next column (and that would limit the nonfootnote lines that might actually appear in this column).  Below we may encounter a new footnote, it will try to grab its own space, and maybe generate its own remnants.  ")

          (TEDIT.SETQS (COLUMNBOTTOM ALLFOOTNOTELINES)
                 (\TEDIT.FORMAT.FOOTNOTE.REMNANTS FORMATTINGSTATE REGION TEXTOBJ))
          (bind LINE PREVLINE PARALOOKS LHEIGHT BREAKAFTERLASTPARA COLUMN-YBASE THISFOOTNOTELINES 
                YBOT (TEXTLEN _ (TEXTLEN TEXTOBJ)) while (ILEQ CHNO TEXTLEN)
             do                                              (* ; 
                                                             "Format the line, noting any form-feeds")
                (SETQ LINE (\TEDIT.FORMATLINE TSTREAM CHNO (AND NIL (pop (GETPFS FORMATTINGSTATE 
                                                                                PAGELINECACHE)))
                                  REGION IMAGESTREAM))
                (SETQ LHEIGHT (FGETLD LINE LHEIGHT))
                (SETQ PARALOOKS (FGETLD LINE LPARALOOKS))
                (if (EQ 'PAGEHEADING (GETPLOOKS PARALOOKS FMTPARATYPE))
                    then 
                         (* ;; "CHNO is the first character of a heading. Save the beginning and ending chnos and skip the rest of the heading.")

                         (SETQ CHNO (\TEDIT.FORMAT.HEADING.NEXTCHNO CHNO TEXTOBJ FORMATTINGSTATE))
                  elseif (FGETLD LINE LMARK)
                    then 
                         (* ;; "This line is a conditional line that is to be skipped (e.g., an EVEN text para on an odd page).  All it tells us is what characters to skip to so we can continue.")

                         (HELP 'LMARK)
                         (SETQ CHNO (FGETLD LINE LCHARLIM))
                  elseif (LISTGET (FGETPLOOKS PARALOOKS FMTUSERINFO)
                                'FOOTNOTE)
                    then 
                         (* ;; "This is a footnote paragraph that may suck space from the bottom of this column and spill over to the next.  The lines for each footnote are positioned and appended at the bottom of the box.")

                         (TEDIT.SETQS (CHNO COLUMNBOTTOM THISFOOTNOTELINES)
                                (\TEDIT.FORMAT.TEXTBOX.FOOTNOTE LINE COLUMNBOTTOM REGION 
                                       FORMATTINGSTATE TSTREAM IMAGESTREAM))
                         (CL:IF ALLFOOTNOTELINES
                             (LINKLD (\TEDIT.LASTLINE ALLFOOTNOTELINES)
                                    THISFOOTNOTELINES)
                             (SETQ ALLFOOTNOTELINES THISFOOTNOTELINES))
                  elseif (AND PREVLINE (FGETLD LINE 1STLN)
                              (OR BREAKAFTERLASTPARA (FGETPLOOKS PARALOOKS FMTNEWPAGEBEFORE)))
                    then 
                         (* ;; "We're supposed to put this line at the start of a new page/column (any box, later).  Don't link it here--throw it away--and break out of the loop.")

                         (SETQ FORCENEXTPAGE 'USERBREAK)
                         (RETURN)
                  else [SETQ YBOT (if (AND (FGETLD LINE 1STLN)
                                           (SPECIALY? PARALOOKS))
                                      then 

                                 (* ;; "The first line of a paragraph with a special page-relative Y position (formatline deals with X).  Later lines (in this paragraph and below) are positioned with respect to this one.")

                                           (FGETPLOOKS PARALOOKS FMTSPECIALY)
                                    elseif (AND COLUMN-YBASE (FGETLD LINE 1STLN)
                                                (EQ 'NEXT (FGETPLOOKS PARALOOKS FMTCOLUMN)))
                                      then 
                                           (* ;; "This is the first line of a new paragraph in a new column; back YBOT down to match the prior column.")

                                           (- COLUMN-YBASE (FGETLD LINE LDESCENT))
                                    elseif PREVLINE
                                      then 

                                 (* ;; "\TEDIT.LINE.BOTTOM calculates the basetobase new ybot from the current ybot.  Here we are doing some sort of adjustment, so convert the newybot to the line height")

                                           (SETQ LHEIGHT (IDIFFERENCE YBOT (\TEDIT.LINE.BOTTOM 
                                                                                  PREVLINE LINE)))
                                           (if (\FIRST-COLUMN-START LINE PARALOOKS)
                                               then (IDIFFERENCE (IMIN PRIOR-COLUMN-YBOT YBOT)
                                                           LHEIGHT)
                                             else (IDIFFERENCE YBOT LHEIGHT))
                                    else                     (* ; 
                                                            "First line is at the top of the region.")
                                         (IDIFFERENCE (fetch (REGION TOP) of REGION)
                                                (FGETLD LINE LTRUEHEIGHT]
                       (SETYBOT LINE YBOT)
                       (CL:IF PREVLINE
                           (LINKLD PREVLINE LINE)
                           (SETQ LINES LINE))
                       (CL:WHEN (SETQ FORCENEXTPAGE (CL:IF (EQ (CHARCODE FORM)
                                                               (FGETLD LINE FORCED-END))
                                                        'USERBREAK
                                                        (ILESSP YBOT COLUMNBOTTOM)))
                                                             (* ; "Break out of the loop")
                           (RETURN))
                       (CL:WHEN (AND (FGETPLOOKS PARALOOKS FMTNEWPAGEAFTER))
                                                             (* ; 
                              "The line after this one will start a new page/column (any box, later)")
                           (SETQ BREAKAFTERLASTPARA T))
                       (SETQ PRIOR-COLUMN-YBOT (CL:IF PRIOR-COLUMN-YBOT
                                                   (IMIN PRIOR-COLUMN-YBOT YBOT)
                                                   YBOT))
                       (CL:WHEN (\FIRST-COLUMN-START LINE PARALOOKS)

                           (* ;; "This is the start of a new group of paragraphs to be lined up in columns.  Save the YBASE for these guys for the other columns.")

                           (SETQ COLUMN-YBASE (FGETLD LINE YBASE))) 
                                                             (* ; 
                   "Note that we have put text out on this page/column/box, for first line checking.")
                       (SETQ CHNO (FGETLD LINE LCHARLIM))
                       (SETQ PREVLINE LINE)))
          (\TEDIT.FORMAT.COLUMNEND LINES COLUMNBOTTOM FORCENEXTPAGE ALLFOOTNOTELINES REGION TEXTOBJ 
                 FORMATTINGSTATE])

(\TEDIT.FORMAT.FOLIO
  [LAMBDA (TEXTOBJ IMAGESTREAM FORMATTINGSTATE PAGEREGION)   (* ; "Edited 28-Jul-2026 00:45 by rmk")
                                                             (* ; "Edited 24-Jul-2026 11:03 by rmk")
                                                             (* ; "Edited 22-Jul-2026 10:07 by rmk")
                                                             (* ; "Edited  7-Jul-2026 16:47 by rmk")
                                                             (* ; "Edited  9-Jan-2025 21:52 by rmk")
                                                             (* ; "Edited  3-Jan-2025 14:28 by rmk")
                                                             (* ; "Edited 24-Nov-2024 11:46 by rmk")
                                                             (* ; "Edited 20-Nov-2024 12:37 by rmk")
                                                             (* ; "Edited 17-Nov-2024 19:16 by rmk")
                                                             (* ; "Edited 26-Oct-2024 10:46 by rmk")
                                                             (* ; "Edited 13-Jun-2024 17:15 by rmk")
                                                             (* ; "Edited 10-May-2024 12:32 by rmk")
                                                             (* ; "Edited 15-Mar-2024 19:24 by rmk")
                                                             (* ; "Edited 13-Mar-2024 09:00 by rmk")
                                                             (* ; "Edited 19-Jan-2024 23:28 by rmk")
                                                             (* ; "Edited 18-Jan-2024 17:04 by rmk")
                                                             (* ; "Edited 13-Nov-2023 00:24 by rmk")
                                                             (* ; "Edited  1-Jun-2023 00:12 by rmk")
                                                             (* ; "Edited  9-May-2023 21:39 by rmk")
                                                             (* ; "Edited 30-May-91 12:51 by jds")

    (* ;; "Print a page number (called a %"folio%" in the biz) at the location and with the alignment specified in the REGIONSPEC.")

    (LET ((REGION (SCALEREGION IMAGESTREAM (fetch (PAGEREGION REGIONSPEC) of PAGEREGION)))
          (FOLIOINFO (fetch (PAGEREGION REGIONLOCALINFO) of PAGEREGION))
          FOLIOSTREAM PAGE# FOLIOFORMAT PRETEXT POSTTEXT INFOLIST)
         (DECLARE (SPECVARS PAGE#))
         (CL:UNLESS (AND (GETPFS FORMATTINGSTATE FIRSTPAGE)
                         (LISTGET FOLIOINFO 'NOFIRSTPAGE))   (* ; 
       "If this isn't the first page, OR we want a page # on the first page, go ahead and format it.")
             (SETQ INFOLIST (LISTGET FOLIOINFO 'FORMATINFO)) (* ; 
                                                             "A LIST OF (FORMAT PRETEXT POSTTEXT)")
             (SETQ FOLIOFORMAT (CAR INFOLIST))
             (SETQ PRETEXT (OR (CADR INFOLIST)
                               ""))
             (SETQ POSTTEXT (OR (CADDR INFOLIST)
                                ""))
             [SETQ PAGE# (if (GETPFS FORMATTINGSTATE PAGE#TEXT)
                             then (MKSTRING (GETPFS FORMATTINGSTATE PAGE#TEXT))
                           else (SELECTQ FOLIOFORMAT
                                    (LOWERROMAN (ROMANNUMERALS (GETPFS FORMATTINGSTATE PAGENUM)))
                                    (UPPERROMAN (ROMANNUMERALS (GETPFS FORMATTINGSTATE PAGENUM)
                                                       T))
                                    (MKSTRING (GETPFS FORMATTINGSTATE PAGENUM]

             (* ;; "Bind the stream to make sure it isn't collected.")

             [SETQ FOLIOSTREAM (OPENTEXTSTREAM NIL NIL NIL NIL
                                      `(PARALOOKS ,(LISTGET FOLIOINFO 'PARALOOKS)
                                              LOOKS
                                              ,(LISTGET FOLIOINFO 'CHARLOOKS]
             (TEDIT.INSERT FOLIOSTREAM (CONCAT PRETEXT PAGE# POSTTEXT)
                    1 NIL T)
             (bind LINE YBOT FORCENEXTPAGE (TEXTLEN _ (TEXTLEN (GETTSTR FOLIOSTREAM TEXTOBJ)))
                   (BOTTOM _ (fetch (REGION BOTTOM) of REGION))
                   (CHNO _ 1) while (ILEQ CHNO TEXTLEN) until FORCENEXTPAGE
                do (SETQ LINE (\TEDIT.FORMATLINE FOLIOSTREAM CHNO NIL REGION IMAGESTREAM))
                   (SETQ FORCENEXTPAGE (EQ (CHARCODE FORM)
                                           (FGETLD LINE FORCED-END))) 
                                                             (* ; "Format the next possible line")
                   [SETQ YBOT (if YBOT
                                  then                       (* ; 
                                                             " Take account of this line's height")
                                       (IDIFFERENCE YBOT (FGETLD LINE LHEIGHT))
                                else                         (* ; 
                                                 "First line:  position it at the top of the region.")
                                     (IDIFFERENCE BOTTOM (FGETLD LINE LDESCENT]
                   (SETYBOT LINE YBOT)                       (* ; "This line is still good")
                   (\TEDIT.HARDCOPY.DISPLAYLINE FOLIOSTREAM LINE REGION IMAGESTREAM)
                   (SETQ CHNO (FGETLD LINE LCHARLIM))        (* ; "Set the start of the next line")))
         ])

(\TEDIT.HARDCOPY.PRINTBOX
  [LAMBDA (LINES TSTREAM IMAGESTREAM PAGEREGION FORMATTINGSTATE)
                                                             (* ; "Edited 28-Jul-2026 00:58 by rmk")
                                                             (* ; "Edited 26-Jul-2026 00:12 by rmk")
                                                             (* ; "Edited 24-Jul-2026 11:04 by rmk")
                                                             (* ; "Edited 22-Jul-2026 11:03 by rmk")

    (* ;; "Print LINES on IMAGESTREAM, then return lines to the cache, for reuse (If cache is in stream, wouldn't need FORMATTINGSTATE).")

    (for LINE (REGION _ (SCALEREGION IMAGESTREAM (fetch (PAGEREGION REGIONSPEC) of PAGEREGION)))
       inlines LINES eachtime (BLOCK) do (\TEDIT.HARDCOPY.DISPLAYLINE TSTREAM LINE REGION IMAGESTREAM
                                                )
                                         (push (GETPFS FORMATTINGSTATE PAGELINECACHE)
                                               LINE])

(\TEDIT.FORMAT.COLUMNEND
  [LAMBDA (LINES COLUMNBOTTOM FORCENEXTPAGE ALLFOOTNOTELINES REGION TEXTOBJ FORMATTINGSTATE 
                 DONT-KEEP-SINGLE-LINE)                      (* ; "Edited 28-Jul-2026 14:46 by rmk")
                                                             (* ; "Edited 25-Jul-2026 22:45 by rmk")
                                                             (* ; "Edited 21-Jul-2026 09:48 by rmk")
                                                             (* ; "Edited  8-Feb-2025 23:39 by rmk")
                                                             (* ; "Edited 17-Nov-2024 19:22 by rmk")
                                                             (* ; "Edited 26-Oct-2024 10:46 by rmk")
                                                             (* ; "Edited 19-Jan-2024 23:30 by rmk")
                                                             (* ; "Edited 29-Oct-2023 18:40 by rmk")
                                                             (* ; "Edited  4-Jul-2023 21:00 by rmk")
                                                             (* ; "Edited 15-Feb-2023 23:45 by rmk")
                                                             (* ; "Edited  3-Oct-2022 18:08 by rmk")
                                                             (* ; "Edited 11-May-93 01:21 by jds")

    (* ;; "Do column-end processing for TEdit hardcopy -- widow/orphan elimination, respect keep-together specifications.")

    (* ;; "    -- Retuns list of line descriptors to appear in the column, sets CHNO in FORMATTINGSTATE to the number of the first character of the next column")

    (* ;; "    -- List of line descriptors removed from the end of the column.")

    (* ;; "Widow:  first line of a multi-line paragraph is the last line of the box.  It moves to the next box.")

    (* ;; "Orphan: last line of a multi-line paragraph is the first line of a box.  It and the line before move to the next box.")

    (* ;; "If the last line crashes through the bottom, it's an orphan.")

    (LET ((LASTLINE (\TEDIT.LASTLINE LINES))
          PUSHED)
         (CL:UNLESS (EQ FORCENEXTPAGE 'USERBREAK)

             (* ;; 
             "Don't do widow/orphan shifting if this is at a user page-break--he is responsible. ")

             (CL:WHEN (AND LASTLINE (IGEQ (FGETLD LASTLINE YBOT)
                                          COLUMNBOTTOM)
                           (ILESSP (FGETLD LASTLINE LCHARLAST)
                                  (TEXTLEN TEXTOBJ)))
                 (SETQ PUSHED (if (AND (FGETLD LASTLINE 1STLN)
                                       (FGETLD LASTLINE LSTLN))
                                  then                       (* ; 
                                                      "Single line paragraph, push just the offender")
                                       LASTLINE
                                elseif (AND (FGETLD LASTLINE PREVLINE)
                                            (FGETLD (FGETLD LASTLINE PREVLINE)
                                                   1STLN))
                                  then                       (* ; "Push the widow too")
                                       (FGETLD LASTLINE PREVLINE)))
                 (CL:WHEN (FGETLD PUSHED PREVLINE)           (* ; 
                                       "Widow/orphan already moved to this page?  Don't push further")
                     (SETQ LASTLINE (FGETLD PUSHED PREVLINE))))
             (CL:WHEN [AND LASTLINE (OR (GETPLOOKS (FGETLD LASTLINE LPARALOOKS)
                                               FMTHEADINGKEEP)
                                        (AND (GETPLOOKS (FGETLD LASTLINE LPARALOOKS)
                                                    FMTKEEP)
                                             (NOT (FGETLD LASTLINE LSTLN]

                 (* ;; "Push forward any paragraphs that must be kept with what follows them, but assure that there is at least one line on a page.")

                 (for L PLOOKS backlines LASTLINE eachtime (SETQ PLOOKS (FGETLD L LPARALOOKS))
                    unless [OR (GETPLOOKS PLOOKS FMTHEADINGKEEP)
                               (AND (GETPLOOKS PLOOKS FMTKEEP)
                                    (NOT (FGETLD L LSTLN] do 

                                      (* ;; "We found a line that DOESN'T need to be kept with the following paragraphs.  Leave it alone but push its following lines.")

                                                             (SETQ PUSHED (FGETLD L NEXTLINE))
                                                             (SETQ LASTLINE L)
                                                             (RETURN)
                    finally (TEDIT.PROMPTPRINT TEXTOBJ (CONCAT "Warning: All paragraphs on page "
                                                              (GETPFS FORMATTINGSTATE PAGENUM)
                                                              " must be kept together")
                                   T))))
         (CL:WHEN PUSHED
             (if (EQ LASTLINE LINES)
                 then 
                      (* ;; "Single line left in column, or all lines pushed")

                      (CL:WHEN DONT-KEEP-SINGLE-LINE         (* ; 
                                                       "Add back the first push (tail deleted below)")
                          (SETQ LASTLINE PUSHED))
               elseif (EQ PUSHED LINES)
                 then 
                      (* ;; "All pushed, bring back 1 or 2")

                      (SETQ LASTLINE (OR (AND DONT-KEEP-SINGLE-LINE (FGETLD PUSHED NEXTLINE))
                                         PUSHED))))
         (SETPFS FORMATTINGSTATE CHNO (FGETLD LASTLINE LCHARLIM))
                                                             (* ; "Pushed lines go to the next box")
         (FSETLD LASTLINE NEXTLINE NIL)                      (* ; 
                                                             "Remove the pushed lines from this box")
         (CL:WHEN ALLFOOTNOTELINES

             (* ;; "There are footnotes--fix up their vertical locations, so they're aligned on the botton of the column, then add them to the end of LINES (could also add them to the front, order doesn't matter after positioning).")

             (for L (YBOT _ (IDIFFERENCE (fetch (REGION BOTTOM) of REGION)
                                   (GETLD (\TEDIT.LASTLINE ALLFOOTNOTELINES)
                                          LDESCENT))) backlines (\TEDIT.LASTLINE ALLFOOTNOTELINES)
                do (SETYBOT L YBOT)
                   (add YBOT (FGETLD L LHEIGHT)))
             (LINKLD LASTLINE ALLFOOTNOTELINES))
         LINES])
)
(DEFINEQ

(\TEDIT.FORMAT.HEADING
  [LAMBDA (TSTREAM IMAGESTREAM FORMATTINGSTATE PAGEREGION)   (* ; "Edited 27-Jul-2026 17:54 by rmk")
                                                             (* ; "Edited 25-Jul-2026 23:09 by rmk")
                                                             (* ; "Edited 24-Jul-2026 22:57 by rmk")
                                                             (* ; "Edited 22-Jul-2026 10:07 by rmk")
                                                             (* ; "Edited 19-Jul-2026 16:07 by rmk")
                                                             (* ; "Edited  7-Jul-2026 23:45 by rmk")
                                                             (* ; "Edited 15-Jun-2026 13:39 by rmk")
                                                             (* ; "Edited  9-Jan-2025 22:27 by rmk")
                                                             (* ; "Edited 24-Nov-2024 11:46 by rmk")
                                                             (* ; "Edited 26-Oct-2024 10:43 by rmk")
                                                             (* ; "Edited 13-Jun-2024 17:14 by rmk")
                                                             (* ; "Edited 17-Mar-2024 00:24 by rmk")
                                                             (* ; "Edited 15-Feb-2024 22:02 by rmk")
                                                             (* ; "Edited 19-Jan-2024 23:20 by rmk")
                                                             (* ; "Edited  9-Sep-2023 22:17 by rmk")
                                                             (* ; "Edited 19-May-2023 21:15 by rmk")
                                                             (* ; "Edited  9-Oct-90 13:24 by jds")

    (* ;; "A heading is represented by a pair of the character number of its first character and the character number of the character just after its last character.  This formats all of the lines between and positions them relative to the page region's bottom-left. ")

    (LET [(REGION (SCALEREGION IMAGESTREAM (fetch (PAGEREGION REGIONSPEC) of PAGEREGION)))
          (PAGE# (GETPFS FORMATTINGSTATE PAGENUM))
          (HCHNOS (GETMULTI (GETPFS FORMATTINGSTATE PAGEHEADINGS)
                         (LISTGET (fetch (PAGEREGION REGIONLOCALINFO) of PAGEREGION)
                                'HEADINGTYPE]
         (CL:WHEN HCHNOS

             (* ;; "The left corner of the baseline of the heading's first line is located at the specified X,Y coordinates. The lines of a multiline heading will go below.  But it is odd that the region is set up so that its BOTTOM is that Y coordinate.  That is, the region doesn't enclose the heading, the YBOT of the lines is set there.  Not sure why the coordinates are being passed as a region structure rather than a point, the width and height are ignored (except whatever might happen inside \TEDIT.FORMATLINE.  But:  shouldn't the PARALOOKS override the region width/height anyway?")

             (bind L FIRSTLINE PREVLINE YBOT FORCENEXTPAGE (BOTTOM _ (fetch (REGION BOTTOM)
                                                                        of REGION))
                   (CHNO _ (CAR HCHNOS))
                   (NEXTCHNO _ (CADR HCHNOS)) while (ILESSP CHNO NEXTCHNO) until FORCENEXTPAGE
                do (SETQ L (\TEDIT.FORMATLINE TSTREAM CHNO NIL REGION IMAGESTREAM))
                   (SETQ FORCENEXTPAGE (EQ (CHARCODE FORM)
                                           (FGETLD L FORCED-END)))
                   [SETQ YBOT (if YBOT
                                  then                       (* ; 
                                                             "Take account of this line's height")
                                       (LINKLD PREVLINE L)
                                       (IDIFFERENCE YBOT (FGETLD L LHEIGHT))
                                else                         (* ; 
                                       "First line:  Its baseline is at the %"bottom%" of the REGION")
                                     (SETQ FIRSTLINE L)
                                     (IDIFFERENCE BOTTOM (FGETLD L LDESCENT]
                   (SETYBOT L YBOT)
                   (SETQ CHNO (FGETLD L LCHARLIM))           (* ; "Set the start of the next line")
                   (SETQ PREVLINE L) finally (RETURN FIRSTLINE)))])

(\TEDIT.FORMAT.HEADING.NEXTCHNO
  [LAMBDA (CHNO TEXTOBJ FORMATTINGSTATE)                     (* ; "Edited 28-Jul-2026 00:56 by rmk")
                                                             (* ; "Edited 25-Jul-2026 23:40 by rmk")

    (* ;; "CHNO is the number of the first character of a paragraph that makes up a heading.  This stores the first and limit character numbers of that heading, and returns the limit number.  ")

    (for P HEADINGSUBTYPE (LIM-CHNO _ CHNO)
         (PC _ (\TEDIT.CHTOPC CHNO TEXTOBJ)) first (SETQ HEADINGSUBTYPE (GETPLOOKS (PPARALOOKS PC)
                                                                               FMTPARASUBTYPE))
       inpieces PC while (AND (EQ 'PAGEHEADING (GETPLOOKS (PPARALOOKS P)
                                                      FMTPARATYPE))
                              (EQ HEADINGSUBTYPE (GETPLOOKS (PPARALOOKS P)
                                                        FMTPARASUBTYPE)))
       do (add LIM-CHNO (PLEN P)) finally (PUTMULTI (GETPFS FORMATTINGSTATE PAGEHEADINGS)
                                                 HEADINGSUBTYPE
                                                 (LIST CHNO LIM-CHNO))
                                        (RETURN LIM-CHNO])
)
(DEFINEQ

(\TEDIT.FORMAT.FOOTNOTE.LINES
  [LAMBDA (TSTREAM IMAGESTREAM LINE REGION)                  (* ; "Edited 26-Jul-2026 23:54 by rmk")
                                                             (* ; "Edited 25-Jul-2026 11:00 by rmk")

    (* ;; "Formats and links all the lines of a footnote paragraph whose first line is LINE.  They may not all fit in a single column.  ")

    (* ;; "This is like other line collectors, except for some reason it adds LEFT.")

    (bind (PREVLINE _ LINE)
          (LEFT _ (fetch (REGION LEFT) of REGION))
          (TEXTLEN _ (TEXTLEN (FTEXTOBJ TSTREAM)))
          (CHNO _ (GETLD LINE LCHAR1)) while (ILEQ CHNO TEXTLEN) until (AND PREVLINE (FGETLD PREVLINE
                                                                                            LSTLN))
       do (SETQ LINE (\TEDIT.FORMATLINE TSTREAM CHNO NIL REGION IMAGESTREAM)) 
                                                             (* ; 
                                                             "Format the line, noting any form-feeds")
          (add (FGETLD LINE LEFTMARGIN)
               LEFT)
          (add (FGETLD LINE RIGHTMARGIN)
               LEFT)                                         (* ; "Format the next possible line")
          (SETQ CHNO (FGETLD LINE LCHARLIM))                 (* ; 
                                                             "Keep track of the next character...")
          (LINKLD PREVLINE LINE)
          (SETQ PREVLINE LINE])

(\TEDIT.FORMAT.FOOTNOTE.REMNANTS
  [LAMBDA (FORMATTINGSTATE REGION TEXTOBJ)                   (* ; "Edited 28-Jul-2026 09:39 by rmk")
                                                             (* ; "Edited 27-Jul-2026 00:57 by rmk")
                                                             (* ; "Edited 25-Jul-2026 16:36 by rmk")
                                                             (* ; "Edited 22-Jul-2026 10:05 by rmk")

    (* ;; "Determine how many currently existing footnote remnants will fit in this column. And move the bottom of the column up to account for them.  We can't set the y positions here, because other footnotes in the text might push these lines up.")

    (for L REMNANTS KEPT-ONE-LINE PAGEFOOTNOTES (COLUMNBOTTOM _ (fetch (REGION BOTTOM) of REGION))
         (RTOP _ (fetch (REGION TOP) of REGION)) inlines (GETPFS FORMATTINGSTATE PAGEFOOTNOTELINES)
       eachtime (add COLUMNBOTTOM (FGETLD L LHEIGHT)) when (IGEQ COLUMNBOTTOM RTOP)
       do 
          (* ;; "We ran out of room for at least one remaining remnant line.   Save the remnants for the next column/page, and return the new bottom and the lines that will be included in this text box.")

          (TEDIT.SETQS (PAGEFOOTNOTES REMNANTS KEPT-ONE-LINE)
                 (\TEDIT.FORMAT.COLUMNEND PAGEFOOTNOTES L NIL NIL REGION TEXTOBJ FORMATTINGSTATE)) 

          (* ;; "Lines above L will fit?  So, return (PREVLINE L) ?")

          (CL:WHEN KEPT-ONE-LINE
              (add COLUMNBOTTOM (FGETLD L LHEIGHT)))
          (SETPFS FORMATTINGSTATE PAGEFOOTNOTELINES REMNANTS)
          (RETURN (TEDIT.VALUES COLUMNBOTTOM PAGEFOOTNOTES)) finally (SETPFS FORMATTINGSTATE 
                                                                            PAGEFOOTNOTELINES NIL) 
                                                             (* ; 
                                                             "All remnants can appear in this column")
                                                                   (RETURN (TEDIT.VALUES COLUMNBOTTOM
                                                                                  REMNANTS])

(\TEDIT.FORMAT.TEXTBOX.FOOTNOTE
  [LAMBDA (FIRSTLINE COLUMNBOTTOM REGION FORMATTINGSTATE TSTREAM IMAGESTREAM)
                                                             (* ; "Edited 28-Jul-2026 09:39 by rmk")
                                                             (* ; "Edited 25-Jul-2026 14:32 by rmk")

    (* ;; "This deals with footnotes that are encountered in the middle of a column.  (Space for previous remnants has already been taken out of the column")

    (LET ((TEXTOBJ (FGETTSTR TSTREAM TEXTOBJ))
          (THISFOOTNOTELINES (\TEDIT.FORMAT.FOOTNOTE.LINES TSTREAM IMAGESTREAM FIRSTLINE REGION))
          REMNANTLINES)
         (for L RTOP YBOT (RTOP _ (ffetch (REGION TOP) of REGION)) inlines THISFOOTNOTELINES
            eachtime (add COLUMNBOTTOM (FGETLD L LHEIGHT)) when (IGREATERP COLUMNBOTTOM
                                                                       (OR YBOT RTOP))
            do 
               (* ;; "This one overflows for sure, maybe we need to further adjust the column bottom to avoid orphans etc?")

               (TEDIT.SETQS (THISFOOTNOTELINES REMNANTLINES)
                      (\TEDIT.FORMAT.COLUMNEND THISFOOTNOTELINES L NIL NIL REGION TEXTOBJ 
                             FORMATTINGSTATE (NOT FIRSTLINE)))
               (RETURN))
         (SETPFS FORMATTINGSTATE PAGEFOOTNOTELINES REMNANTLINES)
         (TEDIT.VALUES (FGETLD (\TEDIT.LASTLINE THISFOOTNOTELINES)
                              LCHARLIM)
                COLUMNBOTTOM THISFOOTNOTELINES])
)



(* ;; "Handle varying paper sizes")

(DEFINEQ

(SCALEPAGEUNITS
  [LAMBDA (VALUE FACTOR PAPERSIZE)                           (* jds "14-Jun-85 15:34")

         (* Scale a page-relative value into points%: Scale VALUE by FACTOR, then allow 
         for negative values to mean "come in from the other side by that much")

    (AND VALUE (PROG [(TVAL (FIXR (FTIMES VALUE FACTOR)))
                      (OTHEREDGE (SELECTQ PAPERSIZE
                                     ((NIL LETTER) 
                                          612)
                                     (LEGAL 612)
                                     (fetch (TEDITPAPERSIZE TPSWIDTH) of (ASSOC PAPERSIZE 
                                                                                TEDIT.PAPER.SIZES]
                     [COND
                        ((ILESSP TVAL 0)                     (* He specified this value as an 
                                                             offset from the opposite edge.
                                                             Convert it.)
                         (SETQ TVAL (IPLUS OTHEREDGE TVAL]
                     (RETURN TVAL])

(SCALEPAGEXUNITS
  [LAMBDA (VALUE FACTOR PAPERSIZE LANDSCAPE?)                (* ; "Edited 21-Apr-88 10:46 by jds")

    (* ;; "Scale a page-relative value into points: Scale VALUE by FACTOR, then allow for negative values to mean 'come in from the other side by that much'")

    (AND VALUE (PROG ((TVAL (FIXR (FTIMES VALUE FACTOR)))
                      OTHEREDGE)
                     [COND
                        ((ILESSP TVAL 0)                     (* ; 
                          "He specified this value as an offset from the opposite edge.  Convert it.")
                         (SETQ OTHEREDGE (\TEDIT.PAPERWIDTH PAPERSIZE LANDSCAPE?))
                         (SETQ TVAL (IPLUS OTHEREDGE TVAL]
                     (RETURN TVAL])

(SCALEPAGEYUNITS
  [LAMBDA (VALUE FACTOR PAPERSIZE LANDSCAPE?)                (* ; "Edited 17-Dec-87 14:52 by jds")

    (* ;; "Scale a page-relative value into points: Scale VALUE by FACTOR, then allow for negative values to mean 'come in from the other side by that much'")

    (AND VALUE (PROG ((TVAL (FIXR (FTIMES VALUE FACTOR)))
                      OTHEREDGE)
                     [COND
                        ((ILESSP TVAL 0)                     (* ; 
                          "He specified this value as an offset from the opposite edge.  Convert it.")
                         (SETQ OTHEREDGE (\TEDIT.PAPERHEIGHT PAPERSIZE LANDSCAPE?))
                         (SETQ TVAL (IPLUS OTHEREDGE TVAL]
                     (RETURN TVAL])

(\TEDIT.PAPERHEIGHT
  [LAMBDA (PAPERSIZE LANDSCAPE?)                             (* ; "Edited 29-Dec-86 15:06 by jds")

(* ;;; "Compute the HEIGHT of a sheet of paper, according to PAPERSIZE, in points.")

    (COND
       (LANDSCAPE?                                           (* ; 
                 "The paper is landscape, so its height is the WIDTH of the same paper size, normal.")
              (\TEDIT.PAPERWIDTH PAPERSIZE NIL))
       (T                                                    (* ; 
                                                           "Not landscape, so look up the size spec:")
          (SELECTQ PAPERSIZE
              ((NIL LETTER Letter) 
                   792)
              ((Legal 8.5x14 LEGAL) 
                   1008)
              ((A4 a4) 
                   842)
              (fetch (TEDITPAPERSIZE TPSHEIGHT) of (ASSOC PAPERSIZE TEDIT.PAPER.SIZES])

(\TEDIT.PAPERWIDTH
  [LAMBDA (PAPERSIZE LANDSCAPE?)                             (* ; "Edited  9-Dec-87 20:10 by jds")

(* ;;; "Compute the WIDTH of a sheet of paper, according to PAPERSIZE and LANDSCAPE?")

    (LET (CANONICAL-PAPERSIZE)
         (COND
            (LANDSCAPE?                                      (* ; 
                     "It's landscape paper, so look at the HEIGHT of the corresponding normal paper.")
                   (\TEDIT.PAPERHEIGHT PAPERSIZE NIL))
            (T                                               (* ; 
                                                           "Not landscape, so look up the size spec:")
               (SELECTQ PAPERSIZE
                   ((NIL Letter LETTER 8.5x11)               (* ; "letter size paper, 8.5inx11in")
                        612)
                   ((Legal LEGAL 8.5x14) 
                        612)
                   ((A4 a4)                                  (* ; "A4 ISO-size paper, 210mmx297mm")
                        595)
                   (COND
                      ((SETQ CANONICAL-PAPERSIZE (ASSOC PAPERSIZE TEDIT.PAPER.SIZES))
                       (fetch (TEDITPAPERSIZE TPSWIDTH) of CANONICAL-PAPERSIZE))
                      (T (\ILLEGAL.ARG PAPERSIZE])
)
(DECLARE%: DOEVAL@COMPILE DONTCOPY

(GLOBALVARS TEDIT.PAPER.SIZES)
)

(RPAQQ TEDIT.PAPER.SIZES
       ((A0 2384 3370)
        (A1 1684 2384)
        (A2 1191 1684)
        (A3 842 1191)
        (A4 595 842)
        (A5 420 595)
        (B0 2835 4008)
        (B1 2004 2835)
        (B2 1417 2004)
        (B3 1001 1417)
        (B4 709 1001)
        (B5 499 709)))



(* ; "Page numbering option support")

(DEFINEQ

(\TEDIT.PAGENO.PARAGRAPH
  [LAMBDA (TEXTOBJ SUBTYPE FORMAT PAGENUMBERX PAGENUMBERY QUAD PRETEXT POSTTEXT CHARLOOKS PARALOOKS)
                                                             (* ; "Edited  5-Jul-2026 16:39 by rmk")
                                                             (* ; "Edited 15-Jun-2026 13:16 by rmk")
                                                             (* ; "Edited  8-Jun-2026 19:48 by rmk")

    (* ;; "This produces a SELPIECE containing a paragraph that represents the page number information  as specified by the arguments.  PAGENUMBERX and PAGENUMBERY are page-relative.  PAGENUMBERX gets converted to a  margin-relative QUAD-based tab, PAGENUMBERY becomes the page-relative SPECIALY location.  The heading paragraph itself can then be located at 0,0 in the pagelayout menu.")

    (LET (PNOPIECE PREPIECE POSTPIECE)
         (CL:UNLESS PARALOOKS
             (SETQ PARALOOKS (GETTOBJ TEXTOBJ DEFAULTPARALOOKS)))
         [SETQ PNOPIECE (create PIECE
                               PTYPE _ OBJECT.PTYPE
                               POBJ _ (TEDIT.PAGENO.CREATE FORMAT)
                               PLEN _ 1
                               PCHARLOOKS _ (OR CHARLOOKS (GETTOBJ TEXTOBJ DEFAULTCHARLOOKS))
                               PPARALOOKS _ (create PARALOOKS
                                               using PARALOOKS FMTPARATYPE _ 'PAGEHEADING 
                                                     FMTPARASUBTYPE _ SUBTYPE QUAD _ 'LEFT 
                                                     FMTSPECIALX _ 0 FMTSPECIALY _ PAGENUMBERY 
                                                     FMTTABS _
                                                     (LIST (create TAB
                                                                  TABX _ PAGENUMBERX
                                                                  TABKIND _ QUAD]
         (CL:WHEN (EQ QUAD 'RIGHT)
             (SETQ PRETEXT (CONCAT (CHARACTER (CHARCODE TAB))
                                  (OR PRETEXT ""))))
         (SETQ PREPIECE (CL:IF PRETEXT
                            (\TEDIT.MAKE.STRINGPIECE PNOPIECE PRETEXT T)
                            PNOPIECE))

         (* ;; "An EOL, always")

         [SETQ POSTPIECE (\TEDIT.MAKE.STRINGPIECE PNOPIECE (CONCAT (OR POSTTEXT "")
                                                                  (CHARACTER (CHARCODE EOL]
         (FSETPC POSTPIECE PPARALAST T)

         (* ;; "SPCHARFIRST and SPCHARLAST don't matter")

         (create SELPIECES
                SPFIRST _ PREPIECE
                SPLAST _ POSTPIECE
                SPLEN _ (IPLUS (GETPC PREPIECE PLEN)
                               1
                               (GETPC POSTPIECE PLEN])

(ROMANNUMERALS
  [LAMBDA (NUMBER UCFLG)                                     (* jds "12-Jul-85 13:19")

         (* * Take a NUMBER, and render it as a string of roman numerals.
         If UCFLG, then the numerals will be upper-case;
         otherwise, they are lower-case.)

    (PROG ((CHARS NIL))
          [while (NOT (ZEROP NUMBER)) do (COND
                                            ((IGEQ NUMBER 1000)
                                             (push CHARS 'm)
                                             (add NUMBER -1000))
                                            ((IGEQ NUMBER 900)
                                             (push CHARS 'c)
                                             (push CHARS 'm)
                                             (add NUMBER -900))
                                            ((IGEQ NUMBER 500)
                                             (push CHARS 'd)
                                             (add NUMBER -500))
                                            ((IGEQ NUMBER 400)
                                             (push CHARS 'c)
                                             (push CHARS 'd)
                                             (add NUMBER -400))
                                            ((IGEQ NUMBER 100)
                                             (push CHARS 'c)
                                             (add NUMBER -100))
                                            ((IGEQ NUMBER 90)
                                             (push CHARS 'x)
                                             (push CHARS 'c)
                                             (add NUMBER -90))
                                            ((IGEQ NUMBER 50)
                                             (push CHARS 'l)
                                             (add NUMBER -50))
                                            ((IGEQ NUMBER 40)
                                             (push CHARS 'x)
                                             (push CHARS 'l)
                                             (add NUMBER -40))
                                            ((IGEQ NUMBER 10)
                                             (push CHARS 'x)
                                             (add NUMBER -10))
                                            ((IGEQ NUMBER 9)
                                             (push CHARS 'i)
                                             (push CHARS 'x)
                                             (add NUMBER -9))
                                            ((IGEQ NUMBER 5)
                                             (push CHARS 'v)
                                             (add NUMBER -5))
                                            ((IGEQ NUMBER 4)
                                             (push CHARS 'i)
                                             (push CHARS 'v)
                                             (add NUMBER -4))
                                            (T (push CHARS 'i)
                                               (add NUMBER -1]
          (RETURN (COND
                     [UCFLG                                  (* The caller wants his roman numerals 
                                                             upper case)
                            (U-CASE (CONCATLIST (REVERSE CHARS]
                     (T (CONCATLIST (REVERSE CHARS])
)



(* ; "Page number image obj")

(DEFINEQ

(TEDIT.PAGENO.CREATE
  [LAMBDA (FORMAT)                                           (* ; "Edited 14-Jun-2026 22:27 by rmk")
                                                             (* ; "Edited  7-Jan-2025 14:14 by rmk")
                                                             (* ; "Edited  3-Jan-2025 14:44 by rmk")
    (LET ((OBJ (IMAGEOBJCREATE NIL TEDIT.PAGENOOBJ.IMAGEFNS)))
         (IMAGEOBJPROP OBJ 'FORMAT (SELECTQ FORMAT
                                       ((x LOWERROMAN) 
                                            'LOWERROMAN)
                                       ((X UPPERROMAN) 
                                            'UPPERROMAN)
                                       'ARABIC))
         OBJ])

(\TEDIT.PAGENO.OBJINIT
  [LAMBDA NIL                                                (* ; "Edited 23-Jun-2026 23:30 by rmk")
                                                             (* ; "Edited  7-Jan-2025 22:54 by rmk")
                                                             (* ; "Edited  3-Jan-2025 15:01 by rmk")
                                                             (* jds " 9-Feb-86 15:17")

    (* ;; "Initialize the IMAGEFNS for a page-number image object")

    (DECLARE (GLOBALVARS TEDIT.PAGENOOBJ.IMAGEFNS))
    (SETQ TEDIT.PAGENOOBJ.IMAGEFNS (IMAGEFNSCREATE (FUNCTION \TEDIT.PAGENO.DISPLAYFN)
                                          (FUNCTION \TEDIT.PAGENO.IMAGEBOXFN)
                                          (FUNCTION \TEDIT.PAGENO.PUTFN)
                                          (FUNCTION \TEDIT.PAGENO.GETFN)
                                          [FUNCTION (LAMBDA (OBJ)
                                                      (create IMAGEOBJ copying OBJ]
                                          (FUNCTION \TEDIT.PAGENO.BUTTONEVENTINFN)
                                          'NILL
                                          'NILL
                                          'NILL
                                          'NILL
                                          'NILL NIL 'NILL 'PageNumber])

(\TEDIT.PAGENO.BUTTONEVENTINFN
  [LAMBDA (IMAGEOBJ WINDOW SELECTION X Y SELWINDOW TEXTSTREAM BUTTON OPERATION)
                                                             (* ; "Edited  3-Jan-2025 14:32 by rmk")
                                                             (* ; "Edited 14-Aug-93 19:44 by rmk:")

    (* ;; "Allow the user to change the page-number printed format.")

(* ;;; "the user has pressed a button inside the bitmap object IMAGEOBJ.  Bring up a menu of bitmap edit operations.")

    (CL:WHEN (AND (EQ BUTTON 'LEFT)
                  (EQ OPERATION 'NORMAL))
        (LET (FORMAT)
             [SETQ FORMAT (MENU (create MENU
                                       ITEMS _ '((Arabic 'ARABIC)
                                                 ("Lower Roman" 'LOWERROMAN)
                                                 (" Upper Roman" 'UPPERROMAN]
             (CL:WHEN [AND FORMAT (NEQ FORMAT (IMAGEOBJPROP IMAGEOBJ 'FORMAT]
                 (IMAGEOBJPROP IMAGEOBJ 'FORMAT FORMAT)
                 'CHANGED)))])

(\TEDIT.PAGENO.IMAGEBOXFN
  [LAMBDA (OBJ IMAGESTREAM)                                  (* ; "Edited  7-Jul-2026 14:04 by rmk")
                                                             (* ; "Edited  5-Jul-2026 21:46 by rmk")
                                                             (* ; "Edited  3-Jan-2025 14:30 by rmk")
                                                             (* ; "Edited 26-Aug-2024 09:36 by rmk")
                                                             (* ; "Edited  3-Aug-2024 13:10 by rmk")
                                                             (* ; "Edited 19-Jul-2024 23:26 by rmk")
                                                             (* ; "Edited 11-Oct-2022 22:51 by rmk")
                                                             (* ; "Edited  4-Oct-2022 11:59 by rmk")

    (* ;; "Creates the box for a page number, a place holder on the display, otherwise the properly formatted number.  Looks come from the font.")

    (* ;; 
    "Create the box for a menu button containing LABEL in font FONT on STREAM (NIL means display).")

    (DECLARE (USEDFREE PAGE#))
    (LET ((FONT (DSPFONT NIL IMAGESTREAM))
          (FORMAT (IMAGEOBJPROP OBJ 'FORMAT))
          XSIZE)
         (SETQ XSIZE (STRINGWIDTH (if (DISPLAYSTREAMP IMAGESTREAM)
                                      then (CONCAT "[P#" (SELECTQ FORMAT
                                                             (LOWERROMAN "x")
                                                             (UPPERROMAN "X")
                                                             "1")
                                                  "]")
                                    else (SELECTQ FORMAT
                                             (LOWERROMAN (ROMANNUMERALS PAGE#))
                                             (UPPERROMAN (ROMANNUMERALS PAGE# T))
                                             PAGE#))
                            FONT))
         (create IMAGEBOX
                XSIZE _ XSIZE
                YSIZE _ (FONTPROP FONT 'HEIGHT)
                YDESC _ (FONTPROP FONT 'DESCENT)
                XKERN _ 0])

(\TEDIT.PAGENO.DISPLAYFN
  [LAMBDA (OBJ IMAGESTREAM IMAGESTREAMTYPE HOSTSTREAM)       (* ; "Edited  5-Jul-2026 16:26 by rmk")
                                                             (* ; "Edited  3-Jan-2025 14:30 by rmk")
                                                             (* ; "Edited 26-Aug-2024 09:36 by rmk")
                                                             (* ; "Edited  3-Aug-2024 13:10 by rmk")
                                                             (* ; "Edited 19-Jul-2024 23:26 by rmk")
                                                             (* ; "Edited 11-Oct-2022 22:51 by rmk")
                                                             (* ; "Edited  4-Oct-2022 11:59 by rmk")
                                                             (* jds "30-Aug-84 11:24")

    (* ;; "Display the page number on IMAGESTREAM, a place holder for display, otherwise a formatted number.  Looks come from the font.")

    (DECLARE (USEDFREE PAGE#))
    (LET [(FORMAT (IMAGEOBJPROP OBJ 'FORMAT]
         (PRIN3 (if (DISPLAYSTREAMP IMAGESTREAM)
                    then (CONCAT "[P#" (SELECTQ FORMAT
                                           (LOWERROMAN "x")
                                           (UPPERROMAN "X")
                                           "1")
                                "]")
                  else (SELECTQ FORMAT
                           (LOWERROMAN (ROMANNUMERALS PAGE#))
                           (UPPERROMAN (ROMANNUMERALS PAGE# T))
                           PAGE#))
                IMAGESTREAM])

(\TEDIT.PAGENO.GETFN
  [LAMBDA (FILESTREAM)                                       (* ; "Edited 23-Jun-2026 23:40 by rmk")
                                                             (* ; "Edited  3-Jan-2025 14:13 by rmk")
    (LET ((X (READ FILESTREAM (FIND-READTABLE "INTERLISP")))
          OBJ)
         (SETQ OBJ (IMAGEOBJCREATE (CAR X)
                          TEDIT.PAGENOOBJ.IMAGEFNS))
         (replace (IMAGEOBJ IMAGEOBJPLIST) of OBJ with (CDR X))
         OBJ])

(\TEDIT.PAGENO.PUTFN
  [LAMBDA (OBJ FILESTREAM)                                   (* ; "Edited  3-Jan-2025 15:01 by rmk")
    (PRINT (CONS (fetch (IMAGEOBJ OBJECTDATUM) of OBJ)
                 (fetch (IMAGEOBJ IMAGEOBJPLIST) of OBJ))
           FILESTREAM
           (FIND-READTABLE "INTERLISP"])
)

(\TEDIT.PAGENO.OBJINIT)



(* ;; "Foot note support")

(DEFINEQ

(\TEDIT.FORMAT.FOOTNOTE
  [LAMBDA (TSTREAM IMAGESTREAM LINE REGION FORMATTINGSTATE)  (* ; "Edited 25-Jul-2026 10:48 by rmk")
                                                             (* ; "Edited 22-Jul-2026 08:11 by rmk")
                                                             (* ; "Edited  7-Jul-2026 16:41 by rmk")
                                                             (* ; "Edited 21-Apr-2025 14:03 by rmk")
                                                             (* ; "Edited 20-Nov-2024 12:37 by rmk")
                                                             (* ; "Edited 17-Nov-2024 19:22 by rmk")
                                                             (* ; "Edited 13-Jun-2024 17:13 by rmk")
                                                             (* ; "Edited 15-Mar-2024 19:24 by rmk")
                                                             (* ; "Edited 13-Mar-2024 17:00 by rmk")
                                                             (* ; "Edited 19-Jan-2024 23:30 by rmk")
                                                             (* ; "Edited  6-May-2023 20:38 by rmk")
                                                             (* ; "Edited  7-Mar-2023 13:11 by rmk")
                                                             (* ; "Edited 30-May-91 12:52 by jds")
                                                             (* ; 
                                                             "Footnotes aren't so long, but why not?")
    (bind PREVLINE (LEFT _ (fetch (REGION LEFT) of REGION))
          (TEXTLEN _ (TEXTLEN (FTEXTOBJ TSTREAM)))
          (CHNO _ (GETLD LINE LCHAR1)) eachtime (BLOCK) while (ILEQ CHNO TEXTLEN)
       until (AND PREVLINE (FGETLD PREVLINE LSTLN)) collect 

                                                          (* ;; 
                              "Grab a line descriptor from the formatting list, or create a new one.")

                                                          (SETQ LINE (\TEDIT.FORMATLINE TSTREAM CHNO
                                                                            (GETPFS FORMATTINGSTATE 
                                                                                   PAGELINECACHE)
                                                                            REGION IMAGESTREAM)) 
                                                             (* ; 
                                                             "Format the line, noting any form-feeds")
                                                          (add (FGETLD LINE LEFTMARGIN)
                                                               LEFT)
                                                          (add (FGETLD LINE RIGHTMARGIN)
                                                               LEFT) 
                                                             (* ; "Format the next possible line")
                                                          (SETQ CHNO (FGETLD LINE LCHARLIM)) 
                                                             (* ; 
                                                             "Keep track of the next character...")
                                                          (SETQ PREVLINE LINE)
                                                          LINE])
)
(DECLARE%: DONTCOPY
  (FILEMAP (NIL (14081 17693 (\TEDIT.PARSE.PAGEFRAMES 14091 . 15870) (\TEDIT.PUT.PAGEFRAMES 15872 . 
16696) (\TEDIT.UNPARSE.PAGEFRAMES 16698 . 17691)) (17756 40360 (TEDIT.SINGLE.PAGEFORMAT 17766 . 28910)
 (TEDIT.COMPOUND.PAGEFORMAT 28912 . 29995) (TEDIT.PAGEFORMAT 29997 . 37286) (TEDIT.GET.PAGEFORMAT 
37288 . 40358)) (40647 48073 (TEDIT.TO.IMAGEFILE 40657 . 48071)) (48221 92636 (\TEDIT.FORMATBOX 48231
 . 58057) (\TEDIT.FORMAT.PAGE 58059 . 68073) (\TEDIT.FORMAT.TEXT 68075 . 78919) (\TEDIT.FORMAT.FOLIO 
78921 . 84626) (\TEDIT.HARDCOPY.PRINTBOX 84628 . 85720) (\TEDIT.FORMAT.COLUMNEND 85722 . 92634)) (
92637 98509 (\TEDIT.FORMAT.HEADING 92647 . 97210) (\TEDIT.FORMAT.HEADING.NEXTCHNO 97212 . 98507)) (
98510 103896 (\TEDIT.FORMAT.FOOTNOTE.LINES 98520 . 100073) (\TEDIT.FORMAT.FOOTNOTE.REMNANTS 100075 . 
102313) (\TEDIT.FORMAT.TEXTBOX.FOOTNOTE 102315 . 103894)) (103941 108882 (SCALEPAGEUNITS 103951 . 
105092) (SCALEPAGEXUNITS 105094 . 105864) (SCALEPAGEYUNITS 105866 . 106637) (\TEDIT.PAPERHEIGHT 106639
 . 107574) (\TEDIT.PAPERWIDTH 107576 . 108880)) (109298 115669 (\TEDIT.PAGENO.PARAGRAPH 109308 . 
112109) (ROMANNUMERALS 112111 . 115667)) (115708 123682 (TEDIT.PAGENO.CREATE 115718 . 116473) (
\TEDIT.PAGENO.OBJINIT 116475 . 117864) (\TEDIT.PAGENO.BUTTONEVENTINFN 117866 . 118932) (
\TEDIT.PAGENO.IMAGEBOXFN 118934 . 121179) (\TEDIT.PAGENO.DISPLAYFN 121181 . 122846) (
\TEDIT.PAGENO.GETFN 122848 . 123353) (\TEDIT.PAGENO.PUTFN 123355 . 123680)) (123747 127255 (
\TEDIT.FORMAT.FOOTNOTE 123757 . 127253)))))
STOP
