Split DrillingGui into its own file and base it off of PathOpGui.

This commit is contained in:
Markus Lampert
2017-08-07 22:02:05 -07:00
committed by Yorik van Havre
parent 693cefd780
commit dbbee79378
13 changed files with 534 additions and 433 deletions

View File

@@ -33,6 +33,7 @@ SET(PathScripts_SRCS
PathScripts/PathDressupTagGui.py
PathScripts/PathDressupTagPreferences.py
PathScripts/PathDrilling.py
PathScripts/PathDrillingGui.py
PathScripts/PathEngrave.py
PathScripts/PathFacePocket.py
PathScripts/PathFaceProfile.py

View File

@@ -62,8 +62,10 @@
<file>panels/JobEdit.ui</file>
<file>panels/MillFaceEdit.ui</file>
<file>panels/PageBaseGeometryEdit.ui</file>
<file>panels/PageBaseHoleGeometryEdit.ui</file>
<file>panels/PageDepthsEdit.ui</file>
<file>panels/PageHeightsEdit.ui</file>
<file>panels/PageOpDrillingEdit.ui</file>
<file>panels/PageOpPocketFullEdit.ui</file>
<file>panels/PageOpProfileFullEdit.ui</file>
<file>panels/PocketEdit.ui</file>

View File

@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>415</width>
<height>573</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="3">
<widget class="QTableWidget" name="baseList">
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<column>
<property name="text">
<string>Feature</string>
</property>
</column>
<column>
<property name="text">
<string>Diameter</string>
</property>
</column>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="resetBase">
<property name="toolTip">
<string>Remove all custom objects and find holes from base object.</string>
</property>
<property name="text">
<string>Reset</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="QLabel" name="label">
<property name="text">
<string>All objects will be processed using the same operation properties.</string>
</property>
<property name="textFormat">
<enum>Qt::AutoText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="deleteBase">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="addBase">
<property name="toolTip">
<string>Add selected items from Gui View to drill</string>
</property>
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,127 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>255</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QFrame" name="frame">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>ToolController</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="toolController"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="0" rowspan="2" colspan="2">
<widget class="QCheckBox" name="dwellEnabled">
<property name="text">
<string>Dwell</string>
</property>
</widget>
</item>
<item row="3" column="2" rowspan="2">
<widget class="Gui::InputField" name="dwellTime">
<property name="text">
<string>0 sec</string>
</property>
<property name="unit" stdset="0">
<string notr="true">sec</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="Gui::InputField" name="retractHeight">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Retract Height</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="peckEnabled">
<property name="text">
<string>Peck</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="Gui::InputField" name="peckDepth">
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="useTipLength">
<property name="text">
<string>Use Tip Length</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Gui::InputField</class>
<extends>QLineEdit</extends>
<header>Gui/InputField.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@@ -52,7 +52,7 @@ class PathWorkbench (Workbench):
from PathScripts import PathDressupDragknife
from PathScripts import PathDressupRampEntry
from PathScripts import PathDressupTagGui
from PathScripts import PathDrilling
from PathScripts import PathDrillingGui
from PathScripts import PathEngrave
from PathScripts import PathFacePocket
from PathScripts import PathFaceProfile

View File

@@ -47,7 +47,7 @@ def translate(context, text, disambig=None):
class ObjectOp(PathOp.ObjectOp):
def opFeatures(self, obj):
return PathOp.FeatureTool | PathOp.FeatureDepths | PathOp.FeatureHeights | PathOp.FeatureStartPoint | self.areaOpFeatures(obj)
return PathOp.FeatureTool | PathOp.FeatureDepths | PathOp.FeatureStepDown | PathOp.FeatureHeights | PathOp.FeatureStartPoint | self.areaOpFeatures(obj)
def initOperation(self, obj):
PathLog.track()
@@ -130,11 +130,13 @@ class ObjectOp(PathOp.ObjectOp):
bb = shape.BoundBox
obj.StartDepth = bb.ZMax
obj.FinalDepth = bb.ZMin
obj.StepDown = 1.0
if PathOp.FeatureStepDown & self.opFeatures(obj):
obj.StepDown = 1.0
else:
obj.StartDepth = 1.0
obj.FinalDepth = 0.0
obj.StepDown = 1.0
if PathOp.FeatureStepDown & self.opFeatures(obj):
obj.StepDown = 1.0
if PathOp.FeatureHeights & self.opFeatures(obj):
try:

View File

@@ -34,22 +34,18 @@ import string
import sys
from PathScripts.PathUtils import fmt, waiting_effects
from PySide import QtCore, QtGui
from PySide import QtCore
# xrange is not available in python3
if sys.version_info.major >= 3:
xrange = range
if True:
if False:
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
PathLog.trackModule(PathLog.thisModule())
else:
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
FreeCADGui = None
if FreeCAD.GuiUp:
import FreeCADGui
"""Path Drilling object and FreeCAD command"""
# Qt tanslation handling
@@ -75,9 +71,6 @@ class ObjectDrilling(PathOp.ObjectOp):
obj.addProperty("App::PropertyDistance", "RetractHeight", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "The height where feed starts and height during retract tool when path is finished"))
if FreeCAD.GuiUp:
_ViewProviderDrill(obj.ViewObject)
self.vertFeed = 0.0
self.horizFeed = 0.0
self.vertRapid = 0.0
@@ -277,379 +270,3 @@ def Create(name):
obj = FreeCAD.ActiveDocument.addObject("Path::FeaturePython", name)
proxy = ObjectDrilling(obj)
return obj
class _ViewProviderDrill:
def __init__(self, obj):
obj.Proxy = self
def __getstate__(self):
return None
def __setstate__(self, state):
return None
def getIcon(self):
return ":/icons/Path-Drilling.svg"
def onChanged(self, obj, prop):
# this is executed when a property of the VIEW PROVIDER changes
pass
def updateData(self, obj, prop):
# this is executed when a property of the APP OBJECT changes
pass
def deleteObjectsOnReject(self):
return hasattr(self, 'deleteOnReject') and self.deleteOnReject
def setEdit(self, vobj, mode=0):
FreeCADGui.Control.closeDialog()
taskd = TaskPanel(vobj.Object, self.deleteObjectsOnReject())
taskd.obj = vobj.Object
FreeCADGui.Control.showDialog(taskd)
taskd.setupUi()
self.deleteOnReject = False
return True
def unsetEdit(self, vobj, mode):
# this is executed when the user cancels or terminates edit mode
pass
class CommandPathDrilling:
def GetResources(self):
return {'Pixmap': 'Path-Drilling',
'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_Drilling", "Drilling"),
'Accel': "P, D",
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_Drilling", "Creates a Path Drilling object")}
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):
ztop = 10.0
zbottom = 0.0
# if everything is ok, execute and register the transaction in the undo/redo stack
FreeCAD.ActiveDocument.openTransaction(translate("Path_Drilling", "Create Drilling"))
FreeCADGui.addModule("PathScripts.PathDrilling")
FreeCADGui.doCommand('obj = PathScripts.PathDrilling.Create("Drilling")')
FreeCADGui.doCommand('obj.ViewObject.Proxy.deleteOnReject = True')
FreeCAD.ActiveDocument.commitTransaction()
FreeCADGui.doCommand('obj.ViewObject.startEditing()')
class TaskPanel:
DataFeatureName = QtCore.Qt.ItemDataRole.UserRole
def __init__(self, obj, deleteOnReject):
FreeCAD.ActiveDocument.openTransaction(translate("Path_Drilling", "Drilling Operation"))
self.form = FreeCADGui.PySideUic.loadUi(":/panels/DrillingEdit.ui")
self.form = QtGui.QWidget()
self.formDrill = FreeCADGui.PySideUic.loadUi(":/panels/DrillingEdit.ui")
self.formPoint = FreeCADGui.PySideUic.loadUi(":/panels/PointEdit.ui")
self.layout = QtGui.QVBoxLayout(self.form)
self.formDrill.setWindowTitle(self.formDrill.windowTitle())
self.formDrill.setSizePolicy(self.formDrill.sizePolicy())
self.formDrill.setParent(self.form)
self.formPoint.setParent(self.form)
self.layout.addWidget(self.formDrill)
self.layout.addWidget(self.formPoint)
self.formPoint.hide()
self.deleteOnReject = deleteOnReject
self.obj = obj
self.isDirty = True
def accept(self):
FreeCADGui.Control.closeDialog()
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.commitTransaction()
if self.isDirty:
FreeCAD.ActiveDocument.recompute()
def reject(self):
FreeCADGui.Control.closeDialog()
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.abortTransaction()
if self.deleteOnReject:
FreeCAD.ActiveDocument.openTransaction(translate("Path_Drilling", "Uncreate Drilling Operation"))
FreeCAD.ActiveDocument.removeObject(self.obj.Name)
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
def clicked(self, button):
if button == QtGui.QDialogButtonBox.Apply:
self.getFields()
FreeCAD.ActiveDocument.recompute()
self.isDirty = False
def getFields(self):
PathLog.track()
if self.obj:
try:
if hasattr(self.obj, "StartDepth"):
self.obj.StartDepth = FreeCAD.Units.Quantity(self.form.startDepth.text()).Value
if hasattr(self.obj, "FinalDepth"):
self.obj.FinalDepth = FreeCAD.Units.Quantity(self.form.finalDepth.text()).Value
if hasattr(self.obj, "PeckDepth"):
if FreeCAD.Units.Quantity(self.form.peckDepth.text()).Value >= 0:
self.obj.PeckDepth = FreeCAD.Units.Quantity(self.form.peckDepth.text()).Value
else:
self.form.peckDepth.setText("0.00")
if hasattr(self.obj, "SafeHeight"):
self.obj.SafeHeight = FreeCAD.Units.Quantity(self.form.safeHeight.text()).Value
if hasattr(self.obj, "ClearanceHeight"):
self.obj.ClearanceHeight = FreeCAD.Units.Quantity(self.form.clearanceHeight.text()).Value
if hasattr(self.obj, "RetractHeight"):
self.obj.RetractHeight = FreeCAD.Units.Quantity(self.form.retractHeight.text()).Value
if hasattr(self.obj, "DwellTime"):
if FreeCAD.Units.Quantity(self.form.dwellTime.text()).Value >= 0:
self.obj.DwellTime = FreeCAD.Units.Quantity(self.form.dwellTime.text()).Value
else:
self.form.dwellTime.setText("0.00")
if hasattr(self.obj, "DwellEnabled"):
self.obj.DwellEnabled = self.form.dwellEnabled.isChecked()
if hasattr(self.obj, "PeckEnabled"):
self.obj.PeckEnabled = self.form.peckEnabled.isChecked()
if hasattr(self.obj, "ToolController"):
PathLog.debug("name: {}".format(self.form.uiToolController.currentText()))
tc = PathUtils.findToolController(self.obj, self.form.uiToolController.currentText())
self.obj.ToolController = tc
if hasattr(self.obj, "AddTipLength"):
self.obj.AddTipLength = self.form.chkTipDepth.isChecked()
except ValueError:
self.setFields()
self.isDirty = True
def updateFeatureList(self):
self.form.baseList.itemChanged.disconnect(self.checkedChanged) # disconnect this slot while creating objects
self.form.baseList.clear()
self.form.baseList.setColumnCount(2)
self.form.baseList.setRowCount(0)
self.form.baseList.setHorizontalHeaderLabels(["Feature", "Diameter"])
self.form.baseList.horizontalHeader().setStretchLastSection(True)
self.form.baseList.resizeColumnToContents(0)
self.form.baseList.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
for i, (base, subs) in enumerate(self.obj.Base):
for sub in subs:
self.form.baseList.insertRow(self.form.baseList.rowCount())
item = QtGui.QTableWidgetItem("%s.%s" % (base.Label, sub))
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
if self.obj.Proxy.isHoleEnabled(self.obj, base, sub):
item.setCheckState(QtCore.Qt.Checked)
else:
item.setCheckState(QtCore.Qt.Unchecked)
self.form.baseList.setItem(self.form.baseList.rowCount()-1, 0, item)
item.setData(self.DataFeatureName, "%s.%s" % (base.Name, sub))
item = QtGui.QTableWidgetItem("{:.3f}".format(self.obj.Proxy.holeDiameter(self.obj, base, sub)))
self.form.baseList.setItem(self.form.baseList.rowCount()-1, 1, item)
self.form.baseList.resizeColumnToContents(0)
self.form.baseList.itemChanged.connect(self.checkedChanged)
self.form.baseList.setSortingEnabled(True)
def setFields(self):
PathLog.track()
self.form.startDepth.setText(FreeCAD.Units.Quantity(self.obj.StartDepth.Value, FreeCAD.Units.Length).UserString)
self.form.finalDepth.setText(FreeCAD.Units.Quantity(self.obj.FinalDepth.Value, FreeCAD.Units.Length).UserString)
self.form.peckDepth.setText(FreeCAD.Units.Quantity(self.obj.PeckDepth.Value, FreeCAD.Units.Length).UserString)
self.form.safeHeight.setText(FreeCAD.Units.Quantity(self.obj.SafeHeight.Value, FreeCAD.Units.Length).UserString)
self.form.clearanceHeight.setText(FreeCAD.Units.Quantity(self.obj.ClearanceHeight.Value, FreeCAD.Units.Length).UserString)
self.form.retractHeight.setText(FreeCAD.Units.Quantity(self.obj.RetractHeight.Value, FreeCAD.Units.Length).UserString)
self.form.dwellTime.setText(str(self.obj.DwellTime))
if self.obj.DwellEnabled:
self.form.dwellEnabled.setCheckState(QtCore.Qt.Checked)
else:
self.form.dwellEnabled.setCheckState(QtCore.Qt.Unchecked)
if self.obj.PeckEnabled:
self.form.peckEnabled.setCheckState(QtCore.Qt.Checked)
else:
self.form.peckEnabled.setCheckState(QtCore.Qt.Unchecked)
if self.obj.AddTipLength:
self.form.chkTipDepth.setCheckState(QtCore.Qt.Checked)
else:
self.form.chkTipDepth.setCheckState(QtCore.Qt.Unchecked)
self.updateFeatureList()
controllers = PathUtils.getToolControllers(self.obj)
labels = [c.Label for c in controllers]
self.form.uiToolController.blockSignals(True)
self.form.uiToolController.addItems(labels)
self.form.uiToolController.blockSignals(False)
if self.obj.ToolController is not None:
index = self.form.uiToolController.findText(
self.obj.ToolController.Label, QtCore.Qt.MatchFixedString)
PathLog.debug("searching for TC label {}. Found Index: {}".format(self.obj.ToolController.Label, index))
if index >= 0:
self.form.uiToolController.blockSignals(True)
self.form.uiToolController.setCurrentIndex(index)
self.form.uiToolController.blockSignals(False)
def open(self):
pass
# self.s = SelObserver()
# FreeCADGui.Selection.addObserver(self.s)
def itemActivated(self):
FreeCADGui.Selection.clearSelection()
slist = self.form.baseList.selectedItems()
# parentJob = PathUtils.findParentJob(self.obj)
for i in slist:
if i.column() == 0:
objstring = i.text().partition(".")
obj = FreeCAD.ActiveDocument.getObject(objstring[0])
if obj is not None:
if objstring[2] != "":
FreeCADGui.Selection.addSelection(obj, objstring[2])
else:
FreeCADGui.Selection.addSelection(obj)
FreeCADGui.updateGui()
def checkedChanged(self):
disabled = []
for i in xrange(0, self.form.baseList.rowCount()):
item = self.form.baseList.item(i, 0)
if item.checkState() != QtCore.Qt.Checked:
disabled.append(item.data(self.DataFeatureName))
self.obj.Disabled = disabled
FreeCAD.ActiveDocument.recompute()
def enableAll(self):
for i in xrange(0, self.form.baseList.rowCount()):
self.form.baseList.item(i, 0).setCheckState(QtCore.Qt.Checked)
def enableSelected(self):
slist = self.form.baseList.selectedItems()
for i in slist:
r = i.row()
self.form.baseList.item(r, 0).setCheckState(QtCore.Qt.Checked)
def disableAll(self):
for i in xrange(0, self.form.baseList.rowCount()):
self.form.baseList.item(i, 0).setCheckState(QtCore.Qt.Unchecked)
def disableSelected(self):
slist = self.form.baseList.selectedItems()
for i in slist:
r = i.row()
self.form.baseList.item(r, 0).setCheckState(QtCore.Qt.Unchecked)
def findAll(self):
""" Reset the list of features by running the findHoles again """
self.obj.Base = []
self.obj.Disabled = []
self.obj.Proxy.execute(self.obj)
self.setFields()
FreeCAD.ActiveDocument.recompute()
def addSelected(self):
for sel in FreeCAD.Gui.Selection.getSelectionEx():
baseObjects = self.obj.Base
objectname = sel.ObjectName
sobj = sel.Object
for i, sub in enumerate(sel.SubObjects):
if hasattr(sub, 'ShapeType'):
item = None
if sub.ShapeType == 'Vertex':
PathLog.debug("Selection is a vertex, lets drill that")
item = (sobj, sel.SubElementNames[i])
elif sub.ShapeType == 'Edge':
if PathUtils.isDrillable(sobj, sub):
PathLog.debug("Selection is a drillable edge, lets drill that")
item = (sobj, sel.SubElementNames[i])
# check for arcs - isDrillable ignores them.
elif type(sub.Curve) == Part.Circle:
PathLog.debug("Selection is an arc or circle edge, lets drill the center")
item = (sobj, sel.SubElementNames[i])
elif sub.ShapeType == 'Face':
if PathUtils.isDrillable(sobj.Shape, sub):
PathLog.debug("Selection is a drillable face, lets drill that")
item = (sobj, sel.SubElementNames[i])
if item and not item in self.obj.Base:
baseObjects.append(item)
self.obj.Base = baseObjects
PathLog.debug("baseObjects=%s, obj.Base=%s" % (baseObjects, self.obj.Base))
self.setFields()
FreeCAD.ActiveDocument.recompute()
def addCustom(self):
self.np.addCustom()
def addCustomPoint(self, point, o):
if point is not None:
names = self.obj.Names
positions = self.obj.Positions
enabled = self.obj.Enabled
diameters = self.obj.Diameters
names.append('CustomX{:.3f}Y{:.3f}'.format(point.x, point.y))
positions.append(FreeCAD.Vector(point.x, point.y, 0))
enabled.append(1)
diameters.append(0)
self.obj.Names = names
self.obj.Positions = positions
self.obj.Enabled = enabled
self.obj.Diameters = diameters
self.updateFeatureList()
FreeCAD.ActiveDocument.recompute()
def getStandardButtons(self):
return int(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Apply | QtGui.QDialogButtonBox.Cancel)
def setupUi(self):
PathLog.track()
# Connect Signals and Slots
self.form.startDepth.editingFinished.connect(self.getFields)
self.form.finalDepth.editingFinished.connect(self.getFields)
self.form.safeHeight.editingFinished.connect(self.getFields)
self.form.retractHeight.editingFinished.connect(self.getFields)
self.form.peckDepth.editingFinished.connect(self.getFields)
self.form.clearanceHeight.editingFinished.connect(self.getFields)
self.form.dwellTime.editingFinished.connect(self.getFields)
self.form.dwellEnabled.stateChanged.connect(self.getFields)
self.form.peckEnabled.stateChanged.connect(self.getFields)
self.form.chkTipDepth.stateChanged.connect(self.getFields)
# buttons
self.form.uiEnableSelected.clicked.connect(self.enableSelected)
self.form.uiDisableSelected.clicked.connect(self.disableSelected)
self.form.uiFindAllHoles.clicked.connect(self.findAll)
self.form.uiAddSelected.clicked.connect(self.addSelected)
self.form.uiAddCustom.clicked.connect(self.addCustom)
self.form.baseList.itemSelectionChanged.connect(self.itemActivated)
self.form.baseList.itemChanged.connect(self.checkedChanged)
self.form.uiToolController.currentIndexChanged.connect(self.getFields)
self.setFields()
if FreeCAD.GuiUp:
# register the FreeCAD command
FreeCADGui.addCommand('Path_Drilling', CommandPathDrilling())
FreeCAD.Console.PrintLog("Loading PathDrilling... done\n")

