
#***************************************************************************
#*                                                                         *
#*   Copyright (c) 2009 Yorik van Havre <yorik@gmx.fr>                     *  
#*                                                                         *
#*   This program is free software; you can redistribute it and/or modify  *
#*   it under the terms of the GNU General Public License (GPL)            *
#*   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                                                                   *
#*                                                                         *
#***************************************************************************

__title__="FreeCAD Draft Workbench - GUI part"
__author__ = "Yorik van Havre <yorik@uncreated.net>"
__url__ = ["http://free-cad.sourceforge.net"]

'''
This is the GUI part of the Draft module.
Report to Draft.py for info
'''

import FreeCAD, FreeCADGui, os, Draft

try:
    from PyQt4 import QtCore,QtGui,QtSvg	
except:
    FreeCAD.Console.PrintMessage("Error: Python-qt4 package must be installed on your system to use the Draft module.")

def getMainWindow():
    "returns the main window"
    # using QtGui.qApp.activeWindow() isn't very reliable because if another
    # widget than the mainwindow is active (e.g. a dialog) the wrong widget is
    # returned
    toplevel = QtGui.qApp.topLevelWidgets()
    for i in toplevel:
        if i.metaObject().className() == "Gui::MainWindow":
            return i
    raise Exception("No main window found")

class todo:
    ''' static todo class, delays execution of functions.  Use todo.delay
    to schedule geometry manipulation that would crash coin if done in the
    event callback'''

    '''List of (function, argument) pairs to be executed by
    QtCore.QTimer.singleShot(0,doTodo).'''
    itinerary = []
    commitlist = []
    
    @staticmethod
    def doTasks():
        # print "debug: doing delayed tasks: commitlist: ",todo.commitlist," itinerary: ",todo.itinerary
        for f, arg in todo.itinerary:
            try:
                # print "debug: executing",f
                f(arg)
            except:
                wrn = "[Draft.todo] Unexpected error:" + sys.exc_info()[0]
                FreeCAD.Console.PrintWarning (wrn)
        todo.itinerary = []
        if todo.commitlist:
            for name,func in todo.commitlist:
                # print "debug: committing ",str(name)
                name = str(name)
                FreeCAD.ActiveDocument.openTransaction(name)
                func()
                FreeCAD.ActiveDocument.commitTransaction()
        todo.commitlist = []

    @staticmethod
    def delay (f, arg):
        # print "debug: delaying",f
        if todo.itinerary == []:
            QtCore.QTimer.singleShot(0, todo.doTasks)
        todo.itinerary.append((f,arg))

    @staticmethod
    def delayCommit (cl):
        # print "debug: delaying commit",cl
        QtCore.QTimer.singleShot(0, todo.doTasks)
        todo.commitlist = cl

def translate(context,text):
        "convenience function for Qt translator"
        return QtGui.QApplication.translate(context, text, None,
                                            QtGui.QApplication.UnicodeUTF8)

#---------------------------------------------------------------------------
# Customized widgets
#---------------------------------------------------------------------------

class DraftDockWidget(QtGui.QWidget):
    "custom Widget that emits a resized() signal when resized"
    def __init__(self,parent = None):
        QtGui.QDockWidget.__init__(self,parent)
    def resizeEvent(self,event):
        self.emit(QtCore.SIGNAL("resized()"))
    def changeEvent(self, event):
        if event.type() == QtCore.QEvent.LanguageChange:
            self.emit(QtCore.SIGNAL("retranslate()"))
        else:
            QtGui.QWidget.changeEvent(self,event)
                        
class DraftLineEdit(QtGui.QLineEdit):
    "custom QLineEdit widget that has the power to catch Escape keypress"
    def __init__(self, parent=None):
        QtGui.QLineEdit.__init__(self, parent)
    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_Escape:
            self.emit(QtCore.SIGNAL("escaped()"))
        elif event.key() == QtCore.Qt.Key_Up:
            self.emit(QtCore.SIGNAL("up()"))
        elif event.key() == QtCore.Qt.Key_Down:
            self.emit(QtCore.SIGNAL("down()"))
        elif (event.key() == QtCore.Qt.Key_Z) and QtCore.Qt.ControlModifier:
            self.emit(QtCore.SIGNAL("undo()"))
        else:
            QtGui.QLineEdit.keyPressEvent(self, event)

class DraftTaskPanel:
    def __init__(self,widget):
        self.form = widget
    def getStandardButtons(self):
        return int(QtGui.QDialogButtonBox.Cancel)
    def accept(self):
        if FreeCAD.activeDraftCommand:
            FreeCAD.activeDraftCommand.finish()
        return True
    def reject(self):
        if FreeCAD.activeDraftCommand:
            FreeCAD.activeDraftCommand.finish()
        return True
  
