BIM: Add support for deactivation active object to BIM Views Tree (#21570)
* BIM: Use checkbox in model tree for Activation/Deactivation of WP * BIM: Set active object after deactivating current object if it exists Currently we can get into a scenario where user can activate two working planes, one after another. For example, Level, and then Level001. If they activate both, and then deactivate Level001, working plane switches back to Level. But, we didn't set the object as the active one, so user didn't have clear information that they can deactivate it, only the working plane was switching it. So this patch sets the object as the active one, if it exists. * BIM: Add support for deactivation active object to BIM Views Tree As the title says - it adds the checkbox that's similarly done in Part workbench, so user can select/deselect the item and if they had previous active object, it will also fall back to the previous object. Also, moved out part of the common logic from ArchBuildingPart and BimViews to utils. * BIM: Handle correct context on activating WP for NativeIFC/BIM * BIM: Remove redundant logic from BIM Views upon double click As all of the logic is being handled now in `activate` function in BimViews, this logic is redundant * BIM: Rename button for taskbar and BIM Views from Activate to Active
This commit is contained in:
@@ -811,15 +811,14 @@ class ViewProviderBuildingPart:
|
||||
if FreeCADGui.activeWorkbench().name() != 'BIMWorkbench':
|
||||
return
|
||||
if (not hasattr(vobj,"DoubleClickActivates")) or vobj.DoubleClickActivates:
|
||||
menuTxt = translate("Arch", "Active")
|
||||
actionActivate = QtGui.QAction(menuTxt, menu)
|
||||
actionActivate.setCheckable(True)
|
||||
if FreeCADGui.ActiveDocument.ActiveView.getActiveObject("Arch") == self.Object:
|
||||
menuTxt = translate("Arch", "Deactivate")
|
||||
actionActivate.setChecked(True)
|
||||
else:
|
||||
menuTxt = translate("Arch", "Activate")
|
||||
actionActivate = QtGui.QAction(menuTxt,
|
||||
menu)
|
||||
QtCore.QObject.connect(actionActivate,
|
||||
QtCore.SIGNAL("triggered()"),
|
||||
self.activate)
|
||||
actionActivate.setChecked(False)
|
||||
actionActivate.triggered.connect(lambda _: self.activate(actionActivate))
|
||||
menu.addAction(actionActivate)
|
||||
|
||||
actionSetWorkingPlane = QtGui.QAction(QtGui.QIcon(":/icons/Draft_SelectPlane.svg"),
|
||||
@@ -859,17 +858,15 @@ class ViewProviderBuildingPart:
|
||||
self.cloneUp)
|
||||
menu.addAction(actionCloneUp)
|
||||
|
||||
def activate(self):
|
||||
def activate(self, action=None):
|
||||
from draftutils.utils import toggle_working_plane
|
||||
vobj = self.Object.ViewObject
|
||||
|
||||
if FreeCADGui.ActiveDocument.ActiveView.getActiveObject("Arch") == self.Object:
|
||||
FreeCADGui.ActiveDocument.ActiveView.setActiveObject("Arch", None)
|
||||
if vobj.SetWorkingPlane:
|
||||
self.setWorkingPlane(restore=True)
|
||||
elif (not hasattr(vobj,"DoubleClickActivates")) or vobj.DoubleClickActivates:
|
||||
FreeCADGui.ActiveDocument.ActiveView.setActiveObject("Arch", self.Object)
|
||||
if vobj.SetWorkingPlane:
|
||||
self.setWorkingPlane()
|
||||
|
||||
if (not hasattr(vobj,"DoubleClickActivates")) or vobj.DoubleClickActivates:
|
||||
if toggle_working_plane(self.Object, action, restore=True):
|
||||
print("Setting active working plane to: ", self.Object.Label)
|
||||
else:
|
||||
print("Deactivating working plane from: ", self.Object.Label)
|
||||
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
|
||||
@@ -883,7 +880,24 @@ class ViewProviderBuildingPart:
|
||||
autoclip = vobj.AutoCutView
|
||||
if restore:
|
||||
if wp.label.rstrip("*") == self.Object.Label:
|
||||
wp._previous()
|
||||
prev_data = wp._previous()
|
||||
if prev_data:
|
||||
prev_label = prev_data.get("label", "").rstrip("*")
|
||||
prev_obj = None
|
||||
for obj in FreeCAD.ActiveDocument.Objects:
|
||||
if hasattr(obj, "Label") and obj.Label == prev_label:
|
||||
prev_obj = obj
|
||||
break
|
||||
|
||||
if prev_obj:
|
||||
# check in which context we need to set the active object
|
||||
context = "Arch"
|
||||
obj_type = Draft.getType(prev_obj)
|
||||
if obj_type == "IfcBuildingStorey":
|
||||
context = "NativeIFC"
|
||||
FreeCADGui.ActiveDocument.ActiveView.setActiveObject(context, prev_obj)
|
||||
print(f"Set active object to: {prev_obj.Label} (context: {context})")
|
||||
|
||||
if autoclip:
|
||||
vobj.CutView = False
|
||||
else:
|
||||
|
||||
@@ -86,7 +86,7 @@ class BIM_Views:
|
||||
|
||||
# set button
|
||||
self.dialog.menu = QtGui.QMenu()
|
||||
for button in [("Activate", translate("BIM","Activate (default)")),
|
||||
for button in [("Active", translate("BIM","Active (default)")),
|
||||
("AddLevel", translate("BIM","Add level")),
|
||||
("AddProxy", translate("BIM","Add proxy")),
|
||||
("Delete", translate("BIM","Delete")),
|
||||
@@ -97,10 +97,11 @@ class BIM_Views:
|
||||
action = QtGui.QAction(button[1])
|
||||
|
||||
# Make the "Activate" button bold, as this is the default one
|
||||
if button[0] == "Activate":
|
||||
if button[0] == "Active":
|
||||
font = action.font()
|
||||
font.setBold(True)
|
||||
action.setFont(font)
|
||||
action.setCheckable(True)
|
||||
|
||||
self.dialog.menu.addAction(action)
|
||||
setattr(self.dialog,"button"+button[0], action)
|
||||
@@ -115,7 +116,6 @@ class BIM_Views:
|
||||
self.dialog.buttonRename.setIcon(
|
||||
QtGui.QIcon(":/icons/accessories-text-editor.svg")
|
||||
)
|
||||
self.dialog.buttonActivate.setIcon(QtGui.QIcon(":/icons/edit_OK.svg"))
|
||||
|
||||
# set tooltips
|
||||
self.dialog.buttonAddLevel.setToolTip(translate("BIM","Creates a new level"))
|
||||
@@ -125,7 +125,7 @@ class BIM_Views:
|
||||
self.dialog.buttonIsolate.setToolTip(translate("BIM","Turns all items off except the selected ones"))
|
||||
self.dialog.buttonSaveView.setToolTip(translate("BIM","Saves the current camera position to the selected items"))
|
||||
self.dialog.buttonRename.setToolTip(translate("BIM","Renames the selected item"))
|
||||
self.dialog.buttonActivate.setToolTip(translate("BIM","Activates the selected item"))
|
||||
self.dialog.buttonActive.setToolTip(translate("BIM","Activates the selected item"))
|
||||
|
||||
# connect signals
|
||||
self.dialog.buttonAddLevel.triggered.connect(self.addLevel)
|
||||
@@ -135,7 +135,7 @@ class BIM_Views:
|
||||
self.dialog.buttonIsolate.triggered.connect(self.isolate)
|
||||
self.dialog.buttonSaveView.triggered.connect(self.saveView)
|
||||
self.dialog.buttonRename.triggered.connect(self.rename)
|
||||
self.dialog.buttonActivate.triggered.connect(self.activate)
|
||||
self.dialog.buttonActive.triggered.connect(lambda: BIM_Views.activate(self.dialog))
|
||||
self.dialog.tree.itemClicked.connect(self.select)
|
||||
self.dialog.tree.itemDoubleClicked.connect(show)
|
||||
self.dialog.viewtree.itemDoubleClicked.connect(show)
|
||||
@@ -431,14 +431,16 @@ class BIM_Views:
|
||||
item = vm.tree.selectedItems()[-1]
|
||||
vm.tree.editItem(item, 0)
|
||||
@staticmethod
|
||||
def activate():
|
||||
def activate(dialog=None):
|
||||
from draftutils.utils import toggle_working_plane
|
||||
vm = findWidget()
|
||||
if vm:
|
||||
if vm.tree.selectedItems():
|
||||
if vm.tree.selectedItems():
|
||||
item = vm.tree.selectedItems()[-1]
|
||||
obj = FreeCAD.ActiveDocument.getObject(item.toolTip(0))
|
||||
obj.ViewObject.Proxy.setWorkingPlane()
|
||||
item = vm.tree.selectedItems()[-1]
|
||||
obj = FreeCAD.ActiveDocument.getObject(item.toolTip(0))
|
||||
if obj:
|
||||
toggle_working_plane(obj, None, restore=True, dialog=dialog)
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
|
||||
def editObject(self, item, column):
|
||||
"renames or edit height of the actual object"
|
||||
@@ -564,6 +566,10 @@ class BIM_Views:
|
||||
if selobj:
|
||||
if Draft.getType(selobj).startswith("Ifc"):
|
||||
self.dialog.buttonAddProxy.setEnabled(False)
|
||||
if FreeCADGui.ActiveDocument.ActiveView.getActiveObject("Arch") == selobj:
|
||||
self.dialog.buttonActive.setChecked(True)
|
||||
else:
|
||||
self.dialog.buttonActive.setChecked(False)
|
||||
self.dialog.menu.exec_(self.dialog.tree.mapToGlobal(pos))
|
||||
|
||||
def getViews(self):
|
||||
@@ -655,19 +661,10 @@ def show(item, column=None):
|
||||
vparam.SetBool("RadialGradient", False)
|
||||
else:
|
||||
# case 3: This is maybe a BuildingPart. Place the WP on it")
|
||||
BIM_Views.activate()
|
||||
type = Draft.getType(obj)
|
||||
if type == "BuildingPart" or type == "IfcBuildingStorey":
|
||||
BIM_Views.activate()
|
||||
|
||||
# perform stored interactions
|
||||
if getattr(obj.ViewObject, "SetWorkingPlane", False):
|
||||
obj.ViewObject.Proxy.setWorkingPlane()
|
||||
if getattr(obj.ViewObject, "DoubleClickActivates", True):
|
||||
if Draft.getType(obj) == "BuildingPart":
|
||||
FreeCADGui.ActiveDocument.ActiveView.setActiveObject("Arch", obj)
|
||||
elif Draft.getType(obj) == "IfcBuildingStorey":
|
||||
FreeCADGui.ActiveDocument.ActiveView.setActiveObject("NativeIFC", obj)
|
||||
else:
|
||||
FreeCADGui.ActiveDocument.ActiveView.setActiveObject("Arch", None)
|
||||
FreeCADGui.ActiveDocument.ActiveView.setActiveObject("NativeIFC", None)
|
||||
if vm:
|
||||
# store the last double-clicked item for the BIM WPView command
|
||||
if isinstance(item, str) or (
|
||||
|
||||
@@ -1667,6 +1667,7 @@ class PlaneGui(PlaneBase):
|
||||
self.set_parameters(self._history["data_list"][idx])
|
||||
self._history["idx"] = idx
|
||||
self._update_all(_hist_add=False)
|
||||
return self._history["data_list"][idx]
|
||||
|
||||
def _next(self):
|
||||
idx = self._history["idx"]
|
||||
|
||||
@@ -1068,4 +1068,69 @@ def pyopen(file, mode='r', buffering=-1, encoding=None, errors=None, newline=Non
|
||||
encoding = 'utf-8'
|
||||
return open(file, mode, buffering, encoding, errors, newline, closefd, opener)
|
||||
|
||||
def toggle_working_plane(obj, action=None, restore=False, dialog=None):
|
||||
"""Toggle the active state of a working plane object.
|
||||
|
||||
This function handles the common logic for activating and deactivating
|
||||
working plane objects like BuildingParts and WorkingPlaneProxies.
|
||||
It can be used by different modules that need to implement similar
|
||||
working plane activation behavior.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
obj : App::DocumentObject
|
||||
The object to activate or deactivate as a working plane.
|
||||
action : QAction, optional
|
||||
The action button that triggered this function, to update its checked state.
|
||||
restore : bool, optional
|
||||
If True, will restore the previous working plane when deactivating.
|
||||
Defaults to False.
|
||||
dialog : QDialog, optional
|
||||
If provided, will update the checked state of the activate button in the dialog.
|
||||
|
||||
Returns
|
||||
-------
|
||||
bool
|
||||
True if the object was activated, False if it was deactivated.
|
||||
"""
|
||||
import FreeCADGui
|
||||
import Draft
|
||||
|
||||
# Determine the appropriate context based on object type
|
||||
context = "Arch"
|
||||
obj_type = get_type(obj)
|
||||
if obj_type == "IfcBuildingStorey":
|
||||
context = "NativeIFC"
|
||||
|
||||
# Check if the object is already active in its context
|
||||
is_active_arch = (FreeCADGui.ActiveDocument.ActiveView.getActiveObject("Arch") == obj)
|
||||
is_active_ifc = (FreeCADGui.ActiveDocument.ActiveView.getActiveObject("NativeIFC") == obj)
|
||||
is_active = is_active_arch or is_active_ifc
|
||||
if is_active:
|
||||
# Deactivate the object
|
||||
if is_active_arch:
|
||||
FreeCADGui.ActiveDocument.ActiveView.setActiveObject("Arch", None)
|
||||
if is_active_ifc:
|
||||
FreeCADGui.ActiveDocument.ActiveView.setActiveObject("NativeIFC", None)
|
||||
|
||||
if hasattr(obj, "ViewObject") and hasattr(obj.ViewObject, "Proxy") and \
|
||||
hasattr(obj.ViewObject.Proxy, "setWorkingPlane"):
|
||||
obj.ViewObject.Proxy.setWorkingPlane(restore=True)
|
||||
if action:
|
||||
action.setChecked(False)
|
||||
if dialog and hasattr(dialog, "buttonActive"):
|
||||
dialog.buttonActive.setChecked(False)
|
||||
return False
|
||||
else:
|
||||
# Activate the object
|
||||
FreeCADGui.ActiveDocument.ActiveView.setActiveObject(context, obj)
|
||||
if hasattr(obj, "ViewObject") and hasattr(obj.ViewObject, "Proxy") and \
|
||||
hasattr(obj.ViewObject.Proxy, "setWorkingPlane"):
|
||||
obj.ViewObject.Proxy.setWorkingPlane()
|
||||
if action:
|
||||
action.setChecked(True)
|
||||
if dialog and hasattr(dialog, "buttonActive"):
|
||||
dialog.buttonActive.setChecked(True)
|
||||
return True
|
||||
|
||||
## @}
|
||||
|
||||
Reference in New Issue
Block a user