FreeCAD

Форк
0
/
DraftGui.py 
1804 строки · 75.2 Кб
1
# -*- coding: utf8 -*-
2
#***************************************************************************
3
#*   Copyright (c) 2009 Yorik van Havre <yorik@uncreated.net>              *
4
#*                                                                         *
5
#*   This program is free software; you can redistribute it and/or modify  *
6
#*   it under the terms of the GNU Lesser General Public License (LGPL)    *
7
#*   as published by the Free Software Foundation; either version 2 of     *
8
#*   the License, or (at your option) any later version.                   *
9
#*   for detail see the LICENCE text file.                                 *
10
#*                                                                         *
11
#*   This program is distributed in the hope that it will be useful,       *
12
#*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13
#*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14
#*   GNU Library General Public License for more details.                  *
15
#*                                                                         *
16
#*   You should have received a copy of the GNU Library General Public     *
17
#*   License along with this program; if not, write to the Free Software   *
18
#*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
19
#*   USA                                                                   *
20
#*                                                                         *
21
#***************************************************************************
22

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

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

35
"""This is the GUI part of the Draft module.
36
Report to Draft.py for info
37
"""
38

39
import os
40
import sys
41
import math
42
import PySide.QtCore as QtCore
43
import PySide.QtGui as QtGui
44
import PySide.QtWidgets as QtWidgets
45

46
import FreeCAD
47
import FreeCADGui
48
import Draft
49
import DraftVecUtils
50
import WorkingPlane
51
from draftutils import params
52
from draftutils import utils
53
from draftutils.todo import todo
54
from draftutils.translate import translate
55
from draftutils.units import display_external
56

57
translate("draft", "Relative")
58
translate("draft", "Global")
59
translate("draft", "Continue")
60
translate("draft", "Close")
61
translate("draft", "Copy")
62
translate("draft", "Subelement mode")
63
translate("draft", "Fill")
64
translate("draft", "Exit")
65
translate("draft", "Snap On/Off")
66
translate("draft", "Increase snap radius")
67
translate("draft", "Decrease snap radius")
68
translate("draft", "Restrict X")
69
translate("draft", "Restrict Y")
70
translate("draft", "Restrict Z")
71
translate("draft", "Select edge")
72
translate("draft", "Add custom snap point")
73
translate("draft", "Length mode")
74
translate("draft", "Wipe")
75
translate("draft", "Set Working Plane")
76
translate("draft", "Cycle snap object")
77
translate("draft", "Undo last segment")
78

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

82

83
#---------------------------------------------------------------------------
84
# Customized widgets
85
#---------------------------------------------------------------------------
86

87
class DraftBaseWidget(QtWidgets.QWidget):
88
    def __init__(self,parent = None):
89
        super().__init__(parent)
90
    def eventFilter(self, widget, event):
91
        if (event.type() == QtCore.QEvent.KeyPress
92
            and event.text().upper() == _get_incmd_shortcut("CycleSnap")):
93
            if hasattr(FreeCADGui,"Snapper"):
94
                FreeCADGui.Snapper.cycleSnapObject()
95
            return True
96
        return super().eventFilter(widget, event)
97

98
class DraftDockWidget(DraftBaseWidget):
99
    """custom Widget that emits a resized() signal when resized"""
100
    def __init__(self,parent = None):
101
        super().__init__(parent)
102
    def resizeEvent(self,event):
103
        self.emit(QtCore.SIGNAL("resized()"))
104
    def changeEvent(self, event):
105
        if event.type() == QtCore.QEvent.LanguageChange:
106
            self.emit(QtCore.SIGNAL("retranslate()"))
107
        else:
108
            super().changeEvent(event)
109

110
class DraftLineEdit(QtWidgets.QLineEdit):
111
    """custom QLineEdit widget that has the power to catch Escape keypress"""
112
    def __init__(self, parent=None):
113
        super().__init__(parent)
114
    def keyPressEvent(self, event):
115
        if event.key() == QtCore.Qt.Key_Escape:
116
            self.emit(QtCore.SIGNAL("escaped()"))
117
        elif event.key() == QtCore.Qt.Key_Up:
118
            self.emit(QtCore.SIGNAL("up()"))
119
        elif event.key() == QtCore.Qt.Key_Down:
120
            self.emit(QtCore.SIGNAL("down()"))
121
        else:
122
            super().keyPressEvent(event)
123

124
class DraftTaskPanel:
125
    def __init__(self,widget,extra=None):
126
        if extra:
127
            if isinstance(extra,list):
128
                self.form = [widget] + extra
129
            else:
130
                self.form = [widget,extra]
131
        else:
132
            self.form = widget
133
    def getStandardButtons(self):
134
        return int(QtWidgets.QDialogButtonBox.Close)
135
    def accept(self):
136
        if hasattr(FreeCADGui,"draftToolBar"):
137
            return FreeCADGui.draftToolBar.validatePoint()
138
        else:
139
            if FreeCADGui.ActiveDocument:
140
                FreeCADGui.ActiveDocument.resetEdit()
141
            return True
142
    def reject(self):
143
        FreeCADGui.draftToolBar.isTaskOn = False
144
        FreeCADGui.draftToolBar.escape()
145
        if FreeCADGui.ActiveDocument:
146
            FreeCADGui.ActiveDocument.resetEdit()
147
        return True
148
    def isAllowedAlterDocument(self):
149
        return False
150

151
class DraftToolBar:
152
    """The Draft Task panel UI
153
    Draft Toolbar is the main ui of the Draft Module. Once displayed as a
154
    toolbar, now it define the ui of the Task Panel.
155
    Toolbar become obsolete due to lack of manteinence and was disabled
156
    by default in February 2020.
157
    Draft Ui Commands call and get information such as point coordinates,
158
    subcommands activation, continue mode, etc. from Task Panel Ui
159
    """
160
    def __init__(self):
161
        self.tray = None
162
        self.sourceCmd = None
163
        self.mouse = True
164
        self.cancel = None
165
        self.pointcallback = None
166

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

173
        self.paramconstr = utils.rgba_to_argb(params.get_param("constructioncolor"))
174
        self.constrMode = False
175
        self.continueMode = False
176
        self.relativeMode = True
177
        self.globalMode = False
178
        self.state = None
179
        self.textbuffer = []
180
        self.crossedViews = []
181
        self.isTaskOn = False
182
        self.fillmode = True
183
        self.mask = None
184
        self.alock = False
185
        self.x = 0
186
        self.y = 0
187
        self.z = 0
188
        self.lvalue = 0
189
        self.pvalue = 90
190
        self.avalue = 0
191
        self.angle = None
192
        self.radius = 0
193
        self.offset = 0
194
        self.uiloader = FreeCADGui.UiLoader()
195
        self.autogroup = None
196
        self.isCenterPlane = False
197
        self.input_fields = {
198
            "xValue":{"value":"x","unit":"Length"},
199
            "yValue":{"value":"y","unit":"Length"},
200
            "zValue":{"value":"z","unit":"Length"},
201
            "lengthValue":{"value":"lvalue","unit":"Length"},
202
            "radiusValue":{"value":"radius","unit":"Length"},
203
            "angleValue":{"value":"avalue","unit":"Angle"}
204
        }
205

206
        # add only a dummy widget, since widgets are created on demand
207
        self.baseWidget = DraftBaseWidget()
208
        self.tray = QtWidgets.QToolBar(None)
209
        self.tray.setObjectName("Draft tray")
210
        self.tray.setWindowTitle("Draft tray")
211
        self.toptray = self.tray
212
        self.bottomtray = self.tray
213
        self.setupTray()
214
        self.setupStyle()
215
        mw = FreeCADGui.getMainWindow()
216
        mw.addToolBar(self.tray)
217
        self.tray.setParent(mw)
218
        self.tray.hide()
219

220
#---------------------------------------------------------------------------
221
# General UI setup
222
#---------------------------------------------------------------------------
223

224
    def _pushbutton(self,name, layout, hide=True, icon=None,
225
                    width=None, checkable=False, square=False):
226
        button = QtWidgets.QPushButton(self.baseWidget)
227
        button.setObjectName(name)
228
        if square:
229
            button.setMaximumSize(QtCore.QSize(button.height(), button.height()))
230
            button.setFlat(True)
231
        if hide:
232
            button.hide()
233
        if icon:
234
            if icon.endswith(".svg"):
235
                button.setIcon(QtGui.QIcon(icon))
236
            else:
237
                button.setIcon(QtGui.QIcon.fromTheme(
238
                    icon, QtGui.QIcon(':/icons/'+icon+'.svg')))
239
        if checkable:
240
            button.setCheckable(True)
241
            button.setChecked(False)
242
        layout.addWidget(button)
243
        return button
244

245
    def _label (self,name, layout, hide=True, wrap=False):
246
        label = QtWidgets.QLabel(self.baseWidget)
247
        label.setObjectName(name)
248
        if wrap:
249
            label.setWordWrap(True)
250
        if hide: label.hide()
251
        layout.addWidget(label)
252
        return label
253

254
    def _lineedit (self,name, layout, hide=True, width=None):
255
        bsize = params.get_param("ToolbarIconSize", path="General") - 2
256
        lineedit = DraftLineEdit(self.baseWidget)
257
        lineedit.setObjectName(name)
258
        if hide: lineedit.hide()
259
        #if not width: width = 800
260
        #lineedit.setMaximumSize(QtCore.QSize(width,bsize))
261
        layout.addWidget(lineedit)
262
        return lineedit
263

264
    def _inputfield (self,name, layout, hide=True, width=None):
265
        inputfield = self.uiloader.createWidget("Gui::InputField")
266
        inputfield.setObjectName(name)
267
        if hide: inputfield.hide()
268
        if not width:
