Moved existing holding tag dressup to use the common UI implementation.
This commit is contained in:
@@ -51,7 +51,6 @@ class PathWorkbench (Workbench):
|
||||
from PathScripts import PathDressup
|
||||
from PathScripts import PathDressupDogbone
|
||||
from PathScripts import PathDressupDragknife
|
||||
from PathScripts import PathDressupHoldingTags
|
||||
from PathScripts import PathDressupRampEntry
|
||||
from PathScripts import PathDressupTagGui
|
||||
from PathScripts import PathDrilling
|
||||
@@ -87,7 +86,7 @@ class PathWorkbench (Workbench):
|
||||
twodopcmdlist = ["Path_Contour", "Path_Profile", "Path_Profile_Edges", "Path_Pocket", "Path_Drilling", "Path_Engrave", "Path_MillFace", "Path_Helix"]
|
||||
threedopcmdlist = ["Path_Surfacing"]
|
||||
modcmdlist = ["Path_Copy", "Path_CompoundExtended", "Path_Array", "Path_SimpleCopy" ]
|
||||
dressupcmdlist = ["PathDressup_Dogbone", "PathDressup_DragKnife", "PathDressup_HoldingTags", "PathDressup_Tag", "PathDressup_RampEntry"]
|
||||
dressupcmdlist = ["PathDressup_Dogbone", "PathDressup_DragKnife", "PathDressup_Tag", "PathDressup_RampEntry"]
|
||||
extracmdlist = ["Path_SelectLoop", "Path_Shape", "Path_Area", "Path_Area_Workplane", "Path_Stock"]
|
||||
#modcmdmore = ["Path_Hop",]
|
||||
#remotecmdlist = ["Path_Remote"]
|
||||
@@ -145,7 +144,6 @@ class PathWorkbench (Workbench):
|
||||
if "Job" in selectedName:
|
||||
self.appendContextMenu("", ["Path_ExportTemplate"])
|
||||
if "Profile" in selectedName or "Contour" in selectedName:
|
||||
#self.appendContextMenu("", ["Add_Tag"])
|
||||
#self.appendContextMenu("", ["Set_StartPoint"])
|
||||
#self.appendContextMenu("", ["Set_EndPoint"])
|
||||
for cmd in self.dressupcmds:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2016 sliptonic <shopinthewoods@gmail.com> *
|
||||
# * Copyright (c) 2017 sliptonic <shopinthewoods@gmail.com> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
@@ -22,12 +22,13 @@
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
import Draft
|
||||
import DraftGeomUtils
|
||||
import Path
|
||||
import PathScripts.PathLog as PathLog
|
||||
import Part
|
||||
import Path
|
||||
import PathScripts
|
||||
import PathScripts.PathLog as PathLog
|
||||
import PathScripts.PathPreferencesPathDressup as PathPreferencesPathDressup
|
||||
import PathScripts.PathUtils as PathUtils
|
||||
import copy
|
||||
import math
|
||||
|
||||
@@ -40,20 +41,15 @@ from PySide import QtCore
|
||||
|
||||
"""Holding Tags Dressup object and FreeCAD command"""
|
||||
|
||||
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
|
||||
#PathLog.trackModule()
|
||||
|
||||
# Qt tanslation handling
|
||||
def translate(context, text, disambig=None):
|
||||
return QtCore.QCoreApplication.translate(context, text, disambig)
|
||||
|
||||
|
||||
LOG_MODULE = PathLog.thisModule()
|
||||
PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE)
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
from pivy import coin
|
||||
from PySide import QtGui
|
||||
|
||||
def debugEdge(edge, prefix, force = False):
|
||||
if force or PathLog.getLevel(LOG_MODULE) == PathLog.Level.DEBUG:
|
||||
if force or PathLog.getLevel(PathLog.thisModule()) == PathLog.Level.DEBUG:
|
||||
pf = edge.valueAt(edge.FirstParameter)
|
||||
pl = edge.valueAt(edge.LastParameter)
|
||||
if type(edge.Curve) == Part.Line or type(edge.Curve) == Part.LineSegment:
|
||||
@@ -63,7 +59,7 @@ def debugEdge(edge, prefix, force = False):
|
||||
print("%s %s((%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f))" % (prefix, type(edge.Curve), pf.x, pf.y, pf.z, pm.x, pm.y, pm.z, pl.x, pl.y, pl.z))
|
||||
|
||||
def debugMarker(vector, label, color = None, radius = 0.5):
|
||||
if PathLog.getLevel(LOG_MODULE) == PathLog.Level.DEBUG:
|
||||
if PathLog.getLevel(PathLog.thisModule()) == PathLog.Level.DEBUG:
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::Sphere", label)
|
||||
obj.Label = label
|
||||
obj.Radius = radius
|
||||
@@ -72,7 +68,7 @@ def debugMarker(vector, label, color = None, radius = 0.5):
|
||||
obj.ViewObject.ShapeColor = color
|
||||
|
||||
def debugCylinder(vector, r, height, label, color = None):
|
||||
if PathLog.getLevel(LOG_MODULE) == PathLog.Level.DEBUG:
|
||||
if PathLog.getLevel(PathLog.thisModule()) == PathLog.Level.DEBUG:
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::Cylinder", label)
|
||||
obj.Label = label
|
||||
obj.Radius = r
|
||||
@@ -83,7 +79,7 @@ def debugCylinder(vector, r, height, label, color = None):
|
||||
obj.ViewObject.ShapeColor = color
|
||||
|
||||
def debugCone(vector, r1, r2, height, label, color = None):
|
||||
if PathLog.getLevel(LOG_MODULE) == PathLog.Level.DEBUG:
|
||||
if PathLog.getLevel(PathLog.thisModule()) == PathLog.Level.DEBUG:
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::Cone", label)
|
||||
obj.Label = label
|
||||
obj.Radius1 = r1
|
||||
@@ -658,10 +654,10 @@ class PathData:
|
||||
return False
|
||||
|
||||
|
||||
class ObjectDressup:
|
||||
class ObjectTagDressup:
|
||||
|
||||
def __init__(self, obj, base):
|
||||
|
||||
def __init__(self, obj):
|
||||
self.obj = obj
|
||||
obj.addProperty("App::PropertyLink", "Base","Base", QtCore.QT_TRANSLATE_NOOP("PathDressup_HoldingTags", "The base path to modify"))
|
||||
obj.addProperty("App::PropertyLength", "Width", "Tag", QtCore.QT_TRANSLATE_NOOP("PathDressup_HoldingTags", "Width of tags."))
|
||||
obj.addProperty("App::PropertyLength", "Height", "Tag", QtCore.QT_TRANSLATE_NOOP("PathDressup_HoldingTags", "Height of tags."))
|
||||
@@ -670,11 +666,15 @@ class ObjectDressup:
|
||||
obj.addProperty("App::PropertyVectorList", "Positions", "Tag", QtCore.QT_TRANSLATE_NOOP("PathDressup_HoldingTags", "Locations of insterted holding tags"))
|
||||
obj.addProperty("App::PropertyIntegerList", "Disabled", "Tag", QtCore.QT_TRANSLATE_NOOP("PathDressup_HoldingTags", "Ids of disabled holding tags"))
|
||||
obj.addProperty("App::PropertyInteger", "SegmentationFactor", "Tag", QtCore.QT_TRANSLATE_NOOP("PathDressup_HoldingTags", "Factor determining the # segments used to approximate rounded tags."))
|
||||
|
||||
obj.Proxy = self
|
||||
obj.Base = base
|
||||
|
||||
self.obj = obj
|
||||
self.solids = []
|
||||
|
||||
def __getstate__(self):
|
||||
return None
|
||||
|
||||
def __setstate__(self, state):
|
||||
return None
|
||||
|
||||
@@ -887,16 +887,19 @@ class ObjectDressup:
|
||||
|
||||
# update disabled in case there are some additional ones
|
||||
disabled = copy.copy(self.obj.Disabled)
|
||||
solids = []
|
||||
for tag in self.tags:
|
||||
solids.append(tag.solid)
|
||||
if not tag.enabled and tag.id not in disabled:
|
||||
disabled.append(tag.id)
|
||||
self.solids = solids
|
||||
if obj.Disabled != disabled:
|
||||
obj.Disabled = disabled
|
||||
|
||||
@waiting_effects
|
||||
def processTags(self, obj):
|
||||
tagID = 0
|
||||
if PathLog.getLevel(LOG_MODULE) == PathLog.Level.DEBUG:
|
||||
if PathLog.getLevel(PathLog.thisModule()) == PathLog.Level.DEBUG:
|
||||
for tag in self.tags:
|
||||
tagID += 1
|
||||
if tag.enabled:
|
||||
@@ -948,539 +951,25 @@ class ObjectDressup:
|
||||
self.setup(obj)
|
||||
return self.pathData.pointIsOnPath(point)
|
||||
|
||||
class TaskPanel:
|
||||
DataX = QtCore.Qt.ItemDataRole.UserRole
|
||||
DataY = QtCore.Qt.ItemDataRole.UserRole + 1
|
||||
DataZ = QtCore.Qt.ItemDataRole.UserRole + 2
|
||||
DataID = QtCore.Qt.ItemDataRole.UserRole + 3
|
||||
|
||||
def __init__(self, obj, viewProvider, jvoVisibility=None):
|
||||
self.obj = obj
|
||||
self.obj.Proxy.obj = obj
|
||||
self.viewProvider = viewProvider
|
||||
self.form = QtGui.QWidget()
|
||||
self.formTags = FreeCADGui.PySideUic.loadUi(":/panels/HoldingTagsEdit.ui")
|
||||
self.formPoint = FreeCADGui.PySideUic.loadUi(":/panels/PointEdit.ui")
|
||||
self.layout = QtGui.QVBoxLayout(self.form)
|
||||
#self.form.setGeometry(self.formTags.geometry())
|
||||
self.form.setWindowTitle(self.formTags.windowTitle())
|
||||
self.form.setSizePolicy(self.formTags.sizePolicy())
|
||||
self.formTags.setParent(self.form)
|
||||
self.formPoint.setParent(self.form)
|
||||
self.layout.addWidget(self.formTags)
|
||||
self.layout.addWidget(self.formPoint)
|
||||
self.formPoint.hide()
|
||||
self.jvo = PathUtils.findParentJob(obj).ViewObject
|
||||
if jvoVisibility is None:
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("PathDressup_HoldingTags", "Edit HoldingTags Dress-up"))
|
||||
self.jvoVisible = self.jvo.isVisible()
|
||||
if self.jvoVisible:
|
||||
self.jvo.hide()
|
||||
else:
|
||||
self.jvoVisible = jvoVisibility
|
||||
self.pt = FreeCAD.Vector(0, 0, 0)
|
||||
|
||||
closeButton = self.formPoint.buttonBox.button(QtGui.QDialogButtonBox.StandardButton.Close)
|
||||
closeButton.setText(translate("PathDressup_HoldingTags", "Done"))
|
||||
|
||||
def addEscapeShortcut(self):
|
||||
# The only way I could get to intercept the escape key, or really any key was
|
||||
# by creating an action with a shortcut .....
|
||||
self.escape = QtGui.QAction(self.formPoint)
|
||||
self.escape.setText('Done')
|
||||
self.escape.setShortcut(QtGui.QKeySequence.fromString('Esc'))
|
||||
QtCore.QObject.connect(self.escape, QtCore.SIGNAL('triggered()'), self.pointDone)
|
||||
self.formPoint.addAction(self.escape)
|
||||
|
||||
def removeEscapeShortcut(self):
|
||||
if self.escape:
|
||||
self.formPoint.removeAction(self.escape)
|
||||
self.escape = None
|
||||
|
||||
def modifyStandardButtons(self, buttonBox):
|
||||
self.buttonBox = buttonBox
|
||||
|
||||
def abort(self):
|
||||
FreeCAD.ActiveDocument.abortTransaction()
|
||||
self.cleanup(False)
|
||||
|
||||
def reject(self):
|
||||
FreeCAD.ActiveDocument.abortTransaction()
|
||||
self.cleanup(True)
|
||||
|
||||
def accept(self):
|
||||
self.getFields()
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
self.cleanup(True)
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def cleanup(self, gui):
|
||||
self.removeGlobalCallbacks()
|
||||
self.viewProvider.clearTaskPanel()
|
||||
if gui:
|
||||
FreeCADGui.ActiveDocument.resetEdit()
|
||||
FreeCADGui.Control.closeDialog()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
if self.jvoVisible:
|
||||
self.jvo.show()
|
||||
|
||||
def getTags(self, includeCurrent):
|
||||
tags = []
|
||||
index = self.formTags.lwTags.currentRow()
|
||||
for i in range(0, self.formTags.lwTags.count()):
|
||||
item = self.formTags.lwTags.item(i)
|
||||
enabled = item.checkState() == QtCore.Qt.CheckState.Checked
|
||||
x = item.data(self.DataX)
|
||||
y = item.data(self.DataY)
|
||||
#print("(%.2f, %.2f) i=%d/%s" % (x, y, i, index))
|
||||
if includeCurrent or i != index:
|
||||
tags.append((x, y, enabled))
|
||||
return tags
|
||||
|
||||
def getTagParameters(self):
|
||||
self.obj.Width = FreeCAD.Units.Quantity(self.formTags.ifWidth.text()).Value
|
||||
self.obj.Height = FreeCAD.Units.Quantity(self.formTags.ifHeight.text()).Value
|
||||
self.obj.Angle = self.formTags.dsbAngle.value()
|
||||
self.obj.Radius = FreeCAD.Units.Quantity(self.formTags.ifRadius.text()).Value
|
||||
|
||||
def getFields(self):
|
||||
self.getTagParameters()
|
||||
tags = self.getTags(True)
|
||||
self.obj.Proxy.setXyEnabled(tags)
|
||||
|
||||
def updateTagsView(self):
|
||||
PathLog.track()
|
||||
self.formTags.lwTags.blockSignals(True)
|
||||
self.formTags.lwTags.clear()
|
||||
for i, pos in enumerate(self.obj.Positions):
|
||||
lbl = "%d: (%.2f, %.2f)" % (i, pos.x, pos.y)
|
||||
item = QtGui.QListWidgetItem(lbl)
|
||||
item.setData(self.DataX, pos.x)
|
||||
item.setData(self.DataY, pos.y)
|
||||
item.setData(self.DataZ, pos.z)
|
||||
item.setData(self.DataID, i)
|
||||
if i in self.obj.Disabled:
|
||||
item.setCheckState(QtCore.Qt.CheckState.Unchecked)
|
||||
else:
|
||||
item.setCheckState(QtCore.Qt.CheckState.Checked)
|
||||
flags = QtCore.Qt.ItemFlag.ItemIsSelectable
|
||||
flags |= QtCore.Qt.ItemFlag.ItemIsEnabled
|
||||
flags |= QtCore.Qt.ItemFlag.ItemIsUserCheckable
|
||||
item.setFlags(flags)
|
||||
self.formTags.lwTags.addItem(item)
|
||||
self.formTags.lwTags.blockSignals(False)
|
||||
self.whenTagSelectionChanged()
|
||||
|
||||
def generateNewTags(self):
|
||||
count = self.formTags.sbCount.value()
|
||||
if not self.obj.Proxy.generateTags(self.obj, count):
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
|
||||
self.updateTagsView()
|
||||
#if PathLog.getLevel(LOG_MODULE) == PathLog.Level.DEBUG:
|
||||
# # this causes a big of an echo and a double click on the spin buttons, don't know why though
|
||||
# FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
|
||||
def updateModel(self):
|
||||
self.getFields()
|
||||
self.updateTagsView()
|
||||
#FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
def whenCountChanged(self):
|
||||
count = self.formTags.sbCount.value()
|
||||
self.formTags.pbGenerate.setEnabled(count)
|
||||
|
||||
def selectTagWithId(self, index):
|
||||
self.formTags.lwTags.setCurrentRow(index)
|
||||
|
||||
def whenTagSelectionChanged(self):
|
||||
index = self.formTags.lwTags.currentRow()
|
||||
count = self.formTags.lwTags.count()
|
||||
self.formTags.pbDelete.setEnabled(index != -1 and count > 2)
|
||||
self.formTags.pbEdit.setEnabled(index != -1)
|
||||
self.viewProvider.selectTag(index)
|
||||
|
||||
def deleteSelectedTag(self):
|
||||
self.obj.Proxy.setXyEnabled(self.getTags(False))
|
||||
self.updateTagsView()
|
||||
|
||||
def addNewTagAt(self, point, obj):
|
||||
if point and obj and self.obj.Proxy.pointIsOnPath(self.obj, point):
|
||||
#print("addNewTagAt(%s)" % (point))
|
||||
tags = self.tags
|
||||
tags.append((point.x, point.y, True))
|
||||
self.obj.Proxy.setXyEnabled(tags)
|
||||
self.updateTagsView()
|
||||
else:
|
||||
print("ignore new tag at %s" % (point))
|
||||
|
||||
def addNewTag(self):
|
||||
self.tags = self.getTags(True)
|
||||
self.getPoint(self.addNewTagAt)
|
||||
|
||||
def editTagAt(self, point, obj):
|
||||
if point and obj and (obj or point != FreeCAD.Vector()) and self.obj.Proxy.pointIsOnPath(self.obj, point):
|
||||
tags = []
|
||||
for i, (x, y, enabled) in enumerate(self.tags):
|
||||
if i == self.editItem:
|
||||
tags.append((point.x, point.y, enabled))
|
||||
else:
|
||||
tags.append((x, y, enabled))
|
||||
self.obj.Proxy.setXyEnabled(tags)
|
||||
self.updateTagsView()
|
||||
|
||||
def editTag(self, item):
|
||||
if item:
|
||||
self.tags = self.getTags(True)
|
||||
self.editItem = item.data(self.DataID)
|
||||
x = item.data(self.DataX)
|
||||
y = item.data(self.DataY)
|
||||
z = item.data(self.DataZ)
|
||||
self.getPoint(self.editTagAt, FreeCAD.Vector(x, y, z))
|
||||
|
||||
def editSelectedTag(self):
|
||||
self.editTag(self.formTags.lwTags.currentItem())
|
||||
|
||||
def removeGlobalCallbacks(self):
|
||||
if hasattr(self, 'view') and self.view:
|
||||
if self.pointCbClick:
|
||||
self.view.removeEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(), self.pointCbClick)
|
||||
self.pointCbClick = None
|
||||
if self.pointCbMove:
|
||||
self.view.removeEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(), self.pointCbMove)
|
||||
self.pointCbMove = None
|
||||
self.view = None
|
||||
|
||||
def getPoint(self, whenDone, start=None):
|
||||
|
||||
def displayPoint(p):
|
||||
self.formPoint.ifValueX.setText(FreeCAD.Units.Quantity(p.x, FreeCAD.Units.Length).UserString)
|
||||
self.formPoint.ifValueY.setText(FreeCAD.Units.Quantity(p.y, FreeCAD.Units.Length).UserString)
|
||||
self.formPoint.ifValueZ.setText(FreeCAD.Units.Quantity(p.z, FreeCAD.Units.Length).UserString)
|
||||
self.formPoint.ifValueX.setFocus()
|
||||
self.formPoint.ifValueX.selectAll()
|
||||
|
||||
def mouseMove(cb):
|
||||
event = cb.getEvent()
|
||||
pos = event.getPosition()
|
||||
cntrl = event.wasCtrlDown()
|
||||
shift = event.wasShiftDown()
|
||||
self.pt = FreeCADGui.Snapper.snap(pos, lastpoint=start, active=cntrl, constrain=shift)
|
||||
plane = FreeCAD.DraftWorkingPlane
|
||||
p = plane.getLocalCoords(self.pt)
|
||||
displayPoint(p)
|
||||
|
||||
def click(cb):
|
||||
event = cb.getEvent()
|
||||
if event.getButton() == 1 and event.getState() == coin.SoMouseButtonEvent.DOWN:
|
||||
accept()
|
||||
|
||||
def accept():
|
||||
if start:
|
||||
self.pointAccept()
|
||||
else:
|
||||
self.pointAcceptAndContinue()
|
||||
|
||||
def cancel():
|
||||
self.pointCancel()
|
||||
|
||||
self.pointWhenDone = whenDone
|
||||
self.formTags.hide()
|
||||
self.formPoint.show()
|
||||
self.addEscapeShortcut()
|
||||
if start:
|
||||
displayPoint(start)
|
||||
else:
|
||||
displayPoint(FreeCAD.Vector(0,0,0))
|
||||
|
||||
self.view = Draft.get3DView()
|
||||
self.pointCbClick = self.view.addEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(), click)
|
||||
self.pointCbMove = self.view.addEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(), mouseMove)
|
||||
|
||||
self.buttonBox.setEnabled(False)
|
||||
|
||||
def setupSpinBox(self, widget, val, decimals = 2):
|
||||
if decimals:
|
||||
widget.setDecimals(decimals)
|
||||
widget.setValue(val)
|
||||
|
||||
def setFields(self):
|
||||
self.updateTagsView()
|
||||
self.formTags.sbCount.setValue(len(self.obj.Positions))
|
||||
self.formTags.ifHeight.setText(FreeCAD.Units.Quantity(self.obj.Height, FreeCAD.Units.Length).UserString)
|
||||
self.formTags.ifWidth.setText(FreeCAD.Units.Quantity(self.obj.Width, FreeCAD.Units.Length).UserString)
|
||||
self.formTags.dsbAngle.setValue(self.obj.Angle)
|
||||
self.formTags.ifRadius.setText(FreeCAD.Units.Quantity(self.obj.Radius, FreeCAD.Units.Length).UserString)
|
||||
|
||||
def setupUi(self):
|
||||
self.setFields()
|
||||
self.whenCountChanged()
|
||||
|
||||
if self.obj.Proxy.supportsTagGeneration(self.obj):
|
||||
self.formTags.sbCount.valueChanged.connect(self.whenCountChanged)
|
||||
self.formTags.pbGenerate.clicked.connect(self.generateNewTags)
|
||||
else:
|
||||
self.formTags.cbTagGeneration.setEnabled(False)
|
||||
|
||||
self.formTags.ifHeight.editingFinished.connect(self.updateModel)
|
||||
self.formTags.ifWidth.editingFinished.connect(self.updateModel)
|
||||
self.formTags.dsbAngle.editingFinished.connect(self.updateModel)
|
||||
self.formTags.ifRadius.editingFinished.connect(self.updateModel)
|
||||
self.formTags.lwTags.itemChanged.connect(self.updateModel)
|
||||
self.formTags.lwTags.itemSelectionChanged.connect(self.whenTagSelectionChanged)
|
||||
self.formTags.lwTags.itemActivated.connect(self.editTag)
|
||||
|
||||
self.formTags.pbDelete.clicked.connect(self.deleteSelectedTag)
|
||||
self.formTags.pbEdit.clicked.connect(self.editSelectedTag)
|
||||
self.formTags.pbAdd.clicked.connect(self.addNewTag)
|
||||
|
||||
self.formPoint.buttonBox.accepted.connect(self.pointAccept)
|
||||
self.formPoint.buttonBox.rejected.connect(self.pointReject)
|
||||
|
||||
self.formPoint.ifValueX.editingFinished.connect(self.updatePoint)
|
||||
self.formPoint.ifValueY.editingFinished.connect(self.updatePoint)
|
||||
self.formPoint.ifValueZ.editingFinished.connect(self.updatePoint)
|
||||
|
||||
self.viewProvider.turnMarkerDisplayOn(True)
|
||||
|
||||
def pointFinish(self, ok, cleanup = True):
|
||||
obj = FreeCADGui.Snapper.lastSnappedObject
|
||||
|
||||
if cleanup:
|
||||
self.removeGlobalCallbacks();
|
||||
FreeCADGui.Snapper.off()
|
||||
self.buttonBox.setEnabled(True)
|
||||
self.removeEscapeShortcut()
|
||||
self.formPoint.hide()
|
||||
self.formTags.show()
|
||||
self.formTags.setFocus()
|
||||
|
||||
if ok:
|
||||
self.pointWhenDone(self.pt, obj)
|
||||
else:
|
||||
self.pointWhenDone(None, None)
|
||||
|
||||
def pointDone(self):
|
||||
self.pointFinish(False)
|
||||
|
||||
def pointReject(self):
|
||||
self.pointFinish(False)
|
||||
|
||||
def pointAccept(self):
|
||||
self.pointFinish(True)
|
||||
|
||||
def pointAcceptAndContinue(self):
|
||||
self.pointFinish(True, False)
|
||||
|
||||
def updatePoint(self):
|
||||
x = FreeCAD.Units.Quantity(self.formPoint.ifValueX.text()).Value
|
||||
y = FreeCAD.Units.Quantity(self.formPoint.ifValueY.text()).Value
|
||||
z = FreeCAD.Units.Quantity(self.formPoint.ifValueZ.text()).Value
|
||||
self.pt = FreeCAD.Vector(x, y, z)
|
||||
|
||||
class HoldingTagMarker:
|
||||
def __init__(self, point, colors):
|
||||
self.point = point
|
||||
self.color = colors
|
||||
self.sep = coin.SoSeparator()
|
||||
self.pos = coin.SoTranslation()
|
||||
self.pos.translation = (point.x, point.y, point.z)
|
||||
self.sphere = coin.SoSphere()
|
||||
self.scale = coin.SoType.fromName('SoShapeScale').createInstance()
|
||||
self.scale.setPart('shape', self.sphere)
|
||||
self.scale.scaleFactor.setValue(7)
|
||||
self.material = coin.SoMaterial()
|
||||
self.sep.addChild(self.pos)
|
||||
self.sep.addChild(self.material)
|
||||
self.sep.addChild(self.scale)
|
||||
self.enabled = True
|
||||
self.selected = False
|
||||
|
||||
def setSelected(self, select):
|
||||
self.selected = select
|
||||
self.sphere.radius = 1.5 if select else 1.0
|
||||
self.setEnabled(self.enabled)
|
||||
|
||||
def setEnabled(self, enabled):
|
||||
self.enabled = enabled
|
||||
if enabled:
|
||||
self.material.diffuseColor = self.color[0] if not self.selected else self.color[2]
|
||||
self.material.transparency = 0.0
|
||||
else:
|
||||
self.material.diffuseColor = self.color[1] if not self.selected else self.color[2]
|
||||
self.material.transparency = 0.6
|
||||
|
||||
class ViewProviderDressup:
|
||||
|
||||
def __init__(self, vobj):
|
||||
vobj.Proxy = self
|
||||
self.panel = None
|
||||
|
||||
def setupColors(self):
|
||||
def colorForColorValue(val):
|
||||
v = [((val >> n) & 0xff) / 255. for n in [24, 16, 8, 0]]
|
||||
return coin.SbColor(v[0], v[1], v[2])
|
||||
|
||||
pref = PathPreferences.preferences()
|
||||
# R G B A
|
||||
npc = pref.GetUnsigned("DefaultPathMarkerColor", (( 85*256 + 255)*256 + 0)*256 + 255)
|
||||
hpc = pref.GetUnsigned("DefaultHighlightPathColor", ((255*256 + 125)*256 + 0)*256 + 255)
|
||||
dpc = pref.GetUnsigned("DefaultDisabledPathColor", ((205*256 + 205)*256 + 205)*256 + 154)
|
||||
self.colors = [colorForColorValue(npc), colorForColorValue(dpc), colorForColorValue(hpc)]
|
||||
|
||||
def attach(self, vobj):
|
||||
self.setupColors()
|
||||
self.obj = vobj.Object
|
||||
self.tags = []
|
||||
self.switch = coin.SoSwitch()
|
||||
vobj.RootNode.addChild(self.switch)
|
||||
self.turnMarkerDisplayOn(False)
|
||||
|
||||
def turnMarkerDisplayOn(self, display):
|
||||
sw = coin.SO_SWITCH_ALL if display else coin.SO_SWITCH_NONE
|
||||
self.switch.whichChild = sw
|
||||
|
||||
|
||||
def claimChildren(self):
|
||||
PathLog.notice(self.obj)
|
||||
if self.obj and self.obj.Base:
|
||||
for i in self.obj.Base.InList:
|
||||
if hasattr(i, "Group"):
|
||||
group = i.Group
|
||||
for g in group:
|
||||
if g.Name == self.obj.Base.Name:
|
||||
group.remove(g)
|
||||
i.Group = group
|
||||
#print i.Group
|
||||
if self.obj.Base:
|
||||
obj = FreeCADGui.ActiveDocument.getObject(self.obj.Base.Name)
|
||||
if obj:
|
||||
obj.Visibility = False
|
||||
return [self.obj.Base]
|
||||
return []
|
||||
|
||||
def setEdit(self, vobj, mode=0):
|
||||
panel = TaskPanel(vobj.Object, self)
|
||||
self.setupTaskPanel(panel)
|
||||
return True
|
||||
|
||||
def unsetEdit(self, vobj, mode):
|
||||
if hasattr(self, 'panel') and self.panel:
|
||||
self.panel.abort()
|
||||
|
||||
def setupTaskPanel(self, panel):
|
||||
self.panel = panel
|
||||
FreeCADGui.Control.closeDialog()
|
||||
FreeCADGui.Control.showDialog(panel)
|
||||
panel.setupUi()
|
||||
FreeCADGui.Selection.addSelectionGate(self)
|
||||
FreeCADGui.Selection.addObserver(self)
|
||||
|
||||
def clearTaskPanel(self):
|
||||
self.panel = None
|
||||
FreeCADGui.Selection.removeSelectionGate()
|
||||
FreeCADGui.Selection.removeObserver(self)
|
||||
self.turnMarkerDisplayOn(False)
|
||||
|
||||
def __getstate__(self):
|
||||
def Create(baseObject, name = 'DressupTag'):
|
||||
'''
|
||||
Create(basePath, name = 'DressupTag') ... create tag dressup object for the given base path.
|
||||
'''
|
||||
if not baseObject.isDerivedFrom('Path::Feature'):
|
||||
PathLog.error(translate('PathDressup_Tag', 'The selected object is not a path\n'))
|
||||
return None
|
||||
|
||||
def __setstate__(self, state):
|
||||
if baseObject.isDerivedFrom('Path::FeatureCompoundPython'):
|
||||
PathLog.error(translate('PathDressup_Tag', 'Please select a Profile object'))
|
||||
return None
|
||||
|
||||
def onDelete(self, arg1=None, arg2=None):
|
||||
'''this makes sure that the base operation is added back to the project and visible'''
|
||||
if arg1.Object.Base:
|
||||
obj = FreeCADGui.ActiveDocument.getObject(arg1.Object.Base.Name)
|
||||
if obj:
|
||||
obj.Visibility = True
|
||||
PathUtils.addToJob(arg1.Object.Base)
|
||||
arg1.Object.Base = None
|
||||
return True
|
||||
|
||||
def updateData(self, obj, propName):
|
||||
if 'Disabled' == propName:
|
||||
for tag in self.tags:
|
||||
self.switch.removeChild(tag.sep)
|
||||
tags = []
|
||||
for i, p in enumerate(obj.Positions):
|
||||
tag = HoldingTagMarker(p, self.colors)
|
||||
tag.setEnabled(not i in obj.Disabled)
|
||||
tags.append(tag)
|
||||
self.switch.addChild(tag.sep)
|
||||
self.tags = tags
|
||||
|
||||
def selectTag(self, index):
|
||||
PathLog.track(index)
|
||||
for i, tag in enumerate(self.tags):
|
||||
tag.setSelected(i == index)
|
||||
|
||||
def tagAtPoint(self, point):
|
||||
p = FreeCAD.Vector(point[0], point[1], point[2])
|
||||
for i, tag in enumerate(self.tags):
|
||||
if PathGeom.pointsCoincide(p, tag.point, tag.sphere.radius.getValue() * 1.1):
|
||||
return i
|
||||
return -1
|
||||
|
||||
# SelectionObserver interface
|
||||
def allow(self, doc, obj, sub):
|
||||
if obj == self.obj:
|
||||
return True
|
||||
return False
|
||||
|
||||
def addSelection(self, doc, obj, sub, point):
|
||||
i = self.tagAtPoint(point)
|
||||
if self.panel:
|
||||
self.panel.selectTagWithId(i)
|
||||
FreeCADGui.updateGui()
|
||||
|
||||
class CommandPathDressupHoldingTags:
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap': 'Path-Dressup',
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("PathDressup_HoldingTags", "HoldingTags Dress-up"),
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("PathDressup_HoldingTags", "Creates a HoldingTags Dress-up object from a selected path")}
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument is not None:
|
||||
for o in FreeCAD.ActiveDocument.Objects:
|
||||
if o.Name[:3] == "Job":
|
||||
return True
|
||||
return False
|
||||
|
||||
def Activated(self):
|
||||
|
||||
# check that the selection contains exactly what we want
|
||||
selection = FreeCADGui.Selection.getSelection()
|
||||
if len(selection) != 1:
|
||||
PathLog.error(translate("PathDressup_HoldingTags", "Please select one path object\n"))
|
||||
return
|
||||
baseObject = selection[0]
|
||||
if not baseObject.isDerivedFrom("Path::Feature"):
|
||||
PathLog.error(translate("PathDressup_HoldingTags", "The selected object is not a path\n"))
|
||||
return
|
||||
if baseObject.isDerivedFrom("Path::FeatureCompoundPython"):
|
||||
PathLog.error(translate("PathDressup_HoldingTags", "Please select a Profile object"))
|
||||
return
|
||||
|
||||
# everything ok!
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("PathDressup_HoldingTags", "Create HoldingTags Dress-up"))
|
||||
FreeCADGui.addModule("PathScripts.PathDressupHoldingTags")
|
||||
FreeCADGui.addModule("PathScripts.PathUtils")
|
||||
FreeCADGui.doCommand('obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", "HoldingTagsDressup")')
|
||||
FreeCADGui.doCommand('dbo = PathScripts.PathDressupHoldingTags.ObjectDressup(obj)')
|
||||
FreeCADGui.doCommand('obj.Base = FreeCAD.ActiveDocument.' + selection[0].Name)
|
||||
FreeCADGui.doCommand('PathScripts.PathDressupHoldingTags.ViewProviderDressup(obj.ViewObject)')
|
||||
FreeCADGui.doCommand('PathScripts.PathUtils.addToJob(obj)')
|
||||
FreeCADGui.doCommand('Gui.ActiveDocument.getObject(obj.Base.Name).Visibility = False')
|
||||
FreeCADGui.doCommand('dbo.setup(obj, True)')
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
# register the FreeCAD command
|
||||
FreeCADGui.addCommand('PathDressup_HoldingTags', CommandPathDressupHoldingTags())
|
||||
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", "TagDressup")
|
||||
dbo = ObjectTagDressup(obj, baseObject)
|
||||
job = PathUtils.findParentJob(baseObject)
|
||||
PathUtils.addObjectToJob(obj, job)
|
||||
dbo.setup(obj, True)
|
||||
return obj
|
||||
|
||||
PathLog.notice("Loading PathDressupHoldingTags... done\n")
|
||||
|
||||
@@ -108,10 +108,10 @@ class TagSolid:
|
||||
return clone
|
||||
|
||||
|
||||
class ObjectDressup(QtCore.QObject):
|
||||
changed = QtCore.Signal()
|
||||
class ObjectDressup:
|
||||
|
||||
def __init__(self, obj, base):
|
||||
|
||||
obj.addProperty('App::PropertyLink', 'Base','Base', QtCore.QT_TRANSLATE_NOOP('PathDressup_Tag', 'The base path to modify'))
|
||||
obj.addProperty('App::PropertyLength', 'Width', 'Tag', QtCore.QT_TRANSLATE_NOOP('PathDressup_Tag', 'Width of tags.'))
|
||||
obj.addProperty('App::PropertyLength', 'Height', 'Tag', QtCore.QT_TRANSLATE_NOOP('PathDressup_Tag', 'Height of tags.'))
|
||||
@@ -120,19 +120,12 @@ class ObjectDressup(QtCore.QObject):
|
||||
obj.addProperty('App::PropertyVectorList', 'Positions', 'Tag', QtCore.QT_TRANSLATE_NOOP('PathDressup_Tag', 'Locations of insterted holding tags'))
|
||||
obj.addProperty('App::PropertyIntegerList', 'Disabled', 'Tag', QtCore.QT_TRANSLATE_NOOP('PathDressup_Tag', 'Ids of disabled holding tags'))
|
||||
obj.addProperty('App::PropertyInteger', 'SegmentationFactor', 'Tag', QtCore.QT_TRANSLATE_NOOP('PathDressup_Tag', 'Factor determining the # segments used to approximate rounded tags.'))
|
||||
obj.addProperty('App::PropertyLink', 'Debug', 'Debug', QtCore.QT_TRANSLATE_NOOP('PathDressup_Tag', 'Some elements for debugging'))
|
||||
|
||||
obj.Proxy = self
|
||||
obj.Base = base
|
||||
|
||||
if PathLog.getLevel(PathLog.thisModule()) != PathLog.Level.DEBUG:
|
||||
obj.setEditorMode('Debug', 2) # hide
|
||||
dbg = obj.Document.addObject('App::DocumentObjectGroup', 'TagDebug')
|
||||
obj.Debug = dbg
|
||||
|
||||
self.obj = obj
|
||||
self.solids = []
|
||||
super(ObjectDressup, self).__init__()
|
||||
|
||||
def __getstate__(self):
|
||||
return None
|
||||
@@ -196,7 +189,7 @@ class ObjectDressup(QtCore.QObject):
|
||||
self.wire, rapid = PathGeom.wireForPath(obj.Base.Path)
|
||||
self.edges = self.wire.Edges
|
||||
|
||||
maxTagZ = minZ + obj.Height
|
||||
maxTagZ = minZ + obj.Height.Value
|
||||
|
||||
lastX = 0
|
||||
lastY = 0
|
||||
@@ -214,7 +207,6 @@ class ObjectDressup(QtCore.QObject):
|
||||
commands.append(cmd)
|
||||
|
||||
obj.Path = obj.Base.Path
|
||||
self.changed.emit()
|
||||
|
||||
PathLog.track()
|
||||
|
||||
|
||||
@@ -26,7 +26,8 @@ import FreeCAD
|
||||
import FreeCADGui
|
||||
import Path
|
||||
import PathScripts
|
||||
import PathScripts.PathDressupTag as PathDressupTag
|
||||
#import PathScripts.PathDressupTag as PathDressupTag
|
||||
import PathScripts.PathDressupHoldingTags as PathDressupTag
|
||||
import PathScripts.PathLog as PathLog
|
||||
import PathScripts.PathUtils as PathUtils
|
||||
|
||||
@@ -35,13 +36,16 @@ from PathScripts.PathPreferences import PathPreferences
|
||||
from PySide import QtCore, QtGui
|
||||
from pivy import coin
|
||||
|
||||
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
|
||||
PathLog.trackModule()
|
||||
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
|
||||
#PathLog.trackModule()
|
||||
|
||||
# Qt tanslation handling
|
||||
def translate(context, text, disambig=None):
|
||||
return QtCore.QCoreApplication.translate(context, text, disambig)
|
||||
|
||||
def addDebugDisplay():
|
||||
return PathLog.getLevel(PathLog.thisModule()) == PathLog.Level.DEBUG
|
||||
|
||||
class PathDressupTagTaskPanel:
|
||||
DataX = QtCore.Qt.ItemDataRole.UserRole
|
||||
DataY = QtCore.Qt.ItemDataRole.UserRole + 1
|
||||
@@ -455,6 +459,17 @@ class PathDressupTagViewProvider:
|
||||
self.vobj = vobj
|
||||
self.panel = None
|
||||
|
||||
self.debugDisplay()
|
||||
|
||||
def debugDisplay(self):
|
||||
#if False and addDebugDisplay():
|
||||
# if not hasattr(self.vobj, 'Debug'):
|
||||
# self.vobj.addProperty('App::PropertyLink', 'Debug', 'Debug', QtCore.QT_TRANSLATE_NOOP('PathDressup_TagGui', 'Some elements for debugging'))
|
||||
# dbg = self.vobj.Object.Document.addObject('App::DocumentObjectGroup', 'TagDebug')
|
||||
# self.vobj.Debug = dbg
|
||||
# return True
|
||||
return False
|
||||
|
||||
def __getstate__(self):
|
||||
return None
|
||||
def __setstate__(self, state):
|
||||
@@ -475,6 +490,7 @@ class PathDressupTagViewProvider:
|
||||
def attach(self, vobj):
|
||||
PathLog.track()
|
||||
self.setupColors()
|
||||
self.vobj = vobj
|
||||
self.obj = vobj.Object
|
||||
self.tags = []
|
||||
self.switch = coin.SoSwitch()
|
||||
@@ -487,10 +503,8 @@ class PathDressupTagViewProvider:
|
||||
i.Group = [o for o in i.Group if o.Name != self.obj.Base.Name]
|
||||
if self.obj.Base.ViewObject:
|
||||
self.obj.Base.ViewObject.Visibility = False
|
||||
if PathLog.getLevel(PathLog.thisModule()) != PathLog.Level.DEBUG and self.obj.Debug.ViewObject:
|
||||
self.obj.Debug.ViewObject.Visibility = False
|
||||
|
||||
self.obj.Proxy.changed.connect(self.onModelChanged)
|
||||
#if self.debugDisplay() and self.vobj.Debug.ViewObject:
|
||||
# self.vobj.Debug.ViewObject.Visibility = False
|
||||
|
||||
def turnMarkerDisplayOn(self, display):
|
||||
sw = coin.SO_SWITCH_ALL if display else coin.SO_SWITCH_NONE
|
||||
@@ -498,7 +512,9 @@ class PathDressupTagViewProvider:
|
||||
|
||||
def claimChildren(self):
|
||||
PathLog.track()
|
||||
return [self.obj.Base, self.obj.Debug]
|
||||
#if self.debugDisplay():
|
||||
# return [self.obj.Base, self.vobj.Debug]
|
||||
return [self.obj.Base]
|
||||
|
||||
def onDelete(self, arg1=None, arg2=None):
|
||||
PathLog.track()
|
||||
@@ -506,9 +522,10 @@ class PathDressupTagViewProvider:
|
||||
if self.obj.Base.ViewObject:
|
||||
self.obj.Base.ViewObject.Visibility = True
|
||||
PathUtils.addToJob(arg1.Object.Base)
|
||||
self.obj.Debug.removeObjectsFromDocument()
|
||||
self.obj.Debug.Document.removeObject(self.obj.Debug.Name)
|
||||
self.obj.Debug = None
|
||||
#if self.debugDisplay():
|
||||
# self.vobj.Debug.removeObjectsFromDocument()
|
||||
# self.vobj.Debug.Document.removeObject(self.vobj.Debug.Name)
|
||||
# self.vobj.Debug = None
|
||||
return True
|
||||
|
||||
def updatePositions(self, positions, disabled):
|
||||
@@ -529,15 +546,16 @@ class PathDressupTagViewProvider:
|
||||
|
||||
def onModelChanged(self):
|
||||
PathLog.track()
|
||||
self.obj.Debug.removeObjectsFromDocument()
|
||||
for solid in self.obj.Proxy.solids:
|
||||
tag = self.obj.Document.addObject('Part::Feature', 'tag')
|
||||
tag.Shape = solid
|
||||
if tag.ViewObject and self.obj.Debug.ViewObject:
|
||||
tag.ViewObject.Visibility = self.obj.Debug.ViewObject.Visibility
|
||||
tag.ViewObject.Transparency = 80
|
||||
self.obj.Debug.addObject(tag)
|
||||
tag.purgeTouched()
|
||||
#if self.debugDisplay():
|
||||
# self.vobj.Debug.removeObjectsFromDocument()
|
||||
# for solid in self.obj.Proxy.solids:
|
||||
# tag = self.obj.Document.addObject('Part::Feature', 'tag')
|
||||
# tag.Shape = solid
|
||||
# if tag.ViewObject and self.vobj.Debug.ViewObject:
|
||||
# tag.ViewObject.Visibility = self.vobj.Debug.ViewObject.Visibility
|
||||
# tag.ViewObject.Transparency = 80
|
||||
# self.vobj.Debug.addObject(tag)
|
||||
# tag.purgeTouched()
|
||||
|
||||
def setEdit(self, vobj, mode=0):
|
||||
panel = PathDressupTagTaskPanel(vobj.Object, self)
|
||||
|
||||
Reference in New Issue
Block a user