Jump to content

AutoCAD LISP: Bring Back Layout Arrows (Next/Previous Tab Navigation)


Recommended Posts

Posted (edited)

Anyone who’s used AutoCAD for a while probably remembers the little arrow buttons on the layout tabs that let you flip between sheets quickly. For some reason Autodesk removed them, and it’s always been a small but annoying thing to lose — especially when you’re working with lots of sheets.

This LISP is a simple fix. It adds two commands: LNEXT to jump to the next layout and LPREV to go back. It reads the tabs in the proper order, can skip the Model tab if you want, and will loop around from the end back to the start. You can even put the commands on your Quick Access Toolbar so they’re always there, just like the old arrows used to be.

Nothing fancy — just a small script that makes working with layouts feel normal again.

 

How to install and use:

  • 📁 Save the LISP: Copy the code into a file called LAYOUT_ARROWS.lsp.
  • 🔧 Load it in AutoCAD:
    • Type APPLOAD → browse to your .lsp file → click Load.
    • (Optional) To load automatically every time: place it in a support folder and add (load "LAYOUT_ARROWS.lsp") to your acaddoc.lsp.
  • ▶️ Use the commands:
    • LNEXT – jumps to the next layout tab
    • LPREV – jumps to the previous layout tab
    • LTABS – lists layouts in order
    • LGOTO – jump to a specific layout number

Add arrow buttons to the Quick Access Toolbar (QAT):

  • Type CUI and press Enter.
  • In the Command List panel, click New Command twice.
  • For the first command:
    • Name: Next Layout
    • Macro: ^C^C_LNEXT
  • For the second command:
    • Name: Previous Layout
    • Macro: ^C^C_LPREV

(Optional) Assign arrow icons to each command.

  • Drag both commands into Quick Access Toolbar 1 (left panel).
  • Click Apply and OK — your new arrow buttons will appear at the top of AutoCAD.

✅ Done. You now have simple arrow buttons to flip between layout tabs — just like AutoCAD used to have.

 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

; -----------------------------------------
; LAYOUT_ARROWS.lsp  —  Next/Prev/Goto layout tabs
; Brings back “arrowing” between layout tabs.
; Commands: LNEXT, LPREV, LGOTO, LTABS, LSETMODEL, LSETWRAP
; Settings: NB*INCLUDE-MODEL* (T/NIL), NB*WRAP* (T/NIL)
; -----------------------------------------

(vl-load-com)

;; -----------------------------
;; SETTINGS (tweak as you like)
;; -----------------------------
(setq NB*INCLUDE-MODEL* nil) ; T = include "Model" in rotation; NIL = skip it
(setq NB*WRAP*          T)   ; T = wrap around at ends; NIL = stop at ends