269
            sizePolicy = QtWidgets.QSizePolicy(
270
                QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
271
            inputfield.setSizePolicy(sizePolicy)
272
            inputfield.setMinimumWidth(110)
273
        else:
274
            inputfield.setMaximumWidth(width)
275
        layout.addWidget(inputfield)
276
        return inputfield
277

278
    def _spinbox (self,name, layout, val=None, vmax=None,
279
                  hide=True, double=False, size=None):
280
        if double:
281
            sbox = QtWidgets.QDoubleSpinBox(self.baseWidget)
282
            sbox.setDecimals(params.get_param("Decimals", path="Units"))
283
        else:
284
            sbox = QtWidgets.QSpinBox(self.baseWidget)
285
        sbox.setObjectName(name)
286
        if vmax: sbox.setMaximum(vmax)
287
        if val: sbox.setValue(val)
288
        #if size: sbox.setMaximumSize(QtCore.QSize(size[0],size[1]))
289
        if hide: sbox.hide()
290
        layout.addWidget(sbox)
291
        return sbox
292

293
    def _checkbox (self,name, layout, checked=True, hide=True):
294
        chk = QtWidgets.QCheckBox(self.baseWidget)
295
        chk.setChecked(checked)
296
        chk.setObjectName(name)
297
        if hide: chk.hide()
298
        layout.addWidget(chk)
299
        return chk
300

301
    def _combo (self,name,layout,hide=True):
302
        cb = QtWidgets.QComboBox(self.baseWidget)
303
        cb.setObjectName(name)
304
        if hide: cb.hide()
305
        layout.addWidget(cb)
306

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

310
        # command
311

312
        self.promptlabel = self._label("promptlabel", self.layout, hide=task)
313
        self.cmdlabel = self._label("cmdlabel", self.layout, hide=task)
314
        boldtxt = QtGui.QFont()
315
        boldtxt.setWeight(75)
316
        boldtxt.setBold(True)
317
        self.cmdlabel.setFont(boldtxt)
318

319
        # point
320

321
        xl = QtWidgets.QHBoxLayout()
322
        yl = QtWidgets.QHBoxLayout()
323
        zl = QtWidgets.QHBoxLayout()
324
        bl = QtWidgets.QHBoxLayout()
325
        self.layout.addLayout(xl)
326
        self.layout.addLayout(yl)
327
        self.layout.addLayout(zl)
328
        self.layout.addLayout(bl)
329
        self.labelx = self._label("labelx", xl)
330
        self.xValue = self._inputfield("xValue", xl) #width=60
331
        self.xValue.installEventFilter(self.baseWidget)
332
        self.xValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Length).UserString)
333
        self.labely = self._label("labely", yl)
334
        self.yValue = self._inputfield("yValue", yl)
335
        self.yValue.installEventFilter(self.baseWidget) # Required to detect snap cycling in case of Y constraining.
336
        self.yValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Length).UserString)
337
        self.labelz = self._label("labelz", zl)
338
        self.zValue = self._inputfield("zValue", zl)
339
        self.zValue.installEventFilter(self.baseWidget) # Required to detect snap cycling in case of Z constraining.
340
        self.zValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Length).UserString)
341
        self.pointButton = self._pushbutton("addButton", bl, icon="Draft_AddPoint")
342

343
        # text
344

345
        self.textValue = QtWidgets.QTextEdit(self.baseWidget)
346
        self.textValue.setObjectName("textValue")
347
        self.textValue.setTabChangesFocus(True)
348
        self.layout.addWidget(self.textValue)
349
        self.textValue.hide()
350
        tl = QtWidgets.QHBoxLayout()
351
        self.layout.addLayout(tl)
352
        self.textOkButton = self._pushbutton("textButton", tl, icon="button_valid")
353

354
        # additional line controls
355

356
        ll = QtWidgets.QHBoxLayout()
357
        al = QtWidgets.QHBoxLayout()
358
        self.layout.addLayout(ll)
359
        self.layout.addLayout(al)
360
        self.labellength = self._label("labellength", ll)
361
        self.lengthValue = self._inputfield("lengthValue", ll)
362
        self.lengthValue.installEventFilter(self.baseWidget) # Required to detect snap cycling if focusOnLength is True.
363
        self.lengthValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Length).UserString)
364
        self.labelangle = self._label("labelangle", al)
365
        self.angleLock = self._checkbox("angleLock",al,checked=self.alock)
366
        self.angleValue = self._inputfield("angleValue", al)
367
        self.angleValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Angle).UserString)
368

369
        # options
370

371
        fl = QtWidgets.QHBoxLayout()
372
        self.layout.addLayout(fl)
373
        self.numFacesLabel = self._label("numfaceslabel", fl)
374
        self.numFaces = self._spinbox("numFaces", fl, 3)
375
        ol = QtWidgets.QHBoxLayout()
376
        self.layout.addLayout(ol)
377
        rl = QtWidgets.QHBoxLayout()
378
        self.layout.addLayout(rl)
379
        self.labelRadius = self._label("labelRadius", rl)
380
        self.radiusValue = self._inputfield("radiusValue", rl)
381
        self.radiusValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Length).UserString)
382
        bl = QtWidgets.QHBoxLayout()
383
        self.layout.addLayout(bl)
384
        self.undoButton = self._pushbutton("undoButton", bl, icon='Draft_Rotate')
385
        bl = QtWidgets.QHBoxLayout()
386
        self.layout.addLayout(bl)
387
        self.finishButton = self._pushbutton("finishButton", bl, icon='Draft_Finish')
388
        bl = QtWidgets.QHBoxLayout()
389
        self.layout.addLayout(bl)
390
        self.closeButton = self._pushbutton("closeButton", bl, icon='Draft_Lock')
391
        bl = QtWidgets.QHBoxLayout()
392
        self.layout.addLayout(bl)
393
        self.wipeButton = self._pushbutton("wipeButton", bl, icon='Draft_Wipe')
394
        bl = QtWidgets.QHBoxLayout()
395
        self.layout.addLayout(bl)
396
        self.orientWPButton = self._pushbutton("orientWPButton", bl, icon='Draft_SelectPlane')
397
        bl = QtWidgets.QHBoxLayout()
398
        self.layout.addLayout(bl)
399
        self.selectButton = self._pushbutton("selectButton", bl, icon='view-select')
400

401
        # update modes from parameters:
402
        self.relativeMode = params.get_param("RelativeMode")
403
        self.globalMode = params.get_param("GlobalMode")
404
        self.fillmode = params.get_param("fillmode")
405
        self.continueMode = params.get_param("ContinueMode")
406

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

410
        # update checkboxes with parameters and internal modes:
411
        self.isRelative = self._checkbox("isRelative", self.layout, checked=self.relativeMode)
412
        self.isGlobal = self._checkbox("isGlobal", self.layout, checked=self.globalMode)
413
        self.hasFill = self._checkbox("hasFill", self.layout, checked=self.fillmode)
414
        self.continueCmd = self._checkbox("continueCmd", self.layout, checked=self.continueMode)
415

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

419
        # update checkboxes with parameters but without internal modes:
420
        # self.isCopy is also updated in modUi ("CopyMode") and offsetUi ("OffsetCopyMode")
421
        self.isCopy = self._checkbox("isCopy",
422
                                     self.layout,
423
                                     checked=params.get_param("CopyMode"))
424
        self.isSubelementMode = self._checkbox("isSubelementMode",
425
                                               self.layout,
426
                                               checked=params.get_param("SubelementMode"))
427

428
        # spacer
429
        spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum,
430
                                       QtWidgets.QSizePolicy.Expanding)
431
        self.layout.addItem(spacerItem)
432

433
        QtCore.QObject.connect(self.xValue,QtCore.SIGNAL("valueChanged(double)"),self.changeXValue)
434
        QtCore.QObject.connect(self.yValue,QtCore.SIGNAL("valueChanged(double)"),self.changeYValue)
435
        QtCore.QObject.connect(self.zValue,QtCore.SIGNAL("valueChanged(double)"),self.changeZValue)
436
        QtCore.QObject.connect(self.lengthValue,QtCore.SIGNAL("valueChanged(double)"),self.changeLengthValue)
437
        QtCore.QObject.connect(self.angleValue,QtCore.SIGNAL("valueChanged(double)"),self.changeAngleValue)
438
        QtCore.QObject.connect(self.angleLock,QtCore.SIGNAL("stateChanged(int)"),self.toggleAngle)
439
        QtCore.QObject.connect(self.radiusValue,QtCore.SIGNAL("valueChanged(double)"),self.changeRadiusValue)
440
        QtCore.QObject.connect(self.xValue,QtCore.SIGNAL("returnPressed()"),self.checkx)
441
        QtCore.QObject.connect(self.yValue,QtCore.SIGNAL("returnPressed()"),self.checky)
442
        QtCore.QObject.connect(self.lengthValue,QtCore.SIGNAL("returnPressed()"),self.checklength)
443
        QtCore.QObject.connect(self.xValue,QtCore.SIGNAL("textEdited(QString)"),self.checkSpecialChars)
444
        QtCore.QObject.connect(self.yValue,QtCore.SIGNAL("textEdited(QString)"),self.checkSpecialChars)
445
        QtCore.QObject.connect(self.zValue,QtCore.SIGNAL("textEdited(QString)"),self.checkSpecialChars)
446
        QtCore.QObject.connect(self.lengthValue,QtCore.SIGNAL("textEdited(QString)"),self.checkSpecialChars)
447
        QtCore.QObject.connect(self.radiusValue,QtCore.SIGNAL("textEdited(QString)"),self.checkSpecialChars)
448
        QtCore.QObject.connect(self.angleValue,QtCore.SIGNAL("textEdited(QString)"),self.checkSpecialChars)
449
        QtCore.QObject.connect(self.zValue,QtCore.SIGNAL("returnPressed()"),self.validatePoint)