class DraftToolBar:
    "main draft Toolbar"
    def __init__(self):
        self.tray = None
        self.sourceCmd = None
        self.taskmode = Draft.getParam("UiMode")
        self.paramcolor = Draft.getParam("color")>>8
        self.color = QtGui.QColor(self.paramcolor)
        self.facecolor = QtGui.QColor(204,204,204)
        self.linewidth = Draft.getParam("linewidth")
        self.fontsize = Draft.getParam("textheight")
        self.paramconstr = Draft.getParam("constructioncolor")>>8
        self.constrMode = False
        self.continueMode = False
        self.state = None
        self.textbuffer = []
        self.crossedViews = []
        self.isTaskOn = False
        
        if self.taskmode:
            # only a dummy widget, since widgets are created on demand
            self.baseWidget = QtGui.QWidget()
        else:
            # create the draft Toolbar                
            self.draftWidget = QtGui.QDockWidget()
            self.baseWidget = DraftDockWidget()
            self.draftWidget.setObjectName("draftToolbar")
            self.draftWidget.setTitleBarWidget(self.baseWidget)
            self.draftWidget.setWindowTitle(translate("draft", "draft Command Bar"))
            self.mw = getMainWindow()
            self.mw.addDockWidget(QtCore.Qt.TopDockWidgetArea,self.draftWidget)
            self.draftWidget.setVisible(False)
            self.draftWidget.toggleViewAction().setVisible(False)                
            self.mw = getMainWindow()                
            self.baseWidget.setObjectName("draftToolbar")
            self.layout = QtGui.QHBoxLayout(self.baseWidget)
            self.layout.setObjectName("layout")
            self.toptray = self.layout
            self.bottomtray = self.layout
            self.setupToolBar()
            self.setupTray()
            self.setupStyle()
            self.retranslateUi(self.baseWidget)
		
