From f847a7c91b9dc60054de4ec983773ee571ea7621 Mon Sep 17 00:00:00 2001 From: Thomas-Alexandre Moreau Date: Wed, 23 Apr 2025 15:26:41 +0200 Subject: [PATCH] big updates on UI and macro --- MultiExport.FCMacro | 138 ++++++++++------- MultiExport/MultiExport.ui | 293 ++++++++++++++++++------------------- 2 files changed, 228 insertions(+), 203 deletions(-) diff --git a/MultiExport.FCMacro b/MultiExport.FCMacro index 8b31008..fd89b4c 100755 --- a/MultiExport.FCMacro +++ b/MultiExport.FCMacro @@ -5,6 +5,7 @@ import Draft import os import Mesh from PySide2.QtWidgets import QWidget, QLabel, QSpinBox, QHBoxLayout, QListWidgetItem +from datetime import datetime class ObjectListItem(QWidget): @@ -34,18 +35,21 @@ class WindowDialog(): self.form = FreeCADGui.PySideUic.loadUi(self.ui_file) self._connect_widgets() self._populate_selector_list() + + # Connect the selection change signal to keep the list in sync + FreeCADGui.Selection.addObserver(self._on_selection_changed) + self.form.show() - def _connect_widgets(self): - self.form.pushButtonSVG.pressed.connect(lambda: self.exportSVG(False)) - self.form.pushButtonCalepinage.pressed.connect(lambda: self.exportSVG(True)) - self.form.pushButtonSTLSingle.pressed.connect(lambda: self.exportSTL(True)) - self.form.pushButtonSTLMulti.pressed.connect(lambda: self.exportSTL(False)) - self.form.listWidgetSelector.itemSelectionChanged.connect(self._on_selector_item_changed) + def _connect_widgets(self): + self.form.pushButtonExport.pressed.connect(self.export) + self.form.listWidgetSelector.itemClicked.connect(self._on_list_item_clicked) def _populate_selector_list(self): self.form.listWidgetSelector.clear() + FreeCADGui.Selection.clearSelection() + for obj in FreeCAD.ActiveDocument.Objects: if obj.Label.startswith("SVG-") or obj.Label.startswith("STL-"): item = QListWidgetItem() @@ -55,19 +59,39 @@ class WindowDialog(): self.form.listWidgetSelector.addItem(item) self.form.listWidgetSelector.setItemWidget(item, widget) - def _on_selector_item_changed(self): - self.selectedItems = [] - FreeCADGui.Selection.clearSelection() + # Sync selection: add the object to the selection and select the item in the list + item.setSelected(True) + FreeCADGui.Selection.addSelection(obj) + + + def _on_list_item_clicked(self, item): + widget = self.form.listWidgetSelector.itemWidget(item) + obj = widget.obj + if obj in FreeCADGui.Selection.getSelection(): + FreeCADGui.Selection.removeSelection(obj) + else: + FreeCADGui.Selection.addSelection(obj) + + def _on_selection_changed(self, doc, objects): + # Clear current selection in the list for index in range(self.form.listWidgetSelector.count()): item = self.form.listWidgetSelector.item(index) widget = self.form.listWidgetSelector.itemWidget(item) - if item.isSelected(): - FreeCADGui.Selection.addSelection(widget.obj) - self.selectedItems.append((widget.obj, widget.get_value())) + item.setSelected(False) # Deselect in the list + + # Sync the list selection with FreeCAD's current selection + for obj in FreeCADGui.Selection.getSelection(): + for index in range(self.form.listWidgetSelector.count()): + item = self.form.listWidgetSelector.item(index) + widget = self.form.listWidgetSelector.itemWidget(item) + if widget.obj == obj: + item.setSelected(True) # Select the corresponding item in the list + break + def _createFolder(self): - folderPath = f"{FreeCAD.activeDocument().getFileName().rpartition('.')[0]}-Exports/" + folderPath = f"{FreeCAD.activeDocument().getFileName().rpartition('.')[0]}-{datetime.today().strftime('%Y-%m-%d')}-Exports/" if not os.path.exists(folderPath): os.makedirs(folderPath) @@ -184,54 +208,64 @@ class WindowDialog(): spacing = self.form.doubleSpinBoxSpacing.value() sketchList = [] - # Loop over all selected items in list widget, not GUI selection - for index in range(self.form.listWidgetSelector.count()): - item = self.form.listWidgetSelector.item(index) - widget = self.form.listWidgetSelector.itemWidget(item) - if item.isSelected(): - count = widget.get_value() - obj = widget.obj + for obj in FreeCADGui.Selection.getSelection(): + if not obj.Label.startswith("SVG-"): + continue - for _ in range(count): - # Create 2D view and sketch for each instance - if hasattr(obj, 'Dir'): - sv0 = Draft.make_shape2dview(obj, FreeCAD.Vector(obj.Dir)) - elif hasattr(obj, 'Objects'): - for child in obj.Objects: - if hasattr(child, 'Dir'): - sv0 = Draft.make_shape2dview(child, FreeCAD.Vector(child.Dir)) - break + count = 1 # default if not using spinboxes (or fetch from list if desired) + # Optional: match count from list + for index in range(self.form.listWidgetSelector.count()): + item = self.form.listWidgetSelector.item(index) + widget = self.form.listWidgetSelector.itemWidget(item) + if widget.obj == obj: + count = widget.get_value() + break - FreeCAD.ActiveDocument.recompute() - sk = Draft.make_sketch(sv0, autoconstraints=True) - sk.ViewObject.LineColor = (1.0, 0.0, 0.0) - FreeCAD.ActiveDocument.recompute() - sketchList.append(sk) + for _ in range(count): + if hasattr(obj, 'Dir'): + sv0 = Draft.make_shape2dview(obj, FreeCAD.Vector(obj.Dir)) + elif hasattr(obj, 'Objects'): + for child in obj.Objects: + if hasattr(child, 'Dir'): + sv0 = Draft.make_shape2dview(child, FreeCAD.Vector(child.Dir)) + break - if hasattr(sv0, 'Name'): - FreeCAD.ActiveDocument.removeObject(sv0.Name) + FreeCAD.ActiveDocument.recompute() + sk = Draft.make_sketch(sv0, autoconstraints=True) + sk.ViewObject.LineColor = (1.0, 0.0, 0.0) + FreeCAD.ActiveDocument.recompute() + sketchList.append(sk) + + if hasattr(sv0, 'Name'): + FreeCAD.ActiveDocument.removeObject(sv0.Name) if isCalepinage: self._exportSketchCalepinage(sketchList, plateLength, plateWidth, spacing) else: self._exportSketchBasic(sketchList) - FreeCADGui.Selection.clearSelection() self._populate_selector_list() + def exportSTL(self, singleMode): objects_to_export = [] - for index in range(self.form.listWidgetSelector.count()): - item = self.form.listWidgetSelector.item(index) - widget = self.form.listWidgetSelector.itemWidget(item) - if item.isSelected(): - count = widget.get_value() - obj = widget.obj - for i in range(count): - clone = Draft.clone(obj) - objects_to_export.append((clone, obj.Label, i + 1)) + for obj in FreeCADGui.Selection.getSelection(): + if not obj.Label.startswith("STL-"): + continue + + count = 1 + for index in range(self.form.listWidgetSelector.count()): + item = self.form.listWidgetSelector.item(index) + widget = self.form.listWidgetSelector.itemWidget(item) + if widget.obj == obj: + count = widget.get_value() + break + + for i in range(count): + clone = Draft.clone(obj) + objects_to_export.append((clone, obj.Label, i + 1)) FreeCAD.ActiveDocument.recompute() @@ -242,7 +276,6 @@ class WindowDialog(): print(f"Exported STL: {filename}") FreeCAD.ActiveDocument.removeObject(obj.Name) else: - # Combine all into one STL export_objs = [obj for obj, _, _ in objects_to_export] if export_objs: label = FreeCAD.activeDocument().Name @@ -253,12 +286,19 @@ class WindowDialog(): FreeCAD.ActiveDocument.removeObject(obj.Name) FreeCAD.ActiveDocument.recompute() - FreeCADGui.Selection.clearSelection() self._populate_selector_list() + def export(self): + isCalepinage = self.form.checkBoxCalepinage.isChecked() + isCombine = self.form.checkBoxCombine.isChecked() + + self.exportSVG(isCalepinage) + self.exportSTL(isCombine) + + if __name__ == '__main__': try: - WindowDialog() + mainWindow = WindowDialog() except Exception as e: print(e) \ No newline at end of file diff --git a/MultiExport/MultiExport.ui b/MultiExport/MultiExport.ui index 1d28331..5ad2ca2 100644 --- a/MultiExport/MultiExport.ui +++ b/MultiExport/MultiExport.ui @@ -9,172 +9,157 @@ 0 0 - 600 - 500 + 500 + 400 - Multi Exporting + Multi Export - + QAbstractItemView::MultiSelection - - - - 0 + + + + Qt::Vertical - - - Exportation SVG - - - - - - - - - Longueur du plateau (mm) : - - - - - - - 999999.0 - - - 729.0 - - - - - - - Largeur du plateau (mm) : - - - - - - - 999999.0 - - - 430.0 - - - - - - - Espacement (mm) : - - - - - - - 999999.0 - - - 5.0 - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Export en .svg (calepinage) - - - - 0 - 50 - - - - - - - - Export en .svg (sans calepinage) - - - - 0 - 50 - - - - - - - - - Exportation STL - - - - - - Export en .stl (combiné) - - - - 0 - 50 - - - - - - - - Export en .stl (séparé) - - - - 0 - 50 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - + + + 20 + 40 + + + + + + + + Dimensions du plateau de découpe + + + + 12 + + + + + + + + + + + + + + Longueur du plateau (mm) : + + + + + + + 999999.0 + + + 729.0 + + + + + + + Largeur du plateau (mm) : + + + + + + + 999999.0 + + + 430.0 + + + + + + + Espacement (mm) : + + + + + + + 999999.0 + + + 5.0 + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + SVG : Calepinage + + + false + + + + + + + STL : Combiné + + + false + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Exporter + + + +