Layers panel

Layer Snapshot

Saves which layers are on, frozen and locked under a name for this drawing, and puts a saved state back later.

On the ribbonButton, Layers panel
NeedsAn open drawing
CommandPYLAYERSNAPSHOT, PYLAYERSNAPSHOTCFG for Shift+Click
AliasLSN
ShortcutNone set (bind one in Shortcuts)
Shift+ClickLists the states saved for this drawing

What it does#

Takes a snapshot of every layer's on, frozen and locked state and saves it under a name, so you can switch layers around freely and come back. Restoring sets those three things back on every layer the snapshot knows. The command is PYLAYERSNAPSHOT; Shift+Click is PYLAYERSNAPSHOTCFG.

How to use it#

  1. Click Layer Snapshot and choose Save, Restore or Delete.
  2. Save: type a name (the date and time is filled in). A name already used for this drawing, in any case, asks before it is replaced.
  3. Restore: pick a saved state from the list, newest first, each with when it was saved and how many layers it holds. The toast says how many layers changed and how many saved layers the drawing no longer has.
  4. Delete: tick one or more saved states and confirm.
  5. Shift+Click lists this drawing's saved states without changing anything, with a Copy button.

Good to know / limits#

  • Only on, frozen and locked are restored. Colour, linetype and the rest are saved in the snapshot but never put back.
  • Layers created after the snapshot are left as they are. Layers deleted since are skipped.
  • The current layer is never frozen by a restore.
  • The states are not stored in the drawing. They live in a file under %APPDATA%\pyACAD\data, keyed by the drawing's full path. So they are yours alone, they do not travel with the DWG, and moving or renaming the drawing leaves them behind. Every drawing that has never been saved shares one set.
  • A restore is one AutoCAD command, so U takes it back.
  • AutoCAD's own Layer States (LAYERSTATE) are stored in the drawing and can restore more properties. Use them when the state must travel with the file; use this when you want a quick personal bookmark.

Other uses#

  • Save before you Isolate in the Layer Manager, and restore to get every layer back exactly as it was.
  • Keep a "plot" and a "work" state for a drawing and switch between them in two clicks.

Source#

The tool's own files, word for word as shipped in Layers.panel/Layer_Snapshot.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 -*-
"""Saves the drawing's layer state under a name, puts a saved one back, or deletes one.

A state is which layers are on, frozen and locked (layers.snapshot). States are
kept per drawing with script.store_data(per_document=True), as one 'slots' entry
mapping each name to {'saved': 'YYYY-MM-DD HH:MM', 'layers': snapshot}.
Restoring changes only those three flags and skips layers the drawing no longer
has. Shift+Click (config.py) lists the saved states.
"""

__title__ = 'Layer Snapshot'

import datetime

from pyacad import doc, forms, layers, script, toast

SLOTS = 'slots'
TITLE = 'Layer Snapshot'


def has_drawing():
    try:
        doc.active()
        return True
    except RuntimeError:
        return False


def plural(n, word):
    return '%d %s%s' % (n, word, '' if n == 1 else 's')


def load_slots():
    slots = script.load_data(SLOTS, {}, per_document=True)
    return slots if isinstance(slots, dict) else {}


def saved_layers(slots, name):
    slot = slots.get(name)
    saved = slot.get('layers') if isinstance(slot, dict) else None
    return saved if isinstance(saved, dict) else {}


def save(slots):
    now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M')
    name = (forms.ask_string('Name this layer state', now, 'Save layer state') or '').strip()
    if not name:
        return
    same = [key for key in slots if key.lower() == name.lower()]
    if same and not forms.confirm('Replace the saved state %s?' % same[0], 'Save layer state'):
        return
    for key in same:
        del slots[key]
    snapshot = layers.snapshot()
    slots[name] = {'saved': now, 'layers': snapshot}
    script.store_data(SLOTS, slots, per_document=True)
    toast.success('Saved layer state %s' % name, plural(len(snapshot), 'layer'))


def restore(slots):
    if not slots:
        toast.info('No layer states saved for this drawing', 'Choose Save first')
        return
    name = forms.select_from_list(layers.snapshot_choices(slots), title='Restore layer state',
                                  prompt='Pick the state to put back')
    if name is None:
        return
    saved = saved_layers(slots, name)
    present = set(n.lower() for n in layers.names())
    missing = len([n for n in saved if n.lower() not in present])
    changed = layers.restore(saved)
    detail = plural(changed, 'layer') + ' changed'
    if missing:
        detail += '; %s no longer in the drawing' % plural(missing, 'saved layer')
    toast.success('Restored %s' % name, detail)


def delete(slots):
    if not slots:
        toast.info('No layer states saved for this drawing')
        return
    names = forms.select_from_list(layers.snapshot_choices(slots), title='Delete layer states',
                                   multiselect=True, prompt='Tick the states to delete')
    if not names:
        return
    if not forms.confirm('Delete %s?\n\n%s' % (plural(len(names), 'saved layer state'),
                                               '\n'.join(names)), 'Delete layer states'):
        return
    for name in names:
        slots.pop(name, None)
    script.store_data(SLOTS, slots, per_document=True)
    toast.success('Deleted %s' % plural(len(names), 'layer state'))


def run():
    if not has_drawing():
        toast.warning('Open a drawing first', 'Layer states are saved per drawing')
        return
    choice = forms.ask_options('Save the layers as they are now, or bring back a saved state?',
                               ['Save', 'Restore', 'Delete'], TITLE)
    if choice is None:
        return
    try:
        {'Save': save, 'Restore': restore, 'Delete': delete}[choice](load_slots())
    except Exception as error:
        script.get_logger().error('%s failed: %s' % (choice, error))
        toast.error('Layer Snapshot: %s failed' % choice.lower(), str(error))


if '__commandpath__' in globals():
    run()
config.py Runs on Shift+Click. View on GitHub
# -*- coding: utf-8 -*-
"""Shift+Click on Layer Snapshot: lists the layer states saved for this drawing.

Reads the same per-drawing 'slots' entry script.py writes; changes nothing.
"""

__title__ = 'Layer Snapshot'

from pyacad import doc, forms, layers, script, toast


def run():
    try:
        doc.active()
    except RuntimeError:
        toast.warning('Open a drawing first', 'Layer states are saved per drawing')
        return
    slots = script.load_data('slots', {}, per_document=True)
    choices = layers.snapshot_choices(slots if isinstance(slots, dict) else {})
    if not choices:
        toast.info('No layer states saved for this drawing', 'Click Layer Snapshot to save one')
        return
    text = '\n'.join(label for label, _ in choices)
    forms.alert('%d saved layer state%s, newest first:\n\n%s'
                % (len(choices), '' if len(choices) == 1 else 's', text),
                'Layer Snapshot', copy=text)


if '__commandpath__' in globals():
    run()
bundle.yaml The bundle contract: the keys pyACAD reads for this tool. View on GitHub
title: Layer Snapshot
tooltip: Saves which layers are on, frozen and locked under a name kept with this drawing, and puts a saved state back later. Shift+Click lists the saved states.
context: doc
keytip: LS
alias: LSN