#---------------------------------------------------------------------------
# General UI setup
#---------------------------------------------------------------------------

    def _pushbutton (self,name, layout, hide=True, icon=None, width=66, checkable=False):
        button = QtGui.QPushButton(self.baseWidget)
        button.setObjectName(name)
        button.setMaximumSize(QtCore.QSize(width,26))
        if hide:
            button.hide()
        if icon:
            button.setIcon(QtGui.QIcon(':/icons/'+icon+'.svg'))
            button.setIconSize(QtCore.QSize(16, 16))
        if checkable:
            button.setCheckable(True)
            button.setChecked(False)
        layout.addWidget(button)
        return button

    def _label (self,name, layout, hide=True):
        label = QtGui.QLabel(self.baseWidget)
        label.setObjectName(name)
        if hide: label.hide()
        layout.addWidget(label)
        return label

    def _lineedit (self,name, layout, hide=True, width=None):
        lineedit = DraftLineEdit(self.baseWidget)
        lineedit.setObjectName(name)
        if hide: lineedit.hide()
        if not width: width = 800
        lineedit.setMaximumSize(QtCore.QSize(width,22))
        layout.addWidget(lineedit)
        return lineedit

    def _spinbox (self,name, layout, val=None, vmax=None, hide=True, double=False, size=None):
        if double:
            sbox = QtGui.QDoubleSpinBox(self.baseWidget)
            sbox.setDecimals(2)
        else:
            sbox = QtGui.QSpinBox(self.baseWidget)
        sbox.setObjectName(name)
        if val: sbox.setValue(val)
        if vmax: sbox.setMaximum(vmax)
        if size: sbox.setMaximumSize(QtCore.QSize(size[0],size[1]))
        if hide: sbox.hide()
        layout.addWidget(sbox)
        return sbox

    def _checkbox (self,name, layout, checked=True, hide=True):
        chk = QtGui.QCheckBox(self.baseWidget)
        chk.setChecked(checked)
        chk.setObjectName(name)
        if hide: chk.hide()
        layout.addWidget(chk)
        return chk
                        
    def setupToolBar(self,task=False):
        "sets the draft toolbar up"
        
        # command

        self.promptlabel = self._label("promptlabel", self.layout, hide=task)
        self.cmdlabel = self._label("cmdlabel", self.layout, hide=task)
        boldtxt = QtGui.QFont()
        boldtxt.setWeight(75)
        boldtxt.setBold(True)
        self.cmdlabel.setFont(boldtxt)

        # subcommands

        self.addButton = self._pushbutton("addButton", self.layout, icon="Draft_AddPoint", width=22, checkable=True)
        self.delButton = self._pushbutton("delButton", self.layout, icon="Draft_DelPoint", width=22, checkable=True)

        # point

        xl = QtGui.QHBoxLayout()
        yl = QtGui.QHBoxLayout()
        zl = QtGui.QHBoxLayout()
        self.layout.addLayout(xl)
        self.layout.addLayout(yl)
        self.layout.addLayout(zl)
        self.labelx = self._label("labelx", xl)
        self.xValue = self._lineedit("xValue", xl, width=60)
        self.xValue.setText("0.00")
        self.labely = self._label("labely", yl)
        self.yValue = self._lineedit("yValue", yl, width=60)
        self.yValue.setText("0.00")
        self.labelz = self._label("labelz", zl)
        self.zValue = self._lineedit("zValue", zl, width=60)
        self.zValue.setText("0.00")
        self.textValue = self._lineedit("textValue", self.layout)

        # options

        self.numFaces = self._spinbox("numFaces", self.layout, 3)
        self.offsetLabel = self._label("offsetlabel", self.layout)
        self.offsetValue = self._lineedit("offsetValue", self.layout, width=60)
        self.offsetValue.setText("0.00")
        self.labelRadius = self._label("labelRadius", self.layout)
        self.radiusValue = self._lineedit("radiusValue", self.layout, width=60)
        self.radiusValue.setText("0.00")
        self.isRelative = self._checkbox("isRelative",self.layout,checked=True)
        self.hasFill = self._checkbox("hasFill",self.layout,checked=Draft.getParam("fillmode"))
        self.continueCmd = self._checkbox("continueCmd",self.layout,checked=False)
        self.occOffset = self._checkbox("occOffset",self.layout,checked=False)
        self.undoButton = self._pushbutton("undoButton", self.layout, icon='Draft_Rotate')
        self.finishButton = self._pushbutton("finishButton", self.layout, icon='Draft_Finish')
        self.closeButton = self._pushbutton("closeButton", self.layout, icon='Draft_Lock')
        self.wipeButton = self._pushbutton("wipeButton", self.layout, icon='Draft_Wipe')
        self.xyButton = self._pushbutton("xyButton", self.layout)
        self.xzButton = self._pushbutton("xzButton", self.layout)
        self.yzButton = self._pushbutton("yzButton", self.layout)
        self.currentViewButton = self._pushbutton("view", self.layout)
        self.resetPlaneButton = self._pushbutton("none", self.layout)
        self.isCopy = self._checkbox("isCopy",self.layout,checked=False)

        # spacer
        if not self.taskmode:
            spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding,
                                           QtGui.QSizePolicy.Minimum)
        else:
            spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum,
                                           QtGui.QSizePolicy.Expanding)
        self.layout.addItem(spacerItem)
        
        QtCore.QObject.connect(self.xValue,QtCore.SIGNAL("returnPressed()"),self.checkx)
        QtCore.QObject.connect(self.yValue,QtCore.SIGNAL("returnPressed()"),self.checky)
        QtCore.QObject.connect(self.xValue,QtCore.SIGNAL("textEdited(QString)"),self.checkSpecialChars)
        QtCore.QObject.connect(self.yValue,QtCore.SIGNAL("textEdited(QString)"),self.checkSpecialChars)
        QtCore.QObject.connect(self.zValue,QtCore.SIGNAL("textEdited(QString)"),self.checkSpecialChars)
        QtCore.QObject.connect(self.radiusValue,QtCore.SIGNAL("textEdited(QString)"),self.checkSpecialChars)
        QtCore.QObject.connect(self.zValue,QtCore.SIGNAL("returnPressed()"),self.validatePoint)
        QtCore.QObject.connect(self.radiusValue,QtCore.SIGNAL("returnPressed()"),self.validatePoint)
        QtCore.QObject.connect(self.textValue,QtCore.SIGNAL("textChanged(QString)"),self.storeCurrentText)
        QtCore.QObject.connect(self.textValue,QtCore.SIGNAL("returnPressed()"),self.sendText)
        QtCore.QObject.connect(self.textValue,QtCore.SIGNAL("escaped()"),self.finish)
        QtCore.QObject.connect(self.textValue,QtCore.SIGNAL("down()"),self.sendText)
        QtCore.QObject.connect(self.textValue,QtCore.SIGNAL("up()"),self.lineUp)
        QtCore.QObject.connect(self.zValue,QtCore.SIGNAL("returnPressed()"),self.xValue.setFocus)
        QtCore.QObject.connect(self.zValue,QtCore.SIGNAL("returnPressed()"),self.xValue.selectAll)
        QtCore.QObject.connect(self.offsetValue,QtCore.SIGNAL("textEdited(QString)"),self.checkSpecialChars)
        QtCore.QObject.connect(self.offsetValue,QtCore.SIGNAL("returnPressed()"),self.validatePoint)
        QtCore.QObject.connect(self.addButton,QtCore.SIGNAL("toggled(bool)"),self.setAddMode)
        QtCore.QObject.connect(self.delButton,QtCore.SIGNAL("toggled(bool)"),self.setDelMode)
        QtCore.QObject.connect(self.finishButton,QtCore.SIGNAL("pressed()"),self.finish)
        QtCore.QObject.connect(self.closeButton,QtCore.SIGNAL("pressed()"),self.closeLine)
        QtCore.QObject.connect(self.wipeButton,QtCore.SIGNAL("pressed()"),self.wipeLine)
        QtCore.QObject.connect(self.undoButton,QtCore.SIGNAL("pressed()"),self.undoSegment)
        QtCore.QObject.connect(self.xyButton,QtCore.SIGNAL("clicked()"),self.selectXY)
        QtCore.QObject.connect(self.xzButton,QtCore.SIGNAL("clicked()"),self.selectXZ)
        QtCore.QObject.connect(self.yzButton,QtCore.SIGNAL("clicked()"),self.selectYZ)
        QtCore.QObject.connect(self.continueCmd,QtCore.SIGNAL("stateChanged(int)"),self.setContinue)               
        QtCore.QObject.connect(self.currentViewButton,QtCore.SIGNAL("clicked()"),self.selectCurrentView)
        QtCore.QObject.connect(self.resetPlaneButton,QtCore.SIGNAL("clicked()"),self.selectResetPlane)
        QtCore.QObject.connect(self.xValue,QtCore.SIGNAL("escaped()"),self.finish)
        QtCore.QObject.connect(self.xValue,QtCore.SIGNAL("undo()"),self.undoSegment)
        QtCore.QObject.connect(self.yValue,QtCore.SIGNAL("escaped()"),self.finish)
        QtCore.QObject.connect(self.yValue,QtCore.SIGNAL("undo()"),self.undoSegment)
        QtCore.QObject.connect(self.zValue,QtCore.SIGNAL("escaped()"),self.finish)
        QtCore.QObject.connect(self.zValue,QtCore.SIGNAL("undo()"),self.undoSegment)
        QtCore.QObject.connect(self.radiusValue,QtCore.SIGNAL("escaped()"),self.finish)
        QtCore.QObject.connect(self.baseWidget,QtCore.SIGNAL("resized()"),self.relocate)
        QtCore.QObject.connect(self.baseWidget,QtCore.SIGNAL("retranslate()"),self.retranslateUi)

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

        self.wplabel = self._pushbutton("wplabel", self.toptray, icon='Draft_SelectPlane',hide=False,width=120)
        defaultWP = Draft.getParam("defaultWP")
        if defaultWP == 1:
            self.wplabel.setText("Top")
        elif defaultWP == 2:
            self.wplabel.setText("Front")
        elif defaultWP == 3:
            self.wplabel.setText("Side")
        else:
            self.wplabel.setText("None")
        self.constrButton = self._pushbutton("constrButton", self.toptray, hide=False, icon='Draft_Construction',width=22, checkable=True)
        self.constrColor = QtGui.QColor(self.paramconstr)
        self.colorButton = self._pushbutton("colorButton",self.bottomtray, hide=False,width=22)
        self.colorPix = QtGui.QPixmap(16,16)
        self.colorPix.fill(self.color)
        self.colorButton.setIcon(QtGui.QIcon(self.colorPix))
        self.facecolorButton = self._pushbutton("facecolorButton",self.bottomtray, hide=False,width=22)
        self.facecolorPix = QtGui.QPixmap(16,16)
        self.facecolorPix.fill(self.facecolor)
        self.facecolorButton.setIcon(QtGui.QIcon(self.facecolorPix))
        self.widthButton = self._spinbox("widthButton", self.bottomtray, val=self.linewidth,hide=False,size=(50,22))
        self.widthButton.setSuffix("px")
        self.fontsizeButton = self._spinbox("fontsizeButton",self.bottomtray, val=self.fontsize,hide=False,double=True,size=(50,22))
        self.applyButton = self._pushbutton("applyButton", self.toptray, hide=False, icon='Draft_Apply',width=22)

        QtCore.QObject.connect(self.wplabel,QtCore.SIGNAL("pressed()"),self.selectplane)
        QtCore.QObject.connect(self.colorButton,QtCore.SIGNAL("pressed()"),self.getcol)
        QtCore.QObject.connect(self.facecolorButton,QtCore.SIGNAL("pressed()"),self.getfacecol)
        QtCore.QObject.connect(self.widthButton,QtCore.SIGNAL("valueChanged(int)"),self.setwidth)
        QtCore.QObject.connect(self.fontsizeButton,QtCore.SIGNAL("valueChanged(double)"),self.setfontsize)
        QtCore.QObject.connect(self.applyButton,QtCore.SIGNAL("pressed()"),self.apply)
        QtCore.QObject.connect(self.constrButton,QtCore.SIGNAL("toggled(bool)"),self.toggleConstrMode)

    def setupStyle(self):
        style = "#constrButton:Checked {background-color: "
        style += self.getDefaultColor("constr",rgb=True)+" } "
        style += "#addButton:Checked, #delButton:checked {"
        style += "background-color: rgb(20,100,250) }"
        self.baseWidget.setStyleSheet(style)