View File

@@ -0,0 +1,212 @@
# -*- coding: utf-8 -*-
# ***************************************************************************
# * *
# * 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) *
# * as published by the Free Software Foundation; either version 2 of *
# * the License, or (at your option) any later version. *
# * for detail see the LICENCE text file. *
# * *
# * This program is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this program; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
# * USA *
# * *
# ***************************************************************************
import FreeCAD
import FreeCADGui
import PathScripts.PathOpGui as PathOpGui
import PathScripts.PathDrilling as PathDrilling
import PathScripts.PathLog as PathLog
import PathScripts.PathPocketBaseGui as PathPocketBaseGui
from PySide import QtCore, QtGui
if True:
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
PathLog.trackModule(PathLog.thisModule())
else:
PathLog.setLevel(PathLog.Level.NOTICE, PathLog.thisModule())
class TaskPanelHoleGeometryPage(PathOpGui.TaskPanelBaseGeometryPage):
DataFeatureName = QtCore.Qt.ItemDataRole.UserRole
DataObject = QtCore.Qt.ItemDataRole.UserRole + 1
DataObjectSub = QtCore.Qt.ItemDataRole.UserRole + 2
def getForm(self):
return FreeCADGui.PySideUic.loadUi(":/panels/PageBaseHoleGeometryEdit.ui")
def setFields(self, obj):
PathLog.track()
self.form.baseList.blockSignals(True)
self.form.baseList.clearContents()
self.form.baseList.setRowCount(0)
for i, (base, subs) in enumerate(self.obj.Base):
for sub in subs:
self.form.baseList.insertRow(self.form.baseList.rowCount())
item = QtGui.QTableWidgetItem("%s.%s" % (base.Label, sub))
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
if self.obj.Proxy.isHoleEnabled(self.obj, base, sub):
item.setCheckState(QtCore.Qt.Checked)
else:
item.setCheckState(QtCore.Qt.Unchecked)
name = "%s.%s" % (base.Name, sub)
item.setData(self.DataFeatureName, name)
item.setData(self.DataObject, base)
item.setData(self.DataObjectSub, sub)
self.form.baseList.setItem(self.form.baseList.rowCount()-1, 0, item)
item = QtGui.QTableWidgetItem("{:.3f}".format(self.obj.Proxy.holeDiameter(self.obj, base, sub)))
item.setData(self.DataFeatureName, name)
item.setData(self.DataObject, base)
item.setData(self.DataObjectSub, sub)
item.setTextAlignment(QtCore.Qt.AlignHCenter)
self.form.baseList.setItem(self.form.baseList.rowCount()-1, 1, item)
self.form.baseList.resizeColumnToContents(0)
self.form.baseList.blockSignals(False)
def itemActivated(self):
PathLog.track()
FreeCADGui.Selection.clearSelection()
activatedRows = []
for item in self.form.baseList.selectedItems():
row = item.row()
if not row in activatedRows:
activatedRows.append(row)
obj = item.data(self.DataObject)
sub = str(item.data(self.DataObjectSub))
PathLog.debug("itemActivated() -> %s.%s" % (obj.Label, sub))
if sub:
FreeCADGui.Selection.addSelection(obj, sub)
else:
FreeCADGui.Selection.addSelection(obj)
#FreeCADGui.updateGui()
def deleteBase(self):
PathLog.track()
deletedRows = []
selected = self.form.baseList.selectedItems()
for item in selected:
row = self.form.baseList.row(item)
if not row in deletedRows:
deletedRows.append(row)
self.form.baseList.removeRow(row)
self.updateBase()
#self.obj.Proxy.execute(self.obj)
FreeCAD.ActiveDocument.recompute()
def updateBase(self):
PathLog.track()
newlist = []
for i in range(self.form.baseList.rowCount()):
item = self.form.baseList.item(i, 0)
obj = item.data(self.DataObject)
sub = str(item.data(self.DataObjectSub))
base = (obj, sub)
PathLog.debug("keeping (%s.%s)" % (obj.Label, sub))
newlist.append(base)
PathLog.debug("obj.Base=%s newlist=%s" % (self.obj.Base, newlist))
self.obj.Base = newlist
def checkedChanged(self):
PathLog.track()
disabled = []
for i in xrange(0, self.form.baseList.rowCount()):
item = self.form.baseList.item(i, 0)
if item.checkState() != QtCore.Qt.Checked:
disabled.append(item.data(self.DataFeatureName))
self.obj.Disabled = disabled
FreeCAD.ActiveDocument.recompute()
def registerSignalHandlers(self, obj):
self.form.baseList.itemSelectionChanged.connect(self.itemActivated)
self.form.addBase.clicked.connect(self.addBase)
self.form.deleteBase.clicked.connect(self.deleteBase)
self.form.resetBase.clicked.connect(self.resetBase)
self.form.baseList.itemChanged.connect(self.checkedChanged)
def resetBase(self):
self.obj.Base = []
self.obj.Disabled = []
self.obj.Proxy.execute(self.obj)
FreeCAD.ActiveDocument.recompute()
def updateData(self, obj, prop):
if prop in ['Base', 'Disabled']:
self.setFields(self.obj)
class TaskPanelOpPage(PathOpGui.TaskPanelPage):
def getForm(self):
return FreeCADGui.PySideUic.loadUi(":/panels/PageOpDrillingEdit.ui")
def getFields(self, obj):
PathLog.track()
self.obj.PeckDepth = FreeCAD.Units.Quantity(self.form.peckDepth.text()).Value
self.obj.RetractHeight = FreeCAD.Units.Quantity(self.form.retractHeight.text()).Value
self.obj.DwellTime = FreeCAD.Units.Quantity(self.form.dwellTime.text()).Value
self.obj.DwellEnabled = self.form.dwellEnabled.isChecked()
self.obj.PeckEnabled = self.form.peckEnabled.isChecked()
self.obj.AddTipLength = self.form.useTipLength.isChecked()
self.updateToolController(obj, self.form.toolController)
def setFields(self, obj):
PathLog.track()
self.form.peckDepth.setText(FreeCAD.Units.Quantity(self.obj.PeckDepth.Value, FreeCAD.Units.Length).UserString)
self.form.retractHeight.setText(FreeCAD.Units.Quantity(self.obj.RetractHeight.Value, FreeCAD.Units.Length).UserString)
self.form.dwellTime.setText(str(self.obj.DwellTime))
if self.obj.DwellEnabled:
self.form.dwellEnabled.setCheckState(QtCore.Qt.Checked)
else:
self.form.dwellEnabled.setCheckState(QtCore.Qt.Unchecked)
if self.obj.PeckEnabled:
self.form.peckEnabled.setCheckState(QtCore.Qt.Checked)
else:
self.form.peckEnabled.setCheckState(QtCore.Qt.Unchecked)
if self.obj.AddTipLength:
self.form.useTipLength.setCheckState(QtCore.Qt.Checked)
else:
self.form.useTipLength.setCheckState(QtCore.Qt.Unchecked)
self.setupToolController(self.obj, self.form.toolController)
def getSignalsForUpdate(self, obj):
signals = []
signals.append(self.form.retractHeight.editingFinished)
signals.append(self.form.peckDepth.editingFinished)
signals.append(self.form.dwellTime.editingFinished)
signals.append(self.form.dwellEnabled.stateChanged)
signals.append(self.form.peckEnabled.stateChanged)
signals.append(self.form.useTipLength.stateChanged)
return signals
def taskPanelBaseGeometryPage(self, obj, features):
return TaskPanelHoleGeometryPage(obj, features)
PathOpGui.SetupOperation('Drilling',
PathDrilling.Create,
TaskPanelOpPage,
'Path-Drilling',
QtCore.QT_TRANSLATE_NOOP("PathDrilling", "Drilling"),
"P, O",
QtCore.QT_TRANSLATE_NOOP("PathDrilling", "Creates a Path Drilling object from a features of a base object"))
FreeCAD.Console.PrintLog("Loading PathDrillingGui... done\n")