450
        QtCore.QObject.connect(self.pointButton,QtCore.SIGNAL("clicked()"),self.validatePoint)
451
        QtCore.QObject.connect(self.radiusValue,QtCore.SIGNAL("returnPressed()"),self.validatePoint)
452
        QtCore.QObject.connect(self.angleValue,QtCore.SIGNAL("returnPressed()"),self.validatePoint)
453
        QtCore.QObject.connect(self.textValue,QtCore.SIGNAL("textChanged()"),self.checkEnterText)
454
        QtCore.QObject.connect(self.textOkButton,QtCore.SIGNAL("clicked()"),self.sendText)
455
        QtCore.QObject.connect(self.zValue,QtCore.SIGNAL("returnPressed()"),self.setFocus)
456

457
        QtCore.QObject.connect(self.finishButton,QtCore.SIGNAL("pressed()"),self.finish)
458
        QtCore.QObject.connect(self.closeButton,QtCore.SIGNAL("pressed()"),self.closeLine)
459
        QtCore.QObject.connect(self.wipeButton,QtCore.SIGNAL("pressed()"),self.wipeLine)
460
        QtCore.QObject.connect(self.orientWPButton,QtCore.SIGNAL("pressed()"),self.orientWP)
461
        QtCore.QObject.connect(self.undoButton,QtCore.SIGNAL("pressed()"),self.undoSegment)
462
        QtCore.QObject.connect(self.selectButton,QtCore.SIGNAL("pressed()"),self.selectEdge)
463
        QtCore.QObject.connect(self.continueCmd,QtCore.SIGNAL("stateChanged(int)"),self.setContinue)
464

465
        QtCore.QObject.connect(self.isCopy,QtCore.SIGNAL("stateChanged(int)"),self.setCopymode)
466
        QtCore.QObject.connect(self.isSubelementMode, QtCore.SIGNAL("stateChanged(int)"), self.setSubelementMode)
467

468
        QtCore.QObject.connect(self.isRelative,QtCore.SIGNAL("stateChanged(int)"),self.setRelative)
469
        QtCore.QObject.connect(self.isGlobal,QtCore.SIGNAL("stateChanged(int)"),self.setGlobal)
470
        QtCore.QObject.connect(self.hasFill,QtCore.SIGNAL("stateChanged(int)"),self.setFill)
471
        QtCore.QObject.connect(self.baseWidget,QtCore.SIGNAL("resized()"),self.relocate)
472
        QtCore.QObject.connect(self.baseWidget,QtCore.SIGNAL("retranslate()"),self.retranslateUi)
473

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

477
        self.wplabel = self._pushbutton(
478
            "wplabel", self.toptray, icon='Draft_SelectPlane',
479
            hide=False,width=120)
480

481
        self.styleButton = self._pushbutton(
482
            "stylebutton", self.toptray, icon='Draft_Apply', hide=False,
483
            width=120)
484
        self.setStyleButton()
485
        self.constrButton = self._pushbutton(
486
            "constrButton", self.toptray, hide=False, icon='Draft_Construction',
487
             checkable=True, square=True)
488
        self.constrColor = QtGui.QColor(self.paramconstr)
489
        self.autoGroupButton = self._pushbutton(
490
            "autoGroup", self.bottomtray,icon=":/icons/button_invalid.svg",
491
            hide=False, width=120)
492
        self.autoGroupButton.setText(translate("draft", "None"))
493
        self.autoGroupButton.setFlat(True)
494

495
        QtCore.QObject.connect(self.wplabel,QtCore.SIGNAL("pressed()"),self.selectplane)
496
        QtCore.QObject.connect(self.styleButton,QtCore.SIGNAL("pressed()"),self.setstyle)
497
        QtCore.QObject.connect(self.constrButton,QtCore.SIGNAL("toggled(bool)"),self.toggleConstrMode)
498
        QtCore.QObject.connect(self.autoGroupButton,QtCore.SIGNAL("pressed()"),self.runAutoGroup)
499

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

502
    def setupStyle(self):
503
        style = "#constrButton:Checked {background-color: "
504
        style += self.getDefaultColor("constr",rgb=True)+" } "
505
        style += "#addButton:Checked, #delButton:checked, "
506
        style += "#sharpButton:Checked, "
507
        style += "#tangentButton:Checked, #symmetricButton:checked {"
508
        style += "background-color: rgb(20,100,250) }"
509
        self.baseWidget.setStyleSheet(style)
510
        #if hasattr(self,"tray"):
511
        #    self.tray.setStyleSheet(style)
512

513

514
#---------------------------------------------------------------------------
515
# language tools
516
#---------------------------------------------------------------------------
517

518
    def retranslateUi(self, widget=None):
519
        self.promptlabel.setText(translate("draft", "active command:"))
520
        self.cmdlabel.setText(translate("draft", "None"))
521
        self.cmdlabel.setToolTip(translate("draft", "Active Draft command"))
522
        self.xValue.setToolTip(translate("draft", "X coordinate of next point"))
523
        self.labelx.setText(translate("draft", "X"))
524
        self.labely.setText(translate("draft", "Y"))
525
        self.labelz.setText(translate("draft", "Z"))
526
        self.yValue.setToolTip(translate("draft", "Y coordinate of next point"))
527
        self.zValue.setToolTip(translate("draft", "Z coordinate of next point"))
528
        self.pointButton.setText(translate("draft", "Enter point"))
529
        self.pointButton.setToolTip(translate(
530
            "draft","Enter a new point with the given coordinates"))
531
        self.labellength.setText(translate("draft", "Length"))
532
        self.labelangle.setText(translate("draft", "Angle"))
533
        self.lengthValue.setToolTip(translate("draft", "Length of current segment"))
534
        self.angleValue.setToolTip(translate("draft", "Angle of current segment"))
535
        self.angleLock.setToolTip(translate(
536
            "draft", "Check this to lock the current angle")\
537
            + " (" + _get_incmd_shortcut("Length") + ")")
538
        self.labelRadius.setText(translate("draft", "Radius"))
539
        self.radiusValue.setToolTip(translate("draft", "Radius of Circle"))
540
        self.isRelative.setText(translate(
541
            "draft", "Relative") + " (" + _get_incmd_shortcut("Relative") + ")")
542
        self.isRelative.setToolTip(translate(
543
            "draft", "Coordinates relative to last point or to coordinate system "
544
                     + "origin\nif is the first point to set"))
545
        self.isGlobal.setText(translate(
546
            "draft", "Global") + " (" + _get_incmd_shortcut("Global") + ")")
547
        self.isGlobal.setToolTip(translate(
548
            "draft", "Coordinates relative to global coordinate system."
549
                     + "\nUncheck to use working plane coordinate system"))
550
        self.hasFill.setText(translate(
551
            "draft", "Filled") + " (" + _get_incmd_shortcut("Fill") + ")")
552
        self.hasFill.setToolTip(translate(
553
            "draft", "Check this if the object should appear as filled, "
554
                     + "otherwise it will appear as wireframe.\nNot available if "
555
                     + "Draft preference option 'Use Part Primitives' is enabled"))
556
        self.finishButton.setText(translate(
557
            "draft", "Finish") + " (" + _get_incmd_shortcut("Exit") + ")")
558
        self.finishButton.setToolTip(translate(
559
            "draft", "Finishes the current drawing or editing operation"))
560
        self.continueCmd.setToolTip(translate(
561
            "draft", "If checked, command will not finish until you press "
562
                     + "the command button again"))
563
        self.continueCmd.setText(translate(
564
            "draft", "Continue") + " (" + _get_incmd_shortcut("Continue") + ")")
565
        self.occOffset.setToolTip(translate(
566
            "draft", "If checked, an OCC-style offset will be performed"
567
                     + " instead of the classic offset"))
568
        self.occOffset.setText(translate("draft", "OCC-style offset"))
569

570
        self.undoButton.setText(translate("draft", "Undo") + " (" + _get_incmd_shortcut("Undo") + ")")
571
        self.undoButton.setToolTip(translate("draft", "Undo the last segment"))
572
        self.closeButton.setText(translate("draft", "Close") + " (" + _get_incmd_shortcut("Close") + ")")
573
        self.closeButton.setToolTip(translate("draft", "Finishes and closes the current line"))
574
        self.wipeButton.setText(translate("draft", "Wipe") + " (" + _get_incmd_shortcut("Wipe") + ")")
575
        self.wipeButton.setToolTip(translate("draft", "Wipes the existing segments of this line and starts again from the last point"))
576
        self.orientWPButton.setText(translate("draft", "Set WP") + " (" + _get_incmd_shortcut("SetWP") + ")")
577
        self.orientWPButton.setToolTip(translate("draft", "Reorients the working plane on the last segment"))
578
        self.selectButton.setText(translate("draft", "Select edge") + " (" + _get_incmd_shortcut("SelectEdge") + ")")
579
        self.selectButton.setToolTip(translate("draft", "Selects an existing edge to be measured by this dimension"))
580
        self.numFacesLabel.setText(translate("draft", "Sides"))
581
        self.numFaces.setToolTip(translate("draft", "Number of sides"))
582

583
        self.isCopy.setText(translate("draft", "Copy") + " (" + _get_incmd_shortcut("Copy") + ")")
584
        self.isCopy.setToolTip(translate("draft", "If checked, objects will be copied instead of moved"))
585
        self.isSubelementMode.setText(translate("draft", "Modify subelements") + " (" + _get_incmd_shortcut("SubelementMode") + ")")
586
        self.isSubelementMode.setToolTip(translate("draft", "If checked, subelements will be modified instead of entire objects"))
587
        self.textOkButton.setText(translate("draft", "Create text"))
588
        self.textOkButton.setToolTip(translate("draft", "Press this button to create the text object, or finish your text with two blank lines"))
