big updates on UI and macro

This commit is contained in:
Thomas-Alexandre Moreau 2025-04-23 15:26:41 +02:00
parent f6e39d597a
commit f847a7c91b
2 changed files with 228 additions and 203 deletions

View file

@ -5,6 +5,7 @@ import Draft
import os import os
import Mesh import Mesh
from PySide2.QtWidgets import QWidget, QLabel, QSpinBox, QHBoxLayout, QListWidgetItem from PySide2.QtWidgets import QWidget, QLabel, QSpinBox, QHBoxLayout, QListWidgetItem
from datetime import datetime
class ObjectListItem(QWidget): class ObjectListItem(QWidget):
@ -34,18 +35,21 @@ class WindowDialog():
self.form = FreeCADGui.PySideUic.loadUi(self.ui_file) self.form = FreeCADGui.PySideUic.loadUi(self.ui_file)
self._connect_widgets() self._connect_widgets()
self._populate_selector_list() 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() 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): def _populate_selector_list(self):
self.form.listWidgetSelector.clear() self.form.listWidgetSelector.clear()
FreeCADGui.Selection.clearSelection()
for obj in FreeCAD.ActiveDocument.Objects: for obj in FreeCAD.ActiveDocument.Objects:
if obj.Label.startswith("SVG-") or obj.Label.startswith("STL-"): if obj.Label.startswith("SVG-") or obj.Label.startswith("STL-"):
item = QListWidgetItem() item = QListWidgetItem()
@ -55,19 +59,39 @@ class WindowDialog():
self.form.listWidgetSelector.addItem(item) self.form.listWidgetSelector.addItem(item)
self.form.listWidgetSelector.setItemWidget(item, widget) self.form.listWidgetSelector.setItemWidget(item, widget)
def _on_selector_item_changed(self): # Sync selection: add the object to the selection and select the item in the list
self.selectedItems = [] item.setSelected(True)
FreeCADGui.Selection.clearSelection() 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()): for index in range(self.form.listWidgetSelector.count()):
item = self.form.listWidgetSelector.item(index) item = self.form.listWidgetSelector.item(index)
widget = self.form.listWidgetSelector.itemWidget(item) widget = self.form.listWidgetSelector.itemWidget(item)
if item.isSelected(): item.setSelected(False) # Deselect in the list
FreeCADGui.Selection.addSelection(widget.obj)
self.selectedItems.append((widget.obj, widget.get_value())) # 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): 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): if not os.path.exists(folderPath):
os.makedirs(folderPath) os.makedirs(folderPath)
@ -184,54 +208,64 @@ class WindowDialog():
spacing = self.form.doubleSpinBoxSpacing.value() spacing = self.form.doubleSpinBoxSpacing.value()
sketchList = [] sketchList = []
# Loop over all selected items in list widget, not GUI selection for obj in FreeCADGui.Selection.getSelection():
for index in range(self.form.listWidgetSelector.count()): if not obj.Label.startswith("SVG-"):
item = self.form.listWidgetSelector.item(index) continue
widget = self.form.listWidgetSelector.itemWidget(item)
if item.isSelected():
count = widget.get_value()
obj = widget.obj
for _ in range(count): count = 1 # default if not using spinboxes (or fetch from list if desired)
# Create 2D view and sketch for each instance # Optional: match count from list
if hasattr(obj, 'Dir'): for index in range(self.form.listWidgetSelector.count()):
sv0 = Draft.make_shape2dview(obj, FreeCAD.Vector(obj.Dir)) item = self.form.listWidgetSelector.item(index)
elif hasattr(obj, 'Objects'): widget = self.form.listWidgetSelector.itemWidget(item)
for child in obj.Objects: if widget.obj == obj:
if hasattr(child, 'Dir'): count = widget.get_value()
sv0 = Draft.make_shape2dview(child, FreeCAD.Vector(child.Dir)) break
break
FreeCAD.ActiveDocument.recompute() for _ in range(count):
sk = Draft.make_sketch(sv0, autoconstraints=True) if hasattr(obj, 'Dir'):
sk.ViewObject.LineColor = (1.0, 0.0, 0.0) sv0 = Draft.make_shape2dview(obj, FreeCAD.Vector(obj.Dir))
FreeCAD.ActiveDocument.recompute() elif hasattr(obj, 'Objects'):
sketchList.append(sk) 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.recompute()
FreeCAD.ActiveDocument.removeObject(sv0.Name) 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: if isCalepinage:
self._exportSketchCalepinage(sketchList, plateLength, plateWidth, spacing) self._exportSketchCalepinage(sketchList, plateLength, plateWidth, spacing)
else: else:
self._exportSketchBasic(sketchList) self._exportSketchBasic(sketchList)
FreeCADGui.Selection.clearSelection()
self._populate_selector_list() self._populate_selector_list()
def exportSTL(self, singleMode): def exportSTL(self, singleMode):
objects_to_export = [] objects_to_export = []
for index in range(self.form.listWidgetSelector.count()): for obj in FreeCADGui.Selection.getSelection():
item = self.form.listWidgetSelector.item(index) if not obj.Label.startswith("STL-"):
widget = self.form.listWidgetSelector.itemWidget(item) continue
if item.isSelected():
count = widget.get_value() count = 1
obj = widget.obj for index in range(self.form.listWidgetSelector.count()):
for i in range(count): item = self.form.listWidgetSelector.item(index)
clone = Draft.clone(obj) widget = self.form.listWidgetSelector.itemWidget(item)
objects_to_export.append((clone, obj.Label, i + 1)) 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() FreeCAD.ActiveDocument.recompute()
@ -242,7 +276,6 @@ class WindowDialog():
print(f"Exported STL: {filename}") print(f"Exported STL: {filename}")
FreeCAD.ActiveDocument.removeObject(obj.Name) FreeCAD.ActiveDocument.removeObject(obj.Name)
else: else:
# Combine all into one STL
export_objs = [obj for obj, _, _ in objects_to_export] export_objs = [obj for obj, _, _ in objects_to_export]
if export_objs: if export_objs:
label = FreeCAD.activeDocument().Name label = FreeCAD.activeDocument().Name
@ -253,12 +286,19 @@ class WindowDialog():
FreeCAD.ActiveDocument.removeObject(obj.Name) FreeCAD.ActiveDocument.removeObject(obj.Name)
FreeCAD.ActiveDocument.recompute() FreeCAD.ActiveDocument.recompute()
FreeCADGui.Selection.clearSelection()
self._populate_selector_list() 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__': if __name__ == '__main__':
try: try:
WindowDialog() mainWindow = WindowDialog()
except Exception as e: except Exception as e:
print(e) print(e)