View File

@@ -46,12 +46,13 @@ FeatureDepths = 0x0002
FeatureHeights = 0x0004
FeatureStartPoint = 0x0008
FeatureFinishDepth = 0x0010
FeatureBaseFeatures = 0x1000
FeatureBaseFaces = 0x2000
FeatureBaseEdges = 0x4000
FeatureStepDown = 0x0020
FeatureBaseVertexes = 0x1000
FeatureBaseEdges = 0x2000
FeatureBaseFaces = 0x4000
FeatureBasePanels = 0x8000
FeatureBaseGeometry = FeatureBaseFeatures | FeatureBaseFaces | FeatureBaseEdges | FeatureBasePanels
FeatureBaseGeometry = FeatureBaseVertexes | FeatureBaseFaces | FeatureBaseEdges | FeatureBasePanels
class ObjectOp(object):
@@ -69,10 +70,12 @@ class ObjectOp(object):
obj.addProperty("App::PropertyLink", "ToolController", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "The tool controller that will be used to calculate the path"))
if FeatureDepths & self.opFeatures(obj):
obj.addProperty("App::PropertyDistance", "StepDown", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Incremental Step Down of Tool"))
obj.addProperty("App::PropertyDistance", "StartDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Starting Depth of Tool- first cut depth in Z"))
obj.addProperty("App::PropertyDistance", "FinalDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Final Depth of Tool- lowest value in Z"))
if FeatureStepDown & self.opFeatures(obj):
obj.addProperty("App::PropertyDistance", "StepDown", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Incremental Step Down of Tool"))
if FeatureFinishDepth & self.opFeatures(obj):
obj.addProperty("App::PropertyDistance", "FinishDepth", "Depth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Maximum material removed on final pass."))
@@ -116,6 +119,8 @@ class ObjectOp(object):
if FeatureDepths & self.opFeatures(obj):
obj.StartDepth = 1.0
obj.FinalDepth = 0.0
if FeatureStepDown & self.opFeatures(obj):
obj.StepDown = 1.0
if FeatureHeights & self.opFeatures(obj):