589
        self.retranslateTray(widget)
590

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

599
        for i in pb:
600
            fm = QtGui.QFontMetrics(i.font())
601
            fw = fm.width(i.text())
602
            fw = max(fw, maxwidth)
603

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

608
    def retranslateTray(self,widget=None):
609

610
        self.styleButton.setToolTip(translate("draft", "Change default style for new objects"))
611
        self.constrButton.setToolTip(translate("draft", "Toggle construction mode"))
612
        self.autoGroupButton.setToolTip(translate("draft", "Autogroup off"))
613

614

615
#---------------------------------------------------------------------------
616
# Interface modes
617
#---------------------------------------------------------------------------
618

619
    def taskUi(self,title="Draft",extra=None,icon="Draft_Draft"):
620
        # reset InputField values
621
        self.reset_ui_values()
622
        self.isTaskOn = True
623
        todo.delay(FreeCADGui.Control.closeDialog,None)
624
        self.baseWidget = DraftBaseWidget()
625
        self.layout = QtWidgets.QVBoxLayout(self.baseWidget)
626
        self.setupToolBar(task=True)
627
        self.retranslateUi(self.baseWidget)
628
        self.panel = DraftTaskPanel(self.baseWidget,extra)
629
        todo.delay(FreeCADGui.Control.showDialog,self.panel)
630
        self.setTitle(title,icon)
631

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

636
    def setFocus(self,f=None):
637
        if params.get_param("focusOnLength") and self.lengthValue.isVisible():
638
            self.lengthValue.setFocus()
639
            self.lengthValue.setSelection(0,self.number_length(self.lengthValue.text()))
640
        elif self.angleLock.isVisible() and self.angleLock.isChecked():
641
            self.lengthValue.setFocus()
642
            self.lengthValue.setSelection(0,self.number_length(self.lengthValue.text()))
643
        elif (f is None) or (f == "x"):
644
            self.xValue.setFocus()
645
            self.xValue.setSelection(0,self.number_length(self.xValue.text()))
646
        elif f == "y":
647
            self.yValue.setFocus()
648
            self.yValue.setSelection(0,self.number_length(self.yValue.text()))
649
        elif f == "z":
650
            self.zValue.setFocus()
651
            self.zValue.setSelection(0,self.number_length(self.zValue.text()))
652
        elif f == "radius":
653
            self.radiusValue.setFocus()
654
            self.radiusValue.setSelection(0,self.number_length(self.radiusValue.text()))
655

656
    def number_length(self, str):
657
        nl = 0
658
        for char in str:
659
            if char in "0123456789.,-":
660
                nl += 1
661
        return nl
662

663
    def extraLineUi(self):
664
        '''shows length and angle controls'''
665
        self.labellength.show()
666
        self.lengthValue.show()
667
        self.labelangle.show()
668
        self.angleValue.show()
669
        self.angleLock.show()
670
        self.angleLock.setChecked(False)
671

672
    def hideXYZ(self):
673
        ''' turn off all the point entry widgets '''
674
        self.labelx.hide()
675
        self.labely.hide()
676
        self.labelz.hide()
677
        self.labellength.hide()
678
        self.labelangle.hide()
679
        self.xValue.hide()
680
        self.yValue.hide()
681
        self.zValue.hide()
682
        self.pointButton.hide()
683
        self.lengthValue.hide()
684
        self.angleValue.hide()
685
        self.angleLock.hide()
686
        self.isRelative.hide()
687
        self.isGlobal.hide()
688

689
    def lineUi(self, title=translate("draft", "Line"), cancel=None, extra=None,
690
               getcoords=None,rel=False,icon="Draft_Line"):
691
        self.pointUi(title, cancel, extra, getcoords, rel, icon)
692
        self.extraLineUi()
693
        self.xValue.setEnabled(True)
694
        self.yValue.setEnabled(True)
695
        self.continueCmd.show()
696

697
    def wireUi(self, title=translate("draft", "DWire"), cancel=None, extra=None,
698
               getcoords=None, rel=False, icon="Draft_Wire"):
699
        self.pointUi(title, cancel, extra, getcoords, rel, icon)
700
        self.xValue.setEnabled(True)
701
        self.yValue.setEnabled(True)
702
        if params.get_param("UsePartPrimitives"):
703
            self.hasFill.setEnabled(False)
704
        else:
705
            self.hasFill.setEnabled(True)
706
        self.hasFill.show()
707
        self.finishButton.show()
708
        self.closeButton.show()
709
        self.wipeButton.show()
710
        self.orientWPButton.show()
711
        self.undoButton.show()
712
        self.continueCmd.show()
713

714
    def circleUi(self):
715
        self.pointUi(translate("draft", "Circle"),icon="Draft_Circle")
716
        self.extUi()
717
        self.isRelative.hide()
718

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

724
    def rotateSetCenterUi(self):
725
        self.pointUi(translate("draft", "Rotate"),icon="Draft_Rotate")
726
        self.modUi()
727
        self.isRelative.hide()
728

729
    def pointUi(self, title=translate("draft","Point"), cancel=None, extra=None,
730
                getcoords=None, rel=False, icon="Draft_Draft"):
731
        if cancel: self.cancel = cancel
732
        if getcoords: self.pointcallback = getcoords
733
        self.taskUi(title,extra,icon)
734
        self.xValue.setEnabled(True)
735
        self.yValue.setEnabled(True)
736
        self.isRelative.show()
737
        self.isGlobal.show()
738
        self.checkLocal()
739
        self.labelx.show()
740
        self.labely.show()
741
        self.labelz.show()
742
        self.xValue.show()
743
        self.yValue.show()
744
        self.zValue.show()
745
        # reset UI to (0,0,0) on start
746
        self.xValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Length).UserString)
747
        self.yValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Length).UserString)
748
        self.zValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Length).UserString)
749
        self.x = 0
750
        self.y = 0
751
        self.z = 0
752
        self.pointButton.show()
753
        if rel: self.isRelative.show()
754
        todo.delay(self.setFocus,None)
755
        self.xValue.selectAll()
756

757
    def labelUi(self,title=translate("draft","Label"),callback=None):
758
        w = QtWidgets.QWidget()
759
        w.setWindowTitle(translate("draft","Label type"))
760
        l = QtWidgets.QVBoxLayout(w)
761
        combo = QtWidgets.QComboBox()
762
        from draftobjects.label import get_label_types
763
        types = get_label_types()
764
        for s in types:
765
            combo.addItem(translate("Draft", s), userData=s)
766
        combo.setCurrentIndex(types.index(params.get_param("labeltype")))
767
        l.addWidget(combo)
768
        QtCore.QObject.connect(combo,QtCore.SIGNAL("currentIndexChanged(int)"),callback)
769
        self.pointUi(title=title, extra=w, icon="Draft_Label")
770

771
    def extraUi(self):
772
        pass
773

774
    def offsetUi(self):
775
        self.taskUi(translate("draft","Offset"), icon="Draft_Offset")
776
        self.radiusUi()
777
        self.isCopy.show()
778
        self.isCopy.setChecked(params.get_param("OffsetCopyMode"))
779
        self.occOffset.show()
780
        self.labelRadius.setText(translate("draft","Distance"))
781
        self.radiusValue.setToolTip(translate("draft", "Offset distance"))
782
        self.radiusValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Length).UserString)
783
        todo.delay(self.radiusValue.setFocus,None)
784
        self.radiusValue.selectAll()
785

786
    def offUi(self):
787
        todo.delay(FreeCADGui.Control.closeDialog,None)
788
        self.cancel = None
789
        self.sourceCmd = None
790
        self.pointcallback = None
791
        self.mask = None
792
        self.isTaskOn = False
793
        self.baseWidget = QtWidgets.QWidget()
794

795
    def trimUi(self,title=translate("draft","Trimex")):
796
        self.taskUi(title, icon="Draft_Trimex")
797
        self.radiusUi()
798
        self.labelRadius.setText(translate("draft","Distance"))
799
        self.radiusValue.setToolTip(translate("draft", "Offset distance"))
800
        self.radiusValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Length).UserString)
801
        todo.delay(self.radiusValue.setFocus,None)
802
        self.radiusValue.selectAll()
803

804
    def radiusUi(self):
805
        self.hideXYZ()
806
        self.labelRadius.setText(translate("draft", "Radius"))
807
        self.radiusValue.setToolTip(translate("draft", "Radius of Circle"))
808
        self.labelRadius.show()
809
        self.radiusValue.setText(FreeCAD.Units.Quantity(0,FreeCAD.Units.Length).UserString)
810
        self.radiusValue.show()
811
        todo.delay(self.radiusValue.setFocus,None)
812
        self.radiusValue.selectAll()
813

814
    def textUi(self):
815
        self.hideXYZ()
816
        self.textValue.show()
817
        self.textOkButton.show()
818
        self.textValue.setText('')
819
        todo.delay(self.textValue.setFocus,None)
820
        self.textbuffer=[]
821
        self.textline=0
822
        self.continueCmd.show()
823
        # Change the checkbox label as the in-command shortcut cannot be used:
824
        self.continueCmd.setText(translate("draft", "Continue"))
825

826
    def switchUi(self,store=True):
827
        if store:
828
            self.state = []
829
            self.state.append(self.labelx.isVisible())
830
            self.state.append(self.labely.isVisible())
831
            self.state.append(self.labelz.isVisible())
832
            self.state.append(self.xValue.isVisible())
833
            self.state.append(self.yValue.isVisible())
834
            self.state.append(self.zValue.isVisible())
835
            self.hideXYZ()
836
        else:
837
            if self.state:
838
                if self.state[0]:self.labelx.show()
839
                if self.state[1]:self.labely.show()
840
                if self.state[2]:self.labelz.show()