View file

@ -9,172 +9,157 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>600</width> <width>500</width>
<height>500</height> <height>400</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string notr="true">Multi Exporting</string> <string notr="true">Multi Export</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="10" column="0" colspan="3"> <item row="0" column="0" colspan="3">
<widget class="QListWidget" name="listWidgetSelector"> <widget class="QListWidget" name="listWidgetSelector">
<property name="selectionMode"> <property name="selectionMode">
<enum>QAbstractItemView::MultiSelection</enum> <enum>QAbstractItemView::MultiSelection</enum>
</property> </property>
</widget> </widget>
</item> </item>
<item row="16" column="0" colspan="3"> <item row="1" column="0">
<widget class="QTabWidget" name="tabWidget"> <spacer name="verticalSpacer1">
<property name="currentIndex"> <property name="orientation">
<number>0</number> <enum>Qt::Vertical</enum>
</property> </property>
<widget class="QWidget" name="tab"> <property name="sizeHint" stdset="0">
<attribute name="title"> <size>
<string notr="true">Exportation SVG</string> <width>20</width>
</attribute> <height>40</height>
<layout class="QGridLayout" name="gridLayout_4"> </size>
<item row="0" column="0"> </property>
<widget class="QLabel" name="label"> </spacer>
<property name="locale"> </item>
<locale language="French" country="France"/> <item row="2" column="0" colspan="2">
</property> <widget class="QLabel" name="labelDecoupe">
<property name="text"> <property name="text">
<string notr="true">Longueur du plateau (mm) :</string> <string notr="true">Dimensions du plateau de découpe</string>
</property> </property>
</widget> <property name="font">
</item> <font>
<item row="0" column="1"> <pointsize>12</pointsize>
<widget class="QDoubleSpinBox" name="doubleSpinBoxLength"> </font>
<property name="maximum"> </property>
<double>999999.0</double> </widget>
</property> </item>
<property name="value"> <item row="3" column="0" colspan="2">
<double>729.0</double> <widget class="QWidget" name="containerWidget">
</property> <layout class="QGridLayout" name="gridLayout2">
</widget> <item row="0" column="0">
</item> <widget class="QLabel" name="label">
<item row="1" column="0"> <property name="locale">
<widget class="QLabel" name="label2"> <locale language="French" country="France"/>
<property name="text"> </property>
<string notr="true">Largeur du plateau (mm) :</string> <property name="text">
</property> <string notr="true">Longueur du plateau (mm) :</string>
</widget> </property>
</item> </widget>
<item row="1" column="1"> </item>
<widget class="QDoubleSpinBox" name="doubleSpinBoxWidth"> <item row="0" column="1">
<property name="maximum"> <widget class="QDoubleSpinBox" name="doubleSpinBoxLength">
<double>999999.0</double> <property name="maximum">
</property> <double>999999.0</double>
<property name="value"> </property>
<double>430.0</double> <property name="value">
</property> <double>729.0</double>
</widget> </property>
</item> </widget>
<item row="2" column="0"> </item>
<widget class="QLabel" name="label3"> <item row="1" column="0">
<property name="text"> <widget class="QLabel" name="label2">
<string notr="true">Espacement (mm) :</string> <property name="text">
</property> <string notr="true">Largeur du plateau (mm) :</string>
</widget> </property>
</item> </widget>
<item row="2" column="1"> </item>
<widget class="QDoubleSpinBox" name="doubleSpinBoxSpacing"> <item row="1" column="1">
<property name="maximum"> <widget class="QDoubleSpinBox" name="doubleSpinBoxWidth">
<double>999999.0</double> <property name="maximum">
</property> <double>999999.0</double>
<property name="value"> </property>
<double>5.0</double> <property name="value">
</property> <double>430.0</double>
</widget> </property>
</item> </widget>
<item row="4" column="0"> </item>
<spacer name="verticalSpacer"> <item row="2" column="0">
<property name="orientation"> <widget class="QLabel" name="label3">
<enum>Qt::Vertical</enum> <property name="text">
</property> <string notr="true">Espacement (mm) :</string>
<property name="sizeHint" stdset="0"> </property>
<size> </widget>
<width>20</width> </item>
<height>40</height> <item row="2" column="1">
</size> <widget class="QDoubleSpinBox" name="doubleSpinBoxSpacing">
</property> <property name="maximum">
</spacer> <double>999999.0</double>
</item> </property>
<item row="5" column="0"> <property name="value">
<widget class="QPushButton" name="pushButtonCalepinage"> <double>5.0</double>
<property name="text"> </property>
<string>Export en .svg (calepinage)</string> </widget>
</property> </item>
<property name="minimumSize"> <item row="3" column="0">
<size> <spacer name="verticalSpacer2">
<width>0</width> <property name="orientation">
<height>50</height> <enum>Qt::Vertical</enum>
</size> </property>
</property> <property name="sizeHint" stdset="0">
</widget> <size>
</item> <width>20</width>
<item row="5" column="1"> <height>40</height>
<widget class="QPushButton" name="pushButtonSVG"> </size>
<property name="text"> </property>
<string>Export en .svg (sans calepinage)</string> </spacer>
</property> </item>
<property name="minimumSize"> <item row="4" column="0">
<size> <widget class="QCheckBox" name="checkBoxCalepinage">
<width>0</width> <property name="text">
<height>50</height> <string notr="true">SVG : Calepinage</string>
</size> </property>
</property> <property name="checked">
</widget> <bool>false</bool>
</item> </property>
</layout> </widget>
</widget> </item>
<widget class="QWidget" name="tab_2"> <item row="5" column="0">
<attribute name="title"> <widget class="QCheckBox" name="checkBoxCombine">
<string notr="true">Exportation STL</string> <property name="text">
</attribute> <string notr="true">STL : Combiné</string>
<layout class="QGridLayout" name="gridLayout_2"> </property>
<item row="1" column="0"> <property name="checked">
<widget class="QPushButton" name="pushButtonSTLSingle"> <bool>false</bool>
<property name="text"> </property>
<string>Export en .stl (combiné)</string> </widget>
</property> </item>
<property name="minimumSize"> <item row="5" column="0">
<size> <spacer name="verticalSpacer3">
<width>0</width> <property name="orientation">
<height>50</height> <enum>Qt::Vertical</enum>
</size> </property>
</property> <property name="sizeHint" stdset="0">
</widget> <size>
</item> <width>20</width>
<item row="1" column="1"> <height>40</height>
<widget class="QPushButton" name="pushButtonSTLMulti"> </size>
<property name="text"> </property>
<string>Export en .stl (séparé)</string> </spacer>
</property> </item>
<property name="minimumSize"> <item row="6" column="1" colspan="2">
<size> <widget class="QPushButton" name="pushButtonExport">
<width>0</width> <property name="text">
<height>50</height> <string notr="true">Exporter</string>
</size> </property>
</property> </widget>
</widget> </item>
</item> </layout>
<item row="0" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget> </widget>
</item> </item>
</layout> </layout>