#---------------------------------------------------------------------------
# language tools
#---------------------------------------------------------------------------
				
    def retranslateUi(self, widget=None):
        self.promptlabel.setText(translate("draft", "active command:"))
        self.cmdlabel.setText(translate("draft", "None"))
        self.cmdlabel.setToolTip(translate("draft", "Active Draft command"))
        self.xValue.setToolTip(translate("draft", "X coordinate of next point"))
        self.labelx.setText(translate("draft", "X"))
        self.labely.setText(translate("draft", "Y"))
        self.labelz.setText(translate("draft", "Z"))
        self.yValue.setToolTip(translate("draft", "Y coordinate of next point"))
        self.zValue.setToolTip(translate("draft", "Z coordinate of next point"))
        self.labelRadius.setText(translate("draft", "Radius"))
        self.radiusValue.setToolTip(translate("draft", "Radius of Circle"))
        self.isRelative.setText(translate("draft", "&Relative"))
        self.isRelative.setToolTip(translate("draft", "Coordinates relative to last point or absolute (SPACE)"))
        self.hasFill.setText(translate("draft", "F&illed"))
        self.hasFill.setToolTip(translate("draft", "Check this if the object should appear as filled, otherwise it will appear as wireframe (i)"))
        self.finishButton.setText(translate("draft", "&Finish"))
        self.finishButton.setToolTip(translate("draft", "Finishes the current drawing or editing operation (F)"))
        self.continueCmd.setToolTip(translate("draft", "If checked, command will not finish until you press the command button again"))
        self.continueCmd.setText(translate("draft", "&Continue"))
        self.occOffset.setToolTip(translate("draft", "If checked, an OCC-style offset will be performed instead of the classic offset"))
        self.occOffset.setText(translate("draft", "&OCC-style offset"))
        self.addButton.setToolTip(translate("draft", "Add points to the current object"))
        self.delButton.setToolTip(translate("draft", "Remove points from the current object"))
        self.undoButton.setText(translate("draft", "&Undo"))
        self.undoButton.setToolTip(translate("draft", "Undo the last segment (CTRL+Z)"))
        self.closeButton.setText(translate("draft", "&Close"))
        self.closeButton.setToolTip(translate("draft", "Finishes and closes the current line (C)"))
        self.wipeButton.setText(translate("draft", "&Wipe"))
        self.wipeButton.setToolTip(translate("draft", "Wipes the existing segments of this line and starts again from the last point (W)"))
        self.numFaces.setToolTip(translate("draft", "Number of sides"))
        self.offsetLabel.setText(translate("draft", "Offset"))
        self.xyButton.setText(translate("draft", "XY"))
        self.xyButton.setToolTip(translate("draft", "Select XY plane"))
        self.xzButton.setText(translate("draft", "XZ"))
        self.xzButton.setToolTip(translate("draft", "Select XZ plane"))
        self.yzButton.setText(translate("draft", "YZ"))
        self.yzButton.setToolTip(translate("draft", "Select YZ plane"))
        self.currentViewButton.setText(translate("draft", "View"))
        self.currentViewButton.setToolTip(translate("draft", "Select plane perpendicular to the current view"))
        self.resetPlaneButton.setText(translate("draft", "None"))
        self.resetPlaneButton.setToolTip(translate("draft", "Do not project points to a drawing plane"))
        self.isCopy.setText(translate("draft", "&Copy"))
        self.isCopy.setToolTip(translate("draft", "If checked, objects will be copied instead of moved (C)"))
        if (not self.taskmode) or self.tray:
            self.colorButton.setToolTip(translate("draft", "Line Color"))
            self.facecolorButton.setToolTip(translate("draft", "Face Color"))
            self.widthButton.setToolTip(translate("draft", "Line Width"))
            self.fontsizeButton.setToolTip(translate("draft", "Font Size"))
            self.applyButton.setToolTip(translate("draft", "Apply to selected objects"))
            self.constrButton.setToolTip(translate("draft", "Toggles Construction Mode"))

