Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@

pyRevit helps you quickly sketch out your automation and addon ideas, in whichever language that you are most comfortable with, inside the Revit environment and using its APIs. It also ships with an extensive set of powerful tools that showcase its capabilities as a development environment. Download and install pyRevit, launch Revit, and note the new pyRevit tab that includes these tools. pyRevit also ships with a handy CLI utility for customized configuration and deployment of your tools, and a telemetry server to monitor pyRevit usage across your teams.

 


### pyRevit can help you

Expand All @@ -84,7 +84,7 @@ pyRevit helps you quickly sketch out your automation and addon ideas, in whichev
- **Distribute your tools** (pyRevit, [Dynamo](https://dynamobim.org/), or [Grasshopper](https://www.rhino3d.com/inside)) easily to your teams using a unified interface
- **Share your tools** with the community

 


# Getting Started

Expand Down
6 changes: 3 additions & 3 deletions dev/_changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def __init__(self, label: github.LabelInfo) -> None:
self._label = label
self._aspect_type = None
self._aspect_pattern = ChangeClass.DefaultPattern
if m := re.match(r".*\[(.+?)(->(.+?))?\].*", label.description):
if label.description and (m := re.match(r".*\[(.+?)(->(.+?))?\].*", label.description)):
self._aspect_type = m.groups()[0]
if pattern := m.groups()[2]:
self._aspect_pattern = f"- {pattern}"
Expand Down Expand Up @@ -125,7 +125,7 @@ def subsystems(self):
return [
ChangeClass(x)
for x in self._ticketdata.labels
if "[subsystem" in x.description
if x.description and "[subsystem" in x.description
]
return []

Expand All @@ -136,7 +136,7 @@ def classes(self):
return [
ChangeClass(x)
for x in self._ticketdata.labels
if "[class" in x.description
if x.description and "[class" in x.description
]
return []

Expand Down
2 changes: 1 addition & 1 deletion dev/scripts/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def get_ticket(ticket: str):
ticket_labels = []
if labels := issue.get("labels", []):
ticket_labels = [
LabelInfo(name=x["name"], description=x["description"])
LabelInfo(name=x["name"], description=x.get("description") or "")
for x in labels
]
else:
Expand Down
9 changes: 7 additions & 2 deletions docs/gen_ref_pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,10 @@
nav_file.writelines(nav.build_literate_nav())

for md in Path(".").glob("*.md"):
with mkdocs_gen_files.open(md, "w") as f:
f.write(Path(md).read_text())
try:
with mkdocs_gen_files.open(md, "w") as f:
f.write(Path(md).read_text(encoding='utf-8', errors='replace'))
except UnicodeDecodeError:
# Skip files that can't be decoded as UTF-8
print(f"Warning: Skipping {md} due to encoding issues")
continue
4 changes: 1 addition & 3 deletions extensions/pyRevitDevTools.extension/startup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
All errors will be printed to the dedicated output window similar to the way
errors are printed from pyRevit commands.
"""
#pylint: disable=import-error,invalid-name,broad-except,superfluous-parens
#pylint: disable=unused-import,wrong-import-position,unused-argument
#pylint: disable=missing-docstring

import sys
import time
import os.path as op
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,32 @@ def Execute(self, uiapp):
if not view:
return
solid_fill_id = solid_fill_pattern_id()

# Get current category and parameter selection
sel_cat = wndw._categories.SelectedItem["Value"]
if sel_cat == 0:
return

# Find which parameter is currently checked
checked_param = None
for indx in range(wndw._list_box1.Items.Count):
if wndw._list_box1.GetItemChecked(indx):
checked_param = wndw._list_box1.Items[indx]["Value"]
break

if checked_param is None:
return

# Refresh element-to-value mappings to reflect current parameter values
refreshed_values = get_range_values(sel_cat, checked_param, view)

# Create a mapping of value strings to user-selected colors
color_map = {}
for indx in range(wndw.list_box2.Items.Count):
item = wndw.list_box2.Items[indx]["Value"]
color_map[item.value] = (item.n1, item.n2, item.n3)

with revit.Transaction("Apply colors to elements"):
sel_cat = wndw._categories.SelectedItem["Value"]
get_elementid_value = get_elementid_value_func()
if get_elementid_value(sel_cat.cat.Id) in (
int(DB.BuiltInCategory.OST_Rooms),
Expand All @@ -137,7 +161,12 @@ def Execute(self, uiapp):
):
# In case of rooms, spaces and areas. Check Color scheme is applied and if not
if version > 2021:
if wndw.crt_view.GetColorFillSchemeId(sel_cat.cat.Id).ToString() == "-1":
if (
wndw.crt_view.GetColorFillSchemeId(
sel_cat.cat.Id
).ToString()
== "-1"
):
color_schemes = (
DB.FilteredElementCollector(new_doc)
.OfClass(DB.ColorFillScheme)
Expand All @@ -156,21 +185,20 @@ def Execute(self, uiapp):
else:
wndw._txt_block5.Visible = False

for indx in range(wndw.list_box2.Items.Count):
ogs = DB.OverrideGraphicSettings()
color = DB.Color(
wndw.list_box2.Items[indx]["Value"].n1,
wndw.list_box2.Items[indx]["Value"].n2,
wndw.list_box2.Items[indx]["Value"].n3,
)
ogs.SetProjectionLineColor(color)
ogs.SetSurfaceForegroundPatternColor(color)
ogs.SetCutForegroundPatternColor(color)
if solid_fill_id is not None:
ogs.SetSurfaceForegroundPatternId(solid_fill_id)
ogs.SetCutForegroundPatternId(solid_fill_id)
for idt in wndw.list_box2.Items[indx]["Value"].ele_id:
view.SetElementOverrides(idt, ogs)
# Apply colors using refreshed element IDs but preserved color choices
for val_info in refreshed_values:
if val_info.value in color_map:
ogs = DB.OverrideGraphicSettings()
r, g, b = color_map[val_info.value]
color = DB.Color(r, g, b)
ogs.SetProjectionLineColor(color)
ogs.SetSurfaceForegroundPatternColor(color)
ogs.SetCutForegroundPatternColor(color)
if solid_fill_id is not None:
ogs.SetSurfaceForegroundPatternId(solid_fill_id)
ogs.SetCutForegroundPatternId(solid_fill_id)
for idt in val_info.ele_id:
view.SetElementOverrides(idt, ogs)
except Exception:
external_event_trace()

Expand Down Expand Up @@ -665,6 +693,7 @@ def __init__(
def InitializeComponent(self):
self._spr_top = Forms.Label()
self._categories = Forms.ComboBox()
self._search_box = Forms.TextBox()
self._list_box1 = Forms.CheckedListBox()
self.list_box2 = Forms.ListBox()
self._button_set_colors = Forms.Button()
Expand All @@ -678,8 +707,11 @@ def InitializeComponent(self):
self._txt_block3 = Forms.Label()
self._txt_block4 = Forms.Label()
self._txt_block5 = Forms.Label()
self._search_label = Forms.Label()
self.tooltips = Forms.ToolTip()
self.SuspendLayout()
self._filtered_parameters = []
self._all_parameters = []
# Separator Top
self._spr_top.Anchor = (
Forms.AnchorStyles.Top | Forms.AnchorStyles.Left | Forms.AnchorStyles.Right
Expand Down Expand Up @@ -724,24 +756,43 @@ def InitializeComponent(self):
self.tooltips.SetToolTip(
self._txt_block3, "Select a parameter to color elements based on its value."
)
# Search Label
self._search_label.Anchor = Forms.AnchorStyles.Top | Forms.AnchorStyles.Left
self._search_label.Location = Drawing.Point(12, 77)
self._search_label.Name = "searchLabel"
self._search_label.Size = Drawing.Size(120, 16)
self._search_label.Text = "Search:"
self._search_label.Font = Drawing.Font(self.Font.FontFamily, 8)
# Search TextBox
self._search_box.Anchor = (
Forms.AnchorStyles.Top | Forms.AnchorStyles.Left | Forms.AnchorStyles.Right
)
self._search_box.Location = Drawing.Point(12, 95)
self._search_box.Name = "searchBox"
self._search_box.Size = Drawing.Size(310, 20)
self._search_box.Text = ""
self._search_box.TextChanged += self.on_search_text_changed
self.tooltips.SetToolTip(
self._search_box, "Type to search and filter parameters."
)
# checkedListBox1
self._list_box1.Anchor = (
Forms.AnchorStyles.Top | Forms.AnchorStyles.Left | Forms.AnchorStyles.Right
)
self._list_box1.FormattingEnabled = True
self._list_box1.CheckOnClick = True
self._list_box1.HorizontalScrollbar = True
self._list_box1.Location = Drawing.Point(12, 80)
self._list_box1.Location = Drawing.Point(12, 122)
self._list_box1.Name = "checkedListBox1"
self._list_box1.DisplayMember = "Key"
self._list_box1.Size = Drawing.Size(310, 158)
self._list_box1.Size = Drawing.Size(310, 116)
self._list_box1.ItemCheck += self.check_item
self.tooltips.SetToolTip(
self._list_box1, "Select a parameter to color elements based on its value."
)
# TextBlock4
self._txt_block4.Anchor = Forms.AnchorStyles.Top | Forms.AnchorStyles.Left
self._txt_block4.Location = Drawing.Point(12, 238)
self._txt_block4.Location = Drawing.Point(12, 240)
self._txt_block4.Name = "txtBlock4"
self._txt_block4.Size = Drawing.Size(120, 23)
self._txt_block4.Text = "Values:"
Expand All @@ -766,7 +817,7 @@ def InitializeComponent(self):
)
self.list_box2.FormattingEnabled = True
self.list_box2.HorizontalScrollbar = True
self.list_box2.Location = Drawing.Point(12, 262)
self.list_box2.Location = Drawing.Point(12, 265)
self.list_box2.Name = "listBox2"
self.list_box2.DisplayMember = "Key"
self.list_box2.DrawMode = Forms.DrawMode.OwnerDrawFixed
Expand All @@ -776,7 +827,7 @@ def InitializeComponent(self):
)
g = self.list_box2.CreateGraphics()
self.list_box2.ItemHeight = int(g.MeasureString("Sample", self.new_fnt).Height)
self.list_box2.Size = Drawing.Size(310, 280)
self.list_box2.Size = Drawing.Size(310, 277)
self.tooltips.SetToolTip(
self.list_box2, "Reassign colors by clicking on their value."
)
Expand Down Expand Up @@ -902,6 +953,8 @@ def InitializeComponent(self):
self.Controls.Add(self._categories)
self.Controls.Add(self._txt_block2)
self.Controls.Add(self._txt_block3)
self.Controls.Add(self._search_label)
self.Controls.Add(self._search_box)
self.Controls.Add(self._txt_block4)
self.Controls.Add(self._txt_block5)
self.Controls.Add(self._list_box1)
Expand Down Expand Up @@ -1015,6 +1068,7 @@ def list_selected_index_changed(self, sender, e):
clr_dlg.Color.R, clr_dlg.Color.G, clr_dlg.Color.B
)
self.list_box2.SelectedIndex = -1
self.list_box2.Refresh()

def colour_item(self, sender, e):
try:
Expand Down Expand Up @@ -1094,15 +1148,51 @@ def update_filter(self, sender, e):
names_par = [x.name for x in sel_cat.par]
for key_, value_ in zip(names_par, sel_cat.par):
self._table_data_2.Rows.Add(key_, value_)
self._all_parameters = [
(key_, value_) for key_, value_ in zip(names_par, sel_cat.par)
]
self._list_box1.DataSource = self._table_data_2
self._list_box1.DisplayMember = "Key"
self._search_box.Text = ""
for indx in range(self._list_box1.Items.Count):
self._list_box1.SetItemChecked(indx, False)
self.list_box2.DataSource = self._table_data_3
else:
self._all_parameters = []
self._list_box1.DataSource = self._table_data_2
self.list_box2.DataSource = self._table_data_3

def on_search_text_changed(self, sender, e):
"""Filter parameters based on search text"""
search_text = self._search_box.Text.lower()

# Create new filtered data table
filtered_table = DataTable("Data")
filtered_table.Columns.Add("Key", System.String)
filtered_table.Columns.Add("Value", System.Object)

# Filter parameters based on search text
if len(self._all_parameters) > 0:
for key_, value_ in self._all_parameters:
if search_text == "" or search_text in key_.lower():
filtered_table.Rows.Add(key_, value_)

# Store current checked state
checked_items = [
self._list_box1.Items[indx]["Value"]
for indx in self._list_box1.CheckedIndices
]

# Update data source
self._list_box1.DataSource = filtered_table
self._list_box1.DisplayMember = "Key"

# Restore checked state for items that are still visible
for indx in range(self._list_box1.Items.Count):
item_value = self._list_box1.Items[indx]["Value"]
if item_value in checked_items:
self._list_box1.SetItemChecked(indx, True)


class FormSaveLoadScheme(Forms.Form):
def __init__(self):
Expand Down Expand Up @@ -1489,12 +1579,10 @@ def get_used_categories_parameters(cat_exc, acti_view):
if par.Definition.BuiltInParameter not in (
DB.BuiltInParameter.ELEM_CATEGORY_PARAM,
DB.BuiltInParameter.ELEM_CATEGORY_PARAM_MT,
):
):
list_parameters.append(ParameterInfo(1, par))
# Sort and add
list_parameters = sorted(
list_parameters, key=lambda x: x.name.upper()
)
list_parameters = sorted(list_parameters, key=lambda x: x.name.upper())
list_cat.append(CategoryInfo(ele.Category, list_parameters))
list_cat = sorted(list_cat, key=lambda x: x.name)
return list_cat
Expand Down
Loading