View File

@@ -24,7 +24,6 @@
import FreeCAD
import FreeCADGui
import PathScripts.PathAreaOp as PathAreaOp
import PathScripts.PathLog as PathLog
import PathScripts.PathSelection as PathSelection
import PathScripts.PathOp as PathOp
@@ -38,11 +37,12 @@ from PySide import QtCore, QtGui
# 1 ... reverse order
# 2 ... multi panel layout
# 3 ... multi panel layout reverse
TaskPanelLayout = 2
TaskPanelLayout = 0
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
PathLog.trackModule(PathLog.thisModule())
if False:
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
PathLog.trackModule(PathLog.thisModule())
def translate(context, text, disambig=None):
return QtCore.QCoreApplication.translate(context, text, disambig)
@@ -62,6 +62,7 @@ class ViewProvider(object):
def attach(self, vobj):
PathLog.track()
self.Object = vobj.Object
self.panel = None
return
def deleteObjectsOnReject(self):
@@ -70,15 +71,21 @@ class ViewProvider(object):
def setEdit(self, vobj, mode=0):
PathLog.track()
FreeCADGui.Control.closeDialog()
page = self.getTaskPanelOpPage(vobj.Object)
selection = self.getSelectionFactory()
taskd = TaskPanel(vobj.Object, self.deleteObjectsOnReject(), page, selection)
FreeCADGui.Control.showDialog(taskd)
taskd.setupUi()
self.setupTaskPanel(TaskPanel(vobj.Object, self.deleteObjectsOnReject(), page, selection))
self.deleteOnReject = False
return True
def setupTaskPanel(self, panel):
self.panel = panel
FreeCADGui.Control.closeDialog()
FreeCADGui.Control.showDialog(panel)
panel.setupUi()
def clearTaskPanel(self):
self.panel = None
def __getstate__(self):
PathLog.track()
state = {}
@@ -105,6 +112,11 @@ class ViewProvider(object):
def getSelectionFactory(self):
return PathSelection.select(self.OpName)
def updateData(self, obj, prop):
# PathLog.track(obj.Label, prop) # Creates a lot of noise
if self.panel:
self.panel.updateData(obj, prop)
class TaskPanelPage(object):
# task panel interaction framework
@@ -132,6 +144,9 @@ class TaskPanelPage(object):
signal.connect(self.pageGetFields)
self.registerSignalHandlers(self.obj)
def pageUpdateData(self, obj, prop):
self.updateData(obj, prop)
def setTitle(self, title):
self.title = title
def getTitle(self, obj):
@@ -150,6 +165,8 @@ class TaskPanelPage(object):
return []
def registerSignalHandlers(self, obj):
pass
def updateData(self, obj, prop):
pass
# helpers
def selectInComboBox(self, name, combo):
@@ -171,14 +188,21 @@ class TaskPanelPage(object):
if obj.ToolController is not None:
self.selectInComboBox(obj.ToolController.Label, combo)
def updateToolController(self, obj, combo):
tc = PathUtils.findToolController(obj, combo.currentText())
self.obj.ToolController = tc
class TaskPanelBaseGeometryPage(TaskPanelPage):
DataObject = QtCore.Qt.ItemDataRole.UserRole
DataObjectSub = QtCore.Qt.ItemDataRole.UserRole + 1
def getForm(self):
return FreeCADGui.PySideUic.loadUi(":/panels/PageBaseGeometryEdit.ui")
def getTitle(self, obj):
return translate("PathOp", "Base Geometry")
def getFields(self, obj):
pass
def setFields(self, obj):
self.form.baseList.blockSignals(True)
self.form.baseList.clear()
@@ -201,6 +225,8 @@ class TaskPanelBaseGeometryPage(TaskPanelPage):
FreeCADGui.Selection.addSelection(obj)
#FreeCADGui.updateGui()
def supportsVertexes(self):
return self.features & PathOp.FeatureBaseVertexes
def supportsEdges(self):
return self.features & PathOp.FeatureBaseEdges
def supportsFaces(self):
@@ -224,11 +250,14 @@ class TaskPanelBaseGeometryPage(TaskPanelPage):
return False
sel = selection[0]
if sel.HasSubObjects:
if not self.supportsVertexes() and selection[0].SubObjects[0].ShapeType == "Vertex":
PathLog.error(translate("PathProject", "Vertexes are not supported"))
return False
if not self.supportsEdges() and selection[0].SubObjects[0].ShapeType == "Edge":
PathLog.error(translate("PathProject", "Please select only %s of a solid" % self.featureName()))
PathLog.error(translate("PathProject", "Edges are not supported"))
return False
if not self.supportsFaces() and selection[0].SubObjects[0].ShapeType == "Face":
PathLog.error(translate("PathProject", "Please select only %s of a solid" % self.featureName()))
PathLog.error(translate("PathProject", "Faces are not supported"))
return False
else:
if not self.supportsPanels() or not 'Panel' in sel.Object.Name:
@@ -249,7 +278,7 @@ class TaskPanelBaseGeometryPage(TaskPanelPage):
selected = self.form.baseList.selectedItems()
for item in selected:
self.form.baseList.takeItem(self.form.baseList.row(item))
self.updateBase()
self.updateBase()
#self.obj.Proxy.execute(self.obj)
#FreeCAD.ActiveDocument.recompute()
@@ -273,6 +302,11 @@ class TaskPanelBaseGeometryPage(TaskPanelPage):
self.form.deleteBase.clicked.connect(self.deleteBase)
self.form.updateBase.clicked.connect(self.updateBase)
def pageUpdateData(self, obj, prop):
if prop in ['Base']:
self.setFields(obj)
class TaskPanelHeightsPage(TaskPanelPage):
def getForm(self):
return FreeCADGui.PySideUic.loadUi(":/panels/PageHeightsEdit.ui")
@@ -287,44 +321,57 @@ class TaskPanelHeightsPage(TaskPanelPage):
def getSignalsForUpdate(self, obj):
return [self.form.safeHeight.editingFinished, self.form.clearanceHeight.editingFinished]
def pageUpdateData(self, obj, prop):
if prop in ['SafeHeight', 'ClearanceHeight']:
self.setFields(obj)
class TaskPanelDepthsPage(TaskPanelPage):
def getForm(self):
return FreeCADGui.PySideUic.loadUi(":/panels/PageDepthsEdit.ui")
def initPage(self, obj):
if PathOp.FeatureFinishDepth & self.features:
self.form.finishDepth.setEnabled(True)
self.form.finishDepthLabel.setEnabled(True)
else:
if not PathOp.FeatureStepDown & self.features:
self.form.stepDown.hide()
self.form.stepDownLabel.hide()
if not PathOp.FeatureFinishDepth & self.features:
self.form.finishDepth.hide()
self.form.finishDepthLabel.hide()
def getTitle(self, obj):
return translate("PathAreaOp", "Depths")
return translate("PathOp", "Depths")
def getFields(self, obj):
obj.StartDepth = FreeCAD.Units.Quantity(self.form.startDepth.text()).Value
obj.FinalDepth = FreeCAD.Units.Quantity(self.form.finalDepth.text()).Value
obj.StepDown = FreeCAD.Units.Quantity(self.form.stepDown.text()).Value
if PathOp.FeatureStepDown & self.features:
obj.StepDown = FreeCAD.Units.Quantity(self.form.stepDown.text()).Value
if PathOp.FeatureFinishDepth & self.features:
obj.FinishDepth = FreeCAD.Units.Quantity(self.form.finishDepth.text()).Value
def setFields(self, obj):
self.form.startDepth.setText(FreeCAD.Units.Quantity(obj.StartDepth.Value, FreeCAD.Units.Length).UserString)
self.form.finalDepth.setText(FreeCAD.Units.Quantity(obj.FinalDepth.Value, FreeCAD.Units.Length).UserString)
self.form.stepDown.setText(FreeCAD.Units.Quantity(obj.StepDown.Value, FreeCAD.Units.Length).UserString)
if PathOp.FeatureStepDown & self.features:
self.form.stepDown.setText(FreeCAD.Units.Quantity(obj.StepDown.Value, FreeCAD.Units.Length).UserString)
if PathOp.FeatureFinishDepth & self.features:
self.form.finishDepth.setText(FreeCAD.Units.Quantity(obj.FinishDepth.Value, FreeCAD.Units.Length).UserString)
def getSignalsForUpdate(self, obj):
signals = []
signals.append(self.form.startDepth.editingFinished)
signals.append(self.form.finalDepth.editingFinished)
signals.append(self.form.stepDown.editingFinished)
if PathOp.FeatureStepDown & self.features:
signals.append(self.form.stepDown.editingFinished)
if PathOp.FeatureFinishDepth & self.features:
signals = super(self.__class__, self).getSignalsForUpdate(obj)
signals.append(self.form.finishDepth.editingFinished)
return signals
def pageUpdateData(self, obj, prop):
if prop in ['StartDepth', 'FinalDepth', 'StepDown', 'FinishDepth']:
self.setFields(obj)
class TaskPanel(object):
def __init__(self, obj, deleteOnReject, opPage, selectionFactory):
@@ -354,7 +401,7 @@ class TaskPanel(object):
else:
self.featurePages.append(TaskPanelHeightsPage(obj, features))
opPage.setTitle(translate('PathAreaOp', 'Operation'))
opPage.setTitle(translate('PathOp', 'Operation'))
self.featurePages.append(opPage)
for page in self.featurePages:
@@ -398,23 +445,27 @@ class TaskPanel(object):
page.setClean()
def accept(self):
FreeCADGui.Control.closeDialog()
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.commitTransaction()
FreeCADGui.Selection.removeObserver(self.s)
self.cleanup()
if self.isDirty:
self.panelGetFields()
FreeCAD.ActiveDocument.recompute()
def reject(self):
FreeCADGui.Control.closeDialog()
FreeCADGui.ActiveDocument.resetEdit()
FreeCAD.ActiveDocument.abortTransaction()
FreeCADGui.Selection.removeObserver(self.s)
self.cleanup()
if self.deleteOnReject:
FreeCAD.ActiveDocument.openTransaction(translate("Path_AreaOp", "Uncreate AreaOp Operation"))
FreeCAD.ActiveDocument.removeObject(self.obj.Name)
FreeCAD.ActiveDocument.commitTransaction()
FreeCAD.ActiveDocument.recompute()
def cleanup(self):
self.obj.ViewObject.Proxy.clearTaskPanel()
FreeCADGui.Control.closeDialog()
FreeCADGui.ActiveDocument.resetEdit()
FreeCADGui.Selection.removeObserver(self.s)
def clicked(self, button):
if button == QtGui.QDialogButtonBox.Apply:
self.panelGetFields()
@@ -453,6 +504,11 @@ class TaskPanel(object):
for page in self.featurePages:
page.pageRegisterSignalHandlers()
def updateData(self, obj, prop):
# PathLog.track(obj.Label, prop) # creates a lot of noise
for page in self.featurePages:
page.pageUpdateData(obj, prop)
class SelObserver:
def __init__(self, factory):