#---------------------------------------------------------------------------
# Interface modes
#---------------------------------------------------------------------------

    def taskUi(self,title):
        if self.taskmode:
            self.isTaskOn = True
            FreeCADGui.Control.closeDialog()
            self.baseWidget = QtGui.QWidget()
            self.setTitle(title)
            self.layout = QtGui.QVBoxLayout(self.baseWidget)
            self.setupToolBar(task=True)
            self.retranslateUi(self.baseWidget)
            self.panel = DraftTaskPanel(self.baseWidget)
            FreeCADGui.Control.showDialog(self.panel)
        else:
            self.setTitle(title)  
                
    def selectPlaneUi(self):
        self.taskUi(translate("draft", "Select Plane"))
        self.xyButton.show()
        self.xzButton.show()
        self.yzButton.show()
        self.currentViewButton.show()
        self.resetPlaneButton.show()
        self.offsetLabel.show()
        self.offsetValue.show()

    def lineUi(self):
        self.pointUi(translate("draft", "Line"))
        self.xValue.setEnabled(True)
        self.yValue.setEnabled(True)
        self.isRelative.show()
        self.hasFill.show()
        self.finishButton.show()
        self.closeButton.show()
        self.wipeButton.show()
        self.undoButton.show()
        self.continueCmd.show()

    def circleUi(self):
        self.pointUi(translate("draft", "Circle"))
        self.continueCmd.show()
        self.labelx.setText(translate("draft", "Center X"))
        self.hasFill.show()

    def arcUi(self):
        self.pointUi(translate("draft", "Arc"))
        self.labelx.setText(translate("draft", "Center X"))
        self.continueCmd.show()

    def pointUi(self,title=translate("draft","Point")):
        self.taskUi(title)
        self.xValue.setEnabled(True)
        self.yValue.setEnabled(True)
        self.labelx.setText(translate("draft", "X"))
        self.labelx.show()
        self.labely.show()
        self.labelz.show()
        self.xValue.show()
        self.yValue.show()
        self.zValue.show()
        self.xValue.setFocus()
        self.xValue.selectAll()

    def offsetUi(self):
        self.taskUi(translate("draft","Offset"))
        self.radiusUi()
        self.isCopy.show()
        self.occOffset.show()
        self.labelRadius.setText(translate("draft","Distance"))
        self.radiusValue.setFocus()
        self.radiusValue.selectAll()

    def offUi(self):
        if self.taskmode:
            self.isTaskOn = False
            FreeCADGui.Control.closeDialog()
            self.baseWidget = QtGui.QWidget()
            # print "UI turned off"
        else:
            self.setTitle(translate("draft", "None"))
            self.labelx.setText(translate("draft", "X"))
            self.labelx.hide()
            self.labely.hide()
            self.labelz.hide()
            self.xValue.hide()
            self.yValue.hide()
            self.zValue.hide()
            self.numFaces.hide()
            self.isRelative.hide()
            self.hasFill.hide()
            self.finishButton.hide()
            self.addButton.hide()
            self.delButton.hide()
            self.undoButton.hide()
            self.closeButton.hide()
            self.wipeButton.hide()
            self.xyButton.hide()
            self.xzButton.hide()
            self.yzButton.hide()
            self.currentViewButton.hide()
            self.resetPlaneButton.hide()
            self.offsetLabel.hide()
            self.offsetValue.hide()
            self.labelRadius.hide()
            self.radiusValue.hide()
            self.isCopy.hide()
            self.textValue.hide()
            self.continueCmd.hide()
            self.occOffset.hide()

    def trimUi(self,title=translate("draft","Trim")):
        self.taskUi(title)
        self.radiusUi()
        self.labelRadius.setText(translate("draft","Distance"))
        self.radiusValue.setFocus()
        self.radiusValue.selectAll()

    def radiusUi(self):
        self.labelx.hide()
        self.labely.hide()
        self.labelz.hide()
        self.xValue.hide()
        self.yValue.hide()
        self.zValue.hide()
        self.labelRadius.setText(translate("draft", "Radius"))
        self.labelRadius.show()
        self.radiusValue.show()

    def textUi(self):
        self.labelx.hide()
        self.labely.hide()
        self.labelz.hide()
        self.xValue.hide()
        self.yValue.hide()
        self.zValue.hide()
        self.textValue.show()
        self.textValue.setText('')
        self.textValue.setFocus()
        self.textbuffer=[]
        self.textline=0
        self.continueCmd.show()
                
    def switchUi(self,store=True):
        if store:
            self.state = []
            self.state.append(self.labelx.isVisible())
            self.state.append(self.labely.isVisible())
            self.state.append(self.labelz.isVisible())
            self.state.append(self.xValue.isVisible())
            self.state.append(self.yValue.isVisible())
            self.state.append(self.zValue.isVisible())
            self.labelx.hide()
            self.labely.hide()
            self.labelz.hide()
            self.xValue.hide()
            self.yValue.hide()
            self.zValue.hide()
        else:
            if self.state:
                if self.state[0]:self.labelx.show()
                if self.state[1]:self.labely.show()
                if self.state[2]:self.labelz.show()
                if self.state[3]:self.xValue.show()
                if self.state[4]:self.yValue.show()
                if self.state[5]:self.zValue.show()
                self.state = None

    def setTitle(self,title):
        if self.taskmode:
            self.baseWidget.setWindowTitle(title)
        else:
            self.cmdlabel.setText(title)

    def selectUi(self):
        if not self.taskmode:
            self.labelx.setText(translate("draft", "Pick Object"))
            self.labelx.show()

    def editUi(self):
        self.taskUi(translate("draft", "Edit"))
        self.labelx.hide()
        self.labely.hide()
        self.labelz.hide()
        self.xValue.hide()
        self.yValue.hide()
        self.zValue.hide()
        self.numFaces.hide()
        self.isRelative.hide()
        self.hasFill.hide()
        self.addButton.show()
        self.delButton.show()
        self.finishButton.show()
        self.closeButton.show()
        
    def extUi(self):
        self.hasFill.show()
        self.continueCmd.show()

    def modUi(self):
        self.isCopy.show()
        self.continueCmd.show()

    def vertUi(self,addmode=True):
        self.addButton.setChecked(addmode)
        self.delButton.setChecked(not(addmode))

    def setEditButtons(self,mode):
        self.addButton.setEnabled(mode)
        self.delButton.setEnabled(mode)

    def relocate(self):
        "relocates the right-aligned buttons depending on the toolbar size"
        if self.baseWidget.geometry().width() < 400:
            self.layout.setDirection(QtGui.QBoxLayout.TopToBottom)
        else:
            self.layout.setDirection(QtGui.QBoxLayout.LeftToRight) 


