FamSlide — live parameter sliders for the Family Editor - #3489
FamSlide — live parameter sliders for the Family Editor#3489Wurschdhaud wants to merge 12 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new pyRevitTools Family Editor utility (“FamSlide”) that provides a modeless WPF panel for interactively editing family parameters (sliders/checkboxes/text) with localized UI strings and a couple of bulk actions.
Changes:
- Introduces the FamSlide modeless WPF window and Revit event wiring to keep the parameter list in sync.
- Adds parameter discovery/classification utilities plus bulk actions (shuffle values, delete unused).
- Adds 8-language localization resources and registers the new pushbutton in the Family pulldown.
Reviewed changes
Copilot reviewed 14 out of 16 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack/Family.pulldown/FamSlide.pushbutton/script.py | Main modeless WPF UI + event hooks + commit logic for parameter edits. |
| extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack/Family.pulldown/FamSlide.pushbutton/FamSlideWindow.xaml | XAML layout for the FamSlide window. |
| extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack/Family.pulldown/FamSlide.pushbutton/FamSlideWindow.ResourceDictionary.en_us.xaml | English UI string resources for in-panel localization. |
| extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack/Family.pulldown/FamSlide.pushbutton/FamSlideWindow.ResourceDictionary.ko.xaml | Korean UI string resources for in-panel localization. |
| extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack/Family.pulldown/FamSlide.pushbutton/FamSlideWindow.ResourceDictionary.fr_fr.xaml | French UI string resources for in-panel localization. |
| extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack/Family.pulldown/FamSlide.pushbutton/FamSlideWindow.ResourceDictionary.ru.xaml | Russian UI string resources for in-panel localization. |
| extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack/Family.pulldown/FamSlide.pushbutton/FamSlideWindow.ResourceDictionary.chinese_s.xaml | Simplified Chinese UI string resources for in-panel localization. |
| extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack/Family.pulldown/FamSlide.pushbutton/FamSlideWindow.ResourceDictionary.es_es.xaml | Spanish UI string resources for in-panel localization. |
| extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack/Family.pulldown/FamSlide.pushbutton/FamSlideWindow.ResourceDictionary.de_de.xaml | German UI string resources for in-panel localization. |
| extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack/Family.pulldown/FamSlide.pushbutton/FamSlideWindow.ResourceDictionary.pt_br.xaml | Brazilian Portuguese UI string resources for in-panel localization. |
| extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack/Family.pulldown/FamSlide.pushbutton/famslide_paramutils.py | Parameter scanning/classification/tagging and default slider ranges. |
| extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack/Family.pulldown/FamSlide.pushbutton/famslide_actions.py | Bulk actions: shuffle values and delete unused parameters. |
| extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack/Family.pulldown/FamSlide.pushbutton/bundle.yaml | Pushbutton metadata, localized tooltip, and persistent engine requirement. |
| extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack/Family.pulldown/bundle.yaml | Adds FamSlide to the Family pulldown layout. |
There was a problem hiding this comment.
PR Summary:
- Adds FamSlide, a modeless WPF panel exposing live sliders/checkboxes/textboxes bound to the active family's parameters in the Family Editor.
- Reactive refresh on
doc-changed/view-activated/doc-opened, plus "shuffle all values" and "delete unused parameters" bulk actions (transaction-wrapped, confirmed viaforms.alert). - Full 8-locale localization for bundle metadata and in-panel UI strings via
ResourceDictionaryXAML files.
Review Summary:
Reviewed script.py, famslide_paramutils.py, famslide_actions.py, bundle.yaml, and the XAML/localization files. The pyrevit.revit.events.execute_in_revit_context bridging pattern and the module-level ui = None + engine: persistent: true singleton idiom are used correctly and match established, shipping precedent in this repo (e.g. Keynotes.pushbutton), so those were not flagged. Localization keys are consistent across all 8 locale files. Found two real gaps in Revit-API-context/state handling:
fm.CurrentTypecan beNonefor a family with no defined types yet — unguarded, this crashesrefresh_from_document/_build_row(precedent:Cycle Family Types.pushbuttonexplicitly checks for this).on_toggle_editable_click/on_toggle_labels_clickreadrevit.doc/doc.FamilyManagerdirectly from a plain button-click handler, breaking the file's own convention of bridging all document access throughexecute_in_revit_context.
No IronPython 2.7/PEP8/black-formatting violations were spotted (no f-strings, no Py3-only syntax, consistent .format() usage).
Suggestions
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
@dnenov good with you if this goes out? |
Thank you for the effort @Wurschdhaud, thank you for letting me know and being considerate of my opinion @jmcouffin . I reviewed the code, the implementation is quite efficient and easy to maintain I reckon. Honestly, it's difficult for me to let go of one of my first Revit add-ins like that, but the thruth is that it serves the community better if it's out in the open and maintained by said community. You have my blessing, let's make it a pyRevit addition. I will update the existing Autodesk Marketplace documentation to point to pyRevit for posterity. (I really appreciate the credentials inside the tooltip too, that tilted the scales - my silly ego got what it wanted I suppose.) Thank you once again @Wurschdhaud @jmcouffin |
|
Reading thru the code, I understand that the shuffle needs to be rolled back from the Revit UI. |
|
Nice |
|
I don't understand what you mean tbh - at least not for the second sentence |
|
Added automatic save on startup - I hope that's what you meant? Was mostly non-AI changes, so I would appreciate another Copilot before this goes live. Will for sure have at least a typo or whatever 😄 |
You'll get a human review for the dame price 😁 |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 16 changed files in this pull request and generated no new comments.
Suppressed comments (4)
extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack/Family.pulldown/FamSlide.pushbutton/script.py:557
- Preset capture currently falls back to fm.CurrentType.AsValueString(...) for any non-numeric storage type. For String parameters this is inconsistent with the edit path (_commit_text uses fm.Set for StorageType.String) and can lead to missing/incorrect preset values for string parameters (and unclear behavior for ElementId).
preset[param_id] = fm.CurrentType.AsInteger(row.param)
elif row.storage_type == DB.StorageType.Double:
preset[param_id] = fm.CurrentType.AsDouble(row.param)
else:
preset[param_id] = fm.CurrentType.AsValueString(row.param)
extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack/Family.pulldown/FamSlide.pushbutton/script.py:590
- Preset restore applies SetValueString(...) for the non-numeric fallback case. This will fail for String parameters (which should use fm.Set) and does not handle ElementId values. As a result, presets saved from string parameters may not be restored correctly.
fm.Set(row.param, int(value))
elif row.storage_type == DB.StorageType.Double:
fm.Set(row.param, float(value))
else:
fm.SetValueString(row.param, value)
extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack/Family.pulldown/FamSlide.pushbutton/script.py:611
- The event handlers are registered via @events.handle, which keys registrations by the current EXEC_PARAMS.exec_id. In persistent-engine + modeless UI scenarios, the user can run other commands before closing FamSlide, so EXEC_PARAMS.exec_id may change; this makes events.stop_events() (called on window close) unregister the wrong handler group, leaving stale doc-changed/view-activated hooks alive and keeping the old ScriptScope/UI instance pinned.
Consider registering handlers under a stable, tool-specific handler_group_id (e.g. script.get_unique_id() or a hardcoded string) via events.register_handler(..., handler_group_id=...) and explicitly unregistering that group on close (events.unregister_exec_handlers(handler_group_id)).
@events.handle("doc-changed", "view-activated", "doc-opened")
def famslide_on_revit_event(sender, args):
if ui is not None:
ui.refresh_from_document()
extensions/pyRevitTools.extension/pyRevit.tab/Project.panel/ptools.stack/Family.pulldown/FamSlide.pushbutton/script.py:296
- The value TextBox becomes editable for any editable parameter, but _commit_text only supports Double/Integer (via SetValueString) and String (via Set). This means ElementId parameters can appear editable but edits will never apply, and Yes/No parameters show localized "Yes/No" text that may not be parseable by SetValueString.
Making the TextBox read-only unless the storage type is actually supported (and excluding Yes/No, which already has a checkbox) avoids a misleading UI and failed commits.
This issue also appears in the following locations of the same file:
- line 553
- line 586
value_box.IsReadOnly = not row.is_editable
value_box.Tag = row
value_box.KeyDown += self.on_value_box_key_down
value_box.LostFocus += self.on_value_box_lost_focus
- set elementid to readonly


Description
What this is
FamSlide gives you a modeless panel of sliders / checkboxes / textboxes bound
to the active family's parameters, so you can see how the model reacts to
parameter changes (shape changes, constraint errors, etc.) without
round-tripping through the Family Types dialog every time. It also has
one-click "shuffle all values" and "delete unused parameters" utilities.
This is effectively a reimplementation of Archilizer's Family Editor
Interface, which unfortunately hasn't been updated
for Revit versions newer than 2024. Credit to Archilizer for the original
concept and UX — this tool exists to keep that workflow alive on current
Revit.
What's in this PR
doc-changed/view-activated/doc-openedso the parameter list stays in sync as you edit, undo/redo, orswitch between open families.
in use,uFused-in-formula,
dFdriven-by-formula,built-in,instance/type,associated).wrapped in a single transaction.
en_us,ko,fr_fr,ru,chinese_s,es_es,de_de,pt_br) for both bundle metadata and in-panel UI text.Screenshots / recording
Recording.2026-07-16.094834.mp4
Checklist
Before submitting your pull request, ensure the following requirements are met:
pipenv run black {source_file_or_directory}