# SPDX-License-Identifier: LGPL-2.1-or-later

# -*- coding: utf8 -*-
# ***************************************************************************
# *   Copyright (c) 2009 Yorik van Havre <yorik@uncreated.net>              *
# *                                                                         *
# *   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.                                 *
# *                                                                         *
# *   This program 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 this program; if not, write to the Free Software   *
# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
# *   USA                                                                   *
# *                                                                         *
# ***************************************************************************

__title__ = "FreeCAD Draft Workbench - GUI part"
__author__ = "Yorik van Havre <yorik@uncreated.net>"
__url__ = "https://www.freecad.org"

## @package DraftGui
#  \ingroup DRAFT
#  \brief GUI elements and utilities of the Draft workbench
#
#  This module provides GUI tools for the Draft workbench, such as
#  toolbars and task panels, and Qt-dependent utilities such as
#  a delayed (todo) commit system

"""This is the GUI part of the Draft module.
Report to Draft.py for info
"""

import os
import sys
import time
import math
import PySide.QtCore as QtCore
import PySide.QtGui as QtGui
import PySide.QtWidgets as QtWidgets

import FreeCAD
import FreeCADGui
import Draft
import DraftVecUtils
import WorkingPlane
from draftutils import params
from draftutils import utils
from draftutils.todo import todo
from draftutils.translate import translate
from draftutils.units import display_external


def _get_incmd_shortcut(itm):
    return params.get_param("inCommandShortcut" + itm).upper()


# ---------------------------------------------------------------------------
# Customized widgets
# ---------------------------------------------------------------------------


class DraftBaseWidget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

    def eventFilter(self, widget, event):
        if event.type() == QtCore.QEvent.KeyPress and event.text().upper() == _get_incmd_shortcut(
            "CycleSnap"
        ):
            if hasattr(FreeCADGui, "Snapper"):
                FreeCADGui.Snapper.cycleSnapObject()
            return True
        return super().eventFilter(widget, event)


class DraftDockWidget(DraftBaseWidget):
    """custom Widget that emits a resized() signal when resized"""

    def __init__(self, parent=None):
        super().__init__(parent)

    def resizeEvent(self, event):
        self.emit(QtCore.SIGNAL("resized()"))

    def changeEvent(self, event):
        if event.type() == QtCore.QEvent.LanguageChange:
            self.emit(QtCore.SIGNAL("retranslate()"))
        else:
            super().changeEvent(event)


class DraftLineEdit(QtWidgets.QLineEdit):
    """custom QLineEdit widget that has the power to catch Escape keypress"""

    def __init__(self, parent=None):
        super().__init__(parent)

    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_Escape:
            self.emit(QtCore.SIGNAL("escaped()"))
        elif event.key() == QtCore.Qt.Key_Up:
            self.emit(QtCore.SIGNAL("up()"))
        elif event.key() == QtCore.Qt.Key_Down:
            self.emit(QtCore.SIGNAL("down()"))
        else:
            super().keyPressEvent(event)


class DraftTaskPanel:
    def __init__(self, widget, extra=None):
        if extra:
            if isinstance(extra, list):
                self.form = [widget] + extra
            else:
                self.form = [widget, extra]
        else:
            self.form = widget

    def getStandardButtons(self):
        return QtWidgets.QDialogButtonBox.Close

    def accept(self):
        if hasattr(FreeCADGui, "draftToolBar"):
            return FreeCADGui.draftToolBar.validatePoint()
        else:
            if FreeCADGui.ActiveDocument:
                FreeCADGui.ActiveDocument.resetEdit()
            return True

    def reject(self):
        # https://github.com/FreeCAD/FreeCAD/issues/17027
        # Function can be called multiple times if Esc is pressed during mouse
        # move. We need to prevent multiple calls to draftToolBar.escape():
        if not FreeCADGui.draftToolBar.isTaskOn:
            return
        FreeCADGui.draftToolBar.isTaskOn = False
        FreeCADGui.draftToolBar.escape()
        if FreeCADGui.ActiveDocument:
            FreeCADGui.ActiveDocument.resetEdit()
        return True

    def isAllowedAlterDocument(self):
        return False