#---------------------------------------------------------------------------
# Processing functions
#---------------------------------------------------------------------------
					
    def getcol(self):
        "opens a color picker dialog"
        self.color=QtGui.QColorDialog.getColor()
        self.colorPix.fill(self.color)
        self.colorButton.setIcon(QtGui.QIcon(self.colorPix))
        if Draft.getParam("saveonexit"):
            Draft.setParam("color",self.color.rgb()<<8)
        r = float(self.color.red()/255.0)
        g = float(self.color.green()/255.0)
        b = float(self.color.blue()/255.0)
        col = (r,g,b,0.0)
        for i in FreeCADGui.Selection.getSelection():
            if (i.Type == "App::Annotation"):
                i.ViewObject.TextColor=col
            else:
                if "LineColor" in i.ViewObject.PropertiesList:
                    i.ViewObject.LineColor = col
                if "PointColor" in i.ViewObject.PropertiesList:
                    i.ViewObject.PointColor = col

    def getfacecol(self):
        "opens a color picker dialog"
        self.facecolor=QtGui.QColorDialog.getColor()
        self.facecolorPix.fill(self.facecolor)
        self.facecolorButton.setIcon(QtGui.QIcon(self.facecolorPix))
        r = float(self.facecolor.red()/255.0)
        g = float(self.facecolor.green()/255.0)
        b = float(self.facecolor.blue()/255.0)
        col = (r,g,b,0.0)
        for i in FreeCADGui.Selection.getSelection():
            if "ShapeColor" in i.ViewObject.PropertiesList:
                i.ViewObject.ShapeColor = col
					
    def setwidth(self,val):
        self.linewidth = float(val)
        if Draft.getParam("saveonexit"):
            Draft.setParam("linewidth",int(val))
        for i in FreeCADGui.Selection.getSelection():
            if "LineWidth" in i.ViewObject.PropertiesList:
                i.ViewObject.LineWidth = float(val)

    def setfontsize(self,val):
        self.fontsize = float(val)
        if Draft.getParam("saveonexit"):
            Draft.setParam("textheight",float(val))
        for i in FreeCADGui.Selection.getSelection():
            if "FontSize" in i.ViewObject.PropertiesList:
                i.ViewObject.FontSize = float(val)

    def setContinue(self,val):
        self.continueMode = bool(val)

    def apply(self):
        for i in FreeCADGui.Selection.getSelection():
            Draft.formatObject(i)	

    def checkx(self):
        if self.yValue.isEnabled():
            self.yValue.setFocus()
            self.yValue.selectAll()
        else:
            self.checky()

    def checky(self):
        if self.zValue.isEnabled():
            self.zValue.setFocus()
            self.zValue.selectAll()
        else:
            self.validatePoint()

    def validatePoint(self):
        "function for checking and sending numbers entered manually"
        if self.sourceCmd != None:
            if (self.labelRadius.isVisible()):
                try:
                    rad=float(self.radiusValue.text())
                except ValueError:
                    pass
                else:
                    self.sourceCmd.numericRadius(rad)
            elif (self.offsetLabel.isVisible()):
                try:
                    offset=float(self.offsetValue.text())
                except ValueError:
                    pass
                else:
                    self.sourceCmd.offsetHandler(offset)
            else:
                try:
                    numx=float(self.xValue.text())
                    numy=float(self.yValue.text())
                    numz=float(self.zValue.text())
                except ValueError:
                    pass
                else:
                    if self.isRelative.isVisible() and self.isRelative.isChecked():
                        if self.sourceCmd.node:
                            if self.sourceCmd.featureName == "Rectangle":
                                last = self.sourceCmd.node[0]
                            else:
                                last = self.sourceCmd.node[-1]
                            numx = last.x + numx
                            numy = last.y + numy
                            numz = last.z + numz
                            if FreeCAD.DraftWorkingPlane:
                                v = FreeCAD.Vector(numx,numy,numz)
                                v = FreeCAD.DraftWorkingPlane.getGlobalCoords(v)
                                numx = v.x
                                numy = v.y
                                numz = v.z
                    self.sourceCmd.numericInput(numx,numy,numz)

    def finish(self):
        "finish button action"
        self.sourceCmd.finish(False)

    def closeLine(self):
        "close button action"
        self.sourceCmd.finish(True)

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

    def selectXY(self):
        self.sourceCmd.selectHandler("XY")

    def selectXZ(self):
        self.sourceCmd.selectHandler("XZ")

    def selectYZ(self):
        self.sourceCmd.selectHandler("YZ")

    def selectCurrentView(self):
        self.sourceCmd.selectHandler("currentView")

    def selectResetPlane(self):
        self.sourceCmd.selectHandler("reset")

    def undoSegment(self):
        "undo last line segment"
        self.sourceCmd.undolast()

    def checkSpecialChars(self,txt):
        '''
        checks for special characters in the entered coords that mut be
        treated as shortcuts
        '''
        spec = False
        if txt.endsWith(" ") or txt.endsWith("r"):
            self.isRelative.setChecked(not self.isRelative.isChecked())
            spec = True
        elif txt.endsWith("i"):
            if self.hasFill.isVisible():
                self.hasFill.setChecked(not self.hasFill.isChecked())
            spec = True
        elif txt.endsWith("f"):
            if self.finishButton.isVisible():
                self.finish()
            spec = True
        elif txt.endsWith("w"):
            self.wipeLine()
        elif txt.endsWith("c"):
            if self.closeButton.isVisible():
                self.closeLine()
            elif self.isCopy.isVisible():
                self.isCopy.setChecked(not self.isCopy.isChecked())
            elif self.continueCmd.isVisible():
                self.continueCmd.setChecked(not self.continueCmd.isChecked())
            spec = True
        if spec and (not self.taskmode):
            for i in [self.xValue,self.yValue,self.zValue]:
                if (i.text() == txt): i.setText("")

    def storeCurrentText(self,qstr):
        self.currEditText = self.textValue.text()

    def setCurrentText(self,tstr):
        if (not self.taskmode) or (self.taskmode and self.isTaskOn):
            self.textValue.setText(tstr)
                                                
    def sendText(self):
        '''
        this function sends the entered text to the active draft command
        if enter has been pressed twice. Otherwise it blanks the line.
        '''
        if self.textline == len(self.textbuffer):
            if self.textline:
                if not self.currEditText:
                    self.sourceCmd.text=self.textbuffer
                    self.sourceCmd.createObject()
            self.textbuffer.append(self.currEditText)
            self.textline += 1
            self.setCurrentText('')
        elif self.textline < len(self.textbuffer):
            self.textbuffer[self.textline] = self.currEditText
            self.textline += 1
            if self.textline < len(self.textbuffer):
                self.setCurrentText(self.textbuffer[self.textline])
            else:
                self.setCurrentText('')

    def lineUp(self):
        "displays previous line in text editor"
        if self.textline:
            if self.textline == len(self.textbuffer):
                self.textbuffer.append(self.textValue.text())
                self.textline -= 1
                if self.textValue.text():
                    self.textValue.setText(self.textbuffer[self.textline])
            elif self.textline < len(self.textbuffer):
                self.textbuffer[self.textline] = self.textValue.text()
                self.textline -= 1
                self.textValue.setText(self.textbuffer[self.textline])

    def displayPoint(self, point, last=None, plane=None):
        "this function displays the passed coords in the x, y, and z widgets"
        dp = point
        if self.isRelative.isChecked() and (last != None):
            if plane:
                dp = plane.getLocalCoords(FreeCAD.Vector(point.x-last.x, point.y-last.y, point.z-last.z))
            else:
                dp = FreeCAD.Vector(point.x-last.x, point.y-last.y, point.z-last.z)
        self.xValue.setText("%.2f" % dp.x)
        self.yValue.setText("%.2f" % dp.y)
        if self.zValue.isEnabled(): self.zValue.setText("%.2f" % dp.z)
        if self.xValue.isEnabled():
            self.xValue.setFocus()
            self.xValue.selectAll()
        else:
            self.yValue.setFocus()
            self.yValue.selectAll()

    def getDefaultColor(self,type,rgb=False):
        "gets color from the preferences or toolbar"
        if type == "snap":
            color = Draft.getParam("snapcolor")
            r = ((color>>24)&0xFF)/255
            g = ((color>>16)&0xFF)/255
            b = ((color>>8)&0xFF)/255
        elif type == "ui":
            r = float(self.color.red()/255.0)
            g = float(self.color.green()/255.0)
            b = float(self.color.blue()/255.0)
        elif type == "face":
            r = float(self.facecolor.red()/255.0)
            g = float(self.facecolor.green()/255.0)
            b = float(self.facecolor.blue()/255.0)
        elif type == "constr":
            color = QtGui.QColor(Draft.getParam("constructioncolor")>>8)
            r = color.red()/255.0
            g = color.green()/255.0
            b = color.blue()/255.0
        else: print "draft: error: couldn't get a color for ",type," type."
        if rgb:
            return("rgb("+str(int(r*255))+","+str(int(g*255))+","+str(int(b*255))+")")
        else:
            return (r,g,b)

    def cross(self,on=True):
        if on:
            if not self.crossedViews:
                mw = getMainWindow()
                self.crossedViews = mw.findChildren(QtGui.QFrame,"SoQtWidgetName")
            for w in self.crossedViews:
                w.setCursor(QtCore.Qt.CrossCursor)
        else:
            for w in self.crossedViews:
                w.unsetCursor()
            self.crossedViews = []

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

    def isConstructionMode(self):
        if self.tray or (not self.taskmode):
            return self.constrButton.isChecked()
        else:
            return False

    def drawPage(self):
        self.sourceCmd.draw()

    def changePage(self,index):
        pagename = str(self.pageBox.itemText(index))
        vobj = FreeCADGui.ActiveDocument.getObject(pagename)
        if vobj:
            self.scaleBox.setEditText(str(vobj.HintScale))
            self.marginXValue.setValue(float(vobj.HintOffsetX))
            self.marginYValue.setValue(float(vobj.HintOffsetY))

    def selectplane(self):
        FreeCADGui.runCommand("Draft_SelectPlane")

    def popupMenu(self,mlist):
        "pops up a menu filled with the given list"
        self.groupmenu = QtGui.QMenu()
        for i in mlist:
            self.groupmenu.addAction(i)
        pos = getMainWindow().cursor().pos()
        self.groupmenu.popup(pos)
        QtCore.QObject.connect(self.groupmenu,QtCore.SIGNAL("triggered(QAction *)"),self.popupTriggered)

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

    def setAddMode(self,bool):
        if self.addButton.isChecked():
            self.delButton.setChecked(False)

    def setDelMode(self,bool):
        if self.delButton.isChecked():
            self.addButton.setChecked(False)

    def setRadiusValue(self,val):
        self.radiusValue.setText("%.2f" % val)
        self.radiusValue.setFocus()
        self.radiusValue.selectAll()

    def show(self):
        if not self.taskmode:
            self.draftWidget.setVisible(True)

    def hide(self):
        if not self.taskmode:
            self.draftWidget.setVisible(False)

    def getXPM(self,iconname,size=16):
        i = QtGui.QIcon(":/icons/"+iconname+".svg")
        p = i.pixmap(size,size)
        a = QtCore.QByteArray()
        b = QtCore.QBuffer(a)
        b.open(QtCore.QIODevice.WriteOnly)
        p.save(b,"XPM")
        b.close()
        return str(a)


