Output panel
Layout Manager
Renames, reorders, copies or deletes paper space layouts, or applies one named page setup to many layouts at once.
On the ribbonButton, Output panel
NeedsAn open drawing with at least one layout (the button is greyed without a drawing)
Command
PYLAYOUTMANAGERAlias
LYMWhat it does#
One action per run, picked from the first window:
- Rename one layout.
- Reorder: move one layout to a new position among the tabs.
- Copy one layout, with everything drawn on it and its plot settings.
- Delete several layouts at once.
- Apply page setup: make one named page setup the plot settings of every layout you tick.
Each run is one AutoCAD command, so a single U takes the change back.
How to use it#
- Click Layout Manager, or type
PYLAYOUTMANAGER, and pick an action. - Rename. Pick the layout (the current one is picked to start with) and type the new name. A name another layout already has is refused; a change of case alone is allowed.
- Reorder. Pick the layout from the numbered list, then type its new position, from 1 to the number of layouts. Position 1 is the first tab after Model.
- Copy. Pick the layout and type a name for the copy. The suggestion is
the source name with
(2); a name already in use gains a counter the way AutoCAD's own Move or Copy does, so copyingA1 (2)again givesA1 (3). - Delete. Tick the layouts and confirm. Everything drawn on them goes with them. If the current layout is among them, the drawing switches to Model first.
- Apply page setup. Pick a named page setup, then tick the layouts to apply it to (all start ticked).
- A toast confirms the change, for example "Moved A-301 to position 2".
Limitations#
- The model tab cannot be renamed, moved, copied or deleted, and is not listed.
- Delete refuses to remove every layout: a drawing keeps at least one. Untick one and run it again.
- Apply page setup offers only page setups made for paper space, and creates none. If the drawing has none, a toast tells you to make one with PAGESETUP first. It is all or nothing: if one layout cannot take the setup, none is changed.
- Reorder moves one layout per run. Copy makes one copy per run.
- Page setups from other drawings are not offered. Import them with PSETUPIN first.
Good to know#
If an action fails, a toast says "Could not ..." with AutoCAD's reason, and the log at
%APPDATA%\pyACAD\logs\pyACAD.log has the detail. Delete reports each layout it
could not remove and still removes the rest.
Other uses#
- After you bring in sheets with Layout from Template, apply the office page setup to all of them in one go before you run Batch Plot.
- Copy a finished sheet as the starting point for the next one: title block, viewports and all.
- Clear out the default Layout1 and Layout2 tabs a template left behind.
Source#
The tool's own files, word for word as shipped in Output.panel/Layout_Manager.pushbutton. Every pyACAD tool is an ordinary bundle: copy these into your own extension and change what you like.
script.py Runs on a click. View on GitHub# -*- coding: utf-8 -*-
"""Renames, reorders, copies and deletes paper space layouts, and applies one
named page setup to many layouts at once.
One action per run, picked from the first dialog. Each run is one AutoCAD
command, so a single Undo takes the change back.
"""
from pyacad import doc, forms, layouts, script, toast
__title__ = 'Layout Manager'
_TITLE = 'Layout manager'
def run():
if not _has_drawing():
toast.warning('No drawing is open', 'Open a drawing and run Layout Manager again.')
return
names = layouts.names()
if not names:
toast.info('No layouts', 'This drawing has only the model tab.')
return
action = forms.ask_options('What do you want to do with the layouts?',
[label for label, _ in _ACTIONS], _TITLE)
if action is None:
return
handler = dict(_ACTIONS)[action]
try:
handler(names)
except Exception as error:
script.get_logger().error('layout manager: %s failed: %s' % (action, error))
toast.error('Could not %s' % action.lower(), str(error))
def _has_drawing():
try:
doc.active()
except RuntimeError:
return False
return True
def _rename(names):
old = _pick_layout(names, 'Layout to rename')
if old is None:
return
new = forms.ask_string('New name for %s' % old, old, _TITLE)
if new is None:
return
new = new.strip()
if not new:
toast.warning('Nothing renamed', 'A layout needs a name.')
return
if new == old:
toast.info('Nothing renamed', 'The name did not change.')
return
layouts.rename(old, new)
toast.success('Renamed %s to %s' % (old, new))
def _reorder(names):
if len(names) < 2:
toast.info('Nothing to reorder', 'The drawing has one layout.')
return
items = [('%d. %s' % (i + 1, name), name) for i, name in enumerate(names)]
name = forms.select_from_list(items, _TITLE, prompt='Layout to move',
checked=_current_among(names))
if name is None:
return
now = names.index(name) + 1
position = forms.ask_number('New position for %s, from 1 to %d (now %d)'
% (name, len(names), now),
default=now, min_value=1, max_value=len(names), title=_TITLE)
if position is None:
return
order = layouts.reorder(names, name, int(round(position)) - 1)
if order == names:
toast.info('Nothing moved', '%s is already at position %d.' % (name, now))
return
layouts.set_order(order)
toast.success('Moved %s to position %d' % (name, order.index(name) + 1))
def _copy(names):
source = _pick_layout(names, 'Layout to copy')
if source is None:
return
wanted = forms.ask_string('Name for the copy of %s' % source,
layouts.unique_name(names, source), _TITLE)
if wanted is None:
return
if not wanted.strip():
toast.warning('Nothing copied', 'The copy needs a name.')
return
# Like AutoCAD's own Move or Copy, a name already in use gains a counter.
name = layouts.copy(source, layouts.unique_name(names, wanted))
toast.success('Copied %s to %s' % (source, name))
def _delete(names):
doomed = forms.select_from_list(names, _TITLE, multiselect=True, prompt='Layouts to delete')
if doomed is None:
return
if not doomed:
toast.info('Nothing deleted', 'No layout was ticked.')
return
if len(doomed) == len(names):
toast.warning('Nothing deleted', 'A drawing keeps at least one layout. Untick one and try again.')
return
if not forms.confirm('Delete %s? Everything drawn on %s goes with %s.'
% (_listing(doomed), 'it' if len(doomed) == 1 else 'them',
'it' if len(doomed) == 1 else 'them'), _TITLE):
return
if layouts.current().lower() in [n.lower() for n in doomed]:
layouts.set_current('Model')
deleted = []
failures = []
for name in doomed:
try:
layouts.delete(name)
deleted.append(name)
except Exception as error:
failures.append('%s: %s' % (name, error))
if failures:
toast.warning('Deleted %d of %d layouts' % (len(deleted), len(doomed)), '; '.join(failures))
else:
toast.success('Deleted %s' % _count(len(deleted), 'layout', 'layouts'), _listing(deleted))
def _apply_page_setup(names):
setups = layouts.page_setups(paper_only=True)
if not setups:
toast.info('No page setups',
'This drawing has no named paper space page setups. Make one with PAGESETUP first.')
return
setup = forms.select_from_list(setups, _TITLE, prompt='Page setup to apply')
if setup is None:
return
targets = forms.select_from_list(names, _TITLE, multiselect=True,
prompt='Layouts to apply %s to' % setup, checked=names)
if targets is None:
return
if not targets:
toast.info('Nothing changed', 'No layout was ticked.')
return
count = layouts.apply_page_setup(setup, targets)
toast.success('Applied %s to %s' % (setup, _count(count, 'layout', 'layouts')))
def _pick_layout(names, prompt):
"""One layout, the current one picked to start with."""
return forms.select_from_list(names, _TITLE, prompt=prompt, checked=_current_among(names))
def _current_among(names):
current = layouts.current()
return [current] if current in names else None
def _listing(names, limit=4):
"""'A1', 'A1 and A2', 'A1, A2 and A3', or the first few and how many more."""
names = list(names)
if len(names) > limit:
return '%s and %d more' % (', '.join(names[:limit - 1]), len(names) - limit + 1)
if len(names) == 1:
return names[0]
return '%s and %s' % (', '.join(names[:-1]), names[-1])
def _count(n, one, many):
return '%d %s' % (n, one if n == 1 else many)
_ACTIONS = [
('Rename', _rename),
('Reorder', _reorder),
('Copy', _copy),
('Delete', _delete),
('Apply page setup', _apply_page_setup),
]
run()bundle.yaml The bundle contract: the keys pyACAD reads for this tool. View on GitHubtitle: Layout Manager
tooltip: Renames, reorders, copies or deletes paper space layouts, or applies one named page setup to many layouts at once.
context: doc
keytip: OL
alias: LYM