View File

@@ -29,7 +29,6 @@ import PathScripts.PathOpGui as PathOpGui
import PathScripts.PathPocket as PathPocket
import PathScripts.PathSelection as PathSelection
from PathScripts import PathUtils
from PySide import QtCore, QtGui
def translate(context, text, disambig=None):
@@ -57,8 +56,7 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
self.obj.OffsetPattern = str(self.form.offsetPattern.currentText())
self.obj.ZigZagAngle = FreeCAD.Units.Quantity(self.form.zigZagAngle.text()).Value
tc = PathUtils.findToolController(self.obj, self.form.toolController.currentText())
self.obj.ToolController = tc
self.updateToolController(self.obj, self.form.toolController)
if FeaturePocket & self.pocketFeatures():
self.obj.MaterialAllowance = FreeCAD.Units.Quantity(self.form.extraOffset.text()).Value

View File

@@ -28,7 +28,6 @@ import PathScripts.PathLog as PathLog
import PathScripts.PathOpGui as PathOpGui
import PathScripts.PathProfileFaces as PathProfileFaces
import PathScripts.PathSelection as PathSelection
import PathScripts.PathUtils as PathUtils
from PySide import QtCore
@@ -60,8 +59,7 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
self.obj.UseStartPoint = self.form.useStartPoint.isChecked()
self.obj.Direction = str(self.form.direction.currentText())
tc = PathUtils.findToolController(self.obj, self.form.toolController.currentText())
self.obj.ToolController = tc
self.updateToolController(self.obj, self.form.toolController)
if FeatureSide & self.profileFeatures():
self.obj.Side = str(self.form.cutSide.currentText())

View File

@@ -28,9 +28,9 @@ import FreeCADGui
import PathScripts.PathLog as PathLog
import PathScripts.PathUtils as PathUtils
LOG_MODULE = 'PathSelection'
PathLog.setLevel(PathLog.Level.INFO, LOG_MODULE)
PathLog.trackModule('PathSelection')
if False:
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
PathLog.trackModule(PathLog.thisModule())
class EGate:
@@ -60,10 +60,10 @@ class ENGRAVEGate:
class DRILLGate:
def allow(self, doc, obj, sub):
PathLog.debug('obj: {} sub: {}'.format(obj, sub))
if hasattr(obj, "Shape"):
obj = obj.Shape
subobj = obj.getElement(sub)
return PathUtils.isDrillable(obj, subobj)
if hasattr(obj, "Shape") and sub:
shape = obj.Shape
subobj = shape.getElement(sub)
return PathUtils.isDrillable(shape, subobj)
else:
return False
@@ -163,6 +163,7 @@ def surfaceselect():
def select(op):
opsel = {}
opsel['Contour'] = contourselect
opsel['Drilling'] = drillselect
opsel['MillFace'] = pocketselect
opsel['Pocket'] = pocketselect
opsel['Profile Edges'] = eselect