841
                if self.state[3]:self.xValue.show()
842
                if self.state[4]:self.yValue.show()
843
                if self.state[5]:self.zValue.show()
844
                self.state = None
845

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

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

853
    def editUi(self):
854
        self.makeDumbTask(on_close_call=self.finish)
855

856
    def extUi(self):
857
        if params.get_param("UsePartPrimitives"):
858
            self.hasFill.setEnabled(False)
859
        else:
860
            self.hasFill.setEnabled(True)
861
        self.hasFill.show()
862
        self.continueCmd.show()
863

864
    def modUi(self):
865
        self.isCopy.show()
866
        self.isSubelementMode.show()
867
        self.isCopy.setChecked(params.get_param("CopyMode"))
868
        self.continueCmd.show()
869

870
    def checkLocal(self):
871
        """checks if x,y,z coords must be displayed as local or global"""
872
        if not self.globalMode and self.relativeMode:
873
            self.labelx.setText(translate("draft", "Local {}").format("\u0394X"))  # \u0394 = ∆ (Greek delta)
874
            self.labely.setText(translate("draft", "Local {}").format("\u0394Y"))
875
            self.labelz.setText(translate("draft", "Local {}").format("\u0394Z"))
876
        elif not self.globalMode and not self.relativeMode:
877
            self.labelx.setText(translate("draft", "Local {}").format("X"))
878
            self.labely.setText(translate("draft", "Local {}").format("Y"))
879
            self.labelz.setText(translate("draft", "Local {}").format("Z"))
880
        elif self.globalMode and self.relativeMode:
881
            self.labelx.setText(translate("draft", "Global {}").format("\u0394X"))
882
            self.labely.setText(translate("draft", "Global {}").format("\u0394Y"))
883
            self.labelz.setText(translate("draft", "Global {}").format("\u0394Z"))
884
        else:
885
            self.labelx.setText(translate("draft", "Global {}").format("X"))
886
            self.labely.setText(translate("draft", "Global {}").format("Y"))
887
            self.labelz.setText(translate("draft", "Global {}").format("Z"))
888

889
    def setNextFocus(self):
890
        def isThere(widget):
891
            if widget.isEnabled() and widget.isVisible():
892
                return True
893
            else:
894
                return False
895
        if self.isTaskOn:
896
            if isThere(self.xValue):
897
                self.setFocus()
898
            elif isThere(self.yValue):
899
                self.yValue.setFocus()
900
                self.yValue.selectAll()
901
            elif isThere(self.zValue):
902
                self.zValue.setFocus()
903
                self.zValue.selectAll()
904
            elif isThere(self.radiusValue):
905
                self.radiusValue.setFocus()
906
                self.radiusValue.selectAll()
907

908
    def relocate(self):
909
        """relocates the right-aligned buttons depending on the toolbar size"""
910
        if self.baseWidget.geometry().width() < 400:
911
            self.layout.setDirection(QtWidgets.QBoxLayout.TopToBottom)
912
        else:
913
            self.layout.setDirection(QtWidgets.QBoxLayout.LeftToRight)
914

915
    def makeDumbTask(self, extra=None, on_close_call=None):
916
        """create a dumb taskdialog to prevent deleting the temp object"""
917
        class TaskPanel:
918
            def __init__(self, extra=None, callback=None):
919
                if extra:
920
                    self.form = [extra]
921
                self.callback = callback
922
            def getStandardButtons(self):
923
                return int(QtWidgets.QDialogButtonBox.Close)
924
            def reject(self):
925
                if self.callback:
926
                    self.callback()
927
                return True
928
        todo.delay(FreeCADGui.Control.closeDialog,None)
929
        panel = TaskPanel(extra, on_close_call)
930
        todo.delay(FreeCADGui.Control.showDialog,panel)
931

932

933
#---------------------------------------------------------------------------
934
# Processing functions
935
#---------------------------------------------------------------------------
936

937
    def setContinue(self, val):
938
        params.set_param("ContinueMode", bool(val))
939
        self.continueMode = bool(val)
940

941
    # val=-1 is used to temporarily switch to relativeMode and disable the checkbox.
942
    # val=-2 is used to switch back.
943
    # Used by:
944
    #     gui_ellipses.py
945
    #     gui_rectangles.py
946
    #     gui_stretch.py
947
    def setRelative(self, val=-1):
948
        if val < 0:
949
            QtCore.QObject.disconnect(self.isRelative,
950
                                      QtCore.SIGNAL("stateChanged(int)"),
951
                                      self.setRelative)
952
            if val == -1:
953
                self.isRelative.setChecked(True)
954
                self.relativeMode = True
955
            elif val == -2:
956
                val = params.get_param("RelativeMode")
957
                self.isRelative.setChecked(val)
958
                self.relativeMode = val
959
            QtCore.QObject.connect(self.isRelative,
960
                                   QtCore.SIGNAL("stateChanged(int)"),
961
                                   self.setRelative)
962
        else:
963
            params.set_param("RelativeMode", bool(val))
964
            self.relativeMode = bool(val)
965
        self.checkLocal()
966

967
    def setGlobal(self, val):
968
        params.set_param("GlobalMode", bool(val))
969
        self.globalMode = bool(val)
970
        self.checkLocal()
971

972
    def setFill(self, val):
973
        params.set_param("fillmode", bool(val))
974
        self.fillmode = bool(val)
975

976
    def setCopymode(self, val):
977
        # special value for offset command
978
        if self.sourceCmd and self.sourceCmd.featureName == "Offset":
979
            params.set_param("OffsetCopyMode", bool(val))
980
        else:
981
            params.set_param("CopyMode", bool(val))
982

983
    def setSubelementMode(self, val):
984
        params.set_param("SubelementMode", bool(val))
985
        self.sourceCmd.set_ghosts()
986

987
    def checkx(self):
988
        if self.yValue.isEnabled():
989
            self.yValue.setFocus()
990
            self.yValue.setSelection(0,self.number_length(self.yValue.text()))
991
            self.updateSnapper()
992
        else:
993
            self.checky()
994

995
    def checky(self):
996
        if self.zValue.isEnabled():
997
            self.zValue.setFocus()
998
            self.zValue.setSelection(0,self.number_length(self.zValue.text()))
999
            self.updateSnapper()
1000
        else:
1001
            self.validatePoint()
1002

1003
    def checklength(self):
1004
        if self.angleValue.isEnabled():
1005
            self.angleValue.setFocus()
1006
            self.angleValue.setSelection(0,self.number_length(self.angleValue.text()))
1007
            self.updateSnapper()
1008
        else:
1009
            self.validatePoint()
1010

1011
    def validatePoint(self):
1012
        """function for checking and sending numbers entered manually"""
1013
        if self.sourceCmd or self.pointcallback:
1014
            if (self.labelRadius.isVisible()):
1015
                try:
1016
                    #rad=float(self.radiusValue.text())
1017
                    rad = self.radius
1018
                except (ValueError, AttributeError):
1019
                    print("debug: DraftGui.validatePoint: AttributeError")
1020
                else:
1021
                    self.sourceCmd.numericRadius(rad)
1022
            elif (self.labelx.isVisible()):
1023
                try:
1024
                    #numx=float(self.xValue.text())
1025
                    numx = self.x
1026
                    #numy=float(self.yValue.text())
1027
                    numy = self.y
1028
                    #numz=float(self.zValue.text())
1029
                    numz = self.z
1030
                except (ValueError, AttributeError):
1031
                    print("debug: DraftGui.validatePoint: AttributeError")
1032
                else:
1033
                    num_vec = FreeCAD.Vector(numx, numy, numz)
1034
                    if self.pointcallback:
1035
                        self.pointcallback(num_vec, self.globalMode, self.relativeMode)
1036
                    else:
1037
                        plane = WorkingPlane.get_working_plane(update=False)
1038
                        ref_vec = FreeCAD.Vector(0, 0, 0)
1039
                        if plane and not self.globalMode:
1040
                            num_vec = plane.get_global_coords(num_vec, as_vector=True)
1041
                            ref_vec = plane.get_global_coords(ref_vec)
1042
                        if self.relativeMode and self.sourceCmd.node:
1043
                            ref_vec = self.sourceCmd.node[-1]
1044

1045
                        numx, numy, numz = num_vec + ref_vec
1046
                        self.sourceCmd.numericInput(numx, numy, numz)
1047

1048
            elif self.textValue.isVisible():
1049
                return False
1050
            else:
1051
                FreeCADGui.ActiveDocument.resetEdit()
1052
        return True
1053

1054
    def finish(self, cont=None):
1055
        """finish button action"""
1056
        if self.sourceCmd:
1057
            if cont is None:
1058
                cont = self.continueMode
1059
            self.sourceCmd.finish(cont=cont)
1060
        if self.cancel:
1061
            self.cancel()
1062
            self.cancel = None
1063
        if FreeCADGui.ActiveDocument:
1064
            FreeCADGui.ActiveDocument.resetEdit()
1065

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

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

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

1079
    def orientWP(self):
1080
        """reorients the current working plane"""
1081
        self.sourceCmd.orientWP()
1082

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

1088
    def undoSegment(self):
1089
        """undo last line segment"""
1090
        if hasattr(self.sourceCmd,"undolast"):
1091
            self.sourceCmd.undolast()
1092

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

1098
        if txt == "" or txt[0] in "0123456789.,-":
1099
            self.updateSnapper()
1100
            if txt[0] in "0123456789.,-":
1101
                self.setMouseMode(False)
1102
            return
1103

1104
        txt = txt[0].upper()
1105
        spec = False
1106
        # Most frequently used shortcuts first:
1107
        if txt == _get_incmd_shortcut("Relative"):
1108
            if self.isRelative.isVisible():
1109
                self.isRelative.setChecked(not self.isRelative.isChecked())
