diff --git a/src/Mod/Draft/Resources/Draft.qrc b/src/Mod/Draft/Resources/Draft.qrc index 1df9126aaa..7907e7423e 100644 --- a/src/Mod/Draft/Resources/Draft.qrc +++ b/src/Mod/Draft/Resources/Draft.qrc @@ -49,6 +49,7 @@ icons/Draft_Join.svg icons/Draft_Label.svg icons/Draft_Layer.svg + icons/Draft_LayerManager.svg icons/Draft_Line.svg icons/Draft_LinkArray.svg icons/Draft_Lock.svg @@ -191,5 +192,6 @@ ui/dialog_AnnotationStyleEditor.ui ui/TaskPanel_SetStyle.ui ui/dialogHatch.ui + ui/dialogLayers.ui diff --git a/src/Mod/Draft/Resources/icons/Draft_LayerManager.svg b/src/Mod/Draft/Resources/icons/Draft_LayerManager.svg new file mode 100644 index 0000000000..34134c781f --- /dev/null +++ b/src/Mod/Draft/Resources/icons/Draft_LayerManager.svg @@ -0,0 +1,515 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Draft/Resources/ui/dialogLayers.ui b/src/Mod/Draft/Resources/ui/dialogLayers.ui new file mode 100644 index 0000000000..32c1468231 --- /dev/null +++ b/src/Mod/Draft/Resources/ui/dialogLayers.ui @@ -0,0 +1,94 @@ + + + Dialog + + + + 0 + 0 + 667 + 320 + + + + Layers manager + + + + + + true + + + + + + + + + New + + + + + + + Delete + + + + + + + Select all + + + + + + + Toggle on/off + + + + + + + Isolate + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Cancel + + + + + + + OK + + + + + + + + + + diff --git a/src/Mod/Draft/draftguitools/gui_layers.py b/src/Mod/Draft/draftguitools/gui_layers.py index ab66fa7347..432e754c7f 100644 --- a/src/Mod/Draft/draftguitools/gui_layers.py +++ b/src/Mod/Draft/draftguitools/gui_layers.py @@ -30,7 +30,10 @@ # @{ from PySide.QtCore import QT_TRANSLATE_NOOP +import os +import FreeCAD import FreeCADGui as Gui +import Draft import Draft_rc import draftguitools.gui_base as gui_base @@ -40,6 +43,18 @@ from draftutils.translate import translate bool(Draft_rc.__name__) +def getColorIcon(color): + + "returns a QtGui.QIcon from a color 3-float tuple" + + from PySide import QtCore,QtGui + c = QtGui.QColor(int(color[0]*255),int(color[1]*255),int(color[2]*255)) + im = QtGui.QImage(48,48,QtGui.QImage.Format_ARGB32) + im.fill(c) + px = QtGui.QPixmap.fromImage(im) + return QtGui.QIcon(px) + + class Layer(gui_base.GuiCommandSimplest): """GuiCommand to create a Layer object in the document.""" @@ -66,6 +81,435 @@ class Layer(gui_base.GuiCommandSimplest): self.doc.commitTransaction() +class LayerManager: + + """GuiCommand that displays a Layers manager dialog""" + + def GetResources(self): + + return {'Pixmap' : 'Draft_LayerManager', + 'MenuText': QT_TRANSLATE_NOOP("Draft_LayerManager", "Manage layers..."), + 'ToolTip' : QT_TRANSLATE_NOOP("Draft_LayerManager", "Set/modify the different layers of this document")} + + def Activated(self): + + from PySide import QtCore, QtGui + + # store changes to be committed + self.deleteList = [] + + # create the dialog + self.dialog = Gui.PySideUic.loadUi(":/ui/dialogLayers.ui") + + # set nice icons + self.dialog.setWindowIcon(QtGui.QIcon(":/icons/Draft_Layer.svg")) + self.dialog.buttonNew.setIcon(QtGui.QIcon(":/icons/document-new.svg")) + self.dialog.buttonDelete.setIcon(QtGui.QIcon(":/icons/delete.svg")) + self.dialog.buttonSelectAll.setIcon(QtGui.QIcon(":/icons/edit-select-all.svg")) + self.dialog.buttonToggle.setIcon(QtGui.QIcon(":/icons/dagViewVisible.svg")) + self.dialog.buttonIsolate.setIcon(QtGui.QIcon(":/icons/view-refresh.svg")) + self.dialog.buttonCancel.setIcon(QtGui.QIcon(":/icons/edit_Cancel.svg")) + self.dialog.buttonOK.setIcon(QtGui.QIcon(":/icons/edit_OK.svg")) + + # restore window geometry from stored state + pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") + w = pref.GetInt("LayersManagerWidth",640) + h = pref.GetInt("LayersManagerHeight",320) + self.dialog.resize(w,h) + + # center the dialog over FreeCAD window + mw = Gui.getMainWindow() + self.dialog.move(mw.frameGeometry().topLeft() + mw.rect().center() - self.dialog.rect().center()) + + # connect signals/slots + self.dialog.buttonNew.clicked.connect(self.addItem) + self.dialog.buttonDelete.clicked.connect(self.onDelete) + self.dialog.buttonSelectAll.clicked.connect(self.dialog.tree.selectAll) + self.dialog.buttonToggle.clicked.connect(self.onToggle) + self.dialog.buttonCancel.clicked.connect(self.dialog.reject) + self.dialog.buttonIsolate.clicked.connect(self.onIsolate) + self.dialog.buttonOK.clicked.connect(self.accept) + self.dialog.rejected.connect(self.reject) + + # set the model up + self.model = QtGui.QStandardItemModel() + self.dialog.tree.setModel(self.model) + self.dialog.tree.setUniformRowHeights(True) + self.dialog.tree.setItemDelegate(Layers_Delegate()) + self.dialog.tree.setItemsExpandable(False) + self.dialog.tree.setRootIsDecorated(False) # removes spacing in first column + self.dialog.tree.setSelectionMode(QtGui.QTreeView.ExtendedSelection) # allow to select many + + # fill the tree view + self.update() + + # rock 'n roll!!! + self.dialog.exec_() + + def accept(self): + + "when OK button is pressed" + + changed = False + + # delete layers + for name in self.deleteList: + if not changed: + FreeCAD.ActiveDocument.openTransaction("Layers change") + changed = True + FreeCAD.ActiveDocument.removeObject(name) + + # apply changes + for row in range(self.model.rowCount()): + + # get or create layer + name = self.model.item(row,1).toolTip() + obj = None + if name: + obj = FreeCAD.ActiveDocument.getObject(name) + if not obj: + if not changed: + FreeCAD.ActiveDocument.openTransaction("Layers change") + changed = True + obj = Draft.make_layer() + + # visibility + checked = True if self.model.item(row,0).checkState() == QtCore.Qt.Checked else False + if checked != obj.ViewObject.Visibility: + if not changed: + FreeCAD.ActiveDocument.openTransaction("Layers change") + changed = True + obj.ViewObject.Visibility = checked + + # label + label = self.model.item(row,1).text() + if label: + if obj.Label != label: + if not changed: + FreeCAD.ActiveDocument.openTransaction("Layers change") + changed = True + obj.Label = label + + # line width + width = self.model.item(row,2).data(QtCore.Qt.DisplayRole) + if width: + if obj.ViewObject.LineWidth != width: + if not changed: + FreeCAD.ActiveDocument.openTransaction("Layers change") + changed = True + obj.ViewObject.LineWidth = width + + # draw style + style = self.model.item(row,3).text() + if style: + if obj.ViewObject.DrawStyle != style: + if not changed: + FreeCAD.ActiveDocument.openTransaction("Layers change") + changed = True + obj.ViewObject.DrawStyle = style + + # line color + color = self.model.item(row,4).data(QtCore.Qt.UserRole) + if color: + if obj.ViewObject.LineColor[3:] != color: + if not changed: + FreeCAD.ActiveDocument.openTransaction("Layers change") + changed = True + obj.ViewObject.LineColor = color + + # shape color + color = self.model.item(row,5).data(QtCore.Qt.UserRole) + if color: + if obj.ViewObject.ShapeColor[3:] != color: + if not changed: + FreeCAD.ActiveDocument.openTransaction("Layers change") + changed = True + obj.ViewObject.ShapeColor = color + + # transparency + transparency = self.model.item(row,6).data(QtCore.Qt.DisplayRole) + if transparency: + if obj.ViewObject.Transparency != transparency: + if not changed: + FreeCAD.ActiveDocument.openTransaction("Layers change") + changed = True + obj.ViewObject.Transparency = transparency + + # line print color + color = self.model.item(row,7).data(QtCore.Qt.UserRole) + if color: + if not "LinePrintColor" in obj.ViewObject.PropertiesList: + if hasattr(obj.ViewObject.Proxy,"set_properties"): + obj.ViewObject.Proxy.set_properties(obj.ViewObject) + if "LinePrintColor" in obj.ViewObject.PropertiesList: + if obj.ViewObject.LinePrintColor[3:] != color: + if not changed: + FreeCAD.ActiveDocument.openTransaction("Layers change") + changed = True + obj.ViewObject.LinePrintColor = color + + # recompute + if changed: + FreeCAD.ActiveDocument.commitTransaction() + FreeCAD.ActiveDocument.recompute() + + # exit + self.dialog.reject() + + def reject(self): + + "when Cancel button is pressed or dialog is closed" + + # save dialog size + pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") + pref.SetInt("LayersManagerWidth",self.dialog.width()) + pref.SetInt("LayersManagerHeight",self.dialog.height()) + + return True + + def update(self): + + "rebuild the model from document contents" + + self.model.clear() + + # set header + self.model.setHorizontalHeaderLabels([translate("Draft","On"), + translate("Draft","Name"), + translate("Draft","Line width"), + translate("Draft","Draw style"), + translate("Draft","Line color"), + translate("Draft","Face color"), + translate("Draft","Transparency"), + translate("Draft","Line print color")]) + self.dialog.tree.header().setDefaultSectionSize(72) + self.dialog.tree.setColumnWidth(0,32) # on/off column + self.dialog.tree.setColumnWidth(1,128) # name column + + # populate + objs = [obj for obj in FreeCAD.ActiveDocument.Objects if Draft.getType(obj) == "Layer"] + objs.sort(key=lambda o:o.Label) + for obj in objs: + self.addItem(obj) + + def addItem(self,obj=None): + + "adds a row to the model" + + from PySide import QtCore, QtGui + + # create row with default values + onItem = QtGui.QStandardItem() + onItem.setCheckable(True) + onItem.setCheckState(QtCore.Qt.Checked) + nameItem = QtGui.QStandardItem(translate("Draft","New Layer")) + widthItem = QtGui.QStandardItem() + widthItem.setData(self.getPref("DefaultShapeLineWidth",2,"Integer"),QtCore.Qt.DisplayRole) + styleItem = QtGui.QStandardItem("Solid") + lineColorItem = QtGui.QStandardItem() + lineColorItem.setData(self.getPref("DefaultShapeLineColor",421075455),QtCore.Qt.UserRole) + shapeColorItem = QtGui.QStandardItem() + shapeColorItem.setData(self.getPref("DefaultShapeColor",3435973887),QtCore.Qt.UserRole) + transparencyItem = QtGui.QStandardItem() + transparencyItem.setData(0,QtCore.Qt.DisplayRole) + linePrintColorItem = QtGui.QStandardItem() + linePrintColorItem.setData(self.getPref("DefaultPrintColor",0),QtCore.Qt.UserRole) + + # populate with object data + if obj: + onItem.setCheckState(QtCore.Qt.Checked if obj.ViewObject.Visibility else QtCore.Qt.Unchecked) + nameItem.setText(obj.Label) + nameItem.setToolTip(obj.Name) + widthItem.setData(obj.ViewObject.LineWidth,QtCore.Qt.DisplayRole) + styleItem.setText(obj.ViewObject.DrawStyle) + lineColorItem.setData(obj.ViewObject.LineColor[:3],QtCore.Qt.UserRole) + shapeColorItem.setData(obj.ViewObject.ShapeColor[:3],QtCore.Qt.UserRole) + transparencyItem.setData(obj.ViewObject.Transparency,QtCore.Qt.DisplayRole) + if hasattr(obj.ViewObject,"LinePrintColor"): + linePrintColorItem.setData(obj.ViewObject.LinePrintColor[:3],QtCore.Qt.UserRole) + lineColorItem.setIcon(getColorIcon(lineColorItem.data(QtCore.Qt.UserRole))) + shapeColorItem.setIcon(getColorIcon(shapeColorItem.data(QtCore.Qt.UserRole))) + linePrintColorItem.setIcon(getColorIcon(linePrintColorItem.data(QtCore.Qt.UserRole))) + + # append row + self.model.appendRow([onItem, + nameItem, + widthItem, + styleItem, + lineColorItem, + shapeColorItem, + transparencyItem, + linePrintColorItem]) + + def getPref(self,value,default,valuetype="Unsigned"): + + "retrieves a view pref value" + + p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View") + if valuetype == "Unsigned": + c = p.GetUnsigned(value,default) + r = float((c>>24)&0xFF)/255.0 + g = float((c>>16)&0xFF)/255.0 + b = float((c>>8)&0xFF)/255.0 + return (r,g,b,) + elif valuetype == "Integer": + return p.GetInt(value,default) + + def onDelete(self): + + "delete selected rows" + + rows = [] + for index in self.dialog.tree.selectedIndexes(): + if not index.row() in rows: + rows.append(index.row()) + + # append layer name to the delete list + if index.column() == 1: + name = self.model.itemFromIndex(index).toolTip() + if name: + if not name in self.deleteList: + self.deleteList.append(name) + + # delete rows starting from the lowest, to not alter row indexes while deleting + rows.sort() + rows.reverse() + for row in rows: + self.model.takeRow(row) + + def onToggle(self): + + "toggle selected layers on/off" + + from PySide import QtCore, QtGui + + state = None + for index in self.dialog.tree.selectedIndexes(): + if index.column() == 0: + # get state from first selected row + if state is None: + if self.model.itemFromIndex(index).checkState() == QtCore.Qt.Checked: + state = QtCore.Qt.Unchecked + else: + state = QtCore.Qt.Checked + self.model.itemFromIndex(index).setCheckState(state) + + def onIsolate(self): + + "isolates the selected layers (turns all the others off" + + from PySide import QtCore, QtGui + + onrows = [] + for index in self.dialog.tree.selectedIndexes(): + if not index.row() in onrows: + onrows.append(index.row()) + for row in range(self.model.rowCount()): + if not row in onrows: + self.model.item(row,0).setCheckState(QtCore.Qt.Unchecked) + + +if FreeCAD.GuiUp: + + from PySide import QtCore, QtGui + + class Layers_Delegate(QtGui.QStyledItemDelegate): + + "model delegate" + + def __init__(self, parent=None, *args): + + QtGui.QStyledItemDelegate.__init__(self, parent, *args) + # setEditorData() is triggered several times. + # But we want to show the color dialog only the first time + self.first = True + + def createEditor(self,parent,option,index): + + if index.column() == 0: # Layer on/off + editor = QtGui.QCheckBox(parent) + if index.column() == 1: # Layer name + editor = QtGui.QLineEdit(parent) + elif index.column() == 2: # Line width + editor = QtGui.QSpinBox(parent) + editor.setMaximum(99) + elif index.column() == 3: # Line style + editor = QtGui.QComboBox(parent) + editor.addItems(["Solid","Dashed","Dotted","Dashdot"]) + elif index.column() == 4: # Line color + editor = QtGui.QLineEdit(parent) + self.first = True + elif index.column() == 5: # Shape color + editor = QtGui.QLineEdit(parent) + self.first = True + elif index.column() == 6: # Transparency + editor = QtGui.QSpinBox(parent) + editor.setMaximum(100) + elif index.column() == 7: # Line print color + editor = QtGui.QLineEdit(parent) + self.first = True + return editor + + def setEditorData(self, editor, index): + + if index.column() == 0: # Layer on/off + editor.setChecked(index.data()) + elif index.column() == 1: # Layer name + editor.setText(index.data()) + elif index.column() == 2: # Line width + editor.setValue(index.data()) + elif index.column() == 3: # Line style + editor.setCurrentIndex(["Solid","Dashed","Dotted","Dashdot"].index(index.data())) + elif index.column() == 4: # Line color + editor.setText(str(index.data(QtCore.Qt.UserRole))) + if self.first: + c = index.data(QtCore.Qt.UserRole) + color = QtGui.QColorDialog.getColor(QtGui.QColor(int(c[0]*255),int(c[1]*255),int(c[2]*255))) + editor.setText(str(color.getRgbF())) + self.first = False + elif index.column() == 5: # Shape color + editor.setText(str(index.data(QtCore.Qt.UserRole))) + if self.first: + c = index.data(QtCore.Qt.UserRole) + color = QtGui.QColorDialog.getColor(QtGui.QColor(int(c[0]*255),int(c[1]*255),int(c[2]*255))) + editor.setText(str(color.getRgbF())) + self.first = False + elif index.column() == 6: # Transparency + editor.setValue(index.data()) + elif index.column() == 7: # Line print color + editor.setText(str(index.data(QtCore.Qt.UserRole))) + if self.first: + c = index.data(QtCore.Qt.UserRole) + color = QtGui.QColorDialog.getColor(QtGui.QColor(int(c[0]*255),int(c[1]*255),int(c[2]*255))) + editor.setText(str(color.getRgbF())) + self.first = False + + def setModelData(self, editor, model, index): + + if index.column() == 0: # Layer on/off + model.setData(index,editor.isChecked()) + elif index.column() == 1: # Layer name + model.setData(index,editor.text()) + elif index.column() == 2: # Line width + model.setData(index,editor.value()) + elif index.column() == 3: # Line style + model.setData(index,["Solid","Dashed","Dotted","Dashdot"][editor.currentIndex()]) + elif index.column() == 4: # Line color + model.setData(index,eval(editor.text()),QtCore.Qt.UserRole) + model.itemFromIndex(index).setIcon(getColorIcon(eval(editor.text()))) + elif index.column() == 5: # Shape color + model.setData(index,eval(editor.text()),QtCore.Qt.UserRole) + model.itemFromIndex(index).setIcon(getColorIcon(eval(editor.text()))) + elif index.column() == 6: # Transparency + model.setData(index,editor.value()) + elif index.column() == 7: # Line prin color + model.setData(index,eval(editor.text()),QtCore.Qt.UserRole) + model.itemFromIndex(index).setIcon(getColorIcon(eval(editor.text()))) + + + + Gui.addCommand('Draft_Layer', Layer()) +Gui.addCommand('Draft_LayerManager', LayerManager()) ## @} diff --git a/src/Mod/Draft/draftutils/init_tools.py b/src/Mod/Draft/draftutils/init_tools.py index 49b401719c..82a7114f0c 100644 --- a/src/Mod/Draft/draftutils/init_tools.py +++ b/src/Mod/Draft/draftutils/init_tools.py @@ -112,6 +112,7 @@ def get_draft_utility_commands_menu(): "Draft_ApplyStyle", "Separator", "Draft_Layer", + "Draft_LayerManager", "Draft_AddNamedGroup", "Draft_AddToGroup", "Draft_SelectGroup", @@ -130,7 +131,7 @@ def get_draft_utility_commands_menu(): def get_draft_utility_commands_toolbar(): """Return the utility commands list for the toolbar.""" - return ["Draft_Layer", + return ["Draft_LayerManager", "Draft_AddNamedGroup", "Draft_AddToGroup", "Draft_SelectGroup",