2
#***************************************************************************
3
#* Copyright (c) 2009 Yorik van Havre <yorik@uncreated.net> *
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. *
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. *
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 *
21
#***************************************************************************
23
__title__ = "FreeCAD Draft Workbench - GUI part"
24
__author__ = "Yorik van Havre <yorik@uncreated.net>"
25
__url__ = "https://www.freecad.org"
29
# \brief GUI elements and utilities of the Draft workbench
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
35
"""This is the GUI part of the Draft module.
36
Report to Draft.py for info
42
import PySide.QtCore as QtCore
43
import PySide.QtGui as QtGui
44
import PySide.QtWidgets as QtWidgets
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
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")
79
def _get_incmd_shortcut(itm):
80
return params.get_param("inCommandShortcut" + itm).upper()
83
#---------------------------------------------------------------------------
85
#---------------------------------------------------------------------------
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()
96
return super().eventFilter(widget, event)
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()"))
108
super().changeEvent(event)
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()"))
122
super().keyPressEvent(event)
125
def __init__(self,widget,extra=None):
127
if isinstance(extra,list):
128
self.form = [widget] + extra
130
self.form = [widget,extra]
133
def getStandardButtons(self):
134
return int(QtWidgets.QDialogButtonBox.Close)
136
if hasattr(FreeCADGui,"draftToolBar"):
137
return FreeCADGui.draftToolBar.validatePoint()
139
if FreeCADGui.ActiveDocument:
140
FreeCADGui.ActiveDocument.resetEdit()
143
FreeCADGui.draftToolBar.isTaskOn = False
144
FreeCADGui.draftToolBar.escape()
145
if FreeCADGui.ActiveDocument:
146
FreeCADGui.ActiveDocument.resetEdit()
148
def isAllowedAlterDocument(self):
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
162
self.sourceCmd = None
165
self.pointcallback = None
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")
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
180
self.crossedViews = []
181
self.isTaskOn = False
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"}
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
215
mw = FreeCADGui.getMainWindow()
216
mw.addToolBar(self.tray)
217
self.tray.setParent(mw)
220
#---------------------------------------------------------------------------
222
#---------------------------------------------------------------------------
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)
229
button.setMaximumSize(QtCore.QSize(button.height(), button.height()))
234
if icon.endswith(".svg"):
235
button.setIcon(QtGui.QIcon(icon))
237
button.setIcon(QtGui.QIcon.fromTheme(
238
icon, QtGui.QIcon(':/icons/'+icon+'.svg')))
240
button.setCheckable(True)
241
button.setChecked(False)
242
layout.addWidget(button)
245
def _label (self,name, layout, hide=True, wrap=False):
246
label = QtWidgets.QLabel(self.baseWidget)
247
label.setObjectName(name)
249
label.setWordWrap(True)
250
if hide: label.hide()
251
layout.addWidget(label)
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)
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()
269
sizePolicy = QtWidgets.QSizePolicy(
270
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
271
inputfield.setSizePolicy(sizePolicy)
272
inputfield.setMinimumWidth(110)
274
inputfield.setMaximumWidth(width)
275
layout.addWidget(inputfield)
278
def _spinbox (self,name, layout, val=None, vmax=None,
279
hide=True, double=False, size=None):
281
sbox = QtWidgets.QDoubleSpinBox(self.baseWidget)
282
sbox.setDecimals(params.get_param("Decimals", path="Units"))
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]))
290
layout.addWidget(sbox)
293
def _checkbox (self,name, layout, checked=True, hide=True):
294
chk = QtWidgets.QCheckBox(self.baseWidget)
295
chk.setChecked(checked)
296
chk.setObjectName(name)
298
layout.addWidget(chk)
301
def _combo (self,name,layout,hide=True):
302
cb = QtWidgets.QComboBox(self.baseWidget)
303
cb.setObjectName(name)
307
def setupToolBar(self,task=False):
308
"""sets the draft toolbar up"""
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)
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")
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")
354
# additional line controls
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)
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')
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")
407
# Note: The order of the calls to self._checkbox() below controls
408
# the position of the checkboxes in the task panel.
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)
416
# update checkboxes without parameters and without internal modes:
417
self.occOffset = self._checkbox("occOffset", self.layout, checked=False)
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",
423
checked=params.get_param("CopyMode"))
424
self.isSubelementMode = self._checkbox("isSubelementMode",
426
checked=params.get_param("SubelementMode"))
429
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum,
430
QtWidgets.QSizePolicy.Expanding)
431
self.layout.addItem(spacerItem)
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)
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)
465
QtCore.QObject.connect(self.isCopy,QtCore.SIGNAL("stateChanged(int)"),self.setCopymode)
466
QtCore.QObject.connect(self.isSubelementMode, QtCore.SIGNAL("stateChanged(int)"), self.setSubelementMode)
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)
475
"""sets draft tray buttons up"""
477
self.wplabel = self._pushbutton(
478
"wplabel", self.toptray, icon='Draft_SelectPlane',
479
hide=False,width=120)
481
self.styleButton = self._pushbutton(
482
"stylebutton", self.toptray, icon='Draft_Apply', hide=False,
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)
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)
500
QtCore.QTimer.singleShot(2000,self.retranslateTray) # delay so translations get a chance to load
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)
514
#---------------------------------------------------------------------------
516
#---------------------------------------------------------------------------
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"))
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"))
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)
591
# Update the maximum width of the push buttons
592
maxwidth = 66 # that's the default
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'):
600
fm = QtGui.QFontMetrics(i.font())
601
fw = fm.width(i.text())
602
fw = max(fw, maxwidth)
604
maxwidth = maxwidth + 16 +10 # add icon width and a margin
606
i.setMaximumWidth(maxwidth)
608
def retranslateTray(self,widget=None):
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"))
615
#---------------------------------------------------------------------------
617
#---------------------------------------------------------------------------
619
def taskUi(self,title="Draft",extra=None,icon="Draft_Draft"):
620
# reset InputField values
621
self.reset_ui_values()
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)
633
"""utility function that is performed after each clicked point"""
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()))
647
self.yValue.setFocus()
648
self.yValue.setSelection(0,self.number_length(self.yValue.text()))
650
self.zValue.setFocus()
651
self.zValue.setSelection(0,self.number_length(self.zValue.text()))
653
self.radiusValue.setFocus()
654
self.radiusValue.setSelection(0,self.number_length(self.radiusValue.text()))
656
def number_length(self, str):
659
if char in "0123456789.,-":
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)
673
''' turn off all the point entry widgets '''
677
self.labellength.hide()
678
self.labelangle.hide()
682
self.pointButton.hide()
683
self.lengthValue.hide()
684
self.angleValue.hide()
685
self.angleLock.hide()
686
self.isRelative.hide()
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)
693
self.xValue.setEnabled(True)
694
self.yValue.setEnabled(True)
695
self.continueCmd.show()
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)
705
self.hasFill.setEnabled(True)
707
self.finishButton.show()
708
self.closeButton.show()
709
self.wipeButton.show()
710
self.orientWPButton.show()
711
self.undoButton.show()
712
self.continueCmd.show()
715
self.pointUi(translate("draft", "Circle"),icon="Draft_Circle")
717
self.isRelative.hide()
720
self.pointUi(translate("draft", "Arc"),icon="Draft_Arc")
721
self.continueCmd.show()
722
self.isRelative.hide()
724
def rotateSetCenterUi(self):
725
self.pointUi(translate("draft", "Rotate"),icon="Draft_Rotate")
727
self.isRelative.hide()
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()
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)
752
self.pointButton.show()
753
if rel: self.isRelative.show()
754
todo.delay(self.setFocus,None)
755
self.xValue.selectAll()
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()
765
combo.addItem(translate("Draft", s), userData=s)
766
combo.setCurrentIndex(types.index(params.get_param("labeltype")))
768
QtCore.QObject.connect(combo,QtCore.SIGNAL("currentIndexChanged(int)"),callback)
769
self.pointUi(title=title, extra=w, icon="Draft_Label")
775
self.taskUi(translate("draft","Offset"), icon="Draft_Offset")
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()
787
todo.delay(FreeCADGui.Control.closeDialog,None)
789
self.sourceCmd = None
790
self.pointcallback = None
792
self.isTaskOn = False
793
self.baseWidget = QtWidgets.QWidget()
795
def trimUi(self,title=translate("draft","Trimex")):
796
self.taskUi(title, icon="Draft_Trimex")
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()
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()
816
self.textValue.show()
817
self.textOkButton.show()
818
self.textValue.setText('')
819
todo.delay(self.textValue.setFocus,None)
822
self.continueCmd.show()
823
# Change the checkbox label as the in-command shortcut cannot be used:
824
self.continueCmd.setText(translate("draft", "Continue"))
826
def switchUi(self,store=True):
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())
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()
846
def setTitle(self,title,icon="Draft_Draft"):
847
self.baseWidget.setWindowTitle(title)
848
self.baseWidget.setWindowIcon(QtGui.QIcon(":/icons/"+icon+".svg"))
850
def selectUi(self,extra=None, on_close_call=None):
851
self.makeDumbTask(extra, on_close_call)
854
self.makeDumbTask(on_close_call=self.finish)
857
if params.get_param("UsePartPrimitives"):
858
self.hasFill.setEnabled(False)
860
self.hasFill.setEnabled(True)
862
self.continueCmd.show()
866
self.isSubelementMode.show()
867
self.isCopy.setChecked(params.get_param("CopyMode"))
868
self.continueCmd.show()
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"))
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"))
889
def setNextFocus(self):
891
if widget.isEnabled() and widget.isVisible():
896
if isThere(self.xValue):
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()
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)
913
self.layout.setDirection(QtWidgets.QBoxLayout.LeftToRight)
915
def makeDumbTask(self, extra=None, on_close_call=None):
916
"""create a dumb taskdialog to prevent deleting the temp object"""
918
def __init__(self, extra=None, callback=None):
921
self.callback = callback
922
def getStandardButtons(self):
923
return int(QtWidgets.QDialogButtonBox.Close)
928
todo.delay(FreeCADGui.Control.closeDialog,None)
929
panel = TaskPanel(extra, on_close_call)
930
todo.delay(FreeCADGui.Control.showDialog,panel)
933
#---------------------------------------------------------------------------
934
# Processing functions
935
#---------------------------------------------------------------------------
937
def setContinue(self, val):
938
params.set_param("ContinueMode", bool(val))
939
self.continueMode = bool(val)
941
# val=-1 is used to temporarily switch to relativeMode and disable the checkbox.
942
# val=-2 is used to switch back.
947
def setRelative(self, val=-1):
949
QtCore.QObject.disconnect(self.isRelative,
950
QtCore.SIGNAL("stateChanged(int)"),
953
self.isRelative.setChecked(True)
954
self.relativeMode = True
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)"),
963
params.set_param("RelativeMode", bool(val))
964
self.relativeMode = bool(val)
967
def setGlobal(self, val):
968
params.set_param("GlobalMode", bool(val))
969
self.globalMode = bool(val)
972
def setFill(self, val):
973
params.set_param("fillmode", bool(val))
974
self.fillmode = bool(val)
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))
981
params.set_param("CopyMode", bool(val))
983
def setSubelementMode(self, val):
984
params.set_param("SubelementMode", bool(val))
985
self.sourceCmd.set_ghosts()
988
if self.yValue.isEnabled():
989
self.yValue.setFocus()
990
self.yValue.setSelection(0,self.number_length(self.yValue.text()))
996
if self.zValue.isEnabled():
997
self.zValue.setFocus()
998
self.zValue.setSelection(0,self.number_length(self.zValue.text()))
1001
self.validatePoint()
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()
1009
self.validatePoint()
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()):
1016
#rad=float(self.radiusValue.text())
1018
except (ValueError, AttributeError):
1019
print("debug: DraftGui.validatePoint: AttributeError")
1021
self.sourceCmd.numericRadius(rad)
1022
elif (self.labelx.isVisible()):
1024
#numx=float(self.xValue.text())
1026
#numy=float(self.yValue.text())
1028
#numz=float(self.zValue.text())
1030
except (ValueError, AttributeError):
1031
print("debug: DraftGui.validatePoint: AttributeError")
1033
num_vec = FreeCAD.Vector(numx, numy, numz)
1034
if self.pointcallback:
1035
self.pointcallback(num_vec, self.globalMode, self.relativeMode)
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]
1045
numx, numy, numz = num_vec + ref_vec
1046
self.sourceCmd.numericInput(numx, numy, numz)
1048
elif self.textValue.isVisible():
1051
FreeCADGui.ActiveDocument.resetEdit()
1054
def finish(self, cont=None):
1055
"""finish button action"""
1058
cont = self.continueMode
1059
self.sourceCmd.finish(cont=cont)
1063
if FreeCADGui.ActiveDocument:
1064
FreeCADGui.ActiveDocument.resetEdit()
1067
"""escapes the current command"""
1068
self.finish(cont=False)
1070
def closeLine(self):
1071
"""close button action"""
1072
self.sourceCmd.finish(cont=self.continueMode, closed=True)
1073
FreeCADGui.ActiveDocument.resetEdit()
1076
"""wipes existing segments of a line"""
1077
self.sourceCmd.wipe()
1080
"""reorients the current working plane"""
1081
self.sourceCmd.orientWP()
1083
def selectEdge(self):
1084
"""allows the dimension command to select an edge"""
1085
if hasattr(self.sourceCmd,"selectEdge"):
1086
self.sourceCmd.selectEdge()
1088
def undoSegment(self):
1089
"""undo last line segment"""
1090
if hasattr(self.sourceCmd,"undolast"):
1091
self.sourceCmd.undolast()
1093
def checkSpecialChars(self,txt):
1094
"""checks for special characters in the entered coords that must be
1095
treated as shortcuts
1098
if txt == "" or txt[0] in "0123456789.,-":
1099
self.updateSnapper()
1100
if txt[0] in "0123456789.,-":
1101
self.setMouseMode(False)
1104
txt = txt[0].upper()
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()
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()
1117
elif txt == _get_incmd_shortcut("Length"):
1118
if self.lengthValue.isVisible():
1119
self.constrain("angle")
1122
elif txt == _get_incmd_shortcut("RestrictX"):
1126
elif txt == _get_incmd_shortcut("RestrictY"):
1130
elif txt == _get_incmd_shortcut("RestrictZ"):
1134
elif txt == _get_incmd_shortcut("Copy"):
1135
if self.isCopy.isVisible():
1136
self.isCopy.setChecked(not self.isCopy.isChecked())
1138
elif txt == _get_incmd_shortcut("Exit"):
1139
if self.finishButton.isVisible():
1141
elif txt == _get_incmd_shortcut("Close"):
1142
if self.closeButton.isVisible():
1144
elif txt == _get_incmd_shortcut("AddHold"):
1145
if hasattr(FreeCADGui,"Snapper"):
1146
FreeCADGui.Snapper.addHoldPoint()
1148
elif txt == _get_incmd_shortcut("Snap"):
1151
elif txt == _get_incmd_shortcut("Fill"):
1152
if self.hasFill.isVisible():
1153
self.hasFill.setChecked(not self.hasFill.isChecked())
1155
elif txt == _get_incmd_shortcut("Continue"):
1156
if self.continueCmd.isVisible():
1157
self.toggleContinue()
1159
elif txt == _get_incmd_shortcut("SetWP"):
1160
if self.orientWPButton.isVisible():
1163
elif txt == _get_incmd_shortcut("SelectEdge"):
1166
elif txt == _get_incmd_shortcut("SubelementMode"):
1167
if self.isSubelementMode.isVisible():
1168
self.isSubelementMode.setChecked(not self.isSubelementMode.isChecked())
1170
elif txt == _get_incmd_shortcut("Wipe"):
1171
if self.wipeButton.isVisible():
1174
elif txt == _get_incmd_shortcut("Undo"):
1177
elif txt == _get_incmd_shortcut("IncreaseRadius"):
1178
self.toggleradius(1)
1180
elif txt == _get_incmd_shortcut("DecreaseRadius"):
1181
self.toggleradius(-1)
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)
1193
self.updateSnapper()
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():
1203
if self.isRelative.isChecked():
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))
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."""
1221
delay = params.get_param("MouseDelay")
1223
if self.mouse is True:
1225
QtCore.QTimer.singleShot(delay*1000, self.setMouseMode)
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"):
1234
"""this function sends the entered text to the active draft command
1235
if enter has been pressed twice. Otherwise it blanks the line.
1237
self.sourceCmd.text = self.textValue.toPlainText()\
1238
.replace("\\","\\\\")\
1239
.replace("\"","\\\"")\
1240
.replace("\'","\\\'")\
1242
self.sourceCmd.createObject()
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:
1250
plane = WorkingPlane.get_working_plane(update=False)
1251
# get coords to display
1254
last = FreeCAD.Vector(0,0,0)
1256
last = plane.position
1260
if self.relativeMode: # and (last is not None):
1264
dp = plane.get_local_coords(point - last, as_vector=True)
1269
dp = plane.get_local_coords(point)
1272
if self.mask in ['y','z']:
1273
self.xValue.setText(display_external(dp.x,None,'Length'))
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'))
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'))
1283
self.zValue.setText(display_external(dp.z,None,'Length'))
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'))
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]:
1298
elif phi in [90,270,-90,-270]:
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)
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)
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)
1321
self.xValue.setEnabled(True)
1322
self.yValue.setEnabled(True)
1323
self.zValue.setEnabled(True)
1324
self.angleValue.setEnabled(True)
1328
def getDefaultColor(self, typ, rgb=False):
1329
"""gets color from the preferences or toolbar"""
1334
r, g, b, _ = utils.get_rgba_tuple(params.get_param("snapcolor"))
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)
1341
r, g, b, _ = utils.get_rgba_tuple(params.get_param_view("DefaultShapeLineColor"))
1343
r, g, b, _ = utils.get_rgba_tuple(params.get_param("DefaultTextColor"))
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"))
1349
print("draft: error: couldn't get a color for ", typ, " typ.")
1351
return("rgb(" + str(int(r * 255)) + "," + str(int(g * 255)) + "," + str(int(b * 255)) + ")")
1355
def cross(self,on=True):
1359
def toggleConstrMode(self,checked):
1360
self.baseWidget.setStyleSheet(
1361
"#constrButton:Checked {background-color: "
1362
+ self.getDefaultColor("constr",rgb=True)+" }")
1363
self.constrMode = checked
1365
def toggleContinue(self):
1366
FreeCAD.Console.PrintMessage("toggle continue\n")
1367
self.continueMode = not self.continueMode
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")
1380
c = self.panel.form.findChild(QtWidgets.QCheckBox,"ContinueCmd")
1386
def isConstructionMode(self):
1387
return self.tray is not None and self.constrButton.isChecked()
1389
def selectplane(self):
1390
FreeCADGui.runCommand("Draft_SelectPlane")
1393
FreeCADGui.runCommand("Draft_SetStyle")
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)
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)
1418
# FOR BACKWARDS COMPATIBILITY
1419
self.color = linecolor
1420
self.facecolor = facecolor
1421
self.linewidth = linewidth
1422
self.fontsize = fontsize
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):
1429
self.groupmenu.addAction(ilist[i],l)
1431
self.groupmenu.addAction(l)
1433
pos = FreeCADGui.getMainWindow().cursor().pos()
1434
self.groupmenu.popup(pos)
1435
QtCore.QObject.connect(self.groupmenu,QtCore.SIGNAL("triggered(QAction *)"),self.popupTriggered)
1437
def getIcon(self,iconpath):
1438
return QtGui.QIcon(iconpath)
1440
def popupTriggered(self,action):
1441
self.sourceCmd.proceed(str(action.text()))
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 ???
1448
t= display_external(val,None, unit)
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()
1455
def runAutoGroup(self):
1456
FreeCADGui.runCommand("Draft_AutoGroup")
1458
def setAutoGroup(self,value=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)
1467
obj = FreeCAD.ActiveDocument.getObject(value)
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)
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)
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)
1492
def togglesnap(self):
1493
FreeCADGui.doCommand('FreeCADGui.runCommand("Draft_Snap_Lock")')
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()
1501
def constrain(self,val):
1503
self.alock = not(self.alock)
1504
self.angleLock.setChecked(self.alock)
1505
elif self.mask == val:
1507
if hasattr(FreeCADGui,"Snapper"):
1508
FreeCADGui.Snapper.mask = None
1511
if hasattr(FreeCADGui,"Snapper"):
1512
FreeCADGui.Snapper.mask = val
1514
def changeXValue(self,d):
1516
if not self.xValue.hasFocus():
1518
self.update_spherical_coords()
1520
def changeYValue(self,d):
1522
if not self.yValue.hasFocus():
1524
self.update_spherical_coords()
1526
def changeZValue(self,d):
1528
if not self.zValue.hasFocus():
1530
self.update_spherical_coords()
1532
def changeRadiusValue(self,d):
1535
def changeLengthValue(self,d):
1537
if not self.lengthValue.hasFocus():
1539
self.update_cartesian_coords()
1541
def changeAngleValue(self,d):
1543
if not self.angleValue.hasFocus():
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)
1551
angle_vec = self.angle
1552
FreeCADGui.Snapper.setAngle(angle_vec)
1554
def toggleAngle(self,b):
1555
self.alock = self.angleLock.isChecked()
1556
self.update_cartesian_coords()
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)
1562
angle_vec = self.angle
1563
FreeCADGui.Snapper.setAngle(angle_vec)
1565
FreeCADGui.Snapper.setAngle()
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(
1576
self.lengthValue.setText(display_external(self.lvalue,None,'Length'))
1577
self.angleValue.setText(display_external(self.avalue,None,'Angle'))
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'))
1588
#---------------------------------------------------------------------------
1589
# TaskView operations
1590
#---------------------------------------------------------------------------
1592
def setWatchers(self):
1593
class DraftCreateWatcher:
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())
1604
class DraftModifyWatcher:
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() != [])
1614
FreeCADGui.Control.addTaskWatcher([DraftCreateWatcher(),DraftModifyWatcher()])
1616
def changeEvent(self, event):
1617
if event.type() == QtCore.QEvent.LanguageChange:
1618
#print("Language changed!")
1619
self.ui.retranslateUi(self)
1621
def Activated(self):
1623
if hasattr(self,"tray"):
1626
def Deactivated(self):
1627
if (FreeCAD.activeDraftCommand is not None):
1628
self.continueMode = False
1629
FreeCAD.activeDraftCommand.finish()
1630
FreeCADGui.Control.clearTaskWatcher()
1632
if hasattr(self,"tray"):
1635
def reset_ui_values(self):
1636
"""Method to reset task panel values"""
1648
class FacebinderTaskPanel:
1649
'''A TaskPanel for the facebinder'''
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)
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"])
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)
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)
1677
QtCore.QObject.connect(self.addButton, QtCore.SIGNAL("clicked()"), self.addElement)
1678
QtCore.QObject.connect(self.delButton, QtCore.SIGNAL("clicked()"), self.removeElement)
1681
def isAllowedAlterSelection(self):
1684
def isAllowedAlterView(self):
1687
def getStandardButtons(self):
1688
return int(QtWidgets.QDialogButtonBox.Ok)
1691
"""fills the treewidget"""
1694
for f in self.obj.Faces:
1695
if isinstance(f[1],tuple):
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)
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)
1708
def addElement(self):
1710
for sel in FreeCADGui.Selection.getSelectionEx():
1711
if sel.HasSubObjects:
1713
for elt in sel.SubElementNames:
1715
flist = self.obj.Faces
1718
if (face[0] == obj.Name):
1719
if isinstance(face[1],tuple):
1720
for subf in face[1]:
1724
if (face[1] == elt):
1727
flist.append((obj,elt))
1728
self.obj.Faces = flist
1729
FreeCAD.ActiveDocument.recompute()
1732
def removeElement(self):
1734
it = self.tree.currentItem()
1736
obj = FreeCAD.ActiveDocument.getObject(str(it.text(0)))
1737
elt = str(it.text(1))
1739
for face in self.obj.Faces:
1740
if (face[0].Name != obj.Name):
1743
if isinstance(face[1],tuple):
1744
for subf in face[1]:
1746
flist.append((obj,subf))
1748
if (face[1] != elt):
1750
self.obj.Faces = flist
1751
FreeCAD.ActiveDocument.recompute()
1755
FreeCAD.ActiveDocument.recompute()
1756
FreeCADGui.ActiveDocument.resetEdit()
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))
1765
#def translateWidget(w, context=None, disAmb=None):
1766
# '''translator for items where retranslateUi() is unavailable.
1767
# translates widget w and children.'''
1769
# if w.metaObject().className() == "QWidget":
1771
# origText = w.windowTitle()
1773
# newText = translate(context, str(origText))
1775
# w.setWindowTitle(newText)
1778
# wKids = w.findChildren(QtWidgets.QWidget)
1780
# className = i.metaObject().className()
1781
# if hasattr(i,"text") and hasattr(i,"setText"):
1782
# origText = i.text()
1783
# newText = translate(context, str(origText))
1786
# elif hasattr(i,"title") and hasattr(i,"setTitle"):
1787
# origText = i.title()
1788
# newText = translate(context, str(origText))
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))
1796
# i.setItemText(item,newText)
1799
## msg = "TranslateWidget: Can not translate widget: {0} type: {1}\n".format(w.objectName(),w.metaObject().className())
1800
## FreeCAD.Console.PrintMessage(msg)
1802
if not hasattr(FreeCADGui,"draftToolBar"):
1803
FreeCADGui.draftToolBar = DraftToolBar()
1804
#----End of Python Features Definitions----#