Skip to content

Layout Persistence

MorquinDevlar edited this page Sep 5, 2026 · 8 revisions

Layout Persistence

MDW automatically saves and restores widget layouts across profile reloads and package updates.

What's Saved

  • Widget dock positions (left, right, or floating)
  • Widget sizes and positions, floating groups included - a float's position is its whole placement, so it is restored from the record rather than re-derived
  • Row order and side-by-side arrangements (including width ratios)
  • Visibility state
  • Active tab and tab order for tabbed widgets
  • Tabbed groups: their members, order, and active tab (and each member's group)
  • Dock widths
  • Sidebar and prompt bar visibility
  • Prompt bar height
  • Font sizes (content, main console, prompt offset, header, menu, and tab)
  • The font family (the one you chose, not a fallback MDW substituted for a session)
  • Per-widget font adjustments
  • Fill state
  • Active theme
  • Your original main-console font size, and its family when applyMainFont is on (so a full uninstall can restore them)
  • Game package settings (mdw.gameSettings, stored under the game key and restored before onReady callbacks run - see Getting Started)

When It Saves

Layout is saved automatically when:

  • The profile exits or the package is updated
  • A widget is docked, undocked, or has its visibility toggled
  • Widgets are grouped, ungrouped, or a group's tab is switched
  • Dock edges, widget borders, or splitters are resized
  • The prompt bar is resized
  • Font sizes or the font family are changed
  • The theme is changed
  • Tabs are reordered
  • A scripted placement, size, or visibility change is made (Scripted Control)
  • Your package calls mdw.saveLayout() after changing mdw.gameSettings

Saves are batched across an operation that touches many widgets. Building the UI or tearing it down would otherwise write the file once per widget - dozens of times for a single package update - and each of those writes records a UI mid-change, which the next build would then restore. A build writes once, at the end; a teardown writes nothing at all, because the layout worth keeping is the one from before it started.

If you do something that touches many widgets yourself, batch it the same way:

mdw.deferLayoutSaves()
-- ... create, dock or destroy a pile of widgets ...
mdw.resumeLayoutSaves(true)   -- write once now (false: write nothing)

The pair nests, so it is safe to use inside code that MDW has already batched.

Hold it across your own uninstall cleanup too. A sysUninstallPackage handler that destroys its widgets is dismantling and saving at the same time, and the file it leaves behind is one with those widgets missing - which is then what a reinstall restores. Bracket the cleanup and release without writing:

mdw.deferLayoutSaves()
-- ... destroy your widgets, remove your bars, withdraw your registrations
mdw.resumeLayoutSaves(false)   -- release WITHOUT writing

The layout worth keeping is the one from before the uninstall started, and it is already on disk. MDW's own reap holds the lock for the same reason, but the order of two handlers on one event is nobody's to choose, so hold it yourself.

Layouts Across a Package Update

A package update is an uninstall immediately followed by an install, so the package that comes back is the same package - and MDW restores it rather than letting it rebuild from scratch. Before your onReady re-runs, MDW re-seeds the saved records for widgets that are not currently present; after it, the groups they were in are re-formed. The player keeps their sizes, per-widget font adjustments, closed widgets, and grouping, including a widget they had dragged into a group belonging to another package or to MDW itself.

This is read from the saved file rather than from the widgets being removed, which is why the hold above matters: the file is the only intact record by the time MDW rebuilds.

Layout API

mdw.saveLayout()       -- Manually save current layout
mdw.deferLayoutSaves() -- Hold saves; nestable
mdw.resumeLayoutSaves(save) -- Release one level; `save` writes once at the last
mdw.loadLayout()       -- Manually load saved layout (usually automatic)
mdw.clearLayout()      -- Delete the saved layout file; defaults apply on the next profile load
mdw.resetLayout(opts)  -- Delete it AND rebuild the UI from the factory defaults right now
                       -- (opts.keepGameSettings, default true, preserves mdw.gameSettings)
mdw.describeLayout()   -- The current layout as plain data (see Scripted Control)
mdw.showLayout()       -- Print saved layout details to main window
mdw.showWidgets()      -- Print current widget state to main window

The layout file is stored at: getMudletHomeDir() .. "/mdw_layout.lua"

Clone this wiki locally