class DraftToolBar:
    """The Draft Task panel UI
    Draft Toolbar is the main ui of the Draft Module. Once displayed as a
    toolbar, now it define the ui of the Task Panel.
    Toolbar become obsolete due to lack of manteinence and was disabled
    by default in February 2020.
    Draft Ui Commands call and get information such as point coordinates,
    subcommands activation, continue mode, etc. from Task Panel Ui
    """

    def __init__(self):
        self.tray = None
        self.sourceCmd = None
        self.mouse = True
        self.mouse_delay_input_start = time.time()
        self.cancel = None
        self.pointcallback = None

        # OBSOLETE BUT STILL USED BY SOME ADDONS AND MACROS
        self.color = QtGui.QColor(
            utils.rgba_to_argb(params.get_param_view("DefaultShapeLineColor"))
        )
        self.facecolor = QtGui.QColor(
            utils.rgba_to_argb(params.get_param_view("DefaultShapeColor"))
        )
        self.linewidth = params.get_param_view("DefaultShapeLineWidth")
        self.fontsize = params.get_param("textheight")

        self.paramconstr = utils.rgba_to_argb(params.get_param("constructioncolor"))
        self.constrMode = False
        self.continueMode = False
        self.chainedMode = False
        self.relativeMode = True
        self.globalMode = False
        self.state = None
        self.textbuffer = []
        self.crossedViews = []
        self.isTaskOn = False
        self.makeFaceMode = True
        self.mask = None
        self.alock = False
        self.x = 0  # coord of the point as displayed in the task panel (global/local and relative/absolute)
        self.y = 0  # idem
        self.z = 0  # idem
        self.new_point = None  # global point value
        self.last_point = None  # idem
        self.lvalue = 0
        self.pvalue = 90
        self.avalue = 0
        self.angle = None
        self.radius = 0
        self.offset = 0
        self.uiloader = FreeCADGui.UiLoader()
        self.autogroup = None
        self.isCenterPlane = False
        self.input_fields = {
            "xValue": {"value": "x", "unit": "Length"},
            "yValue": {"value": "y", "unit": "Length"},
            "zValue": {"value": "z", "unit": "Length"},
            "lengthValue": {"value": "lvalue", "unit": "Length"},
            "radiusValue": {"value": "radius", "unit": "Length"},
            "angleValue": {"value": "avalue", "unit": "Angle"},
        }

        # add only a dummy widget, since widgets are created on demand
        self.baseWidget = DraftBaseWidget()
        self.tray = FreeCADGui.UiLoader().createWidget("Gui::ToolBar")
        self.tray.setObjectName("Draft tray")
        self.tray.setWindowTitle("Draft Tray")
        self.toptray = self.tray
        self.bottomtray = self.tray
        self.setupTray()
        self.setupStyle()
        mw = FreeCADGui.getMainWindow()
        mw.addToolBar(self.tray)
        self.tray.setParent(mw)
        self.tray.hide()
        self.display_point_active = False  # prevent cyclic processing of point values

    # ---------------------------------------------------------------------------
    # General UI setup
    # ---------------------------------------------------------------------------

    def _pushbutton(
        self, name, layout, hide=True, icon=None, width=None, checkable=False, square=False
    ):
        if square:
            button = QtWidgets.QToolButton(self.baseWidget)
            if width is not None:
                button.setFixedHeight(width)
                button.setFixedWidth(width)
        else:
            button = QtWidgets.QPushButton(self.baseWidget)
        button.setObjectName(name)
        if hide:
            button.hide()
        if icon:
            if icon.endswith(".svg"):
                button.setIcon(QtGui.QIcon(icon))
            else:
                button.setIcon(QtGui.QIcon.fromTheme(icon, QtGui.QIcon(":/icons/" + icon + ".svg")))
        if checkable:
            button.setCheckable(True)
            button.setChecked(False)
        layout.addWidget(button)
        return button

    def _label(self, name, layout, hide=True, wrap=False):
        label = QtWidgets.QLabel(self.baseWidget)
        label.setObjectName(name)
        if wrap:
            label.setWordWrap(True)
        if hide:
            label.hide()
        layout.addWidget(label)
        return label

    def _lineedit(self, name, layout, hide=True, width=None):
        bsize = params.get_param("ToolbarIconSize", path="General") - 2
        lineedit = DraftLineEdit(self.baseWidget)
        lineedit.setObjectName(name)
        if hide:
            lineedit.hide()
        # if not width: width = 800
        # lineedit.setMaximumSize(QtCore.QSize(width,bsize))
        layout.addWidget(lineedit)
        return lineedit

    def _inputfield(self, name, layout, hide=True, width=None):
        inputfield = self.uiloader.createWidget("Gui::InputField")
        inputfield.setObjectName(name)
        if hide:
            inputfield.hide()
        if not width:
            sizePolicy = QtWidgets.QSizePolicy(
                QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred
            )
            inputfield.setSizePolicy(sizePolicy)
            inputfield.setMinimumWidth(110)
        else:
            inputfield.setMaximumWidth(width)
        layout.addWidget(inputfield)
        return inputfield

    def _spinbox(self, name, layout, val=None, vmax=None, hide=True, double=False, size=None):
        if double:
            sbox = QtWidgets.QDoubleSpinBox(self.baseWidget)
            sbox.setDecimals(params.get_param("Decimals", path="Units"))
        else:
            sbox = QtWidgets.QSpinBox(self.baseWidget)
        sbox.setObjectName(name)
        if vmax:
            sbox.setMaximum(vmax)
        if val:
            sbox.setValue(val)
        # if size: sbox.setMaximumSize(QtCore.QSize(size[0],size[1]))
        if hide:
            sbox.hide()
        layout.addWidget(sbox)
        return sbox

    def _checkbox(self, name, layout, checked=True, hide=True):
        chk = QtWidgets.QCheckBox(self.baseWidget)
        chk.setChecked(checked)
        chk.setObjectName(name)
        if hide:
            chk.hide()
        layout.addWidget(chk)
        return chk

    def _combo(self, name, layout, hide=True):
        cb = QtWidgets.QComboBox(self.baseWidget)
        cb.setObjectName(name)
        if hide:
            cb.hide()
        layout.addWidget(cb)

    def setupToolBar(self, task=False):
        """sets the draft toolbar up"""

        # command

        self.promptlabel = self._label("promptlabel", self.layout, hide=task)
        self.cmdlabel = self._label("cmdlabel", self.layout, hide=task)
        boldtxt = QtGui.QFont()
        boldtxt.setBold(True)
        self.cmdlabel.setFont(boldtxt)

        # point

        xl = QtWidgets.QHBoxLayout()
        yl = QtWidgets.QHBoxLayout()
        zl = QtWidgets.QHBoxLayout()
        bl = QtWidgets.QHBoxLayout()
        self.layout.addLayout(xl)
        self.layout.addLayout(yl)
        self.layout.addLayout(zl)
        self.layout.addLayout(bl)
        self.labelx = self._label("labelx", xl)
        self.xValue = self._inputfield("xValue", xl)  # width=60
        self.xValue.installEventFilter(self.baseWidget)
        self.xValue.setText(FreeCAD.Units.Quantity(0, FreeCAD.Units.Length).UserString)
        self.labely = self._label("labely", yl)
        self.yValue = self._inputfield("yValue", yl)
        self.yValue.installEventFilter(
            self.baseWidget
        )  # Required to detect snap cycling in case of Y constraining.
        self.yValue.setText(FreeCAD.Units.Quantity(0, FreeCAD.Units.Length).UserString)
        self.labelz = self._label("labelz", zl)
        self.zValue = self._inputfield("zValue", zl)
        self.zValue.installEventFilter(
            self.baseWidget
        )  # Required to detect snap cycling in case of Z constraining.
        self.zValue.setText(FreeCAD.Units.Quantity(0, FreeCAD.Units.Length).UserString)
        self.pointButton = self._pushbutton("addButton", bl, icon="Draft_AddPoint")

        # text

        self.textValue = QtWidgets.QTextEdit(self.baseWidget)
        self.textValue.setObjectName("textValue")
        self.textValue.setTabChangesFocus(True)
        self.layout.addWidget(self.textValue)
        self.textValue.hide()
        tl = QtWidgets.QHBoxLayout()
        self.layout.addLayout(tl)
        self.textOkButton = self._pushbutton("textButton", tl, icon="button_valid")

        # additional line controls

        ll = QtWidgets.QHBoxLayout()
        al = QtWidgets.QHBoxLayout()
        self.layout.addLayout(ll)
        self.layout.addLayout(al)
        self.labellength = self._label("labellength", ll)
        self.lengthValue = self._inputfield("lengthValue", ll)
        self.lengthValue.installEventFilter(
            self.baseWidget
        )  # Required to detect snap cycling if focusOnLength is True.
        self.lengthValue.setText(FreeCAD.Units.Quantity(0, FreeCAD.Units.Length).UserString)
        self.labelangle = self._label("labelangle", al)
        self.angleLock = self._checkbox("angleLock", al, checked=self.alock)
        self.angleValue = self._inputfield("angleValue", al)
        self.angleValue.setText(FreeCAD.Units.Quantity(0, FreeCAD.Units.Angle).UserString)

        # options

        fl = QtWidgets.QHBoxLayout()
        self.layout.addLayout(fl)
        self.numFacesLabel = self._label("numfaceslabel", fl)
        self.numFaces = self._spinbox("numFaces", fl, 3)
        ol = QtWidgets.QHBoxLayout()
        self.layout.addLayout(ol)
        rl = QtWidgets.QHBoxLayout()
        self.layout.addLayout(rl)
        self.labelRadius = self._label("labelRadius", rl)
        self.radiusValue = self._inputfield("radiusValue", rl)
        self.radiusValue.setText(FreeCAD.Units.Quantity(0, FreeCAD.Units.Length).UserString)
        bl = QtWidgets.QHBoxLayout()
        self.layout.addLayout(bl)
        self.undoButton = self._pushbutton("undoButton", bl, icon="Draft_Rotate")
        bl = QtWidgets.QHBoxLayout()
        self.layout.addLayout(bl)
        self.finishButton = self._pushbutton("finishButton", bl, icon="Draft_Finish")
        bl = QtWidgets.QHBoxLayout()
        self.layout.addLayout(bl)
        self.closeButton = self._pushbutton("closeButton", bl, icon="Draft_Lock")
        bl = QtWidgets.QHBoxLayout()
        self.layout.addLayout(bl)
        self.wipeButton = self._pushbutton("wipeButton", bl, icon="Draft_Wipe")
        bl = QtWidgets.QHBoxLayout()
        self.layout.addLayout(bl)
        self.orientWPButton = self._pushbutton("orientWPButton", bl, icon="Draft_SelectPlane")
        bl = QtWidgets.QHBoxLayout()
        self.layout.addLayout(bl)
        self.selectButton = self._pushbutton("selectButton", bl, icon="view-select")

        # update modes from parameters:
        self.relativeMode = params.get_param("RelativeMode")
        self.globalMode = params.get_param("GlobalMode")
        self.makeFaceMode = params.get_param("MakeFaceMode")

        if getattr(FreeCAD, "activeDraftCommand", None) and getattr(
            FreeCAD.activeDraftCommand, "featureName", None
        ):
            self.continueMode = params.get_param(
                FreeCAD.activeDraftCommand.featureName, "Mod/Draft/ContinueMode", silent=True
            )

        self.chainedMode = params.get_param("ChainedMode")

        # Note: The order of the calls to self._checkbox() below controls
        #       the position of the checkboxes in the task panel.

        # update checkboxes with parameters and internal modes:
        self.isRelative = self._checkbox("isRelative", self.layout, checked=self.relativeMode)
        self.isGlobal = self._checkbox("isGlobal", self.layout, checked=self.globalMode)
        self.makeFace = self._checkbox("makeFace", self.layout, checked=self.makeFaceMode)
        self.continueCmd = self._checkbox(
            "continueCmd", self.layout, checked=bool(self.continueMode)
        )
        self.chainedModeCmd = self._checkbox(
            "chainedModeCmd", self.layout, checked=self.chainedMode
        )

        self.chainedModeCmd.setEnabled(
            not (hasattr(self.sourceCmd, "contMode") and self.continueMode)
        )
        self.continueCmd.setEnabled(not (hasattr(self.sourceCmd, "chain") and self.chainedMode))

        # update checkboxes without parameters and without internal modes:
        self.occOffset = self._checkbox("occOffset", self.layout, checked=False)

        # update checkboxes with parameters but without internal modes:
        # self.isCopy is also updated in modUi ("CopyMode") and offsetUi ("OffsetCopyMode")
        self.isCopy = self._checkbox("isCopy", self.layout, checked=params.get_param("CopyMode"))
        self.isSubelementMode = self._checkbox(
            "isSubelementMode", self.layout, checked=params.get_param("SubelementMode")
        )

        # spacer
        spacerItem = QtWidgets.QSpacerItem(
            20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding
        )
        self.layout.addItem(spacerItem)

        self.xValue.valueChanged.connect(self.changeXValue)
        self.yValue.valueChanged.connect(self.changeYValue)
        self.zValue.valueChanged.connect(self.changeZValue)
        self.lengthValue.valueChanged.connect(self.changeLengthValue)
        self.angleValue.valueChanged.connect(self.changeAngleValue)
        if hasattr(self.angleLock, "checkStateChanged"):  # Qt version >= 6.7.0
            self.angleLock.checkStateChanged.connect(self.toggleAngle)
        else:  # Qt version < 6.7.0
            self.angleLock.stateChanged.connect(self.toggleAngle)
        self.radiusValue.valueChanged.connect(self.changeRadiusValue)
        self.xValue.returnPressed.connect(self.checkx)
        self.yValue.returnPressed.connect(self.checky)
        self.lengthValue.returnPressed.connect(self.checklength)
        self.xValue.textEdited.connect(self.checkSpecialChars)
        self.yValue.textEdited.connect(self.checkSpecialChars)
        self.zValue.textEdited.connect(self.checkSpecialChars)
        self.lengthValue.textEdited.connect(self.checkSpecialChars)
        self.radiusValue.textEdited.connect(self.checkSpecialChars)
        self.angleValue.textEdited.connect(self.checkSpecialChars)
        self.zValue.returnPressed.connect(self.validatePoint)
        self.pointButton.clicked.connect(self.validatePoint)
        self.radiusValue.returnPressed.connect(self.validatePoint)
        self.angleValue.returnPressed.connect(self.validatePoint)
        self.textValue.textChanged.connect(self.checkEnterText)
        self.textOkButton.clicked.connect(self.sendText)
        self.zValue.returnPressed.connect(self.setFocus)

        self.finishButton.clicked.connect(self.finish)
        self.closeButton.clicked.connect(self.closeLine)
        self.wipeButton.clicked.connect(self.wipeLine)
        self.orientWPButton.clicked.connect(self.orientWP)
        self.undoButton.clicked.connect(self.undoSegment)
        self.selectButton.clicked.connect(self.selectEdge)
        if hasattr(self.continueCmd, "checkStateChanged"):  # Qt version >= 6.7.0
            self.continueCmd.checkStateChanged.connect(self.setContinue)
            self.chainedModeCmd.checkStateChanged.connect(self.setChainedMode)
            self.isCopy.checkStateChanged.connect(self.setCopymode)
            self.isSubelementMode.checkStateChanged.connect(self.setSubelementMode)
            self.isRelative.checkStateChanged.connect(self.setRelative)
            self.isGlobal.checkStateChanged.connect(self.setGlobal)
            self.makeFace.checkStateChanged.connect(self.setMakeFace)
        else:  # Qt version < 6.7.0
            self.continueCmd.stateChanged.connect(self.setContinue)
            self.chainedModeCmd.stateChanged.connect(self.setChainedMode)
            self.isCopy.stateChanged.connect(self.setCopymode)
            self.isSubelementMode.stateChanged.connect(self.setSubelementMode)
            self.isRelative.stateChanged.connect(self.setRelative)
            self.isGlobal.stateChanged.connect(self.setGlobal)
            self.makeFace.stateChanged.connect(self.setMakeFace)

    def setupTray(self):
        """sets draft tray buttons up"""

        self.wplabel = self._pushbutton(
            "wplabel", self.toptray, icon="Draft_SelectPlane", hide=False, width=120
        )

        self.styleButton = self._pushbutton(
            "stylebutton", self.toptray, icon="Draft_Apply", hide=False, width=120
        )
        self.setStyleButton()
        self.constrButton = self._pushbutton(
            "constrButton",
            self.toptray,
            hide=False,
            icon="Draft_Construction",
            width=self.styleButton.sizeHint().height(),
            checkable=True,
            square=True,
        )
        self.constrColor = QtGui.QColor(self.paramconstr)
        self.autoGroupButton = self._pushbutton(
            "autoGroup", self.bottomtray, icon=":/icons/button_invalid.svg", hide=False, width=120
        )
        self.autoGroupButton.setText(translate("draft", "None"))
        self.autoGroupButton.setFlat(True)

        self.wplabel.clicked.connect(self.selectplane)
        self.styleButton.clicked.connect(self.setstyle)
        self.constrButton.toggled.connect(self.toggleConstrMode)
        self.autoGroupButton.clicked.connect(self.runAutoGroup)

        QtCore.QTimer.singleShot(
            2000, self.retranslateTray
        )  # delay so translations get a chance to load

    def setupStyle(self):
        style = "#constrButton:Checked {background-color: "
        style += self.getDefaultColor("constr", rgb=True) + " } "
        style += "#addButton:Checked, #delButton:checked, "
        style += "#sharpButton:Checked, "
        style += "#tangentButton:Checked, #symmetricButton:checked {"
        style += "background-color: rgb(20,100,250) }"
        self.baseWidget.setStyleSheet(style)
        # if hasattr(self,"tray"):
        #    self.tray.setStyleSheet(style)

    # ---------------------------------------------------------------------------
    # language tools
    # ---------------------------------------------------------------------------

    def retranslateUi(self, widget=None):
        self.promptlabel.setText(translate("draft", "active command:"))
        self.cmdlabel.setText(translate("draft", "None"))
        self.cmdlabel.setToolTip(translate("draft", "Active Draft command"))
        self.xValue.setToolTip(translate("draft", "X coordinate of the point"))
        self.labelx.setText(translate("draft", "X"))
        self.labely.setText(translate("draft", "Y"))
        self.labelz.setText(translate("draft", "Z"))
        self.yValue.setToolTip(translate("draft", "Y coordinate of the point"))
        self.zValue.setToolTip(translate("draft", "Z coordinate of the point"))
        self.pointButton.setText(translate("draft", "Enter Point"))
        self.pointButton.setToolTip(translate("draft", "Enter a point with given coordinates"))
        self.labellength.setText(translate("draft", "Length"))
        self.labelangle.setText(translate("draft", "Angle"))
        self.lengthValue.setToolTip(translate("draft", "Length of the current segment"))
        self.angleValue.setToolTip(translate("draft", "Angle of the current segment"))
        self.angleLock.setToolTip(
            translate("draft", "Locks the current angle")
            + " ("
            + _get_incmd_shortcut("Length")
            + ")"
        )
        self.labelRadius.setText(translate("draft", "Radius"))
        self.radiusValue.setToolTip(translate("draft", "Radius of the circle"))
        self.isRelative.setText(
            translate("draft", "Relative") + " (" + _get_incmd_shortcut("Relative") + ")"
        )
        self.isRelative.setToolTip(
            translate(
                "draft",
                "Coordinates relative to last point or to coordinate system "
                + "origin\nif is the first point to set",
            )
        )
        self.isGlobal.setText(
            translate("draft", "Global") + " (" + _get_incmd_shortcut("Global") + ")"
        )
        self.isGlobal.setToolTip(
            translate(
                "draft",
                "Coordinates relative to global coordinate system."
                + "\nUncheck to use working plane coordinate system",
            )
        )
        self.makeFace.setText(
            translate("draft", "Make face") + " (" + _get_incmd_shortcut("MakeFace") + ")"
        )
        self.makeFace.setToolTip(
            translate(
                "draft",
                "If checked, the object will be filled with a face."
                + "\nNot available if the 'Use Part Primitives' preference is enabled",
            )
        )
        self.finishButton.setText(
            translate("draft", "Finish") + " (" + _get_incmd_shortcut("Exit") + ")"
        )
        self.finishButton.setToolTip(
            translate("draft", "Finishes the current drawing or editing operation")
        )
        self.continueCmd.setText(
            translate("draft", "Continue") + " (" + _get_incmd_shortcut("Continue") + ")"
        )
        self.continueCmd.setToolTip(
            translate(
                "draft",
                "If checked, the command will not finish until pressing "
                + "the command button again",
            )
        )
        self.chainedModeCmd.setText(translate("draft", "Chained mode"))
        self.chainedModeCmd.setToolTip(
            translate(
                "draft",
                "If checked, the next dimension will be placed in a chain"
                " with the previously placed Dimension",
            )
        )
        self.occOffset.setText(translate("draft", "OCC-style offset"))
        self.occOffset.setToolTip(
            translate(
                "draft",
                "If checked, an OCC-style offset will be performed"
                + " instead of the classic offset",
            )
        )
        self.undoButton.setText(
            translate("draft", "Undo") + " (" + _get_incmd_shortcut("Undo") + ")"
        )
        self.undoButton.setToolTip(translate("draft", "Undo the last segment"))
        self.closeButton.setText(
            translate("draft", "Close") + " (" + _get_incmd_shortcut("Close") + ")"
        )
        self.closeButton.setToolTip(translate("draft", "Finishes and closes the current line"))
        self.wipeButton.setText(
            translate("draft", "Wipe") + " (" + _get_incmd_shortcut("Wipe") + ")"
        )
        self.wipeButton.setToolTip(
            translate(
                "draft",
                "Wipes the existing segments of this line and starts again from the last point",
            )
        )
        self.orientWPButton.setText(
            translate("draft", "Set Working Plane") + " (" + _get_incmd_shortcut("SetWP") + ")"
        )
        self.orientWPButton.setToolTip(
            translate("draft", "Reorients the working plane on the last segment")
        )
        self.selectButton.setText(
            translate("draft", "Select Edge") + " (" + _get_incmd_shortcut("SelectEdge") + ")"
        )
        self.selectButton.setToolTip(
            translate("draft", "Selects an existing edge to be measured by this dimension")
        )
        self.numFacesLabel.setText(translate("draft", "Sides"))
        self.numFaces.setToolTip(translate("draft", "Number of sides"))

        self.isCopy.setText(translate("draft", "Copy") + " (" + _get_incmd_shortcut("Copy") + ")")
        self.isCopy.setToolTip(
            translate("draft", "If checked, objects will be copied instead of moved")
        )
        self.isSubelementMode.setText(
            translate("draft", "Modify subelements")
            + " ("
            + _get_incmd_shortcut("SubelementMode")
            + ")"
        )
        self.isSubelementMode.setToolTip(
            translate("draft", "If checked, subelements will be modified instead of entire objects")
        )
        self.textOkButton.setText(translate("draft", "Create Text"))
        self.textOkButton.setToolTip(
            translate("draft", "Creates the text object and finishes the command")
        )
        self.retranslateTray(widget)

        # Update the maximum width of the push buttons
        maxwidth = 66  # that's the default
        pb = []
        for i in range(self.layout.count()):
            w = self.layout.itemAt(i).widget()
            if w is not None and w.inherits("QPushButton"):
                pb.append(w)

        for i in pb:
            fm = QtGui.QFontMetrics(i.font())
            fw = fm.width(i.text())
            fw = max(fw, maxwidth)

        maxwidth = maxwidth + 16 + 10  # add icon width and a margin
        for i in pb:
            i.setMaximumWidth(maxwidth)

    def retranslateTray(self, widget=None):

        self.styleButton.setToolTip(translate("draft", "Changes the default style for new objects"))
        self.constrButton.setToolTip(translate("draft", "Toggles construction mode"))
        self.autoGroupButton.setToolTip(translate("draft", "Autogroup off"))

    # ---------------------------------------------------------------------------
    # Interface modes
    # ---------------------------------------------------------------------------

    def _show_dialog(self, panel):
        task = FreeCADGui.Control.showDialog(panel)
        task.setDocumentName(FreeCADGui.ActiveDocument.Document.Name)
        task.setAutoCloseOnDeletedDocument(True)

    def taskUi(self, title="Draft", extra=None, icon="Draft_Draft"):
        # reset InputField values
        self.reset_ui_values()
        self.isTaskOn = True
        todo.delay(FreeCADGui.Control.closeDialog, None)
        self.baseWidget = DraftBaseWidget()
        self.layout = QtWidgets.QVBoxLayout(self.baseWidget)
        self.setupToolBar(task=True)
        self.retranslateUi(self.baseWidget)
        self.panel = DraftTaskPanel(self.baseWidget, extra)
        todo.delay(self._show_dialog, self.panel)
        self.setTitle(title, icon)

    def redraw(self):
        """utility function that is performed after each clicked point"""
        self.checkLocal()

    def setFocus(self, f=None):

        # Do not set focus on Length if length+angle input is problematic:
        force_xyz = False
        if f in ("x", "y", "z"):
            if not self.globalMode:
                if f == "z":
                    force_xyz = True
            else:
                axis = WorkingPlane.get_working_plane(update=False).axis
                constraint_dir = FreeCAD.Vector(
                    1 if f == "x" else 0, 1 if f == "y" else 0, 1 if f == "z" else 0
                )
                # Using a high tolerance:
                if axis.isEqual(constraint_dir, 0.1) or axis.isEqual(-constraint_dir, 0.1):
                    force_xyz = True

        if not force_xyz and params.get_param("focusOnLength") and self.lengthValue.isVisible():
            self.lengthValue.setFocus()
            self.lengthValue.setSelection(0, self.number_length(self.lengthValue.text()))
        elif not force_xyz and self.angleLock.isVisible() and self.angleLock.isChecked():
            self.lengthValue.setFocus()
            self.lengthValue.setSelection(0, self.number_length(self.lengthValue.text()))
        elif f == "x":
            self.xValue.setFocus()
            self.xValue.setSelection(0, self.number_length(self.xValue.text()))
        elif f == "y":
            self.yValue.setFocus()
            self.yValue.setSelection(0, self.number_length(self.yValue.text()))
        elif f == "z":
            self.zValue.setFocus()
            self.zValue.setSelection(0, self.number_length(self.zValue.text()))
        elif f == "radius":
            self.radiusValue.setFocus()
            self.radiusValue.setSelection(0, self.number_length(self.radiusValue.text()))
        else:
            # f is None
            self.xValue.setFocus()
            self.xValue.setSelection(0, self.number_length(self.xValue.text()))

    def number_length(self, st):
        nl = len(st)
        for char in st[::-1]:
            if char in "0123456789.,-+/":
                break
            nl -= 1
        return nl

    def extraLineUi(self):
        """shows length and angle controls"""
        self.labellength.show()
        self.lengthValue.show()
        self.labelangle.show()
        self.angleValue.show()
        self.angleLock.show()
        self.angleLock.setChecked(False)

    def hideXYZ(self):
        """turn off all the point entry widgets"""
        self.labelx.hide()
        self.labely.hide()
        self.labelz.hide()
        self.labellength.hide()
        self.labelangle.hide()
        self.xValue.hide()
        self.yValue.hide()
        self.zValue.hide()
        self.pointButton.hide()
        self.lengthValue.hide()
        self.angleValue.hide()
        self.angleLock.hide()
        self.isRelative.hide()
        self.isGlobal.hide()

    def lineUi(
        self,
        title=translate("draft", "Line"),
        cancel=None,
        extra=None,
        getcoords=None,
        rel=False,
        icon="Draft_Line",
    ):
        self.pointUi(title, cancel, extra, getcoords, rel, icon)
        self.extraLineUi()
        self.xValue.setEnabled(True)
        self.yValue.setEnabled(True)
        self.continueCmd.show()

    def wireUi(
        self,
        title=translate("draft", "DWire"),
        cancel=None,
        extra=None,
        getcoords=None,
        rel=False,
        icon="Draft_Wire",
    ):
        self.pointUi(title, cancel, extra, getcoords, rel, icon)
        self.xValue.setEnabled(True)
        self.yValue.setEnabled(True)
        if params.get_param("UsePartPrimitives"):
            self.makeFace.setEnabled(False)
        else:
            self.makeFace.setEnabled(True)
        self.makeFace.show()
        self.finishButton.show()
        self.closeButton.show()
        self.wipeButton.show()
        self.orientWPButton.show()
        self.undoButton.show()
        self.continueCmd.show()

    def circleUi(self):
        self.pointUi(translate("draft", "Circle"), icon="Draft_Circle")
        self.extUi()
        self.isRelative.hide()

    def arcUi(self):
        self.pointUi(translate("draft", "Arc"), icon="Draft_Arc")
        self.continueCmd.show()
        self.isRelative.hide()

    def rotateSetCenterUi(self):
        self.pointUi(translate("draft", "Rotate"), icon="Draft_Rotate")
        self.modUi()
        self.isRelative.hide()

    def pointUi(
        self,
        title=translate("draft", "Point"),
        cancel=None,
        extra=None,
        getcoords=None,
        rel=False,
        icon="Draft_Draft",
    ):
        if cancel:
            self.cancel = cancel
        if getcoords:
            self.pointcallback = getcoords
        self.taskUi(title, extra, icon)
        self.xValue.setEnabled(True)
        self.yValue.setEnabled(True)
        self.isRelative.show()
        self.isGlobal.show()
        self.checkLocal()
        self.labelx.show()
        self.labely.show()
        self.labelz.show()
        self.xValue.show()
        self.yValue.show()
        self.zValue.show()
        # reset UI to (0,0,0) on start
        self.xValue.setText(FreeCAD.Units.Quantity(0, FreeCAD.Units.Length).UserString)
        self.yValue.setText(FreeCAD.Units.Quantity(0, FreeCAD.Units.Length).UserString)
        self.zValue.setText(FreeCAD.Units.Quantity(0, FreeCAD.Units.Length).UserString)
        self.x = 0
        self.y = 0
        self.z = 0
        self.new_point = None
        self.last_point = None
        self.pointButton.show()
        if rel:
            self.isRelative.show()
        todo.delay(self.setFocus, None)

    def labelUi(self, title=translate("draft", "Label"), callback=None):
        w = QtWidgets.QWidget()
        w.setWindowTitle(translate("draft", "Label Type"))
        l = QtWidgets.QVBoxLayout(w)
        combo = QtWidgets.QComboBox()
        from draftobjects.label import get_label_types

        types = get_label_types()
        for s in types:
            combo.addItem(translate("Draft", s), userData=s)
        combo.setCurrentIndex(types.index(params.get_param("labeltype")))
        l.addWidget(combo)
        combo.currentIndexChanged.connect(callback)
        self.pointUi(title=title, extra=w, icon="Draft_Label")

    def extraUi(self):
        pass

    def offsetUi(self):
        self.taskUi(translate("draft", "Offset"), icon="Draft_Offset")
        self.radiusUi()
        self.isCopy.show()
        self.isCopy.setChecked(params.get_param("OffsetCopyMode"))
        self.occOffset.show()
        self.labelRadius.setText(translate("draft", "Distance"))
        self.radiusValue.setToolTip(translate("draft", "Offset distance"))
        self.radiusValue.setText(FreeCAD.Units.Quantity(0, FreeCAD.Units.Length).UserString)
        todo.delay(self.setFocus, "radius")

    def offUi(self):
        todo.delay(FreeCADGui.Control.closeDialog, None)
        self.cancel = None
        self.sourceCmd = None
        self.pointcallback = None
        self.mask = None
        self.isTaskOn = False
        self.baseWidget = QtWidgets.QWidget()

    def trimUi(self, title=translate("draft", "Trimex")):
        self.taskUi(title, icon="Draft_Trimex")
        self.radiusUi()
        self.labelRadius.setText(translate("draft", "Distance"))
        self.radiusValue.setToolTip(translate("draft", "Offset distance"))
        self.radiusValue.setText(FreeCAD.Units.Quantity(0, FreeCAD.Units.Length).UserString)
        todo.delay(self.setFocus, "radius")

    def radiusUi(self):
        self.hideXYZ()
        self.labelRadius.setText(translate("draft", "Radius"))
        self.radiusValue.setToolTip(translate("draft", "Radius of Circle"))
        self.labelRadius.show()
        self.radiusValue.setText(FreeCAD.Units.Quantity(0, FreeCAD.Units.Length).UserString)
        self.radiusValue.show()
        todo.delay(self.setFocus, "radius")

    def textUi(self):
        self.hideXYZ()
        self.textValue.show()
        self.textOkButton.show()
        self.textValue.setText("")
        todo.delay(self.textValue.setFocus, None)
        self.textbuffer = []
        self.textline = 0
        self.continueCmd.show()
        # Change the checkbox label as the in-command shortcut cannot be used:
        self.continueCmd.setText(translate("draft", "Continue"))

    def switchUi(self, store=True):
        if store:
            self.state = []
            self.state.append(self.labelx.isVisible())
            self.state.append(self.labely.isVisible())
            self.state.append(self.labelz.isVisible())
            self.state.append(self.xValue.isVisible())
            self.state.append(self.yValue.isVisible())
            self.state.append(self.zValue.isVisible())
            self.state.append(self.labellength.isVisible())
            self.state.append(self.labelangle.isVisible())
            self.state.append(self.pointButton.isVisible())
            self.state.append(self.lengthValue.isVisible())
            self.state.append(self.angleValue.isVisible())
            self.state.append(self.angleLock.isVisible())
            self.state.append(self.isRelative.isVisible())
            self.state.append(self.isGlobal.isVisible())
            self.hideXYZ()
        else:
            if self.state:
                if self.state[0]:
                    self.labelx.show()
                if self.state[1]:
                    self.labely.show()
                if self.state[2]:
                    self.labelz.show()
                if self.state[3]:
                    self.xValue.show()
                if self.state[4]:
                    self.yValue.show()
                if self.state[5]:
                    self.zValue.show()
                if self.state[6]:
                    self.labellength.show()
                if self.state[7]:
                    self.labelangle.show()
                if self.state[8]:
                    self.pointButton.show()
                if self.state[9]:
                    self.lengthValue.show()
                if self.state[10]:
                    self.angleValue.show()
                if self.state[11]:
                    self.angleLock.show()
                if self.state[12]:
                    self.isRelative.show()
                if self.state[13]:
                    self.isGlobal.show()
                self.state = None

    def setTitle(self, title, icon="Draft_Draft"):
        self.baseWidget.setWindowTitle(title)
        self.baseWidget.setWindowIcon(QtGui.QIcon(":/icons/" + icon + ".svg"))

    def selectUi(self, extra=None, on_close_call=None):
        self.makeDumbTask(extra, on_close_call)

    def editUi(self):
        self.makeDumbTask(on_close_call=self.finish)

    def extUi(self):
        if params.get_param("UsePartPrimitives"):
            self.makeFace.setEnabled(False)
        else:
            self.makeFace.setEnabled(True)
        self.makeFace.show()
        self.continueCmd.show()

    def modUi(self):
        self.isCopy.show()
        self.isSubelementMode.show()
        self.isCopy.setChecked(params.get_param("CopyMode"))
        self.continueCmd.show()

    def checkLocal(self):
        """checks if x,y,z coords must be displayed as local or global"""
        if not self.globalMode and self.relativeMode:
            self.labelx.setText(
                translate("draft", "Local {}").format("\u0394X")
            )  # \u0394 = ∆ (Greek delta)
            self.labely.setText(translate("draft", "Local {}").format("\u0394Y"))
            self.labelz.setText(translate("draft", "Local {}").format("\u0394Z"))
        elif not self.globalMode and not self.relativeMode:
            self.labelx.setText(translate("draft", "Local {}").format("X"))
            self.labely.setText(translate("draft", "Local {}").format("Y"))
            self.labelz.setText(translate("draft", "Local {}").format("Z"))
        elif self.globalMode and self.relativeMode:
            self.labelx.setText(translate("draft", "Global {}").format("\u0394X"))
            self.labely.setText(translate("draft", "Global {}").format("\u0394Y"))
            self.labelz.setText(translate("draft", "Global {}").format("\u0394Z"))
        else:
            self.labelx.setText(translate("draft", "Global {}").format("X"))
            self.labely.setText(translate("draft", "Global {}").format("Y"))
            self.labelz.setText(translate("draft", "Global {}").format("Z"))

    def setNextFocus(self):
        def isThere(widget):
            if widget.isEnabled() and widget.isVisible():
                return True
            else:
                return False

        if self.isTaskOn:
            if isThere(self.xValue):
                self.setFocus()
            elif isThere(self.yValue):
                self.yValue.setFocus()
                self.yValue.selectAll()
            elif isThere(self.zValue):
                self.zValue.setFocus()
                self.zValue.selectAll()
            elif isThere(self.radiusValue):
                self.radiusValue.setFocus()
                self.radiusValue.selectAll()

    def makeDumbTask(self, extra=None, on_close_call=None):
        """create a dumb taskdialog to prevent deleting the temp object"""

        class TaskPanel:
            def __init__(self, extra=None, callback=None):
                if extra:
                    self.form = [extra]
                self.callback = callback

            def getStandardButtons(self):
                return QtWidgets.QDialogButtonBox.Close

            def reject(self):
                if self.callback:
                    self.callback()
                return True

        todo.delay(FreeCADGui.Control.closeDialog, None)
        panel = TaskPanel(extra, on_close_call)
        todo.delay(self._show_dialog, panel)

    # ---------------------------------------------------------------------------
    # Processing functions
    # ---------------------------------------------------------------------------

    def setContinue(self, val):
        params.set_param(
            FreeCAD.activeDraftCommand.featureName,
            bool(getattr(val, "value", val)),
            "Mod/Draft/ContinueMode",
        )
        self.continueMode = bool(getattr(val, "value", val))
        self.chainedModeCmd.setEnabled(not bool(getattr(val, "value", val)))

    def setChainedMode(self, val):
        params.set_param("ChainedMode", bool(getattr(val, "value", val)))
        self.chainedMode = bool(getattr(val, "value", val))
        self.continueCmd.setEnabled(not bool(getattr(val, "value", val)))
        if bool(getattr(val, "value", val)) == False:
            # If user has deselected the checkbox, reactive the command
            # which will result in closing it
            FreeCAD.activeDraftCommand.Activated()

    # val=-1 is used to temporarily switch to relativeMode and disable the checkbox.
    # val=-2 is used to switch back.
    # Used by:
    #     gui_ellipses.py
    #     gui_rectangles.py
    #     gui_stretch.py
    def setRelative(self, val=-1):
        val = getattr(val, "value", val)
        if val < 0:
            if hasattr(self.isRelative, "checkStateChanged"):  # Qt version >= 6.7.0
                self.isRelative.checkStateChanged.disconnect(self.setRelative)
            else:  # Qt version < 6.7.0
                self.isRelative.stateChanged.disconnect(self.setRelative)
            if val == -1:
                self.isRelative.setChecked(True)
                self.relativeMode = True
            elif val == -2:
                val = params.get_param("RelativeMode")
                self.isRelative.setChecked(val)
                self.relativeMode = val
            if hasattr(self.isRelative, "checkStateChanged"):  # Qt version >= 6.7.0
                self.isRelative.checkStateChanged.connect(self.setRelative)
            else:  # Qt version < 6.7.0
                self.isRelative.stateChanged.connect(self.setRelative)
        else:
            params.set_param("RelativeMode", bool(val))
            self.relativeMode = bool(val)
        self.checkLocal()
        self.displayPoint(self.new_point, self.get_last_point())
        self.updateSnapper()

    def setGlobal(self, val):
        params.set_param("GlobalMode", bool(getattr(val, "value", val)))
        self.globalMode = bool(getattr(val, "value", val))
        self.checkLocal()
        self.displayPoint(self.new_point, self.get_last_point())
        self.updateSnapper()

    def setMakeFace(self, val):
        params.set_param("MakeFaceMode", bool(getattr(val, "value", val)))
        self.makeFaceMode = bool(getattr(val, "value", val))

    def setCopymode(self, val):
        # special value for offset command
        if self.sourceCmd and self.sourceCmd.featureName == "Offset":
            params.set_param("OffsetCopyMode", bool(getattr(val, "value", val)))
        else:
            params.set_param("CopyMode", bool(getattr(val, "value", val)))
            # if CopyMode is changed ghosts must be updated.
            # Moveable children should not be included if CopyMode is True.
            self.sourceCmd.set_ghosts()

    def setSubelementMode(self, val):
        params.set_param("SubelementMode", bool(getattr(val, "value", val)))
        self.sourceCmd.set_ghosts()

    def checkx(self):
        if self.yValue.isEnabled():
            self.yValue.setFocus()
            self.yValue.setSelection(0, self.number_length(self.yValue.text()))
            self.updateSnapper()
        else:
            self.checky()

    def checky(self):
        if self.zValue.isEnabled():
            self.zValue.setFocus()
            self.zValue.setSelection(0, self.number_length(self.zValue.text()))
            self.updateSnapper()
        else:
            self.validatePoint()

    def checklength(self):
        if self.angleValue.isEnabled():
            self.angleValue.setFocus()
            self.angleValue.setSelection(0, self.number_length(self.angleValue.text()))
            self.updateSnapper()
        else:
            self.validatePoint()

    def validatePoint(self):
        """function for checking and sending numbers entered manually"""
        self.mouse = True
        self.mouse_delay_input_start = time.time()
        if self.sourceCmd or self.pointcallback:
            if self.labelRadius.isVisible():
                try:
                    rad = self.radius
                except (ValueError, AttributeError):
                    print("debug: DraftGui.validatePoint: AttributeError")
                else:
                    self.sourceCmd.numericRadius(rad)
            elif self.labelx.isVisible():
                try:
                    numx = self.x
                    numy = self.y
                    numz = self.z
                except (ValueError, AttributeError):
                    print("debug: DraftGui.validatePoint: AttributeError")
                else:
                    delta = FreeCAD.Vector(numx, numy, numz)
                    if self.pointcallback:
                        self.pointcallback(delta, self.globalMode, self.relativeMode)
                    else:
                        self.new_point = self.get_new_point(delta)
                        self.sourceCmd.numericInput(*self.new_point)
            elif self.textValue.isVisible():
                return False
            else:
                FreeCADGui.ActiveDocument.resetEdit()
        return True

    def finish(self, cont=None):
        """finish button action"""
        if self.sourceCmd:
            if cont is None:
                cont = self.continueMode
            self.sourceCmd.finish(cont=cont)
        if self.cancel:
            self.cancel()
            self.cancel = None
        if FreeCADGui.ActiveDocument:
            FreeCADGui.ActiveDocument.resetEdit()

    def escape(self):
        """escapes the current command"""
        self.finish(cont=False)

    def closeLine(self):
        """close button action"""
        self.sourceCmd.finish(cont=self.continueMode, closed=True)
        FreeCADGui.ActiveDocument.resetEdit()

    def wipeLine(self):
        """wipes existing segments of a line"""
        self.sourceCmd.wipe()

    def orientWP(self):
        """reorients the current working plane"""
        self.sourceCmd.orientWP()

    def selectEdge(self):
        """allows the dimension command to select an edge"""
        if hasattr(self.sourceCmd, "selectEdge"):
            self.sourceCmd.selectEdge()

    def undoSegment(self):
        """undo last line segment"""
        if hasattr(self.sourceCmd, "undolast"):
            self.sourceCmd.undolast()

    def checkSpecialChars(self, txt):
        """checks for special characters in the entered coords that must be
        treated as shortcuts
        """

        if txt == "":
            self.updateSnapper()
            return

        if txt[0] in "0123456789.,-":
            self.updateSnapper()
            self.setMouseMode(mode=False)
            return

        txt = txt[0].upper()
        spec = False
        self.last_point = self.get_last_point()
        # Most frequently used shortcuts first:
        if txt == _get_incmd_shortcut("Relative"):
            if self.isRelative.isVisible():
                self.isRelative.setChecked(not self.isRelative.isChecked())
                # setRelative takes care of rest
            spec = True
        elif txt == _get_incmd_shortcut("Global"):
            if self.isGlobal.isVisible():
                self.isGlobal.setChecked(not self.isGlobal.isChecked())
                # setGlobal takes care of rest
            spec = True
        elif txt == _get_incmd_shortcut("Length"):
            if self.lengthValue.isVisible():
                self.constrain("angle")
            self.displayPoint(self.new_point, self.last_point)
            spec = True
        elif txt == _get_incmd_shortcut("RestrictX"):
            self.constrain("x")
            self.displayPoint(self.new_point, self.last_point)
            spec = True
        elif txt == _get_incmd_shortcut("RestrictY"):
            self.constrain("y")
            self.displayPoint(self.new_point, self.last_point)
            spec = True
        elif txt == _get_incmd_shortcut("RestrictZ"):
            self.constrain("z")
            self.displayPoint(self.new_point, self.last_point)
            spec = True
        elif txt == _get_incmd_shortcut("Copy"):
            if self.isCopy.isVisible():
                self.isCopy.setChecked(not self.isCopy.isChecked())
            spec = True
        elif txt == _get_incmd_shortcut("Exit"):
            if self.finishButton.isVisible():
                self.finish()
        elif txt == _get_incmd_shortcut("Close"):
            if self.closeButton.isVisible():
                self.closeLine()
        elif txt == _get_incmd_shortcut("AddHold"):
            if hasattr(FreeCADGui, "Snapper"):
                FreeCADGui.Snapper.addHoldPoint()
            spec = True
        elif txt == _get_incmd_shortcut("Recenter"):
            if hasattr(FreeCADGui, "Snapper"):
                FreeCADGui.Snapper.recenter_workingplane()
            spec = True
        elif txt == _get_incmd_shortcut("Snap"):
            self.togglesnap()
            spec = True
        elif txt == _get_incmd_shortcut("MakeFace"):
            if self.makeFace.isVisible():
                self.makeFace.setChecked(not self.makeFace.isChecked())
            spec = True
        elif txt == _get_incmd_shortcut("Continue"):
            if self.continueCmd.isVisible():
                self.toggleContinue()
            spec = True
        elif txt == _get_incmd_shortcut("SetWP"):
            if self.orientWPButton.isVisible():
                self.orientWP()
            spec = True
        elif txt == _get_incmd_shortcut("SelectEdge"):
            self.selectEdge()
            spec = True
        elif txt == _get_incmd_shortcut("SubelementMode"):
            if self.isSubelementMode.isVisible():
                self.isSubelementMode.setChecked(not self.isSubelementMode.isChecked())
            spec = True
        elif txt == _get_incmd_shortcut("Wipe"):
            if self.wipeButton.isVisible():
                self.wipeLine()
            spec = True
        elif txt == _get_incmd_shortcut("Undo"):
            self.undoSegment()
            spec = True
        elif txt == _get_incmd_shortcut("IncreaseRadius"):
            self.toggleradius(1)
            spec = True
        elif txt == _get_incmd_shortcut("DecreaseRadius"):
            self.toggleradius(-1)
            spec = True

        if spec:
            widget = self.baseWidget.focusWidget()
            field = self.input_fields[widget.objectName()]
            value = getattr(self, field["value"])
            unit = getattr(FreeCAD.Units, field["unit"])
            v = FreeCAD.Units.Quantity(value, unit).getUserPreferred()[0]
            widget.setProperty("text", v)
            widget.setFocus()
            widget.selectAll()
        self.updateSnapper()

    def updateSnapper(self):
        """updates the snapper track line if applicable"""
        if not self.xValue.isVisible():
            return
        if (
            hasattr(FreeCADGui, "Snapper")
            and FreeCADGui.Snapper.trackLine
            and FreeCADGui.Snapper.trackLine.Visible
        ):
            point = self.get_new_point(FreeCAD.Vector(self.x, self.y, self.z))
            FreeCADGui.Snapper.trackLine.p2(point)

    def setMouseMode(self, mode=True, recorded_input_start=0.0):
        """Sets self.mouse True (default) or False and sets a timer
        to set it back to True if applicable. self.mouse is then
        used by gui_tools_utils.get_point() to know if the mouse can
        update field values and point position or not."""
        if recorded_input_start and recorded_input_start != self.mouse_delay_input_start:
            # Do nothing if a new input sequence has started.
            return
        if mode:
            self.mouse = True
        elif self.mouse:
            delay = params.get_param("MouseDelay")
            if delay:
                self.mouse = False
                recorded_input_start = self.mouse_delay_input_start
                QtCore.QTimer.singleShot(
                    delay * 1000, lambda: self.setMouseMode(True, recorded_input_start)
                )

    def checkEnterText(self):
        """this function checks if the entered text ends with two blank lines"""
        t = self.textValue.toPlainText()
        if t.endswith("\n\n"):
            self.sendText()

    def sendText(self):
        """this function sends the entered text to the active draft command
        if enter has been pressed twice. Otherwise it blanks the line.
        """
        self.sourceCmd.text = (
            self.textValue.toPlainText()
            .replace("\\", "\\\\")
            .replace('"', '\\"')
            .replace("'", "\\'")
            .splitlines()
        )
        self.sourceCmd.createObject()

    def displayPoint(self, point=None, last=None, plane=None, mask=None):
        """Displays point values in the widgets and updates self."""
        if not self.isTaskOn:
            return

        self.display_point_active = True  # prevent cyclic processing of point values

        if point:
            if not plane:
                plane = WorkingPlane.get_working_plane(update=False)
            if not last:
                if self.globalMode:
                    last = FreeCAD.Vector()
                else:
                    last = plane.position

            self.new_point = FreeCAD.Vector(point)
            self.last_point = FreeCAD.Vector(last)

            if self.relativeMode:
                if self.globalMode:
                    delta = point - last
                else:
                    delta = plane.get_local_coords(point - last, as_vector=True)
            else:
                if self.globalMode:
                    delta = point
                else:
                    delta = plane.get_local_coords(point)

            length, _, phi = DraftVecUtils.get_spherical_coords(*delta)
            phi = math.degrees(phi)

            self.x = delta.x
            self.y = delta.y
            self.z = delta.z
            self.lvalue = length
            self.avalue = phi

            self.xValue.setText(display_external(delta.x, None, "Length"))
            self.yValue.setText(display_external(delta.y, None, "Length"))
            self.zValue.setText(display_external(delta.z, None, "Length"))
            self.lengthValue.setText(display_external(length, None, "Length"))
            self.angleValue.setText(display_external(phi, None, "Angle"))

        # set masks
        if (mask == "x") or (self.mask == "x"):
            self.xValue.setEnabled(True)
            self.yValue.setEnabled(False)
            self.zValue.setEnabled(False)
            self.angleValue.setEnabled(False)
            self.setFocus("x")
        elif (mask == "y") or (self.mask == "y"):
            self.xValue.setEnabled(False)
            self.yValue.setEnabled(True)
            self.zValue.setEnabled(False)
            self.angleValue.setEnabled(False)
            self.setFocus("y")
        elif (mask == "z") or (self.mask == "z"):
            self.xValue.setEnabled(False)
            self.yValue.setEnabled(False)
            self.zValue.setEnabled(True)
            self.angleValue.setEnabled(False)
            self.setFocus("z")
        else:
            self.xValue.setEnabled(True)
            self.yValue.setEnabled(True)
            self.zValue.setEnabled(True)
            self.angleValue.setEnabled(True)
            self.setFocus()

        self.display_point_active = False

    def getDefaultColor(self, typ, rgb=False):
        """gets color from the preferences or toolbar"""
        r = 0
        g = 0
        b = 0
        if typ == "snap":
            r, g, b, _ = utils.get_rgba_tuple(params.get_param("snapcolor"))
        elif typ == "ui":
            print(
                'draft: deprecation warning: Do not use getDefaultColor("ui") anymore - use getDefaultColor("line") instead.'
            )
            r = float(self.color.red() / 255.0)
            g = float(self.color.green() / 255.0)
            b = float(self.color.blue() / 255.0)
        elif typ == "line":
            r, g, b, _ = utils.get_rgba_tuple(params.get_param_view("DefaultShapeLineColor"))
        elif typ == "text":
            r, g, b, _ = utils.get_rgba_tuple(params.get_param("DefaultTextColor"))
        elif typ == "face":
            r, g, b, _ = utils.get_rgba_tuple(params.get_param_view("DefaultShapeColor"))
        elif typ == "constr":
            r, g, b, _ = utils.get_rgba_tuple(params.get_param("constructioncolor"))
        else:
            print("draft: error: couldn't get a color for ", typ, " typ.")
        if rgb:
            return (
                "rgb(" + str(int(r * 255)) + "," + str(int(g * 255)) + "," + str(int(b * 255)) + ")"
            )
        else:
            return (r, g, b)

    def cross(self, on=True):
        """deprecated"""
        pass

    def toggleConstrMode(self, checked):
        self.baseWidget.setStyleSheet(
            "#constrButton:Checked {background-color: "
            + self.getDefaultColor("constr", rgb=True)
            + " }"
        )
        self.constrMode = checked

    def toggleContinue(self):
        FreeCAD.Console.PrintMessage("toggle continue\n")
        self.continueMode = not self.continueMode
        try:
            if hasattr(self, "continueCmd"):
                if self.continueCmd.isVisible():
                    self.continueCmd.toggle()
            if hasattr(self, "panel"):
                if hasattr(self.panel, "form"):
                    if isinstance(self.panel.form, list):
                        for w in self.panel.form:
                            c = w.findChild(QtWidgets.QCheckBox, "ContinueCmd")
                            if c:
                                c.toggle()
                    else:
                        c = self.panel.form.findChild(QtWidgets.QCheckBox, "ContinueCmd")
                        if c:
                            c.toggle()
        except Exception:
            pass

    def isConstructionMode(self):
        return self.tray is not None and self.constrButton.isChecked()

    def selectplane(self):
        FreeCADGui.runCommand("Draft_SelectPlane")

    def setstyle(self):
        FreeCADGui.runCommand("Draft_SetStyle")

    def setStyleButton(self):
        "sets icon and text on the style button"
        linecolor = QtGui.QColor(utils.rgba_to_argb(params.get_param_view("DefaultShapeLineColor")))
        facecolor = QtGui.QColor(utils.rgba_to_argb(params.get_param_view("DefaultShapeColor")))
        im = QtGui.QImage(32, 32, QtGui.QImage.Format_ARGB32)
        im.fill(QtCore.Qt.transparent)
        pt = QtGui.QPainter(im)
        pt.setPen(QtGui.QPen(QtCore.Qt.black, 1, QtCore.Qt.SolidLine, QtCore.Qt.FlatCap))
        pt.setBrush(QtGui.QBrush(linecolor, QtCore.Qt.SolidPattern))
        pts = [QtCore.QPointF(4.0, 4.0), QtCore.QPointF(4.0, 26.0), QtCore.QPointF(26.0, 4.0)]
        pt.drawPolygon(pts, QtCore.Qt.OddEvenFill)
        pt.setBrush(QtGui.QBrush(facecolor, QtCore.Qt.SolidPattern))
        pts = [QtCore.QPointF(28.0, 28.0), QtCore.QPointF(8.0, 28.0), QtCore.QPointF(28.0, 8.0)]
        pt.drawPolygon(pts, QtCore.Qt.OddEvenFill)
        pt.end()
        icon = QtGui.QIcon(QtGui.QPixmap.fromImage(im))
        linewidth = params.get_param_view("DefaultShapeLineWidth")
        fontsize = params.get_param("textheight")
        txt = (
            str(linewidth)
            + "px | "
            + FreeCAD.Units.Quantity(fontsize, FreeCAD.Units.Length).UserString
        )
        self.styleButton.setIcon(icon)
        self.styleButton.setText(txt)

        # FOR BACKWARDS COMPATIBILITY
        self.color = linecolor
        self.facecolor = facecolor
        self.linewidth = linewidth
        self.fontsize = fontsize

    def popupMenu(self, llist, ilist=None, pos=None):
        """pops up a menu filled with the given list

        "---" in llist inserts a separator
        """
        self.groupmenu = QtWidgets.QMenu()
        for i, l in enumerate(llist):
            if "---" in l:
                self.groupmenu.addSeparator()
            elif ilist:
                self.groupmenu.addAction(ilist[i], l)
            else:
                self.groupmenu.addAction(l)
        if not pos:
            pos = FreeCADGui.getMainWindow().cursor().pos()
        self.groupmenu.popup(pos)
        self.groupmenu.triggered.connect(self.popupTriggered)

    def getIcon(self, iconpath):
        return QtGui.QIcon(iconpath)

    def popupTriggered(self, action):
        self.sourceCmd.proceed(str(action.text()))

    def setRadiusValue(self, val, unit=None):
        # print("DEBUG: setRadiusValue val: ", val, " unit: ", unit)
        if not isinstance(val, (int, float)):  # some code passes strings
            t = val
        elif unit:
            t = display_external(val, None, unit)
        else:
            t = display_external(val, None, None)
        self.radiusValue.setText(t)
        self.setFocus("radius")

    def runAutoGroup(self):
        FreeCADGui.runCommand("Draft_AutoGroup")

    def setAutoGroup(self, value=None):
        if value is None:
            self.autogroup = None
            self.autoGroupButton.setText(translate("draft", "None"))
            self.autoGroupButton.setIcon(
                QtGui.QIcon.fromTheme(
                    "Draft_AutoGroup_off", QtGui.QIcon(":/icons/button_invalid.svg")
                )
            )
            self.autoGroupButton.setToolTip(translate("draft", "Autogroup off"))
            self.autoGroupButton.setDown(False)
        else:
            obj = FreeCAD.ActiveDocument.getObject(value)
            if obj:
                self.autogroup = value
                self.autoGroupButton.setText(obj.Label)
                self.autoGroupButton.setIcon(obj.ViewObject.Icon)
                self.autoGroupButton.setToolTip(translate("draft", "Autogroup:") + " " + obj.Label)
                self.autoGroupButton.setDown(False)
            else:
                self.autogroup = None
                self.autoGroupButton.setText(translate("draft", "None"))
                self.autoGroupButton.setIcon(
                    QtGui.QIcon.fromTheme(
                        "Draft_AutoGroup_off", QtGui.QIcon(":/icons/button_invalid.svg")
                    )
                )
                self.autoGroupButton.setToolTip(translate("draft", "Autogroup off"))
                self.autoGroupButton.setDown(False)

    def getXPM(self, iconname, size=16):
        i = QtGui.QIcon(":/icons/" + iconname + ".svg")
        p = i.pixmap(size, size)
        a = QtCore.QByteArray()
        b = QtCore.QBuffer(a)
        b.open(QtCore.QIODevice.WriteOnly)
        p.save(b, "XPM")
        b.close()
        return str(a)

    def togglesnap(self):
        FreeCADGui.doCommand('FreeCADGui.runCommand("Draft_Snap_Lock")')

    def toggleradius(self, val):
        if hasattr(FreeCADGui, "Snapper"):
            par = params.get_param("snapRange")
            params.set_param("snapRange", max(0, par + val))
            FreeCADGui.Snapper.showradius()

    def constrain(self, val):
        if val == "angle":
            self.alock = not (self.alock)
            self.angleLock.setChecked(self.alock)
        elif self.mask == val:
            self.mask = None
            if hasattr(FreeCADGui, "Snapper"):
                FreeCADGui.Snapper.mask = None
        else:
            self.mask = val
            if hasattr(FreeCADGui, "Snapper"):
                FreeCADGui.Snapper.mask = val
                if self.new_point is not None:
                    self.new_point = FreeCADGui.Snapper.constrain(
                        self.new_point, self.get_last_point()
                    )

    def changeXValue(self, d):
        if self.display_point_active:
            return
        if not self.xValue.hasFocus():
            return
        self.x = d.Value
        self.update_spherical_coords()
        self.updateSnapper()

    def changeYValue(self, d):
        if self.display_point_active:
            return
        if not self.yValue.hasFocus():
            return
        self.y = d.Value
        self.update_spherical_coords()
        self.updateSnapper()

    def changeZValue(self, d):
        if self.display_point_active:
            return
        if not self.zValue.hasFocus():
            return
        self.z = d.Value
        self.update_spherical_coords()
        self.updateSnapper()

    def changeRadiusValue(self, d):
        if self.display_point_active:
            return
        if not self.radiusValue.hasFocus():
            return
        self.radius = d.Value

    def changeLengthValue(self, d):
        if self.display_point_active:
            return
        if not self.lengthValue.hasFocus():
            return
        self.lvalue = d.Value
        self.update_cartesian_coords()
        self.updateSnapper()

    def changeAngleValue(self, d):
        if self.display_point_active:
            return
        if not self.angleValue.hasFocus():
            return
        self.avalue = d.Value
        self.update_cartesian_coords()
        self.updateSnapper()
        if self.angleLock.isChecked():
            if not self.globalMode:
                plane = WorkingPlane.get_working_plane(update=False)
                angle_vec = plane.get_global_coords(self.angle, as_vector=True)
            else:
                angle_vec = self.angle
            FreeCADGui.Snapper.setAngle(angle_vec)

    def toggleAngle(self, b):
        self.alock = self.angleLock.isChecked()
        self.update_cartesian_coords()
        self.updateSnapper()
        if self.alock:
            if not self.globalMode:
                plane = WorkingPlane.get_working_plane(update=False)
                angle_vec = plane.get_global_coords(self.angle, as_vector=True)
            else:
                angle_vec = self.angle
            FreeCADGui.Snapper.setAngle(angle_vec)
        else:
            FreeCADGui.Snapper.setAngle()
            self.angle = None

    def update_spherical_coords(self):
        length, theta, phi = DraftVecUtils.get_spherical_coords(self.x, self.y, self.z)
        self.lvalue = length
        self.pvalue = math.degrees(theta)
        self.avalue = math.degrees(phi)
        self.angle = FreeCAD.Vector(DraftVecUtils.get_cartesian_coords(1, theta, phi))
        self.lengthValue.setText(display_external(self.lvalue, None, "Length"))
        self.angleValue.setText(display_external(self.avalue, None, "Angle"))

    def update_cartesian_coords(self):
        self.x, self.y, self.z = DraftVecUtils.get_cartesian_coords(
            self.lvalue, math.radians(self.pvalue), math.radians(self.avalue)
        )
        self.angle = FreeCAD.Vector(
            DraftVecUtils.get_cartesian_coords(
                1, math.radians(self.pvalue), math.radians(self.avalue)
            )
        )
        self.xValue.setText(display_external(self.x, None, "Length"))
        self.yValue.setText(display_external(self.y, None, "Length"))
        self.zValue.setText(display_external(self.z, None, "Length"))

    def get_last_point(self):
        """Get the last point in the GCS."""
        if getattr(self.sourceCmd, "node", []):
            return self.sourceCmd.node[-1]
        if self.last_point is not None:
            return self.last_point
        if self.globalMode:
            return FreeCAD.Vector()
        return WorkingPlane.get_working_plane(update=False).position

    def get_new_point(self, delta):
        """Get the new point in the GCS.

        The delta vector (from the task panel) can be global/local
        and relative/absolute.
        """
        if self.globalMode:
            base_point = FreeCAD.Vector()
        else:
            plane = WorkingPlane.get_working_plane(update=False)
            delta = plane.get_global_coords(delta, as_vector=True)
            base_point = plane.position
        if self.relativeMode:
            base_point = self.get_last_point()
        return base_point + delta

    # ---------------------------------------------------------------------------
    # TaskView operations
    # ---------------------------------------------------------------------------

    def setWatchers(self):
        class DraftCreateWatcher:
            def __init__(self):
                self.commands = [
                    "Draft_Line",
                    "Draft_Wire",
                    "Draft_Rectangle",
                    "Draft_Arc",
                    "Draft_Circle",
                    "Draft_BSpline",
                    "Draft_Text",
                    "Draft_Dimension",
                    "Draft_ShapeString",
                    "Draft_BezCurve",
                ]
                self.title = "Create objects"

            def shouldShow(self):
                return (FreeCAD.ActiveDocument is not None) and (
                    not FreeCADGui.Selection.getSelection()
                )

        class DraftModifyWatcher:
            def __init__(self):
                self.commands = [
                    "Draft_Move",
                    "Draft_Rotate",
                    "Draft_Scale",
                    "Draft_Offset",
                    "Draft_Trimex",
                    "Draft_Upgrade",
                    "Draft_Downgrade",
                    "Draft_Edit",
                ]
                self.title = translate("draft", "Modify Objects")

            def shouldShow(self):
                return (FreeCAD.ActiveDocument is not None) and (
                    FreeCADGui.Selection.getSelection() != []
                )

        FreeCADGui.Control.addTaskWatcher([DraftCreateWatcher(), DraftModifyWatcher()])

    def changeEvent(self, event):
        if event.type() == QtCore.QEvent.LanguageChange:
            # print("Language changed!")
            self.ui.retranslateUi(self)

    def Activated(self):
        self.setWatchers()
        if hasattr(self, "tray"):
            todo.delay(self.tray.show, None)

    def Deactivated(self):
        if FreeCAD.activeDraftCommand is not None:
            self.continueMode = False
            FreeCAD.activeDraftCommand.finish()
        FreeCADGui.Control.clearTaskWatcher()
        # self.tray = None
        if hasattr(self, "tray"):
            todo.delay(self.tray.hide, None)

    def reset_ui_values(self):
        """Method to reset task panel values"""
        self.x = 0
        self.y = 0
        self.z = 0
        self.new_point = None
        self.last_point = None
        self.lvalue = 0
        self.pvalue = 90
        self.avalue = 0
        self.angle = None
        self.radius = 0
        self.offset = 0