;; --------------------------------
;; UTIL: get tab names in TabOrder
;; --------------------------------
(defun nb:layouts-get (/ doc lays pairs name ord)
  (vl-load-com)
  (setq doc  (vla-get-ActiveDocument (vlax-get-acad-object))
        lays (vla-get-Layouts doc)
        pairs '())
  (vlax-for L lays
    (setq name (vla-get-Name L)
          ord  (vla-get-TabOrder L))
    (setq pairs (cons (cons name ord) pairs))
  )
  ;; sort by visible left->right order
  (setq pairs (vl-sort pairs '(lambda (a b) (< (cdr a) (cdr b)))))

  ;; optionally drop MODEL
  (setq pairs
        (if NB*INCLUDE-MODEL*
          pairs
          (vl-remove-if '(lambda (p) (= (strcase (car p)) "MODEL")) pairs)))

  ;; return just the names
  (mapcar 'car pairs)
)

;; --------------------------------
;; UTIL: index of item in list
;; --------------------------------
(defun nb:index-of (x lst / i)
  (setq i 0)
  (while (and lst (/= (car lst) x))
    (setq lst (cdr lst)
          i   (1+ i)))
  (if lst i -1)
)

;; --------------------------------
;; Safe tab switch (case-insensitive)
;; --------------------------------
(defun nb:safe-settab (name / tabs exact)
  (setq tabs (nb:layouts-get))
  ;; find actual-cased name from current tab list
  (setq exact (vl-some '(lambda (x) (if (= (strcase x) (strcase name)) x)) tabs))
  (if exact
    (setvar 'CTAB exact)
    (prompt (strcat "\nLayout not found in current list: " name))
  )
  (princ)
)

;; --------------------------------
;; Core: next/prev logic with wrap
;; --------------------------------
(defun nb:nextprev (dir / tabs cur idx new total)
  (setq tabs (nb:layouts-get))
  (cond
    ((or (null tabs) (null (cdr tabs)))
     (prompt "\nOnly one layout available to cycle."))
    (t
     (setq cur (getvar 'CTAB))
     ;; If Model is excluded but current is Model, start from first paper tab
     (if (and (not NB*INCLUDE-MODEL*) (= (strcase cur) "MODEL"))
       (setq cur (car tabs))
     )
     (setq idx   (nb:index-of cur tabs)
           total (length tabs))
     (if (< idx 0)
       (progn
         (prompt "\nCurrent tab not in list; jumping to first.")
         (nb:safe-settab (car tabs))
       )
       (progn
         (setq new (+ idx dir))
         (cond
           ((and NB*WRAP* (< new 0))      (setq new (- total 1)))
           ((and NB*WRAP* (>= new total)) (setq new 0))
         )
         (if (or (< new 0) (>= new total))
           (prompt "\nReached end; wrapping disabled.")
           (nb:safe-settab (nth new tabs))
         )
       )
     )
    )
  )
  (princ)
)

;; --------------------------------
;; Commands
;; --------------------------------
(defun c:LNEXT () (nb:nextprev  1))
(defun c:LPREV () (nb:nextprev -1))

(defun c:LGOTO (/ tabs n)
  (setq tabs (nb:layouts-get))
  (if (null tabs)
    (prompt "\nNo paper space layouts.")
    (progn
      (c:LTABS)
      (setq n (getint (strcat "\nGo to layout number <1-" (itoa (length tabs)) ">: ")))
      (if (and n (>= n 1) (<= n (length tabs)))
        (nb:safe-settab (nth (1- n) tabs))
        (prompt "\nInvalid number.")
      )
    )
  )
  (princ)
)

(defun c:LTABS (/ tabs i cur)
  (setq tabs (nb:layouts-get)
        i    1
        cur  (getvar 'CTAB))
  (prompt "\nLayouts (TabOrder):")
  (foreach L tabs
    (prompt (strcat "\n  " (itoa i) ". " L (if (equal (strcase L) (strcase cur)) "  <current>" "")))
    (setq i (1+ i)))
  (princ)
)

(defun c:LSETMODEL (/ ans)
  (setq ans (getkword (strcat "\nInclude MODEL in rotation? [Yes/No] <"
                              (if NB*INCLUDE-MODEL* "Yes" "No") ">: ")))
  (cond ((wcmatch (strcase (vl-princ-to-string ans)) "Y*") (setq NB*INCLUDE-MODEL* T))
        ((wcmatch (strcase (vl-princ-to-string ans)) "N*") (setq NB*INCLUDE-MODEL* NIL)))
  (princ (strcat "\nInclude MODEL: " (if NB*INCLUDE-MODEL* "Yes" "No")))
  (princ)
)

(defun c:LSETWRAP (/ ans)
  (setq ans (getkword (strcat "\nWrap-around at ends? [Yes/No] <"
                              (if NB*WRAP* "Yes" "No") ">: ")))
  (cond ((wcmatch (strcase (vl-princ-to-string ans)) "Y*") (setq NB*WRAP* T))
        ((wcmatch (strcase (vl-princ-to-string ans)) "N*") (setq NB*WRAP* NIL)))
  (princ (strcat "\nWrap enabled: " (if NB*WRAP* "Yes" "No")))
  (princ)
)

(prompt "\nLoaded: LNEXT / LPREV / LGOTO / LTABS  (LSETMODEL, LSETWRAP to tweak).")
(princ)

 

 

Edited by SLW210
Added Code Tags!!
Posted

In the future please use Code Tags for your code. (<> in the editor toolbar)

  • Like 1

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...