1110
                self.relativeMode = self.isRelative.isChecked()
1111
            spec = True
1112
        elif txt == _get_incmd_shortcut("Global"):
1113
            if self.isGlobal.isVisible():
1114
                self.isGlobal.setChecked(not self.isGlobal.isChecked())
1115
                self.globalMode = self.isGlobal.isChecked()
1116
            spec = True
1117
        elif txt == _get_incmd_shortcut("Length"):
1118
            if self.lengthValue.isVisible():
1119
                self.constrain("angle")
1120
                self.displayPoint()
1121
            spec = True
1122
        elif txt == _get_incmd_shortcut("RestrictX"):
1123
            self.constrain("x")
1124
            self.displayPoint()
1125
            spec = True
1126
        elif txt == _get_incmd_shortcut("RestrictY"):
1127
            self.constrain("y")
1128
            self.displayPoint()
1129
            spec = True
1130
        elif txt == _get_incmd_shortcut("RestrictZ"):
1131
            self.constrain("z")
1132
            self.displayPoint()
1133
            spec = True
1134
        elif txt == _get_incmd_shortcut("Copy"):
1135
            if self.isCopy.isVisible():
1136
                self.isCopy.setChecked(not self.isCopy.isChecked())
1137
            spec = True
1138
        elif txt == _get_incmd_shortcut("Exit"):
1139
            if self.finishButton.isVisible():
1140
                self.finish()
1141
        elif txt == _get_incmd_shortcut("Close"):
1142
            if self.closeButton.isVisible():
1143
                self.closeLine()
1144
        elif txt == _get_incmd_shortcut("AddHold"):
1145
            if hasattr(FreeCADGui,"Snapper"):
1146
                FreeCADGui.Snapper.addHoldPoint()
1147
            spec = True
1148
        elif txt == _get_incmd_shortcut("Snap"):
1149
            self.togglesnap()
1150
            spec = True
1151
        elif txt == _get_incmd_shortcut("Fill"):
1152
            if self.hasFill.isVisible():
1153
                self.hasFill.setChecked(not self.hasFill.isChecked())
1154
            spec = True
1155
        elif txt == _get_incmd_shortcut("Continue"):
1156
            if self.continueCmd.isVisible():
1157
                self.toggleContinue()
1158
            spec = True
1159
        elif txt == _get_incmd_shortcut("SetWP"):
1160
            if self.orientWPButton.isVisible():
1161
                self.orientWP()
1162
            spec = True
1163
        elif txt == _get_incmd_shortcut("SelectEdge"):
1164
            self.selectEdge()
1165
            spec = True
1166
        elif txt == _get_incmd_shortcut("SubelementMode"):
1167
            if self.isSubelementMode.isVisible():
1168
                self.isSubelementMode.setChecked(not self.isSubelementMode.isChecked())
1169
            spec = True
1170
        elif txt == _get_incmd_shortcut("Wipe"):
1171
            if self.wipeButton.isVisible():
1172
                self.wipeLine()
1173
            spec = True
1174
        elif txt == _get_incmd_shortcut("Undo"):
1175
            self.undoSegment()
1176
            spec = True
1177
        elif txt == _get_incmd_shortcut("IncreaseRadius"):
1178
            self.toggleradius(1)
1179
            spec = True
1180
        elif txt == _get_incmd_shortcut("DecreaseRadius"):
1181
            self.toggleradius(-1)
1182
            spec = True
1183

1184
        if spec:
1185
            widget = self.baseWidget.focusWidget()
1186
            field = self.input_fields[widget.objectName()]
1187
            value = getattr(self, field["value"])
1188
            unit = getattr(FreeCAD.Units, field["unit"])
1189
            v = FreeCAD.Units.Quantity(value, unit).getUserPreferred()[0]
1190
            widget.setProperty("text",v)
1191
            widget.setFocus()
1192
            widget.selectAll()
1193
        self.updateSnapper()
1194

1195
    def updateSnapper(self):
1196
        """updates the snapper track line if applicable"""
1197
        if hasattr(FreeCADGui,"Snapper"):
1198
            if FreeCADGui.Snapper.trackLine:
1199
                if FreeCADGui.Snapper.trackLine.Visible:
1200
                    last = FreeCAD.Vector(0,0,0)
1201
                    if not self.xValue.isVisible():
1202
                        return
1203
                    if self.isRelative.isChecked():
1204
                        if self.sourceCmd:
1205
                            if hasattr(self.sourceCmd,"node"):
1206
                                if self.sourceCmd.node:
1207
                                    last = self.sourceCmd.node[-1]
1208
                    plane = WorkingPlane.get_working_plane(update=False)
1209
                    delta = plane.get_global_coords(
1210
                        FreeCAD.Vector(self.x,self.y,self.z))
1211
                    FreeCADGui.Snapper.trackLine.p2(last.add(delta))
1212

1213
    def setMouseMode(self, mode=True):
1214
        """Sets self.mouse True (default) or False and sets a timer
1215
        to set it back to True if applicable. self.mouse is then
1216
        used by gui_tools_utils.get_point() to know if the mouse can
1217
        update field values and point position or not."""
1218
        if mode == True:
1219
            self.mouse = True
1220
        else:
1221
            delay = params.get_param("MouseDelay")
1222
            if delay:
1223
                if self.mouse is True:
1224
                    self.mouse = False
1225
                    QtCore.QTimer.singleShot(delay*1000, self.setMouseMode)
1226

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

1233
    def sendText(self):
1234
        """this function sends the entered text to the active draft command
1235
        if enter has been pressed twice. Otherwise it blanks the line.
1236
        """
1237
        self.sourceCmd.text = self.textValue.toPlainText()\
1238
            .replace("\\","\\\\")\
1239
            .replace("\"","\\\"")\
1240
            .replace("\'","\\\'")\
1241
            .splitlines()
1242
        self.sourceCmd.createObject()
1243

1244
    def displayPoint(self, point=None, last=None, plane=None, mask=None):
1245
        """this function displays the passed coords in the x, y, and z widgets"""
1246
        if not self.isTaskOn:
1247
            return
1248

1249
        if not plane:
1250
            plane = WorkingPlane.get_working_plane(update=False)
1251
        # get coords to display
1252
        if not last:
1253
            if self.globalMode:
1254
                last = FreeCAD.Vector(0,0,0)
1255
            else:
1256
                last = plane.position
1257
        dp = None
1258
        if point:
1259
            dp = point
1260
            if self.relativeMode: # and (last is not None):
1261
                if self.globalMode:
1262
                    dp = point - last
1263
                else:
1264
                    dp = plane.get_local_coords(point - last, as_vector=True)
1265
            else:
1266
                if self.globalMode:
1267
                    dp = point
1268
                else:
1269
                    dp = plane.get_local_coords(point)
1270
        # set widgets
1271
        if dp:
1272
            if self.mask in ['y','z']:
1273
                self.xValue.setText(display_external(dp.x,None,'Length'))
1274
            else:
1275
                self.xValue.setText(display_external(dp.x,None,'Length'))
1276
            if self.mask in ['x','z']:
1277
                self.yValue.setText(display_external(dp.y,None,'Length'))
1278
            else:
1279
                self.yValue.setText(display_external(dp.y,None,'Length'))
1280
            if self.mask in ['x','y']:
1281
                self.zValue.setText(display_external(dp.z,None,'Length'))
1282
            else:
1283
                self.zValue.setText(display_external(dp.z,None,'Length'))
1284

1285
        # set length and angle
1286
        if last and dp and plane:
1287
            length, theta, phi = DraftVecUtils.get_spherical_coords(*dp)
1288
            theta = math.degrees(theta)
1289
            phi = math.degrees(phi)
1290
            self.lengthValue.setText(display_external(length,None,'Length'))
1291
            #if not self.angleLock.isChecked():
1292
            self.angleValue.setText(display_external(phi,None,'Angle'))
1293
            if not mask:
1294
                # automask, phi is rounded to identify one of the below cases
1295
                phi = round(phi, Draft.precision())
1296
                if phi in [0,180,-180]:
1297
                    mask = "x"
1298
                elif phi in [90,270,-90,-270]:
1299
                    mask = "y"
1300

1301
        # set masks
1302
        if (mask == "x") or (self.mask == "x"):
1303
            self.xValue.setEnabled(True)
1304
            self.yValue.setEnabled(False)
1305
            self.zValue.setEnabled(False)
1306
            self.angleValue.setEnabled(False)
1307
            self.setFocus()
1308
        elif (mask == "y") or (self.mask == "y"):
1309
            self.xValue.setEnabled(False)
1310
            self.yValue.setEnabled(True)
1311
            self.zValue.setEnabled(False)
1312
            self.angleValue.setEnabled(False)
1313
            self.setFocus("y")
1314
        elif (mask == "z") or (self.mask == "z"):
1315
            self.xValue.setEnabled(False)
1316
            self.yValue.setEnabled(False)
1317
            self.zValue.setEnabled(True)
1318
            self.angleValue.setEnabled(False)
1319
            self.setFocus("z")
1320
        else:
1321
            self.xValue.setEnabled(True)
1322
            self.yValue.setEnabled(True)
1323
            self.zValue.setEnabled(True)
1324
            self.angleValue.setEnabled(True)
1325
            self.setFocus()
1326

1327

1328
    def getDefaultColor(self, typ, rgb=False):
1329
        """gets color from the preferences or toolbar"""
1330
        r = 0
1331
        g = 0
1332
        b = 0
1333
        if typ == "snap":
1334
            r, g, b, _ = utils.get_rgba_tuple(params.get_param("snapcolor"))
1335
        elif typ == "ui":
1336
            print("draft: deprecation warning: Do not use getDefaultColor(\"ui\") anymore - use getDefaultColor(\"line\") instead.")
1337
            r = float(self.color.red() / 255.0)