class FacebinderTaskPanel:
    """A TaskPanel for the facebinder"""

    def __init__(self):

        self.obj = None
        self.form = QtWidgets.QWidget()
        self.form.setObjectName("FacebinderTaskPanel")
        self.grid = QtWidgets.QGridLayout(self.form)
        self.grid.setObjectName("grid")
        self.title = QtWidgets.QLabel(self.form)
        self.grid.addWidget(self.title, 0, 0, 1, 2)

        # tree
        self.tree = QtWidgets.QTreeWidget(self.form)
        self.grid.addWidget(self.tree, 1, 0, 1, 2)
        self.tree.setColumnCount(2)
        self.tree.setHeaderLabels(["Name", "Subelement"])

        # buttons
        self.addButton = QtWidgets.QPushButton(self.form)
        self.addButton.setObjectName("addButton")
        self.addButton.setIcon(QtGui.QIcon(":/icons/Arch_Add.svg"))
        self.grid.addWidget(self.addButton, 3, 0, 1, 1)

        self.delButton = QtWidgets.QPushButton(self.form)
        self.delButton.setObjectName("delButton")
        self.delButton.setIcon(QtGui.QIcon(":/icons/Arch_Remove.svg"))
        self.grid.addWidget(self.delButton, 3, 1, 1, 1)

        self.addButton.clicked.connect(self.addElement)
        self.delButton.clicked.connect(self.removeElement)
        self.update()

    def isAllowedAlterSelection(self):
        return True

    def isAllowedAlterView(self):
        return True

    def getStandardButtons(self):
        return QtWidgets.QDialogButtonBox.Ok

    def update(self):
        """fills the treewidget"""
        self.tree.clear()
        if self.obj:
            for f in self.obj.Faces:
                if isinstance(f[1], tuple):
                    for subf in f[1]:
                        item = QtWidgets.QTreeWidgetItem(self.tree)
                        item.setText(0, f[0].Name)
                        item.setIcon(0, QtGui.QIcon(":/icons/Part_3D_object.svg"))
                        item.setText(1, subf)
                else:
                    item = QtWidgets.QTreeWidgetItem(self.tree)
                    item.setText(0, f[0].Name)
                    item.setIcon(0, QtGui.QIcon(":/icons/Part_3D_object.svg"))
                    item.setText(1, f[1])
        self.retranslateUi(self.form)

    def addElement(self):
        if self.obj:
            for sel in FreeCADGui.Selection.getSelectionEx("", 0):
                if sel.HasSubObjects:
                    obj = sel.Object
                    for elt in sel.SubElementNames:
                        if "Face" in elt:
                            flist = self.obj.Faces
                            found = False
                            for face in flist:
                                if face[0] == obj.Name:
                                    if isinstance(face[1], tuple):
                                        for subf in face[1]:
                                            if subf == elt:
                                                found = True
                                    else:
                                        if face[1] == elt:
                                            found = True
                            if not found:
                                flist.append((obj, elt))
                                self.obj.Faces = flist
                                FreeCAD.ActiveDocument.recompute()
            self.update()

    def removeElement(self):
        if self.obj:
            it = self.tree.currentItem()
            if it:
                obj = FreeCAD.ActiveDocument.getObject(str(it.text(0)))
                elt = str(it.text(1))
                flist = []
                for face in self.obj.Faces:
                    if face[0].Name != obj.Name:
                        flist.append(face)
                    else:
                        if isinstance(face[1], tuple):
                            for subf in face[1]:
                                if subf != elt:
                                    flist.append((obj, subf))
                        else:
                            if face[1] != elt:
                                flist.append(face)
                self.obj.Faces = flist
                FreeCAD.ActiveDocument.recompute()
            self.update()

    def accept(self):
        FreeCAD.ActiveDocument.recompute()
        FreeCADGui.ActiveDocument.resetEdit()
        return True

    def retranslateUi(self, TaskPanel):
        TaskPanel.setWindowTitle(QtWidgets.QApplication.translate("draft", "Faces", None))
        self.delButton.setText(QtWidgets.QApplication.translate("draft", "Remove", None))
        self.addButton.setText(QtWidgets.QApplication.translate("draft", "Add", None))
        self.title.setText(QtWidgets.QApplication.translate("draft", "Facebinder Elements", None))


