diff --git a/src/Mod/BIM/ArchBuildingPart.py b/src/Mod/BIM/ArchBuildingPart.py index 48b24dd7c8..f335579d6c 100644 --- a/src/Mod/BIM/ArchBuildingPart.py +++ b/src/Mod/BIM/ArchBuildingPart.py @@ -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: diff --git a/src/Mod/BIM/bimcommands/BimViews.py b/src/Mod/BIM/bimcommands/BimViews.py index d708fe5363..588dd1f530 100644 --- a/src/Mod/BIM/bimcommands/BimViews.py +++ b/src/Mod/BIM/bimcommands/BimViews.py @@ -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 ( diff --git a/src/Mod/Draft/WorkingPlane.py b/src/Mod/Draft/WorkingPlane.py index 3f26173a4c..9516d97fd1 100644 --- a/src/Mod/Draft/WorkingPlane.py +++ b/src/Mod/Draft/WorkingPlane.py @@ -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"] diff --git a/src/Mod/Draft/draftutils/utils.py b/src/Mod/Draft/draftutils/utils.py index a0e2c8fab9..342350249c 100644 --- a/src/Mod/Draft/draftutils/utils.py +++ b/src/Mod/Draft/draftutils/utils.py @@ -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 + ## @}