1338
            g = float(self.color.green() / 255.0)
1339
            b = float(self.color.blue() / 255.0)
1340
        elif typ == "line":
1341
            r, g, b, _ = utils.get_rgba_tuple(params.get_param_view("DefaultShapeLineColor"))
1342
        elif typ == "text":
1343
            r, g, b, _ = utils.get_rgba_tuple(params.get_param("DefaultTextColor"))
1344
        elif typ == "face":
1345
            r, g, b, _ = utils.get_rgba_tuple(params.get_param_view("DefaultShapeColor"))
1346
        elif typ == "constr":
1347
            r, g, b, _ = utils.get_rgba_tuple(params.get_param("constructioncolor"))
1348
        else:
1349
            print("draft: error: couldn't get a color for ", typ, " typ.")
1350
        if rgb:
1351
            return("rgb(" + str(int(r * 255)) + "," + str(int(g * 255)) + "," + str(int(b * 255)) + ")")
1352
        else:
1353
            return (r,g,b)
1354

1355
    def cross(self,on=True):
1356
        """deprecated"""
1357
        pass
1358

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

1365
    def toggleContinue(self):
1366
        FreeCAD.Console.PrintMessage("toggle continue\n")
1367
        self.continueMode = not self.continueMode
1368
        try:
1369
            if hasattr(self,"continueCmd"):
1370
                if self.continueCmd.isVisible():
1371
                    self.continueCmd.toggle()
1372
            if hasattr(self,"panel"):
1373
                if hasattr(self.panel,"form"):
1374
                    if isinstance(self.panel.form,list):
1375
                        for w in self.panel.form:
1376
                            c = w.findChild(QtWidgets.QCheckBox,"ContinueCmd")
1377
                            if c:
1378
                                c.toggle()
1379
                    else:
1380
                        c = self.panel.form.findChild(QtWidgets.QCheckBox,"ContinueCmd")
1381
                        if c:
1382
                            c.toggle()
1383
        except Exception:
1384
            pass
1385

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

1389
    def selectplane(self):
1390
        FreeCADGui.runCommand("Draft_SelectPlane")
1391

1392
    def setstyle(self):
1393
        FreeCADGui.runCommand("Draft_SetStyle")
1394

1395
    def setStyleButton(self):
1396
        "sets icon and text on the style button"
1397
        linecolor = QtGui.QColor(utils.rgba_to_argb(params.get_param_view("DefaultShapeLineColor")))
1398
        facecolor = QtGui.QColor(utils.rgba_to_argb(params.get_param_view("DefaultShapeColor")))
1399
        im = QtGui.QImage(32,32,QtGui.QImage.Format_ARGB32)
1400
        im.fill(QtCore.Qt.transparent)
1401
        pt = QtGui.QPainter(im)
1402
        pt.setPen(QtGui.QPen(QtCore.Qt.black, 1, QtCore.Qt.SolidLine, QtCore.Qt.FlatCap))
1403
        pt.setBrush(QtGui.QBrush(linecolor, QtCore.Qt.SolidPattern))
1404
        pts = [QtCore.QPointF(4.0,4.0), QtCore.QPointF(4.0,26.0), QtCore.QPointF(26.0,4.0)]
1405
        pt.drawPolygon(pts, QtCore.Qt.OddEvenFill)
1406
        pt.setBrush(QtGui.QBrush(facecolor, QtCore.Qt.SolidPattern))
1407
        pts = [QtCore.QPointF(28.0,28.0),QtCore.QPointF(8.0,28.0),QtCore.QPointF(28.0,8.0)]
1408
        pt.drawPolygon(pts,QtCore.Qt.OddEvenFill)
1409
        pt.end()
1410
        icon = QtGui.QIcon(QtGui.QPixmap.fromImage(im))
1411
        linewidth = params.get_param_view("DefaultShapeLineWidth")
1412
        fontsize = params.get_param("textheight")
1413
        txt = str(linewidth) + "px | "\
1414
            + FreeCAD.Units.Quantity(fontsize,FreeCAD.Units.Length).UserString
1415
        self.styleButton.setIcon(icon)
1416
        self.styleButton.setText(txt)
1417

1418
        # FOR BACKWARDS COMPATIBILITY
1419
        self.color = linecolor
1420
        self.facecolor = facecolor
1421
        self.linewidth = linewidth
1422
        self.fontsize = fontsize
1423

1424
    def popupMenu(self,llist,ilist=None,pos=None):
1425
        """pops up a menu filled with the given list"""
1426
        self.groupmenu = QtWidgets.QMenu()
1427
        for i,l in enumerate(llist):
1428
            if ilist:
1429
                self.groupmenu.addAction(ilist[i],l)
1430
            else:
1431
                self.groupmenu.addAction(l)
1432
        if not pos:
1433
            pos = FreeCADGui.getMainWindow().cursor().pos()
1434
        self.groupmenu.popup(pos)
1435
        QtCore.QObject.connect(self.groupmenu,QtCore.SIGNAL("triggered(QAction *)"),self.popupTriggered)
1436

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

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

1443
    def setRadiusValue(self,val,unit=None):
1444
        #print("DEBUG: setRadiusValue val: ", val, " unit: ", unit)
1445
        if  not isinstance(val, (int, float)):       #??some code passes strings or ???
1446
            t = val
1447
        elif unit:
1448
            t= display_external(val,None, unit)
1449
        else:
1450
            print("Error: setRadiusValue called for number without Dimension")
1451
            t = display_external(val,None, None)
1452
        self.radiusValue.setText(t)
1453
        self.radiusValue.setFocus()
1454

1455
    def runAutoGroup(self):
1456
        FreeCADGui.runCommand("Draft_AutoGroup")
1457

1458
    def setAutoGroup(self,value=None):
1459
        if value is None:
1460
            self.autogroup = None
1461
            self.autoGroupButton.setText(translate("draft", "None"))
1462
            self.autoGroupButton.setIcon(QtGui.QIcon.fromTheme('Draft_AutoGroup_off',
1463
                                                               QtGui.QIcon(':/icons/button_invalid.svg')))
1464
            self.autoGroupButton.setToolTip(translate("draft", "Autogroup off"))
1465
            self.autoGroupButton.setDown(False)
1466
        else:
1467
            obj = FreeCAD.ActiveDocument.getObject(value)
1468
            if obj:
1469
                self.autogroup = value
1470
                self.autoGroupButton.setText(obj.Label)
1471
                self.autoGroupButton.setIcon(obj.ViewObject.Icon)
1472
                self.autoGroupButton.setToolTip(translate("draft", "Autogroup:") + " " + obj.Label)
1473
                self.autoGroupButton.setDown(False)
1474
            else:
1475
                self.autogroup = None
1476
                self.autoGroupButton.setText(translate("draft", "None"))
1477
                self.autoGroupButton.setIcon(QtGui.QIcon.fromTheme('Draft_AutoGroup_off',
1478
                                                                   QtGui.QIcon(':/icons/button_invalid.svg')))
1479
                self.autoGroupButton.setToolTip(translate("draft", "Autogroup off"))
1480
                self.autoGroupButton.setDown(False)
1481

1482
    def getXPM(self,iconname,size=16):
1483
        i = QtGui.QIcon(":/icons/"+iconname+".svg")
1484
        p = i.pixmap(size,size)
1485
        a = QtCore.QByteArray()
1486
        b = QtCore.QBuffer(a)
1487
        b.open(QtCore.QIODevice.WriteOnly)
1488
        p.save(b,"XPM")
1489
        b.close()
1490
        return str(a)
1491

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

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

1501
    def constrain(self,val):
1502
        if val == "angle":
1503
            self.alock = not(self.alock)
1504
            self.angleLock.setChecked(self.alock)
1505
        elif self.mask == val:
1506
            self.mask = None
1507
            if hasattr(FreeCADGui,"Snapper"):
1508
                FreeCADGui.Snapper.mask = None
1509
        else:
1510
            self.mask = val
1511
            if hasattr(FreeCADGui,"Snapper"):
1512
                FreeCADGui.Snapper.mask = val
1513

1514
    def changeXValue(self,d):
1515
        self.x = d
1516
        if not self.xValue.hasFocus():
1517
            return None
1518
        self.update_spherical_coords()
1519

1520
    def changeYValue(self,d):
1521
        self.y = d
1522
        if not self.yValue.hasFocus():
1523
            return None
1524
        self.update_spherical_coords()
1525

1526
    def changeZValue(self,d):
1527
        self.z = d
1528
        if not self.zValue.hasFocus():
1529
            return None
1530
        self.update_spherical_coords()
1531

1532
    def changeRadiusValue(self,d):
1533
        self.radius = d
1534

1535
    def changeLengthValue(self,d):
1536
        self.lvalue = d
1537
        if not self.lengthValue.hasFocus():
1538
            return None
1539
        self.update_cartesian_coords()
1540

1541
    def changeAngleValue(self,d):
1542
        self.avalue = d
1543
        if not self.angleValue.hasFocus():
1544
            return None
1545
        self.update_cartesian_coords()
1546
        if self.angleLock.isChecked():
1547
            if not self.globalMode:
1548
                plane = WorkingPlane.get_working_plane(update=False)
1549
                angle_vec = plane.get_global_coords(self.angle, as_vector=True)
1550
            else:
1551
                angle_vec = self.angle
1552
            FreeCADGui.Snapper.setAngle(angle_vec)
1553

1554
    def toggleAngle(self,b):
1555
        self.alock = self.angleLock.isChecked()
1556
        self.update_cartesian_coords()
1557
        if self.alock:
1558
            if not self.globalMode:
1559
                plane = WorkingPlane.get_working_plane(update=False)
1560
                angle_vec = plane.get_global_coords(self.angle, as_vector=True)
1561
            else:
1562
                angle_vec = self.angle
