From 5143369fc9deaecd4ccaef084fc335e0ce41c22f Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Tue, 8 Oct 2019 22:27:40 -0500 Subject: [PATCH] Draft: add new command for Draft CircularArray Added object, viewprovider, icon; gui command definition, task panel, add command to InitGui; add callbacks, and delay system. --- src/Mod/Draft/CMakeLists.txt | 4 + src/Mod/Draft/InitGui.py | 3 +- src/Mod/Draft/Resources/Draft.qrc | 2 + .../Resources/icons/Draft_CircularArray.svg | 667 ++++++++++++++++++ .../Resources/ui/TaskPanel_CircularArray.ui | 292 ++++++++ .../Draft/draftguitools/gui_circulararray.py | 155 ++++ src/Mod/Draft/draftobjects/circulararray.py | 45 ++ .../drafttaskpanels/task_circulararray.py | 402 +++++++++++ .../draftviewproviders/view_circulararray.py | 44 ++ 9 files changed, 1613 insertions(+), 1 deletion(-) create mode 100644 src/Mod/Draft/Resources/icons/Draft_CircularArray.svg create mode 100644 src/Mod/Draft/Resources/ui/TaskPanel_CircularArray.ui create mode 100644 src/Mod/Draft/draftguitools/gui_circulararray.py create mode 100644 src/Mod/Draft/draftobjects/circulararray.py create mode 100644 src/Mod/Draft/drafttaskpanels/task_circulararray.py create mode 100644 src/Mod/Draft/draftviewproviders/view_circulararray.py diff --git a/src/Mod/Draft/CMakeLists.txt b/src/Mod/Draft/CMakeLists.txt index f9dfdd8348..ef552e7414 100644 --- a/src/Mod/Draft/CMakeLists.txt +++ b/src/Mod/Draft/CMakeLists.txt @@ -49,22 +49,26 @@ SET(Draft_tests SET(Draft_objects draftobjects/__init__.py + draftobjects/circulararray.py draftobjects/polararray.py ) SET(Draft_view_providers draftviewproviders/__init__.py + draftviewproviders/view_circulararray.py draftviewproviders/view_polararray.py ) SET(Draft_GUI_tools draftguitools/__init__.py draftguitools/gui_base.py + draftguitools/gui_circulararray.py draftguitools/gui_polararray.py ) SET(Draft_task_panels drafttaskpanels/__init__.py + drafttaskpanels/task_circulararray.py drafttaskpanels/task_polararray.py ) diff --git a/src/Mod/Draft/InitGui.py b/src/Mod/Draft/InitGui.py index a93170e05a..4ed44d0fbe 100644 --- a/src/Mod/Draft/InitGui.py +++ b/src/Mod/Draft/InitGui.py @@ -65,6 +65,7 @@ class DraftWorkbench(Workbench): try: import os, Draft_rc, DraftTools, DraftGui, DraftFillet from DraftTools import translate + from draftguitools import gui_circulararray from draftguitools import gui_polararray FreeCADGui.addLanguagePath(":/translations") FreeCADGui.addIconPath(":/icons") @@ -86,7 +87,7 @@ class DraftWorkbench(Workbench): "Draft_WireToBSpline", "Draft_AddPoint", "Draft_DelPoint", "Draft_Shape2DView", "Draft_Draft2Sketch", "Draft_Array", "Draft_LinkArray", - "Draft_PolarArray", + "Draft_PolarArray", "Draft_CircularArray", "Draft_PathArray", "Draft_PathLinkArray", "Draft_PointArray", "Draft_Clone", "Draft_Drawing", "Draft_Mirror", "Draft_Stretch"] self.treecmdList = ["Draft_ApplyStyle", "Draft_ToggleDisplayMode", diff --git a/src/Mod/Draft/Resources/Draft.qrc b/src/Mod/Draft/Resources/Draft.qrc index faf759e28d..4a1aaa5696 100644 --- a/src/Mod/Draft/Resources/Draft.qrc +++ b/src/Mod/Draft/Resources/Draft.qrc @@ -16,6 +16,7 @@ icons/Draft_BezTanNode.svg icons/Draft_BSpline.svg icons/Draft_Circle.svg + icons/Draft_CircularArray.svg icons/Draft_Clone.svg icons/Draft_Construction.svg icons/Draft_CubicBezCurve.svg @@ -149,6 +150,7 @@ ui/preferences-dxf.ui ui/preferences-oca.ui ui/preferences-svg.ui + ui/TaskPanel_CircularArray.ui ui/TaskPanel_PolarArray.ui ui/TaskSelectPlane.ui ui/TaskShapeString.ui diff --git a/src/Mod/Draft/Resources/icons/Draft_CircularArray.svg b/src/Mod/Draft/Resources/icons/Draft_CircularArray.svg new file mode 100644 index 0000000000..26fbea8978 --- /dev/null +++ b/src/Mod/Draft/Resources/icons/Draft_CircularArray.svg @@ -0,0 +1,667 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + Draft_Array + + Sat Dec 10 18:31:32 2011 +0000 + + + [yorikvanhavre] + + + + + FreeCAD LGPL2+ + + + + + FreeCAD + + + FreeCAD/src/Mod/Draft/Resources/icons/Draft_Array.svg + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + [agryson] Alexander Gryson + + + Six rectangles in a 2 x 3 linear array + + + rectangle + array + + + + + + diff --git a/src/Mod/Draft/Resources/ui/TaskPanel_CircularArray.ui b/src/Mod/Draft/Resources/ui/TaskPanel_CircularArray.ui new file mode 100644 index 0000000000..ece65b12ee --- /dev/null +++ b/src/Mod/Draft/Resources/ui/TaskPanel_CircularArray.ui @@ -0,0 +1,292 @@ + + + DraftCircularArrayTaskPanel + + + + 0 + 0 + 445 + 488 + + + + + 0 + 0 + + + + + 250 + 0 + + + + Circular array + + + + + + + 0 + 0 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + The coordinates of the point through which the axis of rotation passes. + + + Center of rotation + + + + + + + + Z + + + + + + + X + + + + + + + Y + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + + Reset the coordinates of the center of rotation + + + Reset point + + + + + + + + + + + + If checked, the resulting objects in the array will be fused if they touch each other + + + Fuse + + + + + + + If checked, the resulting objects in the array will be Links instead of simple copies + + + Use Links + + + + + + + + + + + Distance from one element in the array to the next element in the same layer. It cannot be zero. + + + Tangential distance + + + + + + + Distance from one element in the array to the next element in the same layer. It cannot be zero. + + + + + + 100.000000000000000 + + + + + + + Distance from the center of the array to the outer layers + + + Radial distance + + + + + + + Distance from the center of the array to the outer layers + + + + + + 200.000000000000000 + + + + + + + Number that controls how the objects will be distributed + + + 1 + + + + + + + Number of circular arrays to create, including a copy of the original object. It must be at least 2. + + + 3 + + + + + + + Number of circular arrays to create, including a copy of the original object. It must be at least 2. + + + Number of circular layers + + + + + + + Number that controls how the objects will be distributed + + + Symmetry + + + + + + + + + (Placeholder for the icon) + + + + + + + + + + + Gui::InputField + QLineEdit +
Gui/InputField.h
+
+ + Gui::QuantitySpinBox + QWidget +
Gui/QuantitySpinBox.h
+
+
+ + spinbox_r_distance + spinbox_tan_distance + spinbox_number + spinbox_symmetry + input_c_x + input_c_y + input_c_z + button_reset + checkbox_fuse + checkbox_link + + + +
diff --git a/src/Mod/Draft/draftguitools/gui_circulararray.py b/src/Mod/Draft/draftguitools/gui_circulararray.py new file mode 100644 index 0000000000..e75139f35e --- /dev/null +++ b/src/Mod/Draft/draftguitools/gui_circulararray.py @@ -0,0 +1,155 @@ +"""This module provides the Draft CircularArray tool. +""" +## @package gui_circulararray +# \ingroup DRAFT +# \brief This module provides the Draft CircularArray tool. + +# *************************************************************************** +# * (c) 2019 Eliud Cabrera Castillo * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * FreeCAD is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with FreeCAD; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +import FreeCAD as App +import FreeCADGui as Gui +import Draft +import DraftGui +import Draft_rc +from . import gui_base +from drafttaskpanels import task_circulararray + + +if App.GuiUp: + from PySide.QtCore import QT_TRANSLATE_NOOP + # import DraftTools + from DraftGui import translate + # from DraftGui import displayExternal + from pivy import coin +else: + def QT_TRANSLATE_NOOP(context, text): + return text + + def translate(context, text): + return text + + +def _tr(text): + """Function to translate with the context set""" + return translate("Draft", text) + + +# So the resource file doesn't trigger errors from code checkers (flake8) +True if Draft_rc.__name__ else False + + +class GuiCommandCircularArray(gui_base.GuiCommandBase): + """Gui command for the CircularArray tool""" + + def __init__(self): + super().__init__() + self.command_name = "CircularArray" + self.location = None + self.mouse_event = None + self.view = None + self.callback_move = None + self.callback_click = None + self.ui = None + self.point = App.Vector() + + def GetResources(self): + _msg = ("Creates copies of a selected object, " + "and places the copies in a circular pattern.\n" + "The properties of the array can be further modified after " + "the new object is created, including turning it into " + "a different type of array.") + d = {'Pixmap': 'Draft_CircularArray', + 'MenuText': QT_TRANSLATE_NOOP("Draft", "Circular array"), + 'ToolTip': QT_TRANSLATE_NOOP("Draft", _msg)} + return d + + def Activated(self): + """This is called when the command is executed. + + We add callbacks that connect the 3D view with + the widgets of the task panel. + """ + self.location = coin.SoLocation2Event.getClassTypeId() + self.mouse_event = coin.SoMouseButtonEvent.getClassTypeId() + self.view = Draft.get3DView() + self.callback_move = \ + self.view.addEventCallbackPivy(self.location, self.move) + self.callback_click = \ + self.view.addEventCallbackPivy(self.mouse_event, self.click) + + self.ui = task_circulararray.TaskPanelCircularArray() + # The calling class (this one) is saved in the object + # of the interface, to be able to call a function from within it. + self.ui.source_command = self + # Gui.Control.showDialog(self.ui) + DraftGui.todo.delay(Gui.Control.showDialog, self.ui) + + def move(self, event_cb): + """This is a callback for when the mouse pointer moves in the 3D view. + + It should automatically update the coordinates in the widgets + of the task panel. + """ + event = event_cb.getEvent() + mousepos = event.getPosition().getValue() + ctrl = event.wasCtrlDown() + self.point = Gui.Snapper.snap(mousepos, active=ctrl) + if self.ui: + self.ui.display_point(self.point) + + def click(self, event_cb=None): + """This is a callback for when the mouse pointer clicks on the 3D view. + + It should act as if the Enter key was pressed, or the OK button + was pressed in the task panel. + """ + if event_cb: + event = event_cb.getEvent() + if (event.getState() != coin.SoMouseButtonEvent.DOWN + or event.getButton() != coin.SoMouseButtonEvent.BUTTON1): + return + if self.ui and self.point: + # The accept function of the interface + # should call the completed function + # of the calling class (this one). + self.ui.accept() + + def completed(self): + """This is called when the command is terminated. + + We should remove the callbacks that were added to the 3D view + and then close the task panel. + """ + self.view.removeEventCallbackPivy(self.location, + self.callback_move) + self.view.removeEventCallbackPivy(self.mouse_event, + self.callback_click) + if Gui.Control.activeDialog(): + Gui.Snapper.off() + Gui.Control.closeDialog() + super().finish() + + +if App.GuiUp: + Gui.addCommand('Draft_CircularArray', GuiCommandCircularArray()) diff --git a/src/Mod/Draft/draftobjects/circulararray.py b/src/Mod/Draft/draftobjects/circulararray.py new file mode 100644 index 0000000000..07982d16e4 --- /dev/null +++ b/src/Mod/Draft/draftobjects/circulararray.py @@ -0,0 +1,45 @@ +"""This module provides the object code for Draft CircularArray. +""" +## @package circulararray +# \ingroup DRAFT +# \brief This module provides the object code for Draft CircularArray. + +# *************************************************************************** +# * (c) 2019 Eliud Cabrera Castillo * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * FreeCAD is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with FreeCAD; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +import FreeCAD as App +import Draft + + +def make_circular_array(obj, + r_distance=100, tan_distance=100, + axis=App.Vector(0, 0, 1), center=App.Vector(0, 0, 0), + number=2, symmetry=1, + use_link=False): + """Create a circular array from the given object. + """ + obj = Draft.makeArray(obj, + arg1=r_distance, arg2=tan_distance, + arg3=axis, arg4=center, arg5=number, arg6=symmetry, + useLink=use_link) + return obj diff --git a/src/Mod/Draft/drafttaskpanels/task_circulararray.py b/src/Mod/Draft/drafttaskpanels/task_circulararray.py new file mode 100644 index 0000000000..a0405bbf52 --- /dev/null +++ b/src/Mod/Draft/drafttaskpanels/task_circulararray.py @@ -0,0 +1,402 @@ +"""This module provides the task panel for the Draft CircularArray tool. +""" +## @package task_circulararray +# \ingroup DRAFT +# \brief This module provides the task panel code for the CircularArray tool. + +# *************************************************************************** +# * (c) 2019 Eliud Cabrera Castillo * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * FreeCAD is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with FreeCAD; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +import FreeCAD as App +import FreeCADGui as Gui +# import Draft +import Draft_rc +import DraftVecUtils + +import PySide.QtCore as QtCore +import PySide.QtGui as QtGui +from PySide.QtCore import QT_TRANSLATE_NOOP +# import DraftTools +from DraftGui import translate +# from DraftGui import displayExternal + +_Quantity = App.Units.Quantity + + +def _Msg(text, end="\n"): + """Print message with newline""" + App.Console.PrintMessage(text + end) + + +def _Wrn(text, end="\n"): + """Print warning with newline""" + App.Console.PrintWarning(text + end) + + +def _tr(text): + """Function to translate with the context set""" + return translate("Draft", text) + + +# So the resource file doesn't trigger errors from code checkers (flake8) +True if Draft_rc.__name__ else False + + +class TaskPanelCircularArray: + """TaskPanel code for the CircularArray command. + + The names of the widgets are defined in the `.ui` file. + In this class all those widgets are automatically created + under the name `self.form.` + + The `.ui` file may use special FreeCAD widgets such as + `Gui::InputField` (based on `QLineEdit`) and + `Gui::QuantitySpinBox` (based on `QAbstractSpinBox`). + See the Doxygen documentation of the corresponding files in `src/Gui/`, + for example, `InputField.h` and `QuantitySpinBox.h`. + """ + + def __init__(self): + ui_file = ":/ui/TaskPanel_CircularArray.ui" + self.form = Gui.PySideUic.loadUi(ui_file) + self.name = self.form.windowTitle() + + icon_name = "Draft_CircularArray" + svg = ":/icons/" + icon_name + pix = QtGui.QPixmap(svg) + icon = QtGui.QIcon.fromTheme(icon_name, QtGui.QIcon(svg)) + self.form.setWindowIcon(icon) + self.form.label_icon.setPixmap(pix.scaled(32, 32)) + + start_distance = _Quantity(1000.0, App.Units.Length) + distance_unit = start_distance.getUserPreferred()[2] + self.form.spinbox_r_distance.setProperty('rawValue', + 2 * start_distance.Value) + self.form.spinbox_r_distance.setProperty('unit', distance_unit) + self.form.spinbox_tan_distance.setProperty('rawValue', + start_distance.Value) + self.form.spinbox_tan_distance.setProperty('unit', distance_unit) + + self.r_distance = 2 * start_distance.Value + self.tan_distance = start_distance.Value + + self.form.spinbox_number.setValue(3) + self.form.spinbox_symmetry.setValue(1) + + self.number = self.form.spinbox_number.value() + self.symmetry = self.form.spinbox_symmetry.value() + + self.axis = App.Vector(0, 0, 1) + + start_point = _Quantity(0.0, App.Units.Length) + length_unit = start_point.getUserPreferred()[2] + self.form.input_c_x.setProperty('rawValue', start_point.Value) + self.form.input_c_x.setProperty('unit', length_unit) + self.form.input_c_y.setProperty('rawValue', start_point.Value) + self.form.input_c_y.setProperty('unit', length_unit) + self.form.input_c_z.setProperty('rawValue', start_point.Value) + self.form.input_c_z.setProperty('unit', length_unit) + self.valid_input = True + + self.c_x_str = "" + self.c_y_str = "" + self.c_z_str = "" + self.center = App.Vector(0, 0, 0) + + # Old style for Qt4 + # QtCore.QObject.connect(self.form.button_reset, + # QtCore.SIGNAL("clicked()"), + # self.reset_point) + # New style for Qt5 + self.form.button_reset.clicked.connect(self.reset_point) + + # The mask is not used at the moment, but could be used in the future + # by a callback to restrict the coordinates of the pointer. + self.mask = "" + + # When the checkbox changes, change the fuse value + self.fuse = False + QtCore.QObject.connect(self.form.checkbox_fuse, + QtCore.SIGNAL("stateChanged(int)"), + self.set_fuse) + + self.use_link = False + QtCore.QObject.connect(self.form.checkbox_link, + QtCore.SIGNAL("stateChanged(int)"), + self.set_link) + + def accept(self): + """Function that executes when clicking the OK button""" + selection = Gui.Selection.getSelection() + self.number = self.form.spinbox_number.value() + + tan_d_str = self.form.spinbox_tan_distance.text() + self.tan_distance = _Quantity(tan_d_str).Value + self.valid_input = self.validate_input(selection, + self.number, + self.tan_distance) + if self.valid_input: + self.create_object(selection) + self.print_messages(selection) + self.finish() + + def validate_input(self, selection, number, tan_distance): + """Check that the input is valid""" + if not selection: + _Wrn(_tr("At least one element must be selected")) + return False + if number < 2: + _Wrn(_tr("Number of elements must be at least 2")) + return False + # Todo: each of the elements of the selection could be tested, + # not only the first one. + if selection[0].isDerivedFrom("App::FeaturePython"): + _Wrn(_tr("Selection is not suitable for array")) + _Wrn(_tr("Object:") + " {}".format(selection[0].Label)) + return False + if tan_distance == 0: + _Wrn(_tr("Tangential distance cannot be zero")) + return False + return True + + def create_object(self, selection): + """Create the actual object""" + r_d_str = self.form.spinbox_r_distance.text() + tan_d_str = self.form.spinbox_tan_distance.text() + self.r_distance = _Quantity(r_d_str).Value + self.tan_distance = _Quantity(tan_d_str).Value + + self.number = self.form.spinbox_number.value() + self.symmetry = self.form.spinbox_symmetry.value() + self.center = self.set_point() + + if len(selection) == 1: + sel_obj = selection[0] + else: + # This can be changed so a compound of multiple + # selected objects is produced + sel_obj = selection[0] + + self.fuse = self.form.checkbox_fuse.isChecked() + self.use_link = self.form.checkbox_link.isChecked() + + # This creates the object immediately + # obj = Draft.makeArray(sel_obj, + # self.center, self.angle, self.number) + # if obj: + # obj.Fuse = self.fuse + + # Instead, we build the commands to execute through the parent + # of this class, the GuiCommand. + # This is needed to schedule geometry manipulation + # that would crash Coin3D if done in the event callback. + _cmd = "obj = Draft.makeArray(" + _cmd += "FreeCAD.ActiveDocument." + sel_obj.Name + ", " + _cmd += "arg1=" + str(self.r_distance) + ", " + _cmd += "arg2=" + str(self.tan_distance) + ", " + _cmd += "arg3=" + DraftVecUtils.toString(self.axis) + ", " + _cmd += "arg4=" + DraftVecUtils.toString(self.center) + ", " + _cmd += "arg5=" + str(self.number) + ", " + _cmd += "arg6=" + str(self.symmetry) + ", " + _cmd += "useLink=" + str(self.use_link) + ")" + + _cmd_list = ["FreeCADGui.addModule('Draft')", + _cmd, + "obj.Fuse = " + str(self.fuse), + "Draft.autogroup(obj)", + "FreeCAD.ActiveDocument.recompute()"] + self.source_command.commit("Circular array", _cmd_list) + + def set_point(self): + """Assign the values to the center""" + self.c_x_str = self.form.input_c_x.text() + self.c_y_str = self.form.input_c_y.text() + self.c_z_str = self.form.input_c_z.text() + center = App.Vector(_Quantity(self.c_x_str).Value, + _Quantity(self.c_y_str).Value, + _Quantity(self.c_z_str).Value) + return center + + def reset_point(self): + """Reset the point to the original distance""" + self.form.input_c_x.setProperty('rawValue', 0) + self.form.input_c_y.setProperty('rawValue', 0) + self.form.input_c_z.setProperty('rawValue', 0) + + self.center = self.set_point() + _Msg(_tr("Center reset:") + + " ({0}, {1}, {2})".format(self.center.x, + self.center.y, + self.center.z)) + + def print_fuse_state(self): + """Print the state translated""" + if self.fuse: + translated_state = QT_TRANSLATE_NOOP("Draft", "True") + else: + translated_state = QT_TRANSLATE_NOOP("Draft", "False") + _Msg(_tr("Fuse:") + " {}".format(translated_state)) + + def set_fuse(self): + """This function is called when the fuse checkbox changes""" + self.fuse = self.form.checkbox_fuse.isChecked() + self.print_fuse_state() + + def print_link_state(self): + """Print the state translated""" + if self.use_link: + translated_state = QT_TRANSLATE_NOOP("Draft", "True") + else: + translated_state = QT_TRANSLATE_NOOP("Draft", "False") + _Msg(_tr("Use Link object:") + " {}".format(translated_state)) + + def set_link(self): + """This function is called when the fuse checkbox changes""" + self.use_link = self.form.checkbox_link.isChecked() + self.print_link_state() + + def print_messages(self, selection): + """Print messages about the operation""" + if len(selection) == 1: + sel_obj = selection[0] + else: + # This can be changed so a compound of multiple + # selected objects is produced + sel_obj = selection[0] + _Msg("{}".format(16*"-")) + _Msg("{}".format(self.name)) + _Msg(_tr("Object:") + " {}".format(sel_obj.Label)) + _Msg(_tr("Radial distance:") + " {}".format(self.r_distance)) + _Msg(_tr("Tangential distance:") + " {}".format(self.tan_distance)) + _Msg(_tr("Number of circular layers:") + " {}".format(self.number)) + _Msg(_tr("Symmetry parameter:") + " {}".format(self.symmetry)) + _Msg(_tr("Center of rotation:") + + " ({0}, {1}, {2})".format(self.center.x, + self.center.y, + self.center.z)) + self.print_fuse_state() + self.print_link_state() + + def display_point(self, point=None, plane=None, mask=None): + """Displays the coordinates in the x, y, and z widgets. + + This function should be used in a Coin callback so that + the coordinate values are automatically updated when the + mouse pointer moves. + This was copied from `DraftGui.py` but needs to be improved + for this particular command. + + point : + is a vector that arrives by the callback. + plane : + is a `WorkingPlane` instance, for example, + `App.DraftWorkingPlane`. It is not used at the moment, + but could be used to set up the grid. + mask : + is a string that specifies which coordinate is being + edited. It is used to restrict edition of a single coordinate. + It is not used at the moment but could be used with a callback. + """ + # Get the coordinates to display + dp = None + if point: + dp = point + + # Set the widgets to the value of the mouse pointer. + # + # setProperty() is used if the widget is a FreeCAD widget like + # Gui::InputField or Gui::QuantitySpinBox, which are based on + # QLineEdit and QAbstractSpinBox. + # + # setText() is used to set the text inside the widget, this may be + # useful in some circumstances. + # + # The mask allows editing only one field, that is, only one coordinate. + # sbx = self.form.spinbox_c_x + # sby = self.form.spinbox_c_y + # sbz = self.form.spinbox_c_z + if dp: + if self.mask in ('y', 'z'): + # sbx.setText(displayExternal(dp.x, None, 'Length')) + self.form.input_c_x.setProperty('rawValue', dp.x) + else: + # sbx.setText(displayExternal(dp.x, None, 'Length')) + self.form.input_c_x.setProperty('rawValue', dp.x) + if self.mask in ('x', 'z'): + # sby.setText(displayExternal(dp.y, None, 'Length')) + self.form.input_c_y.setProperty('rawValue', dp.y) + else: + # sby.setText(displayExternal(dp.y, None, 'Length')) + self.form.input_c_y.setProperty('rawValue', dp.y) + if self.mask in ('x', 'y'): + # sbz.setText(displayExternal(dp.z, None, 'Length')) + self.form.input_c_z.setProperty('rawValue', dp.z) + else: + # sbz.setText(displayExternal(dp.z, None, 'Length')) + self.form.input_c_z.setProperty('rawValue', dp.z) + + # Set masks + if (mask == "x") or (self.mask == "x"): + self.form.input_c_x.setEnabled(True) + self.form.input_c_y.setEnabled(False) + self.form.input_c_z.setEnabled(False) + self.set_focus("x") + elif (mask == "y") or (self.mask == "y"): + self.form.input_c_x.setEnabled(False) + self.form.input_c_y.setEnabled(True) + self.form.input_c_z.setEnabled(False) + self.set_focus("y") + elif (mask == "z") or (self.mask == "z"): + self.form.input_c_x.setEnabled(False) + self.form.input_c_y.setEnabled(False) + self.form.input_c_z.setEnabled(True) + self.set_focus("z") + else: + self.form.input_c_x.setEnabled(True) + self.form.input_c_y.setEnabled(True) + self.form.input_c_z.setEnabled(True) + self.set_focus() + + def set_focus(self, key=None): + """Set the focus on the widget that receives the key signal""" + if key is None or key == "x": + self.form.input_c_x.setFocus() + self.form.input_c_x.selectAll() + elif key == "y": + self.form.input_c_y.setFocus() + self.form.input_c_y.selectAll() + elif key == "z": + self.form.input_c_z.setFocus() + self.form.input_c_z.selectAll() + + def reject(self): + """Function that executes when clicking the Cancel button""" + _Msg(_tr("Aborted:") + " {}".format(self.name)) + self.finish() + + def finish(self): + """Function that runs at the end after OK or Cancel""" + # App.ActiveDocument.commitTransaction() + Gui.ActiveDocument.resetEdit() + # Runs the parent command to complete the call + self.source_command.completed() diff --git a/src/Mod/Draft/draftviewproviders/view_circulararray.py b/src/Mod/Draft/draftviewproviders/view_circulararray.py new file mode 100644 index 0000000000..1a6eab8b4f --- /dev/null +++ b/src/Mod/Draft/draftviewproviders/view_circulararray.py @@ -0,0 +1,44 @@ +"""This module provides the view provider code for Draft CircularArray. +""" +## @package view_circulararray +# \ingroup DRAFT +# \brief This module provides the view provider code for Draft CircularArray. + +# *************************************************************************** +# * (c) 2019 Eliud Cabrera Castillo * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * FreeCAD is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with FreeCAD; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +import Draft +import Draft_rc +ViewProviderDraftArray = Draft._ViewProviderDraftArray + +# So the resource file doesn't trigger errors from code checkers (flake8) +True if Draft_rc.__name__ else False + + +class ViewProviderCircularArray(ViewProviderDraftArray): + + def __init__(self, vobj): + super().__init__(self, vobj) + + def getIcon(self): + return ":/icons/Draft_CircularArray"