# def translateWidget(w, context=None, disAmb=None):
#    '''translator for items where retranslateUi() is unavailable.
#    translates widget w and children.'''
#    #handle w itself
#    if w.metaObject().className() == "QWidget":
#        origText = None
#        origText = w.windowTitle()
#        if origText:
#            newText = translate(context, str(origText))
#            if newText:
#                w.setWindowTitle(newText)

#    #handle children
#    wKids = w.findChildren(QtWidgets.QWidget)
#    for i in wKids:
#        className = i.metaObject().className()
#        if hasattr(i,"text") and hasattr(i,"setText"):
#            origText = i.text()
#            newText = translate(context, str(origText))
#            if newText:
#                i.setText(newText)
#        elif hasattr(i,"title") and hasattr(i,"setTitle"):
#            origText = i.title()
#            newText = translate(context, str(origText))
#            if newText:
#                i.setTitle(newText)
#        elif hasattr(i,"itemText") and hasattr(i,"setItemText"):
#            for item in range(i.count()):
#                oldText = i.itemText(item)
#                newText = translate(context, str(origText))
#                if newText:
#                    i.setItemText(item,newText)
##for debugging:
##        else:
##            msg = "TranslateWidget: Can not translate widget: {0} type: {1}\n".format(w.objectName(),w.metaObject().className())
##            FreeCAD.Console.PrintMessage(msg)

if not hasattr(FreeCADGui, "draftToolBar"):
    FreeCADGui.draftToolBar = DraftToolBar()
# ----End of Python Features Definitions----#