1563
            FreeCADGui.Snapper.setAngle(angle_vec)
1564
        else:
1565
            FreeCADGui.Snapper.setAngle()
1566
            self.angle = None
1567

1568
    def update_spherical_coords(self):
1569
        length, theta, phi = DraftVecUtils.get_spherical_coords(
1570
            self.x,self.y,self.z)
1571
        self.lvalue = length
1572
        self.pvalue = math.degrees(theta)
1573
        self.avalue = math.degrees(phi)
1574
        self.angle = FreeCAD.Vector(DraftVecUtils.get_cartesian_coords(
1575
            1, theta, phi))
1576
        self.lengthValue.setText(display_external(self.lvalue,None,'Length'))
1577
        self.angleValue.setText(display_external(self.avalue,None,'Angle'))
1578

1579
    def update_cartesian_coords(self):
1580
        self.x, self.y, self.z = DraftVecUtils.get_cartesian_coords(
1581
            self.lvalue,math.radians(self.pvalue),math.radians(self.avalue))
1582
        self.angle = FreeCAD.Vector(DraftVecUtils.get_cartesian_coords(
1583
            1, math.radians(self.pvalue), math.radians(self.avalue)))
1584
        self.xValue.setText(display_external(self.x,None,'Length'))
1585
        self.yValue.setText(display_external(self.y,None,'Length'))
1586
        self.zValue.setText(display_external(self.z,None,'Length'))
1587

1588
#---------------------------------------------------------------------------
1589
# TaskView operations
1590
#---------------------------------------------------------------------------
1591

1592
    def setWatchers(self):
1593
        class DraftCreateWatcher:
1594
            def __init__(self):
1595
                self.commands = ["Draft_Line","Draft_Wire",
1596
                                 "Draft_Rectangle","Draft_Arc",
1597
                                 "Draft_Circle","Draft_BSpline",
1598
                                 "Draft_Text","Draft_Dimension",
1599
                                 "Draft_ShapeString","Draft_BezCurve"]
1600
                self.title = "Create objects"
1601
            def shouldShow(self):
1602
                return (FreeCAD.ActiveDocument is not None) and (not FreeCADGui.Selection.getSelection())
1603

1604
        class DraftModifyWatcher:
1605
            def __init__(self):
1606
                self.commands = ["Draft_Move","Draft_Rotate",
1607
                                 "Draft_Scale","Draft_Offset",
1608
                                 "Draft_Trimex","Draft_Upgrade",
1609
                                 "Draft_Downgrade","Draft_Edit"]
1610
                self.title = translate("draft", "Modify objects")
1611
            def shouldShow(self):
1612
                return (FreeCAD.ActiveDocument is not None) and (FreeCADGui.Selection.getSelection() != [])
1613

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

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

1621
    def Activated(self):
1622
        self.setWatchers()
1623
        if hasattr(self,"tray"):
1624
            self.tray.show()
1625

1626
    def Deactivated(self):
1627
        if (FreeCAD.activeDraftCommand is not None):
1628
            self.continueMode = False
1629
            FreeCAD.activeDraftCommand.finish()
1630
        FreeCADGui.Control.clearTaskWatcher()
1631
        #self.tray = None
1632
        if hasattr(self,"tray"):
1633
            self.tray.hide()
1634

1635
    def reset_ui_values(self):
1636
        """Method to reset task panel values"""
1637
        self.x = 0
1638
        self.y = 0
1639
        self.z = 0
1640
        self.lvalue = 0
1641
        self.pvalue = 90
1642
        self.avalue = 0
1643
        self.angle = None
1644
        self.radius = 0
1645
        self.offset = 0
1646

1647

1648
class FacebinderTaskPanel:
1649
    '''A TaskPanel for the facebinder'''
1650
    def __init__(self):
1651

1652
        self.obj = None
1653
        self.form = QtWidgets.QWidget()
1654
        self.form.setObjectName("FacebinderTaskPanel")
1655
        self.grid = QtWidgets.QGridLayout(self.form)
1656
        self.grid.setObjectName("grid")
1657
        self.title = QtWidgets.QLabel(self.form)
1658
        self.grid.addWidget(self.title, 0, 0, 1, 2)
1659

1660
        # tree
1661
        self.tree = QtWidgets.QTreeWidget(self.form)
1662
        self.grid.addWidget(self.tree, 1, 0, 1, 2)
1663
        self.tree.setColumnCount(2)
1664
        self.tree.setHeaderLabels(["Name","Subelement"])
1665

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

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

1677
        QtCore.QObject.connect(self.addButton, QtCore.SIGNAL("clicked()"), self.addElement)
1678
        QtCore.QObject.connect(self.delButton, QtCore.SIGNAL("clicked()"), self.removeElement)
1679
        self.update()
1680

1681
    def isAllowedAlterSelection(self):
1682
        return True
1683

1684
    def isAllowedAlterView(self):
1685
        return True
1686

1687
    def getStandardButtons(self):
1688
        return int(QtWidgets.QDialogButtonBox.Ok)
1689

1690
    def update(self):
1691
        """fills the treewidget"""
1692
        self.tree.clear()
1693
        if self.obj:
1694
            for f in self.obj.Faces:
1695
                if isinstance(f[1],tuple):
1696
                    for subf in f[1]:
1697
                        item = QtWidgets.QTreeWidgetItem(self.tree)
1698
                        item.setText(0,f[0].Name)
1699
                        item.setIcon(0, QtGui.QIcon(":/icons/Part_3D_object.svg"))
1700
                        item.setText(1,subf)
1701
                else:
1702
                    item = QtWidgets.QTreeWidgetItem(self.tree)
1703
                    item.setText(0,f[0].Name)
1704
                    item.setIcon(0, QtGui.QIcon(":/icons/Part_3D_object.svg"))
1705
                    item.setText(1,f[1])
1706
        self.retranslateUi(self.form)
1707

1708
    def addElement(self):
1709
        if self.obj:
1710
            for sel in FreeCADGui.Selection.getSelectionEx():
1711
                if sel.HasSubObjects:
1712
                    obj = sel.Object
1713
                    for elt in sel.SubElementNames:
1714
                        if "Face" in elt:
1715
                            flist = self.obj.Faces
1716
                            found = False
1717
                            for face in flist:
1718
                                if (face[0] == obj.Name):
1719
                                    if isinstance(face[1],tuple):
1720
                                        for subf in face[1]:
1721
                                            if subf == elt:
1722
                                                found = True
1723
                                    else:
1724
                                        if (face[1] == elt):
1725
                                            found = True
1726
                            if not found:
1727
                                flist.append((obj,elt))
1728
                                self.obj.Faces = flist
1729
                                FreeCAD.ActiveDocument.recompute()
1730
            self.update()
1731

1732
    def removeElement(self):
1733
        if self.obj:
1734
            it = self.tree.currentItem()
1735
            if it:
1736
                obj = FreeCAD.ActiveDocument.getObject(str(it.text(0)))
1737
                elt = str(it.text(1))
1738
                flist = []
1739
                for face in self.obj.Faces:
1740
                    if (face[0].Name != obj.Name):
1741
                        flist.append(face)
1742
                    else:
1743
                        if isinstance(face[1],tuple):
1744
                            for subf in face[1]:
1745
                                if subf != elt:
1746
                                    flist.append((obj,subf))
1747
                        else:
1748
                            if (face[1] != elt):
1749
                                flist.append(face)
1750
                self.obj.Faces = flist
1751
                FreeCAD.ActiveDocument.recompute()
1752
            self.update()
1753

1754
    def accept(self):
1755
        FreeCAD.ActiveDocument.recompute()
1756
        FreeCADGui.ActiveDocument.resetEdit()
1757
        return True
1758

1759
    def retranslateUi(self, TaskPanel):
1760
        TaskPanel.setWindowTitle(QtWidgets.QApplication.translate("draft", "Faces", None))
1761
        self.delButton.setText(QtWidgets.QApplication.translate("draft", "Remove", None))
1762
        self.addButton.setText(QtWidgets.QApplication.translate("draft", "Add", None))
1763
        self.title.setText(QtWidgets.QApplication.translate("draft", "Facebinder elements", None))
1764

1765
#def translateWidget(w, context=None, disAmb=None):
1766
#    '''translator for items where retranslateUi() is unavailable.
1767
#    translates widget w and children.'''
1768
#    #handle w itself
1769
#    if w.metaObject().className() == "QWidget":
1770
#        origText = None
1771
#        origText = w.windowTitle()
1772
#        if origText:
1773
#            newText = translate(context, str(origText))
1774
#            if newText:
1775
#                w.setWindowTitle(newText)
1776

1777
#    #handle children
1778
#    wKids = w.findChildren(QtWidgets.QWidget)
1779
#    for i in wKids:
1780
#        className = i.metaObject().className()
1781
#        if hasattr(i,"text") and hasattr(i,"setText"):
1782
#            origText = i.text()
1783
#            newText = translate(context, str(origText))
1784
#            if newText:
1785
#                i.setText(newText)
1786
#        elif hasattr(i,"title") and hasattr(i,"setTitle"):
1787
#            origText = i.title()
1788
#            newText = translate(context, str(origText))
1789
#            if newText:
1790
#                i.setTitle(newText)
1791
#        elif hasattr(i,"itemText") and hasattr(i,"setItemText"):
1792
#            for item in range(i.count()):
1793
#                oldText = i.itemText(item)
1794
#                newText = translate(context, str(origText))
1795
#                if newText:
1796
#                    i.setItemText(item,newText)
1797
##for debugging:
1798
##        else:
1799
##            msg = "TranslateWidget: Can not translate widget: {0} type: {1}\n".format(w.objectName(),w.metaObject().className())
1800
##            FreeCAD.Console.PrintMessage(msg)
1801

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

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.