#---------------------------------------------------------------------------
# TaskView operations
#---------------------------------------------------------------------------
	                
    def setWatchers(self):
        print "adding draft widgets to taskview..."
        class DraftCreateWatcher:
            def __init__(self):
                self.commands = ["Draft_Line","Draft_Wire",
                                 "Draft_Rectangle","Draft_Arc",
                                 "Draft_Circle","Draft_BSpline",
                                 "Draft_Text","Draft_Dimension"]
                self.title = "Create objects"
            def shouldShow(self):
                return (FreeCAD.ActiveDocument != None) and (not FreeCADGui.Selection.getSelection())

        class DraftModifyWatcher:
            def __init__(self):
                self.commands = ["Draft_Move","Draft_Rotate",
                                 "Draft_Scale","Draft_Offset",
                                 "Draft_Trimex","Draft_Upgrade",
                                 "Draft_Downgrade","Draft_Edit",
                                 "Draft_Drawing"]
                self.title = "Modify objects"
            def shouldShow(self):
                return (FreeCAD.ActiveDocument != None) and (FreeCADGui.Selection.getSelection() != [])
                        
        class DraftTrayWatcher:
            def __init__(self,traywidget):
                self.form = traywidget
                self.widgets = [self.form]
            def shouldShow(self):
                return True

        print "setting tray"
        self.traywidget = QtGui.QWidget()
        self.tray = QtGui.QVBoxLayout(self.traywidget)
        self.tray.setObjectName("traylayout")
        self.toptray = QtGui.QHBoxLayout()
        self.bottomtray = QtGui.QHBoxLayout()
        self.tray.addLayout(self.toptray)
        self.tray.addLayout(self.bottomtray)
        self.setupTray()
        self.setupStyle()
        w = DraftTrayWatcher(self.traywidget)        
        FreeCADGui.Control.addTaskWatcher([w,DraftCreateWatcher(),DraftModifyWatcher()])
                                
    def changeEvent(self, event):
        if event.type() == QtCore.QEvent.LanguageChange:
            print "Language changed!"
            self.ui.retranslateUi(self)

    def Activated(self):
        if self.taskmode:
            self.setWatchers()
        else:
            self.draftWidget.setVisible(True)
            self.draftWidget.toggleViewAction().setVisible(True)

    def Deactivated(self):
        if (FreeCAD.activeDraftCommand != None):
            FreeCAD.activeDraftCommand.finish()
        if self.taskmode:
            FreeCADGui.Control.clearTaskWatcher()
            self.tray = None
        else:
            self.draftWidget.setVisible(False)
            self.draftWidget.toggleViewAction().setVisible(False)
                        
if not hasattr(FreeCADGui,"draftToolBar"):
    FreeCADGui.draftToolBar = DraftToolBar()
