diff --git a/src/Mod/Draft/CMakeLists.txt b/src/Mod/Draft/CMakeLists.txt
index f8d319f07d..f9dfdd8348 100644
--- a/src/Mod/Draft/CMakeLists.txt
+++ b/src/Mod/Draft/CMakeLists.txt
@@ -49,19 +49,23 @@ SET(Draft_tests
SET(Draft_objects
draftobjects/__init__.py
+ draftobjects/polararray.py
)
SET(Draft_view_providers
draftviewproviders/__init__.py
+ draftviewproviders/view_polararray.py
)
SET(Draft_GUI_tools
draftguitools/__init__.py
draftguitools/gui_base.py
+ draftguitools/gui_polararray.py
)
SET(Draft_task_panels
drafttaskpanels/__init__.py
+ drafttaskpanels/task_polararray.py
)
SET(Draft_SRCS_all
diff --git a/src/Mod/Draft/InitGui.py b/src/Mod/Draft/InitGui.py
index 8b5e2a0a66..a93170e05a 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_polararray
FreeCADGui.addLanguagePath(":/translations")
FreeCADGui.addIconPath(":/icons")
except Exception as inst:
@@ -85,6 +86,7 @@ class DraftWorkbench(Workbench):
"Draft_WireToBSpline", "Draft_AddPoint",
"Draft_DelPoint", "Draft_Shape2DView",
"Draft_Draft2Sketch", "Draft_Array", "Draft_LinkArray",
+ "Draft_PolarArray",
"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 1d71743871..faf759e28d 100644
--- a/src/Mod/Draft/Resources/Draft.qrc
+++ b/src/Mod/Draft/Resources/Draft.qrc
@@ -51,6 +51,7 @@
icons/Draft_PathLinkArray.svgicons/Draft_Point.svgicons/Draft_PointArray.svg
+ icons/Draft_PolarArray.svgicons/Draft_Polygon.svgicons/Draft_Rectangle.svgicons/Draft_Rotate.svg
@@ -148,6 +149,7 @@
ui/preferences-dxf.uiui/preferences-oca.uiui/preferences-svg.ui
+ ui/TaskPanel_PolarArray.uiui/TaskSelectPlane.uiui/TaskShapeString.ui
diff --git a/src/Mod/Draft/Resources/icons/Draft_PolarArray.svg b/src/Mod/Draft/Resources/icons/Draft_PolarArray.svg
new file mode 100644
index 0000000000..474c8e5689
--- /dev/null
+++ b/src/Mod/Draft/Resources/icons/Draft_PolarArray.svg
@@ -0,0 +1,412 @@
+
+
+
+
diff --git a/src/Mod/Draft/Resources/ui/TaskPanel_PolarArray.ui b/src/Mod/Draft/Resources/ui/TaskPanel_PolarArray.ui
new file mode 100644
index 0000000000..5c85cf69f3
--- /dev/null
+++ b/src/Mod/Draft/Resources/ui/TaskPanel_PolarArray.ui
@@ -0,0 +1,247 @@
+
+
+ DraftPolarArrayTaskPanel
+
+
+
+ 0
+ 0
+ 445
+ 488
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 250
+ 0
+
+
+
+ Polar array
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+ The coordinates of the point through which the axis of rotation passes.
+
+
+ Center of rotation
+
+
+
+
+
+
+
+ Z
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+
+ X
+
+
+
+
+
+
+ Y
+
+
+
+
+
+
+
+
+ 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
+
+
+
+
+
+
+
+
+
+
+ Sweeping angle of the polar distribution
+
+
+ Polar angle
+
+
+
+
+
+
+ Sweeping angle of the polar distribution
+
+
+
+
+
+ 180.000000000000000
+
+
+
+
+
+
+ Number of elements in the array, including a copy of the original object. It must be at least 2.
+
+
+ Number of elements
+
+
+
+
+
+
+ Number of elements in the array, including a copy of the original object. It must be at least 2.
+
+
+ 4
+
+
+
+
+
+
+
+
+ (Placeholder for the icon)
+
+
+
+
+
+
+
+
+
+
+ Gui::InputField
+ QLineEdit
+ Gui/InputField.h
+
+
+ Gui::QuantitySpinBox
+ QWidget
+ Gui/QuantitySpinBox.h
+
+
+
+ spinbox_angle
+ spinbox_number
+ input_c_x
+ input_c_y
+ input_c_z
+ button_reset
+ checkbox_fuse
+ checkbox_link
+
+
+
+
diff --git a/src/Mod/Draft/draftguitools/gui_polararray.py b/src/Mod/Draft/draftguitools/gui_polararray.py
new file mode 100644
index 0000000000..e07a3b0742
--- /dev/null
+++ b/src/Mod/Draft/draftguitools/gui_polararray.py
@@ -0,0 +1,155 @@
+"""This module provides the Draft PolarArray tool.
+"""
+## @package gui_polararray
+# \ingroup DRAFT
+# \brief This module provides the Draft PolarArray 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_polararray
+
+
+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 GuiCommandPolarArray(gui_base.GuiCommandBase):
+ """Gui command for the PolarArray tool"""
+
+ def __init__(self):
+ super().__init__()
+ self.command_name = "PolarArray"
+ 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 polar 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_PolarArray',
+ 'MenuText': QT_TRANSLATE_NOOP("Draft", "Polar 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_polararray.TaskPanelPolarArray()
+ # 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_PolarArray', GuiCommandPolarArray())
diff --git a/src/Mod/Draft/draftobjects/polararray.py b/src/Mod/Draft/draftobjects/polararray.py
new file mode 100644
index 0000000000..ccf155ae44
--- /dev/null
+++ b/src/Mod/Draft/draftobjects/polararray.py
@@ -0,0 +1,42 @@
+"""This module provides the object code for Draft PolarArray.
+"""
+## @package polararray
+# \ingroup DRAFT
+# \brief This module provides the object code for Draft PolarArray.
+
+# ***************************************************************************
+# * (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_polar_array(obj,
+ center=App.Vector(0, 0, 0), angle=180, number=4,
+ use_link=False):
+ """Create a polar array from the given object.
+ """
+ obj = Draft.makeArray(obj,
+ arg1=center, arg2=angle, arg3=number,
+ useLink=use_link)
+ return obj
diff --git a/src/Mod/Draft/drafttaskpanels/task_polararray.py b/src/Mod/Draft/drafttaskpanels/task_polararray.py
new file mode 100644
index 0000000000..64292973f2
--- /dev/null
+++ b/src/Mod/Draft/drafttaskpanels/task_polararray.py
@@ -0,0 +1,377 @@
+"""This module provides the task panel for the Draft PolarArray tool.
+"""
+## @package task_polararray
+# \ingroup DRAFT
+# \brief This module provides the task panel code for the PolarArray 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 TaskPanelPolarArray:
+ """TaskPanel for the PolarArray 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_PolarArray.ui"
+ self.form = Gui.PySideUic.loadUi(ui_file)
+ self.name = self.form.windowTitle()
+
+ icon_name = "Draft_PolarArray"
+ 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_angle = _Quantity(180.0, App.Units.Angle)
+ angle_unit = start_angle.getUserPreferred()[2]
+ self.form.spinbox_angle.setProperty('rawValue', start_angle.Value)
+ self.form.spinbox_angle.setProperty('unit', angle_unit)
+ self.form.spinbox_number.setValue(4)
+
+ self.angle_str = self.form.spinbox_angle.text()
+ self.angle = start_angle.Value
+
+ self.number = self.form.spinbox_number.value()
+
+ 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()
+ self.valid_input = self.validate_input(selection,
+ self.number)
+ if self.valid_input:
+ self.create_object(selection)
+ self.print_messages(selection)
+ self.finish()
+
+ def validate_input(self, selection, number):
+ """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
+ return True
+
+ def create_object(self, selection):
+ """Create the actual object"""
+ self.angle_str = self.form.spinbox_angle.text()
+ self.angle = _Quantity(self.angle_str).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=" + DraftVecUtils.toString(self.center) + ", "
+ _cmd += "arg2=" + str(self.angle) + ", "
+ _cmd += "arg3=" + str(self.number) + ", "
+ _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("Polar 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("Start angle:") + " {}".format(self.angle_str))
+ _Msg(_tr("Number of elements:") + " {}".format(self.number))
+ _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_polararray.py b/src/Mod/Draft/draftviewproviders/view_polararray.py
new file mode 100644
index 0000000000..e0eb35fc55
--- /dev/null
+++ b/src/Mod/Draft/draftviewproviders/view_polararray.py
@@ -0,0 +1,44 @@
+"""This module provides the view provider code for Draft PolarArray.
+"""
+## @package polararray
+# \ingroup DRAFT
+# \brief This module provides the view provider code for Draft PolarArray.
+
+# ***************************************************************************
+# * (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 ViewProviderPolarArray(ViewProviderDraftArray):
+
+ def __init__(self, vobj):
+ super().__init__(self, vobj)
+
+ def getIcon(self):
+ return ":/icons/Draft_PolarArray"