Explicit update of the view template#3192
Conversation
|
Unable to trigger custom agent "Code Reviewer". You have run out of credits 😔 |
There was a problem hiding this comment.
Pull request overview
This PR extends the View Range tool behavior so that when a selected plan view’s view range is controlled by a view template, the update is applied directly to the template (matching the intent introduced in #3155 / issue #3110).
Changes:
- When a controlling view template is detected, the script updates the template’s
ViewRangeinstead of the view’s. - Uses a single resolved
viewtarget (template vs. source view) forGetViewRange()/SetViewRange()inside the transaction.
...RevitTools.extension/pyRevit.tab/Toggles.panel/toggles3.stack/ViewRange.pushbutton/script.py
Show resolved
Hide resolved
|
@thumDer I greatly appreciate your efforts in this. I copied the updated script provided with this pull request to test it out. I was running into an exception so I added a print statement to see what the problem is in the function "_update_view_range_internal" (starts about line 116). What I am seeing is that with view templates, all of the plane ids return as an invalid "-3". Most of the planes get updated as it goes through the function, except for CutPlane. view_range = view.GetViewRange() # Line 127
planes = [
DB.PlanViewPlane.TopClipPlane,
DB.PlanViewPlane.CutPlane,
DB.PlanViewPlane.BottomClipPlane,
DB.PlanViewPlane.ViewDepthPlane,
]
print("-----Before Changing values----")
for p in planes:
lvl = view_range.GetLevelId(p)
off = view_range.GetOffset(p)
print("Plane: {}, LevelId: {}, Offset: {}".format(p, lvl.IntegerValue, off))
So I thought I would try to merge the two methods slightly just to see if this would update the view template correctly. I took the source view's cut plane and set it as the cut plane of the view template. This ended up breaking the view, and view template range. "View Template" greys out (only on the source view, not all views with this template) and "View Range" property appears. If I open up the view template's view range, instead of "Associated Level", they are all explicitly set to the source view's cut plane. I did discover that Revit does actually accept the view templates view range with the "-3" levelid as I commented out everything between getting and setting the view range and forced the offset to be set to "-6.0" which differs from the "-5.0" just to see if we can update the offsets, and that worked. Maybe we have to ignore the Level Id for view templates and only take the "Offset from Level value"? What are your thoughts here?
Before updating view template view range After updating view template view range. "Associated level" is really just "Level 6"
|
|
@jmcouffin I wouldn't merge this in yet by the way, due to the issues above,. |
|
@porrt23 thanks for testing the change, it is somewhat unexpected that it doesn't work, I will have another look at it. FYI the -3 Id for the level is not invalid in this case, this is used internally as one of the relative levels (Current / Above / Below / Unlimited) as you can see here under the static properties of the |
@thumDer Yeah, I figured that out shortly after I commented. It seems that Revit doesn't like mixing the relative levels with actual level ids? So I'm wondering if for templates, it ignores levels and only focuses on the offsets? Or maybe have to update the pulldowns to match when a template is selected so the user sees the same options (Current / Above / Below / Unlimited) that they would for a normal view template. Let me know if you want me to look into anything specific to help with it more. I'm not as familiar with Pull Requests/github so currently the best I can do is upload the code edits here and have you update this pull request. |
You can try, and let me know if you have something. I did some experiments, and views always return explicit levels, while templates return relative levels, with the negative ids. This means that fixing this is slightly more complicated, we need different set of levels for views, and templates, and on views with templates we have to override the level options to the relative ones. I'll also give it a try. |
|
@porrt23 please test my latest commit, I only had time for a quick test, and it seems to be working, but would like you to test it as well. |
|
@thumDer I'm planning on testing within the next few hours. Will keep you updated. |
|
@thumDer this works for me! The only check I would add is for the Cut Plane Level Name. For view templates, I was consistently getting "Unknown" as the level name. The fix I found is to get GenLevel from the source_view. This was giving me the level name as expected. Screenshot and code below. Thanks for fixing this!
As a side note (and probably a separate issue to be logged), if you happen to open two View Range Editor windows, the planes continue to update in the 3D view as if the Editor is still open even after you close both windows. I don't think that would be related to this fix. I just found it odd. |
|
I would rather put Please create a separate issue for the two windows problem. Currently I have a quite dirty solution for that in one of my other tools, but I'm not sure I would admit it publicly :D pyRevit should have a built-in solution for that, following the smartbutton analogy. I will try to figure out something. |
|
Let me know when ready for review @thumDer |
|
@jmcouffin it is ready |
...RevitTools.extension/pyRevit.tab/Toggles.panel/toggles3.stack/ViewRange.pushbutton/script.py
Show resolved
Hide resolved
...RevitTools.extension/pyRevit.tab/Toggles.panel/toggles3.stack/ViewRange.pushbutton/script.py
Show resolved
Hide resolved
| # above | ||
| elif get_elementid_value(level_id) == -2: | ||
| plane_level = self._ordered_levels[ | ||
| ordered_level_ids.index(view_level_id) + 1 | ||
| ] |
There was a problem hiding this comment.
Resolving relative level ids via ordered_level_ids.index(view_level_id) + 1 can raise ValueError/IndexError (e.g., if GenLevel isn’t found in _ordered_levels, or when the view’s level is the topmost level and the template uses "Level Above"). Consider precomputing the index once, validating bounds, and falling back to a safe state (e.g., treat as Unlimited/N/A) instead of throwing inside context_changed().
There was a problem hiding this comment.
This could be improved, related to #3192 (comment)
| plane_level = self._ordered_levels[ | ||
| ordered_level_ids.index(view_level_id) - 1 | ||
| ] |
There was a problem hiding this comment.
The "Level Below" mapping uses ordered_level_ids.index(view_level_id) - 1, which will silently wrap to the last item if the index is 0 (Python negative indexing), producing an incorrect level instead of indicating that there is no level below. Add an explicit lower-bound check before indexing.
| plane_level = self._ordered_levels[ | |
| ordered_level_ids.index(view_level_id) - 1 | |
| ] | |
| view_level_idx = ordered_level_ids.index(view_level_id) | |
| if view_level_idx == 0: | |
| # No level below the lowest level; treat as unset | |
| plane_level = None | |
| else: | |
| plane_level = self._ordered_levels[view_level_idx - 1] |
There was a problem hiding this comment.
This is somewhat valid though, if current is the lowest level, then "Below" can't be interpreted. needs an extra check
...RevitTools.extension/pyRevit.tab/Toggles.panel/toggles3.stack/ViewRange.pushbutton/script.py
Show resolved
Hide resolved
| @events.handle("doc-changed") | ||
| def doc_changed(sender, args): | ||
| try: | ||
| context.collect_levels(args.Document) | ||
| affected_ids = list(args.GetModifiedElementIds()) + list( |
There was a problem hiding this comment.
_source_template is only computed in the source_view setter. If the selected view’s template assignment changes later (or the template’s controlled parameters change) the tool can keep reading/updating the stale template object. Since this PR now applies updates directly to _source_template, this can result in modifying an unintended template. Consider recomputing _source_template inside context_changed()/doc_changed() when the source view or its template-related parameters are affected.
There was a problem hiding this comment.
This is valid, will handle this too.
|
📦 New work-in-progress (wip) builds are available for 6.1.0.26090+1556-wip |
|
📦 New public release are available for 6.2.0.26090+1754 |
|
since it was merged I will create an additional PR to include the suggested valid improvements. |










Explicit update of the view template
Description
As an addition to #3155 the view range update is explicitly executed on the template itself.
Checklist
Before submitting your pull request, ensure the following requirements are met:
pipenv run black {source_file_or_directory}Related Issues
Additional Notes
Include any additional context, screenshots, or considerations for reviewers.
Thank you for contributing to pyRevit! 🎉