diff --git a/src/Mod/TechDraw/App/AppTechDraw.cpp b/src/Mod/TechDraw/App/AppTechDraw.cpp index a8461a119f..21060efd90 100644 --- a/src/Mod/TechDraw/App/AppTechDraw.cpp +++ b/src/Mod/TechDraw/App/AppTechDraw.cpp @@ -40,6 +40,8 @@ #include "DrawViewImage.h" #include "DrawViewDetail.h" #include "DrawViewBalloon.h" +#include "DrawLeaderLine.h" +#include "DrawTextLeader.h" namespace TechDraw { extern PyObject* initModule(); @@ -80,7 +82,8 @@ PyMOD_INIT_FUNC(TechDraw) TechDraw::DrawProjGroupItem ::init(); TechDraw::DrawViewDetail ::init(); TechDraw::DrawViewBalloon ::init(); - + TechDraw::DrawLeaderLine ::init(); + TechDraw::DrawTextLeader ::init(); TechDraw::DrawTemplate ::init(); TechDraw::DrawParametricTemplate::init(); @@ -99,5 +102,7 @@ PyMOD_INIT_FUNC(TechDraw) TechDraw::DrawViewMultiPython ::init(); TechDraw::DrawTemplatePython ::init(); TechDraw::DrawViewSymbolPython::init(); + TechDraw::DrawLeaderLinePython::init(); + TechDraw::DrawTextLeaderPython::init(); PyMOD_Return(mod); } diff --git a/src/Mod/TechDraw/App/CMakeLists.txt b/src/Mod/TechDraw/App/CMakeLists.txt index e749f3e4bb..1670d9ea89 100644 --- a/src/Mod/TechDraw/App/CMakeLists.txt +++ b/src/Mod/TechDraw/App/CMakeLists.txt @@ -44,6 +44,9 @@ generate_from_xml(DrawViewCollectionPy) generate_from_xml(DrawProjGroupPy) generate_from_xml(DrawProjGroupItemPy) generate_from_xml(DrawViewAnnotationPy) +generate_from_xml(DrawLeaderLinePy) +generate_from_xml(DrawTextLeaderPy) + SET(Draw_SRCS DrawPage.cpp @@ -91,7 +94,12 @@ SET(Draw_SRCS DrawViewImage.cpp DrawViewImage.h DrawViewDetail.cpp - DrawViewDetail.h) + DrawViewDetail.h + DrawLeaderLine.cpp + DrawLeaderLine.h + DrawTextLeader.cpp + DrawTextLeader.h + ) SET(TechDraw_SRCS AppTechDraw.cpp @@ -147,7 +155,12 @@ SET(Python_SRCS DrawProjGroupItemPy.xml DrawProjGroupItemPyImp.cpp DrawViewAnnotationPy.xml - DrawViewAnnotationPyImp.cpp) + DrawViewAnnotationPyImp.cpp + DrawLeaderLinePy.xml + DrawLeaderLinePyImp.cpp + DrawTextLeaderPy.xml + DrawTextLeaderPyImp.cpp + ) SOURCE_GROUP("Mod" FILES ${TechDraw_SRCS}) SOURCE_GROUP("Features" FILES ${Draw_SRCS}) diff --git a/src/Mod/TechDraw/App/DrawLeaderLine.cpp b/src/Mod/TechDraw/App/DrawLeaderLine.cpp new file mode 100644 index 0000000000..1adc9f6238 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawLeaderLine.cpp @@ -0,0 +1,193 @@ +/*************************************************************************** + * Copyright (c) 2019 Wanderer Fan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" + +#ifndef _PreComp_ +#endif + +#include +#include +#include +#include + +#include "DrawPage.h" +#include "DrawView.h" +#include "DrawUtil.h" + +#include // generated from DrawLeaderLinePy.xml +#include "DrawLeaderLine.h" + +using namespace TechDraw; + +//=========================================================================== +// DrawLeaderLine - Base class for drawing leader based features +//=========================================================================== + +PROPERTY_SOURCE(TechDraw::DrawLeaderLine, TechDraw::DrawView) + +DrawLeaderLine::DrawLeaderLine(void) +{ + static const char *group = "Leader"; + + ADD_PROPERTY_TYPE(LeaderParent,(0),group,(App::PropertyType)(App::Prop_None), + "View to which this leader is attached"); + LeaderParent.setScope(App::LinkScope::Global); + ADD_PROPERTY_TYPE(WayPoints,(Base::Vector3d()) ,group, App::Prop_None, + "Intermediate points for Leader line"); + ADD_PROPERTY_TYPE(StartSymbol, (-1), group, App::Prop_None, "Symbol (arrowhead) for start of line"); + ADD_PROPERTY_TYPE(EndSymbol, (-1), group, App::Prop_None, "Symbol (arrowhead) for end of line"); + ADD_PROPERTY_TYPE(Scalable ,(false),group,App::Prop_None,"Scale line with LeaderParent"); + + //hide the DrawView properties that don't apply to Leader + ScaleType.setStatus(App::Property::ReadOnly,true); + ScaleType.setStatus(App::Property::Hidden,true); + Scale.setStatus(App::Property::ReadOnly,true); + Scale.setStatus(App::Property::Hidden,true); + Rotation.setStatus(App::Property::ReadOnly,true); + Rotation.setStatus(App::Property::Hidden,true); + + //generally, lines/leaders are not meant to move around. + LockPosition.setValue(true); +} + +DrawLeaderLine::~DrawLeaderLine() +{ +} + +void DrawLeaderLine::onChanged(const App::Property* prop) +{ + if (!isRestoring()) { + //nothing in particular + } + DrawView::onChanged(prop); + +} + +short DrawLeaderLine::mustExecute() const +{ + bool result = 0; + if (!isRestoring()) { + result = (LeaderParent.isTouched()); //Property changed + } + if (result) { + return result; + } + + const App::DocumentObject* docObj = getBaseObject(); + if (docObj != nullptr) { + result = docObj->isTouched(); //object property points to is touched + } + if (result) { + return result; + } + + return DrawView::mustExecute(); +} + +App::DocumentObjectExecReturn *DrawLeaderLine::execute(void) +{ +// Base::Console().Message("DL::execute()\n"); + if (!keepUpdated()) { + return App::DocumentObject::StdReturn; + } + return DrawView::execute(); +} + +DrawView* DrawLeaderLine::getBaseView(void) const +{ + DrawView* result = nullptr; + App::DocumentObject* baseObj = LeaderParent.getValue(); + if (baseObj != nullptr) { + DrawView* cast = dynamic_cast(baseObj); + if (cast != nullptr) { + result = cast; + } + } + return result; +} + + +App::DocumentObject* DrawLeaderLine::getBaseObject(void) const +{ + App::DocumentObject* result = nullptr; + DrawView* view = getBaseView(); + if (view != nullptr) { + result = view; + } + return result; +} + +bool DrawLeaderLine::keepUpdated(void) +{ + bool result = false; + DrawView* view = getBaseView(); + if (view != nullptr) { + result = view->keepUpdated(); + } + return result; +} + +double DrawLeaderLine::getScale(void) +{ + double result = 1.0; + DrawView* parent = getBaseView(); + if (parent != nullptr) { + result = parent->getScale(); + } else { + //TARFU + Base::Console().Log("DrawLeaderLine - %s - scale not found. Using 1.0. \n", getNameInDocument()); + } + return result; +} + +Base::Vector3d DrawLeaderLine::getAttachPoint(void) +{ + Base::Vector3d result(X.getValue(), + Y.getValue(), + 0.0); + return result; +} + +PyObject *DrawLeaderLine::getPyObject(void) +{ + if (PythonObject.is(Py::_None())) { + // ref counter is set to 1 + PythonObject = Py::Object(new DrawLeaderLinePy(this),true); + } + return Py::new_reference_to(PythonObject); +} + +// Python Drawing feature --------------------------------------------------------- + +namespace App { +/// @cond DOXERR +PROPERTY_SOURCE_TEMPLATE(TechDraw::DrawLeaderLinePython, TechDraw::DrawLeaderLine) +template<> const char* TechDraw::DrawLeaderLinePython::getViewProviderName(void) const { + return "TechDrawGui::ViewProviderLeader"; +} +/// @endcond + +// explicit template instantiation +template class TechDrawExport FeaturePythonT; +} + diff --git a/src/Mod/TechDraw/App/DrawLeaderLine.h b/src/Mod/TechDraw/App/DrawLeaderLine.h new file mode 100644 index 0000000000..b755494267 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawLeaderLine.h @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (c) 2019 Wanderer Fan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef _TechDraw_DrawLeaderLine_h_ +#define _TechDraw_DrawLeaderLine_h_ +#include + +# include +# include +# include + +#include "DrawView.h" + + +namespace TechDraw +{ + +class TechDrawExport DrawLeaderLine : public TechDraw::DrawView +{ + PROPERTY_HEADER(TechDraw::DrawLeaderLine); + +public: + DrawLeaderLine(); + virtual ~DrawLeaderLine(); + + App::PropertyLink LeaderParent; + App::PropertyVectorList WayPoints; + App::PropertyInteger StartSymbol; + App::PropertyInteger EndSymbol; + App::PropertyBool Scalable; + + virtual short mustExecute() const; + virtual App::DocumentObjectExecReturn *execute(void); + + virtual const char* getViewProviderName(void) const { + return "TechDrawGui::ViewProviderLeader"; + } + virtual PyObject *getPyObject(void); + virtual QRectF getRect() const { return QRectF(0,0,1,1);} + + Base::Vector3d getAttachPoint(void); + DrawView* getBaseView(void) const; + virtual App::DocumentObject* getBaseObject(void) const; + bool keepUpdated(void); + double getScale(void); + +protected: + virtual void onChanged(const App::Property* prop); + +private: +}; + +typedef App::FeaturePythonT DrawLeaderLinePython; + +} //namespace TechDraw +#endif diff --git a/src/Mod/TechDraw/App/DrawLeaderLinePy.xml b/src/Mod/TechDraw/App/DrawLeaderLinePy.xml new file mode 100644 index 0000000000..f439a241cd --- /dev/null +++ b/src/Mod/TechDraw/App/DrawLeaderLinePy.xml @@ -0,0 +1,18 @@ + + + + + + Feature for adding leaders to Technical Drawings + + + + diff --git a/src/Mod/TechDraw/App/DrawLeaderLinePyImp.cpp b/src/Mod/TechDraw/App/DrawLeaderLinePyImp.cpp new file mode 100644 index 0000000000..54a62775ff --- /dev/null +++ b/src/Mod/TechDraw/App/DrawLeaderLinePyImp.cpp @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (c) 2019 WandererFan (wandererfan@gmail.com) * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +#endif + +#include +#include +#include + +#include "DrawLeaderLine.h" + +// inclusion of the generated files (generated out of DrawLeaderLinePy.xml) +#include +#include +#include + +using namespace TechDraw; + +// returns a string which represents the object e.g. when printed in python +std::string DrawLeaderLinePy::representation(void) const +{ + return std::string(""); +} + +PyObject *DrawLeaderLinePy::getCustomAttributes(const char* /*attr*/) const +{ + return 0; +} + +int DrawLeaderLinePy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} diff --git a/src/Mod/TechDraw/App/DrawTextLeader.cpp b/src/Mod/TechDraw/App/DrawTextLeader.cpp new file mode 100644 index 0000000000..6e19d10ac8 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawTextLeader.cpp @@ -0,0 +1,112 @@ +/*************************************************************************** + * Copyright (c) 2019 Wanderer Fan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" + +#ifndef _PreComp_ +#endif + +#include +#include +#include +#include + +#include "DrawUtil.h" + +#include // generated from DrawTextLeaderPy.xml +#include "DrawTextLeader.h" + +using namespace TechDraw; + +//=========================================================================== +// DrawTextLeader - DrawLeaderLine + movable text block +//=========================================================================== + +PROPERTY_SOURCE(TechDraw::DrawTextLeader, TechDraw::DrawLeaderLine) + +DrawTextLeader::DrawTextLeader(void) +{ + static const char *group = "Text Leader"; + + ADD_PROPERTY_TYPE(LeaderText, (""), group, App::Prop_None, "Leader text"); + Base::Vector3d pos(0.0,0.0,0.0); + ADD_PROPERTY_TYPE(TextPosition, (pos), group, App::Prop_None, "Text position relative to parent"); +} + +DrawTextLeader::~DrawTextLeader() +{ +} + +void DrawTextLeader::onChanged(const App::Property* prop) +{ + if (!isRestoring()) { + //nothing in particular + } + DrawView::onChanged(prop); + +} + +short DrawTextLeader::mustExecute() const +{ + bool result = 0; + if (!isRestoring()) { + result = (LeaderText.isTouched()); + } + if (result) { + return result; + } + + return DrawView::mustExecute(); +} + +App::DocumentObjectExecReturn *DrawTextLeader::execute(void) +{ +// Base::Console().Message("DTL::execute()\n"); + if (!keepUpdated()) { + return App::DocumentObject::StdReturn; + } + return DrawView::execute(); +} + +PyObject *DrawTextLeader::getPyObject(void) +{ + if (PythonObject.is(Py::_None())) { + // ref counter is set to 1 + PythonObject = Py::Object(new DrawTextLeaderPy(this),true); + } + return Py::new_reference_to(PythonObject); +} + +// Python Drawing feature --------------------------------------------------------- + +namespace App { +/// @cond DOXERR +PROPERTY_SOURCE_TEMPLATE(TechDraw::DrawTextLeaderPython, TechDraw::DrawTextLeader) +template<> const char* TechDraw::DrawTextLeaderPython::getViewProviderName(void) const { + return "TechDrawGui::ViewProviderTextLeader"; +} +/// @endcond + +// explicit template instantiation +template class TechDrawExport FeaturePythonT; +} + diff --git a/src/Mod/TechDraw/App/DrawTextLeader.h b/src/Mod/TechDraw/App/DrawTextLeader.h new file mode 100644 index 0000000000..caa847283e --- /dev/null +++ b/src/Mod/TechDraw/App/DrawTextLeader.h @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (c) 2019 Wanderer Fan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef _TechDraw_DrawTextLeader_h_ +#define _TechDraw_DrawTextLeader_h_ + +# include +# include + +#include "DrawLeaderLine.h" + + +namespace TechDraw +{ + +class TechDrawExport DrawTextLeader : public TechDraw::DrawLeaderLine +{ + PROPERTY_HEADER(TechDraw::DrawTextLeader); + +public: + DrawTextLeader(); + virtual ~DrawTextLeader(); + + App::PropertyString LeaderText; + App::PropertyVector TextPosition; + + virtual short mustExecute() const; + virtual App::DocumentObjectExecReturn *execute(void); + + virtual const char* getViewProviderName(void) const { + return "TechDrawGui::ViewProviderTextLeader"; + } + virtual PyObject *getPyObject(void); + virtual QRectF getRect() const { return QRectF(0,0,1,1);} + +protected: + virtual void onChanged(const App::Property* prop); + +private: +}; + +typedef App::FeaturePythonT DrawTextLeaderPython; + +} //namespace TechDraw +#endif diff --git a/src/Mod/TechDraw/App/DrawTextLeaderPy.xml b/src/Mod/TechDraw/App/DrawTextLeaderPy.xml new file mode 100644 index 0000000000..43fbf1d329 --- /dev/null +++ b/src/Mod/TechDraw/App/DrawTextLeaderPy.xml @@ -0,0 +1,18 @@ + + + + + + Feature for adding text leaders to Technical Drawings + + + + diff --git a/src/Mod/TechDraw/App/DrawTextLeaderPyImp.cpp b/src/Mod/TechDraw/App/DrawTextLeaderPyImp.cpp new file mode 100644 index 0000000000..c47375deba --- /dev/null +++ b/src/Mod/TechDraw/App/DrawTextLeaderPyImp.cpp @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (c) 2019 WandererFan (wandererfan@gmail.com) * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +#endif + +#include +#include +#include + +#include "DrawTextLeader.h" + +// inclusion of the generated files (generated out of DrawTextLeaderPy.xml) +#include +#include +#include + +using namespace TechDraw; + +// returns a string which represents the object e.g. when printed in python +std::string DrawTextLeaderPy::representation(void) const +{ + return std::string(""); +} + +PyObject *DrawTextLeaderPy::getCustomAttributes(const char* /*attr*/) const +{ + return 0; +} + +int DrawTextLeaderPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} diff --git a/src/Mod/TechDraw/App/DrawView.cpp b/src/Mod/TechDraw/App/DrawView.cpp index 399fa21eaa..2a7378b144 100644 --- a/src/Mod/TechDraw/App/DrawView.cpp +++ b/src/Mod/TechDraw/App/DrawView.cpp @@ -45,6 +45,7 @@ #include "DrawViewClip.h" #include "DrawProjGroup.h" #include "DrawProjGroupItem.h" +#include "DrawLeaderLine.h" #include "DrawUtil.h" #include // generated from DrawViewPy.xml @@ -91,7 +92,6 @@ DrawView::~DrawView() App::DocumentObjectExecReturn *DrawView::execute(void) { -// Base::Console().Message("DV::execute() - %s\n",getNameInDocument()); handleXYLock(); requestPaint(); return App::DocumentObject::execute(); @@ -287,10 +287,11 @@ bool DrawView::checkFit(TechDraw::DrawPage* p) const return result; } -void DrawView::setPosition(double x, double y) +void DrawView::setPosition(double x, double y, bool force) { // Base::Console().Message("DV::setPosition(%.3f,%.3f) - \n",x,y,getNameInDocument()); - if (!isLocked()) { + if ( (!isLocked()) || + (force) ) { X.setValue(x); Y.setValue(y); } @@ -307,6 +308,26 @@ double DrawView::getScale(void) const return result; } +//return list of Leaders which reference this DV +std::vector DrawView::getLeaders() const +{ + std::vector result; + std::vector children = getInList(); + for (std::vector::iterator it = children.begin(); it != children.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(DrawLeaderLine::getClassTypeId())) { + TechDraw::DrawLeaderLine* lead = dynamic_cast(*it); + result.push_back(lead); + } + } + return result; +} + +void DrawView::addRandomVertex(Base::Vector3d pos) +{ + (void) pos; + Base::Console().Message("DV::addRandomVertex()\n"); +} + void DrawView::Restore(Base::XMLReader &reader) { // this is temporary code for backwards compat (within v0.17). can probably be deleted once there are no development diff --git a/src/Mod/TechDraw/App/DrawView.h b/src/Mod/TechDraw/App/DrawView.h index e69030bed1..3329ced0df 100644 --- a/src/Mod/TechDraw/App/DrawView.h +++ b/src/Mod/TechDraw/App/DrawView.h @@ -37,6 +37,7 @@ namespace TechDraw class DrawPage; class DrawViewClip; +class DrawLeaderLine; /** Base class of all View Features in the drawing module */ @@ -77,11 +78,11 @@ public: //return PyObject as DrawViewPy virtual PyObject *getPyObject(void) override; - DrawPage* findParentPage() const; + virtual DrawPage* findParentPage() const; virtual QRectF getRect() const; //must be overridden by derived class virtual double autoScale(double w, double h) const; virtual bool checkFit(DrawPage*) const; - virtual void setPosition(double x, double y); + virtual void setPosition(double x, double y, bool force = false); bool keepUpdated(void); boost::signals2::signal signalGuiPaint; virtual double getScale(void) const; @@ -89,6 +90,8 @@ public: void requestPaint(void); virtual void handleXYLock(void); virtual bool isLocked(void) const; + virtual void addRandomVertex(Base::Vector3d pos); + std::vector getLeaders() const; protected: virtual void onChanged(const App::Property* prop) override; diff --git a/src/Mod/TechDraw/Gui/AppTechDrawGui.cpp b/src/Mod/TechDraw/Gui/AppTechDrawGui.cpp index d577db6bae..dea779abdb 100644 --- a/src/Mod/TechDraw/Gui/AppTechDrawGui.cpp +++ b/src/Mod/TechDraw/Gui/AppTechDrawGui.cpp @@ -56,6 +56,7 @@ #include "ViewProviderGeomHatch.h" #include "ViewProviderSpreadsheet.h" #include "ViewProviderImage.h" +#include "ViewProviderLeader.h" // use a different name to CreateCommand() @@ -128,6 +129,8 @@ PyMOD_INIT_FUNC(TechDrawGui) TechDrawGui::ViewProviderGeomHatch::init(); TechDrawGui::ViewProviderSpreadsheet::init(); TechDrawGui::ViewProviderImage::init(); + TechDrawGui::ViewProviderLeader::init(); + TechDrawGui::ViewProviderTextLeader::init(); // register preferences pages new Gui::PrefPageProducer ("TechDraw"); diff --git a/src/Mod/TechDraw/Gui/CMakeLists.txt b/src/Mod/TechDraw/Gui/CMakeLists.txt index f947127b92..f97834d914 100644 --- a/src/Mod/TechDraw/Gui/CMakeLists.txt +++ b/src/Mod/TechDraw/Gui/CMakeLists.txt @@ -22,7 +22,6 @@ set(TechDrawGui_LIBS FreeCADGui ) - set(TechDrawGui_MOC_HDRS MDIViewPage.h QGVPage.h @@ -39,6 +38,14 @@ set(TechDrawGui_MOC_HDRS DlgTemplateField.h TaskSectionView.h TaskGeomHatch.h + TaskTextLeader.h + QGEPath.h + QGTracker.h + QGILeaderLine.h + QGITextLeader.h + QGMText.h + mrichtextedit.h + mtextedit.h ) fc_wrap_cpp(TechDrawGui_MOC_SRCS ${TechDrawGui_MOC_HDRS}) @@ -58,7 +65,9 @@ set(TechDrawGui_UIC_SRCS DlgTemplateField.ui TaskSectionView.ui TaskGeomHatch.ui -) + TaskTextLeader.ui + mrichtextedit.ui + ) if(BUILD_QT5) qt5_wrap_ui(TechDrawGui_UIC_HDRS ${TechDrawGui_UIC_SRCS}) @@ -66,9 +75,23 @@ else() qt4_wrap_ui(TechDrawGui_UIC_HDRS ${TechDrawGui_UIC_SRCS}) endif() +SET(MRTE_SRCS + mrichtextedit.ui + mrichtextedit.cpp + mrichtextedit.h + mtextedit.cpp + mtextedit.h +) + +SET(MRTE_HDRS + mtextedit.h +) + + SET(TechDrawGui_SRCS ${CMAKE_SOURCE_DIR}/src/Mod/TechDraw/InitGui.py ${TechDrawGui_SRCS} + ${MRTE_SRCS} AppTechDrawGui.cpp AppTechDrawGuiPy.cpp Command.cpp @@ -100,11 +123,15 @@ SET(TechDrawGui_SRCS TaskGeomHatch.ui TaskGeomHatch.cpp TaskGeomHatch.h + TaskTextLeader.ui + TaskTextLeader.cpp + TaskTextLeader.h DrawGuiUtil.cpp DrawGuiUtil.h Rez.cpp Rez.h ) + SET(TechDrawGuiView_SRCS MDIViewPage.cpp MDIViewPage.h @@ -182,6 +209,16 @@ SET(TechDrawGuiView_SRCS QGICenterLine.h QGIHighlight.cpp QGIHighlight.h + QGEPath.cpp + QGEPath.h + QGTracker.cpp + QGTracker.h + QGILeaderLine.cpp + QGILeaderLine.h + QGITextLeader.cpp + QGITextLeader.h + QGMText.h + QGMText.cpp TemplateTextField.cpp TemplateTextField.h ZVALUE.h @@ -219,8 +256,11 @@ SET(TechDrawGuiViewProvider_SRCS ViewProviderGeomHatch.h ViewProviderImage.cpp ViewProviderImage.h + ViewProviderLeader.cpp + ViewProviderLeader.h ) +SOURCE_GROUP("MRTE" FILES ${MRTE_SRCS}) SOURCE_GROUP("Mod" FILES ${TechDrawGui_SRCS}) SOURCE_GROUP("SVG-View" FILES ${TechDrawGuiView_SRCS}) SOURCE_GROUP("ViewProvider" FILES ${TechDrawGuiViewProvider_SRCS}) @@ -230,6 +270,8 @@ SET(TechDrawGuiTaskDlgs_SRCS TaskLinkDim.ui TaskSectionView.ui TaskGeomHatch.ui + TaskTextLeader.ui + mrichtextedit.ui ) SOURCE_GROUP("TaskDialogs" FILES ${TechDrawGuiTaskDlgs_SRCS}) @@ -244,15 +286,17 @@ SET(TechDrawGuiFonts ) add_library(TechDrawGui SHARED ${TechDrawGui_SRCS} ${TechDrawGuiView_SRCS} ${TechDrawGuiViewProvider_SRCS} - ${TechDrawGuiIcon_SVG} ${TechDrawGuiFonts}) + ${TechDrawGuiIcon_SVG} ${TechDrawGuiFonts} ${MRTE_SRCS}) target_link_libraries(TechDrawGui ${TechDrawGui_LIBS}) -fc_copy_sources(TechDrawGui "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/TechDraw" ${TechDrawGuiIcon_SVG}) +fc_copy_sources(TechDrawGui "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/TechDraw/" ${TechDrawGuiIcon_SVG}) INSTALL(FILES ${TechDrawGuiIcon_SVG} DESTINATION "${CMAKE_INSTALL_DATADIR}/Mod/TechDraw/Resources/icons") fc_copy_sources(TechDrawGui "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/TechDraw" ${TechDrawGuiFonts}) INSTALL(FILES ${TechDrawGuiFonts} DESTINATION "${CMAKE_INSTALL_DATADIR}/Mod/TechDraw/Resources/fonts") +fc_copy_sources(TechDrawGui "${CMAKE_BINARY_DIR}/src/Mod/TechDraw/Gui" ${MRTE_HDRS}) +INSTALL(FILES ${MRTE_HDRS} DESTINATION "${CMAKE_BINARY_DIR}/src/Mod/TechDraw/Gui") SET_BIN_DIR(TechDrawGui TechDrawGui /Mod/TechDraw) SET_PYTHON_PREFIX_SUFFIX(TechDrawGui) diff --git a/src/Mod/TechDraw/Gui/CommandDecorate.cpp b/src/Mod/TechDraw/Gui/CommandDecorate.cpp index ea53889455..d88b38fbaa 100644 --- a/src/Mod/TechDraw/Gui/CommandDecorate.cpp +++ b/src/Mod/TechDraw/Gui/CommandDecorate.cpp @@ -57,6 +57,7 @@ #include "DrawGuiUtil.h" #include "MDIViewPage.h" #include "TaskGeomHatch.h" +#include "TaskTextLeader.h" #include "ViewProviderGeomHatch.h" #include "ViewProviderPage.h" @@ -67,6 +68,133 @@ using namespace std; //internal functions bool _checkSelectionHatch(Gui::Command* cmd); +//=========================================================================== +// TechDraw_Leader +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawLeaderLine); + +CmdTechDrawLeaderLine::CmdTechDrawLeaderLine() + : Command("TechDraw_LeaderLine") +{ + sAppModule = "TechDraw"; + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Add a line to a view"); + sToolTipText = QT_TR_NOOP("Add a line to a view"); + sWhatsThis = "TechDraw_LeaderLine"; + sStatusTip = sToolTipText; + sPixmap = "actions/techdraw-mline"; +} + +void CmdTechDrawLeaderLine::activated(int iMsg) +{ + Q_UNUSED(iMsg); + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Not Available"), + QObject::tr("Line function is not available. Use Text Leader.")); + return; + + Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); + if (dlg != nullptr) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Task In Progress"), + QObject::tr("Close active task dialog and try again.")); + return; + } + + TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); + if (!page) { + return; + } + + std::vector selection = getSelection().getSelectionEx(); + TechDraw::DrawView* baseFeat = nullptr; + if (!selection.empty()) { + baseFeat = dynamic_cast(selection[0].getObject()); + if( baseFeat == nullptr ) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Selection Error"), + QObject::tr("Can not attach leader. No base View selected.")); + return; + } + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Selection Error"), + QObject::tr("You must select a base View for the line.")); + return; + } + + Gui::Control().showDialog(new TaskDlgTextLeader(LINEMODE, + baseFeat, + page)); +// Gui::Control().showDialog(new TaskDlgLeaderLine(1, +// baseFeat, +// page)); +} + +bool CmdTechDrawLeaderLine::isActive(void) +{ + bool havePage = DrawGuiUtil::needPage(this); + bool haveView = DrawGuiUtil::needView(this, false); + return (havePage && haveView); +} + +//=========================================================================== +// TechDraw_TextLeader +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawTextLeader); + +CmdTechDrawTextLeader::CmdTechDrawTextLeader() + : Command("TechDraw_TextLeader") +{ + sAppModule = "TechDraw"; + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Add a text leader to a view"); + sToolTipText = QT_TR_NOOP("Add a text leader to a view"); + sWhatsThis = "TechDraw_TextLeader"; + sStatusTip = sToolTipText; + sPixmap = "actions/techdraw-textleader"; +} + +void CmdTechDrawTextLeader::activated(int iMsg) +{ + Q_UNUSED(iMsg); + Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); + if (dlg != nullptr) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Task In Progress"), + QObject::tr("Close active task dialog and try again.")); + return; + } + + TechDraw::DrawPage* page = DrawGuiUtil::findPage(this); + if (!page) { + return; + } + + std::vector selection = getSelection().getSelectionEx(); + TechDraw::DrawView* baseFeat = nullptr; + if (!selection.empty()) { + baseFeat = dynamic_cast(selection[0].getObject()); + if( baseFeat == nullptr ) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Selection Error"), + QObject::tr("Can not attach leader. No base View selected.")); + return; + } + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Selection Error"), + QObject::tr("You must select a base View for the line.")); + return; + } + + Gui::Control().showDialog(new TaskDlgTextLeader(TEXTMODE, + baseFeat, + page)); +} + +bool CmdTechDrawTextLeader::isActive(void) +{ + bool havePage = DrawGuiUtil::needPage(this); + bool haveView = DrawGuiUtil::needView(this, false); + return (havePage && haveView); +} + //=========================================================================== // TechDraw_NewHatch //=========================================================================== @@ -347,7 +475,9 @@ void CreateTechDrawCommandsDecorate(void) rcCmdMgr.addCommand(new CmdTechDrawNewGeomHatch()); rcCmdMgr.addCommand(new CmdTechDrawImage()); rcCmdMgr.addCommand(new CmdTechDrawToggleFrame()); - rcCmdMgr.addCommand(new CmdTechDrawRedrawPage()); +// rcCmdMgr.addCommand(new CmdTechDrawRedrawPage()); + rcCmdMgr.addCommand(new CmdTechDrawLeaderLine()); + rcCmdMgr.addCommand(new CmdTechDrawTextLeader()); } //=========================================================================== diff --git a/src/Mod/TechDraw/Gui/DrawGuiStd.h b/src/Mod/TechDraw/Gui/DrawGuiStd.h new file mode 100644 index 0000000000..dfcf4f1708 --- /dev/null +++ b/src/Mod/TechDraw/Gui/DrawGuiStd.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (c) 2019 WandererFan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +// "DrawGuiStd.h" +// standard includes for TechDraw/Gui files +#ifndef TECHDRAWGUI_STANDARD_H +#define TECHDRAWGUI_STANDARD_H + +#include + +#include + +#include "Rez.h" +#include "ZVALUE.h" +#include "DrawGuiUtil.h" + +#endif // #ifndef TECHDRAWGUI_STANDARD_H diff --git a/src/Mod/TechDraw/Gui/MDIViewPage.cpp b/src/Mod/TechDraw/Gui/MDIViewPage.cpp index 5c5769efd6..30765c17c0 100644 --- a/src/Mod/TechDraw/Gui/MDIViewPage.cpp +++ b/src/Mod/TechDraw/Gui/MDIViewPage.cpp @@ -81,6 +81,7 @@ #include #include #include +#include #include "Rez.h" #include "QGIDrawingTemplate.h" @@ -94,6 +95,7 @@ #include "QGIFace.h" #include "ViewProviderPage.h" #include "QGVPage.h" +#include "QGILeaderLine.h" using namespace TechDrawGui; @@ -108,6 +110,7 @@ MDIViewPage::MDIViewPage(ViewProviderPage *pageVp, Gui::Document* doc, QWidget* m_frameState(true) { + setMouseTracking(true); m_scene = new QGraphicsScene(this); m_view = new QGVPage(pageVp,m_scene,this); @@ -332,6 +335,9 @@ bool MDIViewPage::attachView(App::DocumentObject *obj) } else if (typeId.isDerivedFrom(TechDraw::DrawViewImage::getClassTypeId()) ) { qview = m_view->addDrawViewImage( static_cast(obj) ); + } else if (typeId.isDerivedFrom(TechDraw::DrawLeaderLine::getClassTypeId()) ) { + qview = m_view->addViewLeader( static_cast(obj) ); + } else if (typeId.isDerivedFrom(TechDraw::DrawHatch::getClassTypeId()) ) { //Hatch is not attached like other Views (since it isn't really a View) return true; @@ -1082,7 +1088,7 @@ void MDIViewPage::sceneSelectionChanged() { sceneSelectionManager(); - QList dbsceneSel = m_view->scene()->selectedItems(); +// QList dbsceneSel = m_view->scene()->selectedItems(); if(isSelectionBlocked) { return; diff --git a/src/Mod/TechDraw/Gui/QGEPath.cpp b/src/Mod/TechDraw/Gui/QGEPath.cpp new file mode 100644 index 0000000000..9d99b050ab --- /dev/null +++ b/src/Mod/TechDraw/Gui/QGEPath.cpp @@ -0,0 +1,408 @@ +/*************************************************************************** + * Copyright (c) 2019 Wandererfan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include + +#include "DrawGuiStd.h" +#include "QGIPrimPath.h" +#include "QGIVertex.h" +#include "QGIView.h" +#include "QGEPath.h" + +using namespace TechDrawGui; + +QGMarker::QGMarker(int idx) : QGIVertex(idx) +{ +// Base::Console().Message("QGMarker::QGMarker(%d)\n", idx); + setFlag(QGraphicsItem::ItemIsMovable, true); +} + +QVariant QGMarker::itemChange(GraphicsItemChange change, const QVariant &value) +{ +// Base::Console().Message("QGMarker::itemChange(%d)\n",change); + return QGIVertex::itemChange(change, value); +} + +void QGMarker::hoverEnterEvent(QGraphicsSceneHoverEvent *event) +{ +// Base::Console().Message("QGMarker::hoverEnterEvent(%d)\n",getProjIndex()); + QGIVertex::hoverEnterEvent(event); +} + +void QGMarker::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) +{ +// Base::Console().Message("QGMarker::hoverLeaveEvent(%d)\n",getProjIndex()); + QGIVertex::hoverLeaveEvent(event); +} + +void QGMarker::mousePressEvent(QGraphicsSceneMouseEvent * event) +{ +// Base::Console().Message("QGMarker::mousePressEvent() - focustype: %d\n", +// scene()->focusItem()->type() - QGraphicsItem::UserType); + + if (event->button() == Qt::RightButton) { //we're done + Q_EMIT endEdit(); + event->accept(); + return; + } else if(scene() && this == scene()->mouseGrabberItem()) { + QPointF mapped = mapToParent(event->pos()); + Q_EMIT dragging(mapped, getProjIndex()); + } + QGIVertex::mousePressEvent(event); +} + +void QGMarker::mouseMoveEvent(QGraphicsSceneMouseEvent * event) +{ +// Base::Console().Message("QGMarker::mouseMoveEvent(%d)\n", getProjIndex()); + QGIVertex::mouseMoveEvent(event); +} + +void QGMarker::mouseReleaseEvent(QGraphicsSceneMouseEvent * event) +{ +// Base::Console().Message("QGMarker::mouseReleaseEvent(%d) - focus: %d\n", getProjIndex(), hasFocus()); + if (event->button() == Qt::RightButton) { //we're done + Q_EMIT endEdit(); + event->accept(); //this is mine! + return; + } + + if(this->scene() && this == this->scene()->mouseGrabberItem()) { + QPointF mapped = mapToParent(event->pos()); + Q_EMIT dragFinished(mapped, getProjIndex()); + event->accept(); + } + + QGIVertex::mouseReleaseEvent(event); +} + +void QGMarker::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event) +{ +// Base::Console().Message("QGMarker::mouseDoubleClickEvent(%d)\n",getProjIndex()); + if (event->button() == Qt::RightButton) { //we're done + Q_EMIT endEdit(); + event->accept(); //this is mine! + return; + } + QGIVertex::mouseDoubleClickEvent(event); +} + +//why can markers get the keyPress, but QGTracker can not?? +void QGMarker::keyPressEvent(QKeyEvent * event) +{ + if (event->key() == Qt::Key_Escape) { + Q_EMIT endEdit(); + } + QGIVertex::keyPressEvent(event); +} + + +void QGMarker::setRadius(float r) +{ + //TODO:: implement different marker shapes. circle, square, triangle, ??? + //if (m_markerShape == Circle) { ... + //setRect(QRectF) for rectangular markers + m_radius = r; + QPainterPath p; + p.addRect(-r/2.0, -r/2.0, r, r); + setPath(p); +} + +//void QGMarker::setShape(int s) +//{ +// m_markerShape = s; +//} + +QRectF QGMarker::boundingRect() const +{ + return QGIVertex::boundingRect(); +} + +QPainterPath QGMarker::shape() const +{ + return QGIVertex::shape(); +} + + +void QGMarker::paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) +{ + QStyleOptionGraphicsItem myOption(*option); + myOption.state &= ~QStyle::State_Selected; + + //~ painter->drawRect(boundingRect()); //good for debugging + + QGIVertex::paint (painter, &myOption, widget); +} + +//****************************************************************************** + +QGEPath::QGEPath() : + m_attach(QPointF(0.0,0.0)), + m_scale(1.0), + m_inEdit(false), + m_parentItem(nullptr) +{ + setHandlesChildEvents(false); + setAcceptHoverEvents(false); + setFlag(QGraphicsItem::ItemIsSelectable, false); + setFlag(QGraphicsItem::ItemIsMovable, false); +// setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true); + setFlag(QGraphicsItem::ItemSendsScenePositionChanges, false); + setFlag(QGraphicsItem::ItemSendsGeometryChanges,true); + + QGraphicsItem* parent = parentItem(); + QGIView* pView = dynamic_cast(parent); + if (pView != nullptr) { + m_parentItem = pView; + } +} + +QVariant QGEPath::itemChange(GraphicsItemChange change, const QVariant &value) +{ +// Base::Console().Message("QGEPath::itemChange(%d)\n",change); +// Q_EMIT dragging(); + + return QGIPrimPath::itemChange(change, value); +} + +void QGEPath::startPathEdit() +{ +// Base::Console().Message("QGEPath::startPathEdit()\n"); + inEdit(true); + showMarkers(m_deltas); +} + +void QGEPath::showMarkers(std::vector deltas) +{ +// Base::Console().Message("QGEPath::showMarkers()\n"); + if (!inEdit()) { + return; + } + QGraphicsItem* qgepParent = parentItem(); + if (qgepParent == nullptr) { + Base::Console().Error("QGEPath::showMarkers - no parent item\n"); + return; + } + + clearMarkers(); + + int pointDx = 0; + for (auto& p: deltas) { + QGMarker* v = new QGMarker(pointDx); + v->setFlag(QGraphicsItem::ItemIsMovable, true); + v->setFlag(QGraphicsItem::ItemIsFocusable, true); + v->setParentItem(this); + QObject::connect( + v, SIGNAL(dragFinished(QPointF, int)), + this , SLOT (onDragFinished(QPointF, int)) + ); + QObject::connect( + v, SIGNAL(dragging(QPointF, int)), + this , SLOT (onDragging(QPointF, int)) + ); + QObject::connect( + v, SIGNAL(doubleClick(QPointF, int)), + this , SLOT (onDoubleClick(QPointF, int)) + ); + QObject::connect( + v, SIGNAL(endEdit()), + this , SLOT (onEndEdit()) + ); +//TODO: double r = getMarkerSize(); +// v->setRadius(r); + v->setRadius(50.0); + v->setNormalColor(QColor(Qt::black)); + v->setZValue(ZVALUE::VERTEX); + v->setPos(p * m_scale); + v->show(); + + m_markers.push_back(v); + pointDx++; + } +} + +void QGEPath::clearMarkers() +{ +// Base::Console().Message("QGEPath::clearMarkers()\n"); + if (m_markers.empty()) { + return; + } + for (auto& m: m_markers) { + if (m != nullptr) { + QGraphicsScene* s = m->scene(); + if (s != nullptr) { + s->removeItem(m); //should this be setParentItem(nullptr) instead?? + } + delete m; + } + } + m_markers.clear(); +} + +// end of node marker drag +void QGEPath::onDragFinished(QPointF pos, int markerIndex) +{ +// Base::Console().Message("QGEPath::onDragFinished()\n"); + m_deltas.at(markerIndex) = pos / m_scale; + updatePath(); +} + +void QGEPath::onDragging(QPointF pos, int markerIndex) +{ + Q_UNUSED(pos); + Q_UNUSED(markerIndex); + //Q_EMIT dragging( + //TODO: could "live update" line during Drag +} + +//this is for double click on a marker +void QGEPath::onDoubleClick(QPointF pos, int markerIndex) +{ + Q_UNUSED(pos); + Q_UNUSED(markerIndex); +// Base::Console().Message("QGEPath::onDoubleClick()\n"); + updatePath(); + updateFeature(); + clearMarkers(); + inEdit(false); +} + +void QGEPath::onEndEdit(void) +{ +// Base::Console().Message("QGEPath::onEndEdit()\n"); + updatePath(); + inEdit(false); + updateFeature(); + clearMarkers(); +} + +//updates the painterpath using our deltas +//path is (0,0),d(p1-p0), d(p2-p1),... +void QGEPath::updatePath(void) +{ +// Base::Console().Message("QGEPath::updatePath() - scale: %.3f\n", m_scale); + if (m_deltas.empty()) { + Base::Console().Log("QGEPath::updatePath - no points\n"); + return; + } + QPainterPath result; + prepareGeometryChange(); + if (m_deltas.size() > 1) { + result.moveTo(m_deltas.front()); //(0,0) + for (int i = 1; i < (int)m_deltas.size(); i++) { + result.lineTo(m_deltas.at(i) * m_scale); + } + } + setPath(result); + setPrettyNormal(); +} + +void QGEPath::makeDeltasFromPoints(std::vector pts) +{ +// Base::Console().Message("QGEPath::makeDeltasFromPoints()\n"); + if (pts.empty()) { + Base::Console().Log("QGEPath::makeDeltasFromPoints - no points\n"); + return; + } + std::vector deltas; + QPointF firstPt = pts.front(); + QPointF newStart(0.0,0.0); + deltas.push_back(newStart); + unsigned int i = 1; + for (; i < pts.size(); i++) { + QPointF mapped = pts.at(i) - firstPt; + deltas.push_back(mapped); + } + m_deltas = deltas; +} + +//tell parent points editing is finished +void QGEPath::updateFeature(void) +{ +// Base::Console().Message("QGEPath::updateFeature()\n"); + if (!inEdit()) { + Q_EMIT pointsUpdated(m_deltas); + } +} + +void QGEPath::paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) { + QStyleOptionGraphicsItem myOption(*option); + myOption.state &= ~QStyle::State_Selected; + + // painter->drawRect(boundingRect()); //good for debugging + + QGIPrimPath::paint (painter, &myOption, widget); +} + +void QGEPath::addPoint(unsigned int before, unsigned int after) +{ + std::vector deltaCopy = getDeltas(); + unsigned int iMax = deltaCopy.size() - 1; + if ( (after <= before) || + (after > iMax) ) { + Base::Console().Message("QGEP::addPoint - parameter out of range\n"); + return; + } + QPointF bPt = deltaCopy.at(before); + QPointF aPt = deltaCopy.at(after); + QPointF newPt = (bPt + aPt) / 2.0; + deltaCopy.insert(deltaCopy.begin() + after, newPt); + setDeltas(deltaCopy); +} + +void QGEPath::deletePoint(unsigned int atX) +{ + std::vector deltaCopy = getDeltas(); + unsigned int iMax = deltaCopy.size() - 1; + if ( (atX < 1) || //can't delete attach point + (atX > iMax) ) { + Base::Console().Message("QGEP::deletePoint - parameter out of range\n"); + return; + } + deltaCopy.erase(deltaCopy.begin() + (unsigned int) atX); + setDeltas(deltaCopy); +} + +void QGEPath::dumpPoints(char* text) +{ + int idb = 0; + for (auto& d: m_deltas) { + Base::Console().Message("QGEP - %s - delta: %d %s\n", text, + idb,TechDraw::DrawUtil::formatVector(d).c_str()); + idb++; + } +} + +#include + diff --git a/src/Mod/TechDraw/Gui/QGEPath.h b/src/Mod/TechDraw/Gui/QGEPath.h new file mode 100644 index 0000000000..699ba91f86 --- /dev/null +++ b/src/Mod/TechDraw/Gui/QGEPath.h @@ -0,0 +1,138 @@ +/*************************************************************************** + * Copyright (c) 2019 Wandererfan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef TECHDRAWGUI_EDITABLEPATH_H +#define TECHDRAWGUI_EDITABLEPATH_H + +/*#include */ +#include +#include +#include +#include + +#include "QGIVertex.h" +#include "QGIPrimPath.h" + +namespace TechDrawGui +{ + +class QGIPrimPath; +class QGIVertex; +class QGIView; + +class TechDrawGuiExport QGMarker : public QObject, public QGIVertex +{ + Q_OBJECT +public: + explicit QGMarker(int idx); + virtual ~QGMarker(void) {} + + enum {Type = QGraphicsItem::UserType + 302}; + int type() const override { return Type;} + virtual QRectF boundingRect() const override; + virtual QPainterPath shape() const override; + virtual void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0 ) override; + + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; + virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override; + virtual void keyPressEvent(QKeyEvent * event); + + virtual void setRadius(float r) override; + +Q_SIGNALS: + void dragging(QPointF pos, int idx); + void dragFinished(QPointF pos, int idx); + void doubleClick(QPointF pos, int idx); + void endEdit(void); + +protected: + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) override; + virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override; + virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override; + +private: + +}; + +//****************************************************************************** + +//the path is in item coords, starting at (0,0) - ie delta vectors between nodes. +// The QGEPath item is positioned at "attachment point" of the view. +class TechDrawGuiExport QGEPath : public QObject, public QGIPrimPath +{ + Q_OBJECT +public: + explicit QGEPath(void); + virtual ~QGEPath() {} + + enum {Type = QGraphicsItem::UserType + 301}; + int type() const override { return Type;} + virtual void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0 ) override; + + void inEdit(bool b) { m_inEdit = b; } + bool inEdit(void) { return m_inEdit; } + void startPathEdit(); + + void showMarkers(std::vector points); + void clearMarkers(); + void addPoint(unsigned int before, unsigned int after); + void deletePoint(unsigned int atX); + + void setDeltas(std::vector pts) { m_deltas = pts; } + std::vector getDeltas(void) { return m_deltas; } + void setScale(double s) { m_scale = s; } + double getScale(void) { return m_scale; } + void setAttach(QPointF s) { m_attach = s; } + QPointF getAttach(void) { return m_attach; } + + void makeDeltasFromPoints(std::vector pts); + void updatePath(); + void updateFeature(); + + void dumpPoints(char* text); + +public Q_SLOTS: + void onDragFinished(QPointF pos, int index); + void onDragging(QPointF pos, int index); + void onDoubleClick(QPointF pos, int markerIndex); + void onEndEdit(void); + +Q_SIGNALS: + void pointsUpdated(std::vector pts); + +protected: + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; + std::vector m_deltas; //deltas between points 1:1 scale, starts at (0,0) + std::vector m_markers; + QPointF m_attach; + double m_scale; + + bool m_inEdit; + + QGIView* m_parentItem; +}; + +} + +#endif // TECHDRAWGUI_EDITABLEPATH_H diff --git a/src/Mod/TechDraw/Gui/QGILeaderLine.cpp b/src/Mod/TechDraw/Gui/QGILeaderLine.cpp new file mode 100644 index 0000000000..1bde7544be --- /dev/null +++ b/src/Mod/TechDraw/Gui/QGILeaderLine.cpp @@ -0,0 +1,377 @@ +/*************************************************************************** + * Copyright (c) 2019 WandererFan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ + #include + #include + # include + # include + # include + # include + # include + + # include + # include + # include + # include + # include + + # include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "Rez.h" +#include "ZVALUE.h" +#include "QGIArrow.h" +#include "ViewProviderLeader.h" +#include "MDIViewPage.h" +#include "DrawGuiUtil.h" +#include "QGVPage.h" +#include "QGIPrimPath.h" +#include "QGEPath.h" + +#include "QGILeaderLine.h" + +using namespace TechDraw; +using namespace TechDrawGui; + + +//************************************************************** +QGILeaderLine::QGILeaderLine(QGraphicsItem* myParent, + TechDraw::DrawLeaderLine* leader) : + m_parentItem(myParent), + m_lineWidth(0.0), + m_lineColor(Qt::black) +{ + setHandlesChildEvents(false); + setAcceptHoverEvents(false); + setFlag(QGraphicsItem::ItemIsSelectable, false); + setFlag(QGraphicsItem::ItemIsMovable, false); + setFlag(QGraphicsItem::ItemSendsScenePositionChanges, false); + setFlag(QGraphicsItem::ItemSendsGeometryChanges,true); + + setCacheMode(QGraphicsItem::NoCache); + + m_lineColor = Qt::blue; + + m_line = new QGEPath(); + addToGroup(m_line); + m_line->setFlag(QGraphicsItem::ItemIsSelectable, false); + m_line->setFlag(QGraphicsItem::ItemIsMovable, false); + setFlag(QGraphicsItem::ItemSendsScenePositionChanges, false); + m_line->setAcceptHoverEvents(false); + m_line->setZValue(ZVALUE::DIMENSION); + + m_arrow1 = new QGIArrow(); + addToGroup(m_arrow1); + m_arrow1->hide(); + m_arrow2 = new QGIArrow(); + addToGroup(m_arrow2); + m_arrow2->hide(); + + setParentItem(m_parentItem); + + setViewFeature(leader); + + setZValue(ZVALUE::DIMENSION); + + QObject::connect( + m_line, SIGNAL(pointsUpdated(std::vector)), + this , SLOT (onLineEditFinished(std::vector)) + ); +} + +QVariant QGILeaderLine::itemChange(GraphicsItemChange change, const QVariant &value) +{ +// Base::Console().Message("QGIV::itemChange(%d)\n", change); + if (change == ItemSelectedHasChanged && scene()) { + //There's nothing special for QGIVL to do when selection changes! + } else if(change == ItemSceneChange && scene()) { + // nothing special! + } + return QGIView::itemChange(change, value); +} + +void QGILeaderLine::onLineEditFinished(std::vector pts) +{ +// Base::Console().Message("QGIVL::onLineEditFinished(%d)\n",pts.size()); + std::vector waypoints; + for (auto& p: pts) { + Base::Vector3d v(p.x(),p.y(),0.0); + waypoints.push_back(v); + } + + if (m_parentItem == nullptr) { + Base::Console().Log("QGIVL::onLineEditFinished - m_parentItem is NULL\n"); + } else { + QGIView* qgiv = dynamic_cast(m_parentItem); + if (qgiv != nullptr) { + Q_EMIT editComplete(pts, qgiv); //leader's parent if QGIView + } + } +} + +void QGILeaderLine::startPathEdit(void) +{ + double scale = getScale(); + m_line->setScale(scale); + m_line->inEdit(true); + m_line->startPathEdit(); +} + +void QGILeaderLine::updateView(bool update) +{ +// Base::Console().Message("QGIL::updateView() %s\n",getViewObject()->getNameInDocument()); + Q_UNUSED(update); + auto leadFeat( dynamic_cast(getViewObject()) ); + if ( leadFeat == nullptr ) { + Base::Console().Log("QGIL::updateView - no feature!\n"); + return; + } + + auto vp = static_cast(getViewProvider(getViewObject())); + if ( vp == nullptr ) { + return; + } + + draw(); +} + +void QGILeaderLine::draw() +{ +// Base::Console().("QGIL::draw()- %s\n", getViewObject()->getNameInDocument()); + if (!isVisible()) { + Base::Console().Log("QGIL::draw - not visible\n"); + return; + } + + TechDraw::DrawLeaderLine* leadFeat = getFeature(); + if((!leadFeat) ) { + Base::Console().Log("QGIL::draw - no feature\n"); + return; + } + + auto vp = static_cast(getViewProvider(getViewObject())); + if ( vp == nullptr ) { + Base::Console().Log("QGIL::draw - no viewprovider\n"); + return; + } + + TechDraw::DrawView* parent = leadFeat->getBaseView(); + QGVPage* view = QGIView::getGraphicsView(parent); + if (view == nullptr) { + Base::Console().Log("QGIL::draw - no graphcisView for parent!! - setup?\n"); + return; + } + + if (leadFeat->isLocked()) { + setFlag(QGraphicsItem::ItemIsMovable, false); + } else { + setFlag(QGraphicsItem::ItemIsMovable, true); + } + + m_lineWidth = Rez::guiX(vp->LineWidth.getValue()); + m_lineColor = vp->Color.getValue().asValue(); + m_lineStyle = (Qt::PenStyle) vp->LineStyle.getValue(); + + double scale = parent->getScale(); //only attach point scales with parent. + double x = Rez::guiX(leadFeat->X.getValue()); + double y = - Rez::guiX(leadFeat->Y.getValue()); + QPointF aPoint(x,y); //1:1 parent coords + aPoint *= scale; //scaled parent coords + setPos(aPoint); + +// this is for Page as parent +// double ptScale = 1.0; +// if (leadFeat->Scalable.getValue()) { +// ptScale = scale; +// } + std::vector qPoints = convertWaypoints(); + if (qPoints.empty()) { + Base::Console().Log("QGIL::draw - no points\n"); + return; + } +// m_line->setAttach(aPoint); + m_line->setStyle(m_lineStyle); + double scaler = 1.0; + m_line->setWidth(scaler * m_lineWidth); + + m_line->setNormalColor(m_lineColor); + scale = getScale(); + m_line->setScale(scale); + m_line->makeDeltasFromPoints(qPoints); + m_line->setPos(0,0); + m_line->updatePath(); + m_line->show(); + + setArrows(qPoints); + + QGIView::draw(); +} + +void QGILeaderLine::drawBorder() +{ +////Leaders have no border! +// QGIView::drawBorder(); //good for debugging +} + +//waypoints converted to QPointF +std::vector QGILeaderLine::convertWaypoints() +{ +// Base::Console().Message("QGIL::convertWaypoints()\n"); + TechDraw::DrawLeaderLine* featLine = getFeature(); + std::vector result; + std::vector vPts = featLine->WayPoints.getValues(); + if (vPts.empty()) { + Base::Console().Log("QGIL::convertWaypoints - no points from feature!\n"); + return result; + } + + QGraphicsItem* myParent = parentItem(); + if (myParent != nullptr) { + for (auto& p: vPts) { + QPointF pConvert(p.x, p.y); + result.push_back(pConvert); + } + } + return result; +} + +void QGILeaderLine::setArrows(std::vector pathPoints) +{ + Base::Vector3d stdX(1.0,0.0,0.0); + TechDraw::DrawLeaderLine* line = getFeature(); + + double scale = getScale(); + QPointF lastOffset = (pathPoints.back() - pathPoints.front()) * scale; + + if (line->StartSymbol.getValue() > -1) { + m_arrow1->setStyle(line->StartSymbol.getValue()); + m_arrow1->setWidth(m_lineWidth); +// TODO: variable size arrow heads + m_arrow1->setSize(QGIArrow::getPrefArrowSize()); + m_arrow1->setDirMode(true); + m_arrow1->setDirection(stdX); + if (pathPoints.size() > 1) { + auto it = pathPoints.begin(); + QPointF s = (*it); + QPointF e = (*(it + 1)); + QPointF qsVec = s - e; + Base::Vector3d sVec(qsVec.x(),qsVec.y(),0.0); + m_arrow1->setDirection(sVec); + m_arrow1->setNormalColor(m_lineColor); + m_arrow1->setPos(0.0,0.0); + m_arrow1->setPrettyNormal(); + } + m_arrow1->draw(); + m_arrow1->show(); + } else { + m_arrow1->hide(); + } + + if (line->EndSymbol.getValue() > -1) { + m_arrow2->setStyle(line->EndSymbol.getValue()); + m_arrow2->setWidth(m_lineWidth); + m_arrow2->setDirMode(true); + m_arrow2->setDirection(-stdX); + if (pathPoints.size() > 1) { + auto itr = pathPoints.rbegin(); + QPointF s = (*itr); + QPointF e = (*(itr + 1)); + QPointF qeVec = s - e; + Base::Vector3d eVec(qeVec.x(),qeVec.y(),0.0); + m_arrow2->setDirection(eVec); + m_arrow2->setNormalColor(m_lineColor); + m_arrow2->setPos(lastOffset); + m_arrow2->setPrettyNormal(); + } + m_arrow2->draw(); + m_arrow2->show(); + } else { + m_arrow2->hide(); + } +} + +void QGILeaderLine::abandonEdit(void) +{ + m_line->clearMarkers(); +} + +double QGILeaderLine::getScale(void) +{ + bool isScalable = getFeature()->Scalable.getValue(); + double scale = getFeature()->getScale(); + if (!isScalable) { + scale = 1.0; + } + return scale; +} + +TechDraw::DrawLeaderLine* QGILeaderLine::getFeature(void) +{ + TechDraw::DrawLeaderLine* result = + static_cast(getViewObject()); + return result; +} + +double QGILeaderLine::getEdgeFuzz(void) const +{ + Base::Reference hGrp = App::GetApplication().GetUserParameter().GetGroup("BaseApp")-> + GetGroup("Preferences")->GetGroup("Mod/TechDraw/General"); + double result = hGrp->GetFloat("EdgeFuzz",10.0); + return result; +} + +QRectF QGILeaderLine::boundingRect() const +{ + return childrenBoundingRect(); +} + +QPainterPath QGILeaderLine::shape() const +{ + return QGraphicsItemGroup::shape(); +} + +void QGILeaderLine::paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) { + QStyleOptionGraphicsItem myOption(*option); + myOption.state &= ~QStyle::State_Selected; + +// painter->drawRect(boundingRect()); //good for debugging + + QGIView::paint (painter, &myOption, widget); +} + +#include diff --git a/src/Mod/TechDraw/Gui/QGILeaderLine.h b/src/Mod/TechDraw/Gui/QGILeaderLine.h new file mode 100644 index 0000000000..76cba3ae91 --- /dev/null +++ b/src/Mod/TechDraw/Gui/QGILeaderLine.h @@ -0,0 +1,108 @@ +/*************************************************************************** + * Copyright (c) 2019 WandererFan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef DRAWINGGUI_QGRAPHICSITEMLEADERLINE_H +#define DRAWINGGUI_QGRAPHICSITEMLEADERLINE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "QGIView.h" + +namespace TechDraw { +class DrawLeaderLine; +} + +namespace TechDrawGui +{ +class QGIPrimPath; +class QGIArrow; +class QGEPath; + + +//******************************************************************* + +class TechDrawGuiExport QGILeaderLine : public QGIView +{ + Q_OBJECT + +public: + enum {Type = QGraphicsItem::UserType + 232}; + + explicit QGILeaderLine(QGraphicsItem* myParent = nullptr, + TechDraw::DrawLeaderLine* lead = nullptr); + ~QGILeaderLine() = default; + + int type() const override { return Type;} + virtual void paint( QPainter * painter, + const QStyleOptionGraphicsItem * option, + QWidget * widget = 0 ) override; + virtual QRectF boundingRect() const override; + virtual QPainterPath shape(void) const override; + double getEdgeFuzz(void) const; + + virtual void drawBorder() override; + virtual void updateView(bool update = false) override; + + virtual TechDraw::DrawLeaderLine* getFeature(void); + QGEPath* getLeaderLine(void) { return m_line; } + std::vector convertWaypoints(void); + void startPathEdit(void); + void setArrows(std::vector pathPoints); + + void abandonEdit(void); + double getScale(void); + +public Q_SLOTS: + void onLineEditFinished(std::vector pts); //QGEPath is finished editing points + +Q_SIGNALS: + void editComplete(std::vector pts, QGIView* parent); //tell caller that edit session is finished + +protected: + virtual void draw() override; + virtual QVariant itemChange( GraphicsItemChange change, + const QVariant &value ) override; + std::vector m_pathPoints; + Base::Vector3d m_attachPoint; + +protected: + QGraphicsItem* m_parentItem; + QGEPath* m_line; + QGIArrow* m_arrow1; + QGIArrow* m_arrow2; + double m_lineWidth; + QColor m_lineColor; + Qt::PenStyle m_lineStyle; +}; + +} + +#endif // DRAWINGGUI_QGRAPHICSITEMLEADERLINE_H diff --git a/src/Mod/TechDraw/Gui/QGITextLeader.cpp b/src/Mod/TechDraw/Gui/QGITextLeader.cpp new file mode 100644 index 0000000000..e2c482a17b --- /dev/null +++ b/src/Mod/TechDraw/Gui/QGITextLeader.cpp @@ -0,0 +1,277 @@ +/*************************************************************************** + * Copyright (c) 2019 WandererFan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ + #include + #include + # include + # include + # include + # include + # include + + # include + # include + # include + # include + # include + # include + #include + + # include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "Rez.h" +#include "ZVALUE.h" +#include "QGIArrow.h" +#include "ViewProviderLeader.h" +#include "MDIViewPage.h" +#include "DrawGuiUtil.h" +#include "QGVPage.h" +#include "QGIPrimPath.h" +#include "QGEPath.h" +#include "QGMText.h" +#include "QGILeaderLine.h" + +#include "QGITextLeader.h" + +using namespace TechDraw; +using namespace TechDrawGui; + + +//************************************************************** +QGITextLeader::QGITextLeader(QGraphicsItem* myParent, + TechDraw::DrawTextLeader* leader) : + QGILeaderLine(myParent,leader) +{ +// Base::Console().Message("QGITL::QGITL() - %s\n", leader->getNameInDocument()); + setHandlesChildEvents(false); + setAcceptHoverEvents(false); + setFlag(QGraphicsItem::ItemIsSelectable, false); + setFlag(QGraphicsItem::ItemIsMovable, false); + setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true); + setFlag(QGraphicsItem::ItemSendsGeometryChanges,true); + + m_text = new QGMText(); + m_text->setTextInteractionFlags(Qt::NoTextInteraction); + addToGroup(m_text); +// m_text->setZValue(ZVALUE::DIMENSION); + + QObject::connect( + m_text, SIGNAL(dragging()), + this , SLOT (textDragging()) + ); + QObject::connect( + m_text, SIGNAL(dragFinished()), + this , SLOT (textDragFinished()) + ); +} + +QVariant QGITextLeader::itemChange(GraphicsItemChange change, const QVariant &value) +{ + if (change == ItemSelectedHasChanged && scene()) { + //There's nothing special for QGIVL to do when selection changes! + } else if(change == ItemSceneChange && scene()) { + // nothing special! + } + return QGILeaderLine::itemChange(change, value); +} + +void QGITextLeader::textDragging(void) +{ +// Base::Console().Message("QGIL::textDragging()\n"); + //this is the long way around. can we do it without crossing the App/Gui boundary? + //just update graphics until drag finished. +// auto lead( dynamic_cast(getFeature()) ); + +// if( lead == nullptr ) { +// return; +// } + +// double x = Rez::appX(m_text->x()), +// y = Rez::appX(m_text->y()); +// Base::Vector3d tPos(x,-y,0.0); +// Gui::Command::openCommand("Drag Text"); +// lead->TextPosition.setValue(tPos); +// Gui::Command::commitCommand(); +// draw(); +} + +void QGITextLeader::textDragFinished(void) +{ +// Base::Console().Message("QGIL::textDragFinished()\n"); + auto lead( dynamic_cast(getFeature()) ); + + if( lead == nullptr ) { + return; + } + + double x = Rez::appX(m_text->x()), + y = Rez::appX(m_text->y()); + Base::Vector3d tPos(x,-y,0.0); + lead->TextPosition.setValue(tPos); +} + +void QGITextLeader::onTextSelect(bool state) +{ + Q_UNUSED(state); + draw(); +} + +void QGITextLeader::draw() +{ +// Base::Console().Message("QGITL::draw()- %s\n", getViewObject()->getNameInDocument()); + if (!isVisible()) { + Base::Console().Log("QGITL::draw - not visible\n"); + return; + } + + TechDraw::DrawTextLeader* leadFeat = getFeature(); + if((!leadFeat) ) { + Base::Console().Log("QGITL::draw - no feature\n"); + return; + } + + auto vp = static_cast(getViewProvider(getFeature())); + if ( vp == nullptr ) { + Base::Console().Log("QGITL::draw - no viewprovider\n"); + return; + } + + TechDraw::DrawView* parent = leadFeat->getBaseView(); + QGVPage* view = QGILeaderLine::getGraphicsView(parent); + if (view == nullptr) { + Base::Console().Log("QGITL::draw - no graphcisView for parent!! - setup?\n"); + return; + } + +// double scale = leadFeat->getScale(); + QGILeaderLine::draw(); + + setTextItem(); + +} + +void QGITextLeader::setTextItem() +{ +// Base::Console().Message("QGIVL::setTextItem()\n"); + TechDraw::DrawTextLeader* leadFeat = getFeature(); + auto vp = static_cast(getViewProvider(getFeature())); + if ( vp == nullptr ) { + Base::Console().Log("QGIVL::setTextItem - no ViewProvider\n"); + return; + } + QFont font = m_text->font(); + font.setPointSizeF(Rez::guiX(vp->Fontsize.getValue())); + font.setFamily(QString::fromLatin1(vp->Font.getValue())); + m_text->setFont(font); + + //convert point font sizes to (Rez,mm) font sizes + QRegExp rxFontSize(QString::fromUtf8("font-size:([0-9]*)pt;")); + QString inHtml = QString::fromUtf8(leadFeat->LeaderText.getValue()); + QString match; + double mmPerPoint = 0.353; + double sizeConvert = Rez::getRezFactor() * mmPerPoint; + int pos = 0; + QStringList findList; + QStringList replList; + while ((pos = rxFontSize.indexIn(inHtml, pos)) != -1) { + QString found = rxFontSize.cap(0); + findList << found; + QString qsOldSize = rxFontSize.cap(1); + + QString repl = found; + double newSize = qsOldSize.toDouble(); + newSize = newSize * sizeConvert; + QString qsNewSize = QString::number(newSize, 'f', 2); + repl.replace(qsOldSize,qsNewSize); + replList << repl; + pos += rxFontSize.matchedLength(); + } + QString outHtml = inHtml; + int iRepl = 0; + //TODO: check list for duplicates? + for ( ; iRepl < findList.size(); iRepl++) { + outHtml = outHtml.replace(findList[iRepl], replList[iRepl]); + } + + m_text->setHtml(outHtml); + m_text->setPrettyNormal(); + + m_text->setTextWidth(Rez::guiX(vp->MaxWidth.getValue())); + m_text->showBox(vp->ShowFrame.getValue()); + + double scale = getScale(); + Base::Vector3d textPos = Rez::guiX(leadFeat->TextPosition.getValue()); + QPointF tPos(textPos.x * scale,- textPos.y * scale); + m_text->setPos(tPos); +} + +//void QGITextLeader::drawBorder() +//{ +//////Leaders have no border! +//// QGIView::drawBorder(); //good for debugging +//} + + +TechDraw::DrawTextLeader* QGITextLeader::getFeature(void) +{ + TechDraw::DrawTextLeader* result = + static_cast(getViewObject()); + return result; +} + +QRectF QGITextLeader::boundingRect() const +{ + return childrenBoundingRect(); +} + +QPainterPath QGITextLeader::shape() const +{ + return QGraphicsItemGroup::shape(); +} + +void QGITextLeader::paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) { + QStyleOptionGraphicsItem myOption(*option); + myOption.state &= ~QStyle::State_Selected; + +// painter->drawRect(boundingRect()); //good for debugging + + QGILeaderLine::paint (painter, &myOption, widget); +} + +#include diff --git a/src/Mod/TechDraw/Gui/QGITextLeader.h b/src/Mod/TechDraw/Gui/QGITextLeader.h new file mode 100644 index 0000000000..77a3e9d6dc --- /dev/null +++ b/src/Mod/TechDraw/Gui/QGITextLeader.h @@ -0,0 +1,93 @@ +/*************************************************************************** + * Copyright (c) 2019 WandererFan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef DRAWINGGUI_QGRAPHICSITEMTEXTLEADER_H +#define DRAWINGGUI_QGRAPHICSITEMTEXTLEADER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "QGILeaderLine.h" + +namespace TechDraw { +class DrawTextLeader; +class DrawLeaderLine; +} + +namespace TechDrawGui +{ +class QGIPrimPath; +class QGIArrow; +class QGEPath; +class QGMText; + + +//******************************************************************* + +class TechDrawGuiExport QGITextLeader : public QGILeaderLine +{ + Q_OBJECT + +public: + enum {Type = QGraphicsItem::UserType + 233}; + + explicit QGITextLeader(QGraphicsItem* myParent = nullptr, + TechDraw::DrawTextLeader* lead = nullptr); + ~QGITextLeader() = default; + + int type() const override { return Type;} + virtual void paint( QPainter * painter, + const QStyleOptionGraphicsItem * option, + QWidget * widget = 0 ) override; + virtual QRectF boundingRect() const override; + virtual QPainterPath shape(void) const override; +/* virtual void updateView(bool update = false) override;*/ + + void setTextItem(void); + + virtual TechDraw::DrawTextLeader* getFeature(void); + +public Q_SLOTS: + void textDragging(void); + void textDragFinished(void); + void onTextSelect(bool state); + +protected: + virtual void draw() override; + virtual QVariant itemChange( GraphicsItemChange change, + const QVariant &value ) override; + +protected: + QGMText* m_text; +}; + +} + +#endif // DRAWINGGUI_QGRAPHICSITEMTEXTLEADER_H diff --git a/src/Mod/TechDraw/Gui/QGIUserTypes.h b/src/Mod/TechDraw/Gui/QGIUserTypes.h index 6cb175b454..4cc1437328 100644 --- a/src/Mod/TechDraw/Gui/QGIUserTypes.h +++ b/src/Mod/TechDraw/Gui/QGIUserTypes.h @@ -41,6 +41,12 @@ QGICaption: 180 QGIViewImage: 200 QGCustomImage: 201 QGIMatting: 205 +QGTracker: 210 +QGILeaderLine: 232 +QGITextLeader: 233 +QGMText: 300 +QGEPath: 301 +QGMarker: 302 */ /* diff --git a/src/Mod/TechDraw/Gui/QGIVertex.h b/src/Mod/TechDraw/Gui/QGIVertex.h index 8c8c79cc8c..542ebdef70 100644 --- a/src/Mod/TechDraw/Gui/QGIVertex.h +++ b/src/Mod/TechDraw/Gui/QGIVertex.h @@ -41,17 +41,17 @@ public: int getProjIndex() const { return projIndex; } float getRadius() { return m_radius; } - void setRadius(float r); + virtual void setRadius(float r); Qt::BrushStyle getFill() { return m_fill; } void setFill(Qt::BrushStyle f) { m_fill = f; } protected: int projIndex; - -private: float m_radius; QBrush m_brush; Qt::BrushStyle m_fill; + +private: }; } diff --git a/src/Mod/TechDraw/Gui/QGIView.cpp b/src/Mod/TechDraw/Gui/QGIView.cpp index 3ef8bf8c44..4d54b7d1b2 100644 --- a/src/Mod/TechDraw/Gui/QGIView.cpp +++ b/src/Mod/TechDraw/Gui/QGIView.cpp @@ -51,6 +51,7 @@ #include "Rez.h" #include "ZVALUE.h" #include "DrawGuiUtil.h" +#include "QGVPage.h" #include "QGCustomBorder.h" #include "QGCustomLabel.h" #include "QGCustomBorder.h" @@ -59,10 +60,12 @@ #include "QGICaption.h" #include "QGCustomClip.h" #include "QGCustomImage.h" +#include "QGIVertex.h" #include "QGIViewClip.h" #include "ViewProviderDrawingView.h" #include "MDIViewPage.h" #include "QGICMark.h" +#include "QGTracker.h" #include #include @@ -113,6 +116,8 @@ QGIView::QGIView() m_lockWidth = (double) sizeLock.width(); m_lockHeight = (double) sizeLock.height(); m_lock->hide(); + + setCursor(Qt::ArrowCursor); } QGIView::~QGIView() @@ -150,7 +155,6 @@ bool QGIView::isVisible(void) return result; } - void QGIView::alignTo(QGraphicsItem*item, const QString &alignment) { alignHash.clear(); @@ -160,8 +164,8 @@ void QGIView::alignTo(QGraphicsItem*item, const QString &alignment) QVariant QGIView::itemChange(GraphicsItemChange change, const QVariant &value) { QPointF newPos(0.0,0.0); +// Base::Console().Message("QGIV::itemChange(%d)\n", change); if(change == ItemPositionChange && scene()) { -// if(change == ItemPositionHasChanged && scene()) { newPos = value.toPointF(); //position within parent! if(m_locked){ newPos.setX(pos().x()); @@ -219,15 +223,20 @@ QVariant QGIView::itemChange(GraphicsItemChange change, const QVariant &value) void QGIView::mousePressEvent(QGraphicsSceneMouseEvent * event) { +// Base::Console().Message("QGIV::mousePressEvent() - %s\n",getViewName()); signalSelectPoint(this, event->pos()); - QGraphicsItemGroup::mousePressEvent(event); + if(m_locked) { + event->ignore(); + return; + } + QGraphicsItem::mousePressEvent(event); } -void QGIView::mouseMoveEvent(QGraphicsSceneMouseEvent * event) -{ - QGraphicsItem::mouseMoveEvent(event); -} +//void QGIView::mouseMoveEvent(QGraphicsSceneMouseEvent * event) +//{ +// QGraphicsItem::mouseMoveEvent(event); +//} void QGIView::mouseReleaseEvent(QGraphicsSceneMouseEvent * event) { @@ -266,8 +275,10 @@ void QGIView::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) drawBorder(); } +//sets position in /Gui(graphics), not /App void QGIView::setPosition(qreal x, qreal y) { +// Base::Console().Message("QGIV::setPosition(%.3f, %.3f) (gui)\n",x, y); double newX = x; double newY; double oldX = pos().x(); @@ -348,6 +359,15 @@ void QGIView::rotateView(void) setTransform(QTransform().translate(centre.x(), centre.y()).rotate(-rot).translate(-centre.x(), -centre.y())); } +double QGIView::getScale() +{ + double result = 1.0; + TechDraw::DrawView* feat = getViewObject(); + if (feat != nullptr) { + result = feat->getScale(); + } + return result; +} const char * QGIView::getViewName() const { return viewName.c_str(); @@ -512,13 +532,21 @@ void QGIView::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q QRectF QGIView::customChildrenBoundingRect() const { QList children = childItems(); - int dimItemType = QGraphicsItem::UserType + 106; // TODO: Magic number warning. + int dimItemType = QGraphicsItem::UserType + 106; // TODO: Get magic number from include by name int borderItemType = QGraphicsItem::UserType + 136; // TODO: Magic number warning int labelItemType = QGraphicsItem::UserType + 135; // TODO: Magic number warning int captionItemType = QGraphicsItem::UserType + 180; // TODO: Magic number warning + int leaderItemType = QGraphicsItem::UserType + 232; // TODO: Magic number warning + int textLeaderItemType = QGraphicsItem::UserType + 233; // TODO: Magic number warning + int editablePathItemType = QGraphicsItem::UserType + 301; // TODO: Magic number warning + int movableTextItemType = QGraphicsItem::UserType + 300; QRectF result; for (QList::iterator it = children.begin(); it != children.end(); ++it) { if ( ((*it)->type() != dimItemType) && + ((*it)->type() != leaderItemType) && + ((*it)->type() != textLeaderItemType) && + ((*it)->type() != editablePathItemType) && + ((*it)->type() != movableTextItemType) && ((*it)->type() != borderItemType) && ((*it)->type() != labelItemType) && ((*it)->type() != captionItemType) ) { @@ -562,6 +590,19 @@ Gui::ViewProvider* QGIView::getViewProvider(App::DocumentObject* obj) return result; } +QGVPage* QGIView::getGraphicsView(TechDraw::DrawView* dv) +{ + QGVPage* graphicsView = nullptr; + Gui::ViewProvider* vp = getViewProvider(dv); + ViewProviderDrawingView* vpdv = dynamic_cast(vp); + if (vpdv != nullptr) { + MDIViewPage* mdi = vpdv->getMDIViewPage(); + if (mdi != nullptr) { + graphicsView = mdi->getQGVPage(); + } + } + return graphicsView; +} MDIViewPage* QGIView::getMDIViewPage(void) const { MDIViewPage* result = nullptr; @@ -634,19 +675,26 @@ void QGIView::dumpRect(char* text, QRectF r) { r.left(),r.top(),r.right(),r.bottom()); } -void QGIView::makeMark(double x, double y) +void QGIView::makeMark(double x, double y, QColor c) { - QGICMark* cmItem = new QGICMark(-1); - cmItem->setParentItem(this); - cmItem->setPos(x,y); - cmItem->setThick(1.0); - cmItem->setSize(40.0); - cmItem->setZValue(ZVALUE::VERTEX); + QGIVertex* vItem = new QGIVertex(-1); + vItem->setParentItem(this); + vItem->setPos(x,y); + vItem->setWidth(2.0); + vItem->setRadius(20.0); + vItem->setNormalColor(c); + vItem->setPrettyNormal(); + vItem->setZValue(ZVALUE::VERTEX); } -void QGIView::makeMark(Base::Vector3d v) +void QGIView::makeMark(Base::Vector3d v, QColor c) { - makeMark(v.x,v.y); + makeMark(v.x,v.y, c); +} + +void QGIView::makeMark(QPointF v, QColor c) +{ + makeMark(v.x(),v.y(), c); } #include diff --git a/src/Mod/TechDraw/Gui/QGIView.h b/src/Mod/TechDraw/Gui/QGIView.h index f93f8c5777..372248df96 100644 --- a/src/Mod/TechDraw/Gui/QGIView.h +++ b/src/Mod/TechDraw/Gui/QGIView.h @@ -24,9 +24,12 @@ #define DRAWINGGUI_QGRAPHICSITEMVIEW_H #include +#include #include #include -#include +#include +#include +#include #include #include @@ -42,6 +45,7 @@ QT_END_NAMESPACE namespace TechDrawGui { +class QGVPage; class QGCustomBorder; class QGCustomLabel; class QGCustomText; @@ -49,6 +53,8 @@ class QGICaption; class MDIViewPage; class QGIViewClip; class QGCustomImage; +class QGTracker; +class QGIVertex; class TechDrawGuiExport QGIView : public QObject, public QGraphicsItemGroup { @@ -69,6 +75,7 @@ public: const std::string getViewNameAsString() const; void setViewFeature(TechDraw::DrawView *obj); TechDraw::DrawView * getViewObject() const; + double getScale(void); virtual void toggleBorder(bool state = true); virtual void toggleCache(bool state); @@ -79,8 +86,9 @@ public: virtual void draw(void); virtual void drawCaption(void); virtual void rotateView(void); - void makeMark(double x, double y); - void makeMark(Base::Vector3d v); + void makeMark(double x, double y, QColor c = Qt::red); + void makeMark(Base::Vector3d v, QColor c = Qt::red); + void makeMark(QPointF p, QColor c = Qt::red); /** Methods to ensure that Y-Coordinates are orientated correctly. @@ -102,6 +110,7 @@ public: virtual QColor getSelectColor(void); static Gui::ViewProvider* getViewProvider(App::DocumentObject* obj); + static QGVPage* getGraphicsView(TechDraw::DrawView* dv); MDIViewPage* getMDIViewPage(void) const; // Mouse handling virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) override; @@ -112,7 +121,7 @@ protected: virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; // Mouse handling - virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; +/* virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;*/ // Preselection events: virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override; virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override; diff --git a/src/Mod/TechDraw/Gui/QGMText.cpp b/src/Mod/TechDraw/Gui/QGMText.cpp new file mode 100644 index 0000000000..91fa521be6 --- /dev/null +++ b/src/Mod/TechDraw/Gui/QGMText.cpp @@ -0,0 +1,109 @@ +/*************************************************************************** + * Copyright (c) 2019 Wandererfan +#include +#include +#include +#include +#endif + +#include "DrawGuiStd.h" +#include "QGMText.h" + +using namespace TechDraw; +using namespace TechDrawGui; + +QGMText::QGMText() +{ + setCacheMode(QGCustomText::NoCache); + setFlag(ItemSendsGeometryChanges, true); +// setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true); + setFlag(ItemIsMovable, true); + setFlag(ItemIsSelectable, true); + setAcceptHoverEvents(true); +} + +QVariant QGMText::itemChange(GraphicsItemChange change, const QVariant &value) +{ + QPointF newPos(0.0,0.0); + if(change == ItemPositionHasChanged && scene()) { + Q_EMIT dragging(); + } + + return QGCustomText::itemChange(change, value); +} + +void QGMText::mousePressEvent(QGraphicsSceneMouseEvent * event) +{ +// if(scene() && this == scene()->mouseGrabberItem()) { //why would we get even if not mousegrabber? +// Q_EMIT dragging(); +// } + QGCustomText::mousePressEvent(event); +} + +void QGMText::mouseMoveEvent(QGraphicsSceneMouseEvent * event) +{ + QGCustomText::mouseMoveEvent(event); +} + +void QGMText::mouseReleaseEvent(QGraphicsSceneMouseEvent * event) +{ + if(scene() && this == scene()->mouseGrabberItem()) { + Q_EMIT dragFinished(); + } + QGCustomText::mouseReleaseEvent(event); +} + +void QGMText::hoverEnterEvent(QGraphicsSceneHoverEvent *event) +{ + Q_EMIT hover(true); + if (!isSelected()) { + setPrettyPre(); + } + QGCustomText::hoverEnterEvent(event); +} + +void QGMText::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) +{ + Q_EMIT hover(false); + if (!isSelected()) { + setPrettyNormal(); + } + QGCustomText::hoverLeaveEvent(event); +} + +void QGMText::paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) { + QStyleOptionGraphicsItem myOption(*option); + myOption.state &= ~QStyle::State_Selected; + +// painter->drawRect(boundingRect()); //good for debugging + if (showBox()) { + painter->drawRect(boundingRect().adjusted(1,1,-1,-1)); + } + + QGCustomText::paint (painter, &myOption, widget); +} + +#include diff --git a/src/Mod/TechDraw/Gui/QGMText.h b/src/Mod/TechDraw/Gui/QGMText.h new file mode 100644 index 0000000000..ee6145bfa1 --- /dev/null +++ b/src/Mod/TechDraw/Gui/QGMText.h @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (c) 2019 WandererFan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +//QGMText.h +//a movable, editable text item + +#ifndef TECHDRAWGUI_MOVABLETEXT_H +#define TECHDRAWGUI_MOVABLETEXT_H + +#include +#include +//#include + +#include "QGCustomText.h" + +QT_BEGIN_NAMESPACE +class QPainter; +class QStyleOptionGraphicsItem; +QT_END_NAMESPACE + +namespace TechDrawGui +{ + +// +class TechDrawGuiExport QGMText : public QGCustomText +{ +Q_OBJECT + +public: + explicit QGMText(void); + ~QGMText() {} + + enum {Type = QGraphicsItem::UserType + 300}; + int type() const { return Type;} + virtual void paint( QPainter * painter, + const QStyleOptionGraphicsItem * option, + QWidget * widget = 0 ) override; + + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; + virtual void showBox(bool b) { m_showBox = b; } + virtual bool showBox(void) { return m_showBox; } + +Q_SIGNALS: + void dragging(); + void hover(bool state); + void selected(bool state); + void dragFinished(); + +protected: + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) override; + virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override; + virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override; + +private: + bool m_showBox; + +}; + +} + +#endif // TECHDRAWGUI_MOVABLETEXT_H diff --git a/src/Mod/TechDraw/Gui/QGTracker.cpp b/src/Mod/TechDraw/Gui/QGTracker.cpp new file mode 100644 index 0000000000..5c780d1f9c --- /dev/null +++ b/src/Mod/TechDraw/Gui/QGTracker.cpp @@ -0,0 +1,488 @@ +/*************************************************************************** + * Copyright (c) 2019 WandererFan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include + +#include + +#include "Rez.h" +#include "ZVALUE.h" +#include "DrawGuiUtil.h" +#include "QGIView.h" +#include "QGTracker.h" + +using namespace TechDrawGui; + +QGTracker::QGTracker(QGraphicsScene* inScene, TrackerMode m): + m_width(0), + m_sleep(false), + m_qgParent(nullptr) +{ + setTrackerMode(m); + if (inScene != nullptr) { + inScene->addItem(this); + } else { + throw Base::ValueError("QGT::QGT() - passed scene is NULL\n"); + } + + setCacheMode(QGraphicsItem::NoCache); + setFlag(QGraphicsItem::ItemIsSelectable, true); + setFlag(QGraphicsItem::ItemIsMovable, false); + setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true); + setFlag(QGraphicsItem::ItemSendsGeometryChanges,true); + setFlag(QGraphicsItem::ItemIsFocusable, true); + setAcceptHoverEvents(true); + setZValue(ZVALUE::TRACKER); + setPos(0.0,0.0); + + QColor tColor = getTrackerColor(); + QColor tailColor(Qt::blue); + double tWeight = getTrackerWeight(); + setWidth(tWeight); + setStyle(Qt::DashLine); +// setStyle(Qt::SolidLine); + setNormalColor(tailColor); + setPrettyNormal(); + + //m_track is the new segment of the line. + m_track = new QGraphicsPathItem(); + m_track->setParentItem(this); + m_trackPen.setColor(tColor); + m_trackPen.setWidthF(tWeight); + m_trackPen.setStyle(Qt::DashLine); + m_track->setPen(m_trackPen); + m_track->setBrush(QBrush(Qt::NoBrush)); + m_track->setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true); + m_track->setFlag(QGraphicsItem::ItemSendsGeometryChanges,true); + m_track->setFocusProxy(this); + + setHandlesChildEvents(true); + setVisible(true); + setEnabled(true); + setFocus(); + scene()->setFocusItem(this); +} + +QGTracker::~QGTracker() +{ +} + +QVariant QGTracker::itemChange(GraphicsItemChange change, const QVariant &value) +{ + return QGIPrimPath::itemChange(change, value); +} + +void QGTracker::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + if (!m_sleep) { + QPointF scenePos(event->scenePos()); + if (event->button() == Qt::LeftButton) { + if (event->modifiers() & Qt::ControlModifier) { + scenePos = snapToAngle(scenePos); + } + onMousePress(scenePos); + + } else if (event->button() == Qt::RightButton) { + terminateDrawing(); + } + } + QGIPrimPath::mousePressEvent(event); +} + +void QGTracker::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + QGIPrimPath::mouseReleaseEvent(event); +} + +void QGTracker::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event) +{ +// Base::Console().Message("QGT::mouseDoubleClickEvent()\n"); + if (!m_sleep) { + onDoubleClick(event->scenePos()); + } + QGIPrimPath::mouseDoubleClickEvent(event); +} + +void QGTracker::hoverEnterEvent(QGraphicsSceneHoverEvent *event) +{ + QGIPrimPath::hoverEnterEvent(event); +} + +void QGTracker::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) +{ + QGIPrimPath::hoverLeaveEvent(event); +} + +void QGTracker::hoverMoveEvent(QGraphicsSceneHoverEvent* event) +{ + if (!m_sleep) { + QPointF scenePos(event->scenePos()); + if (event->modifiers() & Qt::ControlModifier) { + scenePos = snapToAngle(scenePos); + } + onMouseMove(scenePos); + } + QGIPrimPath::hoverMoveEvent(event); +} + +void QGTracker::keyPressEvent(QKeyEvent * event) +{ +// Base::Console().Message("QGT::keyPressEvent()\n"); + if (event->key() == Qt::Key_Escape) { + terminateDrawing(); + } + QGIPrimPath::keyPressEvent(event); +} + +void QGTracker::sleep(bool b) +{ + m_sleep = b; + if (m_sleep) { + setCursor(Qt::ArrowCursor); + } else { + setCursor(Qt::CrossCursor); + } +} + +QPointF QGTracker::snapToAngle(QPointF dumbPt) +{ + QPointF result(dumbPt); + double angleIncr = M_PI / 8.0; //15* + //mirror last clicked point and event point to get sensible coords + QPointF last(m_points.back().x(), -m_points.back().y()); + QPointF pt(dumbPt.x(),-dumbPt.y()); + + //let's do math with sensible coord system. + QPointF qVec = last - pt; //vec from end of track to end of tail + double actual = atan2(-qVec.y(), qVec.x()); + if (actual < 0.0) { + actual = (2 * M_PI) + actual; //map to +ve angle + } + + double intPart; + double remain = modf(actual/angleIncr, &intPart); + if (!TechDraw::DrawUtil::fpCompare(remain, 0.0)) { //not n*15 + double low = intPart * angleIncr; + double high = (intPart + 1) * angleIncr; + double lowGap = actual - low; + double highGap = high - actual; + if (lowGap > highGap) { + actual = high; + } else { + actual = low; + } + + double vecLen = sqrt(pow(qVec.x(),2) + pow(qVec.y(),2)); + double xPart = vecLen * cos(actual) * -1.0; //actual is not in Qt coords + double yPart = vecLen * sin(actual) * -1.0; + result = QPointF(last.x() + xPart, (-last.y()) + yPart); //back to silly qt coords! + } + return result; +} + +//mouse event reactions +void QGTracker::onMousePress(QPointF pos) +{ + m_points.push_back(pos); + TrackerMode mode = getTrackerMode(); + if (m_points.size() > 1) { + switch (mode) { + case TrackerMode::None: + break; + case TrackerMode::Line: + setPathFromPoints(m_points); + break; + case TrackerMode::Rectangle: + setSquareFromPoints(m_points); + break; + case TrackerMode::Circle: + setCircleFromPoints(m_points); + break; + case TrackerMode::Point: + //do nothing + break; + } + } else if (m_points.size() == 1) { //first point selected + getPickedQGIV(pos); + setCursor(Qt::CrossCursor); + Q_EMIT qViewPicked(pos, m_qgParent); + if (mode == TrackerMode::Point) { + setPoint(m_points); + terminateDrawing(); + } + } + + if ( (m_points.size() == 2) && + ( (getTrackerMode() == TrackerMode::Circle) || + (getTrackerMode() == TrackerMode::Rectangle) ) ) { //only 2 points for square/circle + terminateDrawing(); + } +} + +void QGTracker::onMouseMove(QPointF pos) +{ + //check distance moved? + TrackerMode m = getTrackerMode(); + switch (m) { + case TrackerMode::None: + break; + case TrackerMode::Line: + drawTrackLine(pos); + break; + case TrackerMode::Rectangle: + drawTrackSquare(pos); + break; + case TrackerMode::Circle: + drawTrackCircle(pos); + break; + case TrackerMode::Point: + //don't do anything here. + break; + } +} + +void QGTracker::onDoubleClick(QPointF pos) +{ +// Base::Console().Message("QGTracker::onDoubleClick()\n"); + Q_UNUSED(pos); + terminateDrawing(); +} + +void QGTracker::getPickedQGIV(QPointF pos) +{ + setVisible(false); + m_qgParent = nullptr; + QList views = scene()->views(); + QGraphicsView* ourView = views.front(); //only 1 view / 1 scene / 1 mdipage + QTransform viewXForm = ourView->transform(); + QGraphicsItem* pickedItem = scene()->itemAt(pos,viewXForm); + if (pickedItem != nullptr) { + QGraphicsItem* topItem = pickedItem->topLevelItem(); + if (topItem != pickedItem) { + pickedItem = topItem; + } //pickedItem sb a QGIV + QGIView* qgParent = dynamic_cast(pickedItem); + if (qgParent != nullptr) { + m_qgParent = qgParent; + } + } + setVisible(true); + return; +} + +QRectF QGTracker::boundingRect() const +{ + return scene()->sceneRect(); +} + +QPainterPath QGTracker::shape(void) const +{ + QPainterPath result; + result.addRect(boundingRect()); + return result; +} + +//*************** +//actual art routines +void QGTracker::drawTrackLine(QPointF pos) +{ +// Base::Console().Message("QGTracker::drawTrackLine()\n"); + m_segEnd = pos; + QPainterPath tail; + if (!m_points.empty()) { + m_segBegin = m_points.back(); + tail.moveTo(m_segBegin); + tail.lineTo(m_segEnd); + m_track->setPath(tail); + m_track->show(); + } +} + +void QGTracker::drawTrackSquare(QPointF pos) +{ +// Base::Console().Message("QGTracker::drawTrackSquare()\n"); + m_segEnd = pos; + QPainterPath tail; + if (!m_points.empty()) { + m_segBegin = m_points.front(); //sb front? 1st point picked?? + QRectF rect(m_segBegin,m_segEnd); + tail.addRect(rect); + m_track->setPath(tail); + m_track->show(); + } +} + +void QGTracker::drawTrackCircle(QPointF pos) +{ +// Base::Console().Message("QGTracker::drawTrackCircle() - m_points: %d \n", m_points.size()); + QPointF circum = pos; + QPainterPath tail; + if (!m_points.empty()) { + QPointF center = m_points.front(); //not nec (0,0); + QPointF ray = circum - center; + double radius = sqrt(pow(ray.x(),2.0) + pow(ray.y(),2.0)); + tail.addEllipse(center, radius, radius); + m_track->setPath(tail); + } +} + +//don't need this since Tracker ends as soon as 1st point is picked +void QGTracker::drawTrackPoint(QPointF pos) +{ + Q_UNUSED(pos); +} + +void QGTracker::setPathFromPoints(std::vector pts) +{ +// Base::Console().Message("QGTracker::setPathFromPoints()\n"); + if (pts.empty()) { + Base::Console().Log("QGTracker::setPathFromPoints - no pts!\n"); + return; + } + prepareGeometryChange(); + QPainterPath newPath; + newPath.moveTo(pts.front()); + auto it = pts.begin() + 1; + for (; it != pts.end(); it++) { + newPath.lineTo(*it); + } + setPath(newPath); + setPrettyNormal(); +} +void QGTracker::setSquareFromPoints(std::vector pts) +{ +// Base::Console().Message("QGTracker::setSquareFromPoints()\n"); + if (pts.empty()) { + Base::Console().Log("QGTracker::setSquareFromPoints - no pts!\n"); + return; + } + prepareGeometryChange(); + QPainterPath newPath; + QPointF start = pts.front(); + QPointF end = pts.back(); + QRectF rect(start,end); + newPath.addRect(rect); + setPath(newPath); + setPrettyNormal(); +} + +void QGTracker::setCircleFromPoints(std::vector pts) +{ +// Base::Console().Message("QGTracker::setCircleFromPoints()\n"); + if (pts.empty()) { + Base::Console().Log("QGTracker::setCircleFromPoints - no pts!\n"); + return; + } + prepareGeometryChange(); + QPainterPath newPath; + QPointF center = pts.front(); + QPointF circum = pts.back(); + QPointF ray = circum - center; + double radius = sqrt(pow(ray.x(),2.0) + pow(ray.y(),2.0)); + newPath.addEllipse(center, radius, radius); + setPath(newPath); + setPrettyNormal(); +} + +void QGTracker::setPoint(std::vector pts) +{ +// Base::Console().Message("QGTracker::setPoint()\n"); + if (pts.empty()) { + Base::Console().Message("QGTracker::setPoint - no pts!\n"); + return; + } + prepareGeometryChange(); + QPainterPath newPath; + QPointF center = pts.front(); + double radius = 5.0; + newPath.addEllipse(center, radius, radius); + setPath(newPath); + setPrettyNormal(); +} + +std::vector QGTracker::convertPoints(void) +{ + std::vector result; + for (auto& p: m_points) { + Base::Vector3d v(p.x(),p.y(),0.0); + result.push_back(v); + } + return result; +} + +void QGTracker::terminateDrawing(void) +{ +// Base::Console().Message("QGTracker::terminateDrawing()\n"); + m_track->hide(); + setCursor(Qt::ArrowCursor); + Q_EMIT drawingFinished(m_points, m_qgParent); +} + +void QGTracker::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + QStyleOptionGraphicsItem myOption(*option); + myOption.state &= ~QStyle::State_Selected; + +// painter->drawRect(boundingRect()); //good for debugging + painter->drawPath(shape()); + + QGIPrimPath::paint(painter, &myOption, widget); +} + +QColor QGTracker::getTrackerColor() +{ + QColor result; + Base::Reference hGrp = App::GetApplication().GetUserParameter().GetGroup("BaseApp")-> + GetGroup("Preferences")->GetGroup("Mod/TechDraw/Tracker"); + App::Color trackColor = App::Color((uint32_t) hGrp->GetUnsigned("TrackerColor", 0xFF000000)); + result = trackColor.asValue(); + return result; +} + +double QGTracker::getTrackerWeight() +{ + double result = 1.0; + Base::Reference hGrp = App::GetApplication().GetUserParameter().GetGroup("BaseApp")-> + GetGroup("Preferences")->GetGroup("Mod/TechDraw/Tracker"); + result = hGrp->GetFloat("TrackerWeight", 4.0); + + return result; +} + +#include diff --git a/src/Mod/TechDraw/Gui/QGTracker.h b/src/Mod/TechDraw/Gui/QGTracker.h new file mode 100644 index 0000000000..c86b3cb030 --- /dev/null +++ b/src/Mod/TechDraw/Gui/QGTracker.h @@ -0,0 +1,109 @@ +/*************************************************************************** + * Copyright (c) 2016 WandererFan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef DRAWINGGUI_TRACKER_H +#define DRAWINGGUI_TRACKER_H + +#include + +QT_BEGIN_NAMESPACE +class QPainter; +class QStyleOptionGraphicsItem; +QT_END_NAMESPACE + +#include + +#include "QGIPrimPath.h" + +namespace TechDrawGui +{ + +class TechDrawGuiExport QGTracker : public QObject, public QGIPrimPath +{ + Q_OBJECT +public: + enum TrackerMode { None, Line, Circle, Rectangle, Point }; + + explicit QGTracker(QGraphicsScene* scene = nullptr, QGTracker::TrackerMode m = QGTracker::TrackerMode::None); + ~QGTracker(); + + + enum {Type = QGraphicsItem::UserType + 210}; + + int type() const { return Type;} + virtual void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0 ); + virtual QPainterPath shape() const override; + virtual QRectF boundingRect() const override; + + void onMousePress(QPointF); + void onMouseMove(QPointF pos); + void onDoubleClick(QPointF pos); + void drawTrackLine(QPointF pos); + void drawTrackSquare(QPointF pos); + void drawTrackCircle(QPointF pos); + void drawTrackPoint(QPointF pos); + void setPathFromPoints(std::vector pts); + void setSquareFromPoints(std::vector pts); + void setCircleFromPoints(std::vector pts); + void setPoint(std::vector pts); + std::vector convertPoints(void); + void terminateDrawing(void); + void sleep(bool b); + TrackerMode getTrackerMode(void) { return m_trackerMode; } + void setTrackerMode(TrackerMode m) { m_trackerMode = m; } + QPointF snapToAngle(QPointF pt); + +Q_SIGNALS: + void drawingFinished(std::vector pts, QGIView* qgParent); + void qViewPicked(QPointF pos, QGIView* qgParent); + +protected: + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) override; + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; + virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override; + virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override; + virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override; + virtual void hoverMoveEvent(QGraphicsSceneHoverEvent* event) override; + virtual void keyPressEvent(QKeyEvent * event) override; + + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; + void getPickedQGIV(QPointF pos); + + QColor getTrackerColor(); + double getTrackerWeight(); + +private: + double m_width; + QGraphicsPathItem* m_track; + QPointF m_segBegin; + QPointF m_segEnd; + std::vector m_points; + bool m_sleep; + QGIView* m_qgParent; + TrackerMode m_trackerMode; + QPen m_trackPen; + QPen m_tailPen; +}; + +} // namespace + +#endif // DRAWINGGUI_TRACKER_H diff --git a/src/Mod/TechDraw/Gui/QGVPage.cpp b/src/Mod/TechDraw/Gui/QGVPage.cpp index e1893bb818..8fc1e832c9 100644 --- a/src/Mod/TechDraw/Gui/QGVPage.cpp +++ b/src/Mod/TechDraw/Gui/QGVPage.cpp @@ -68,6 +68,8 @@ #include #include #include +#include +#include #include "Rez.h" #include "QGIDrawingTemplate.h" @@ -86,6 +88,8 @@ #include "QGIViewSpreadsheet.h" #include "QGIViewImage.h" #include "QGIFace.h" +#include "QGILeaderLine.h" +#include "QGITextLeader.h" #include "ZVALUE.h" #include "ViewProviderPage.h" @@ -106,6 +110,8 @@ QGVPage::QGVPage(ViewProviderPage *vp, QGraphicsScene* s, QWidget *parent) setObjectName(QString::fromLocal8Bit(name)); setScene(s); + setMouseTracking(true); + viewport()->setMouseTracking(true); setViewportUpdateMode(QGraphicsView::SmartViewportUpdate); setCacheMode(QGraphicsView::CacheBackground); @@ -463,6 +469,43 @@ void QGVPage::addDimToParent(QGIViewDimension* dim, QGIView* parent) dim->setZValue(ZVALUE::DIMENSION); } + +QGIView * QGVPage::addViewLeader(TechDraw::DrawLeaderLine *leader) +{ + QGILeaderLine* leaderGroup = nullptr; + QGITextLeader* textGroup = nullptr; + + App::DocumentObject* parentObj = leader->LeaderParent.getValue(); + TechDraw::DrawView* parentDV = dynamic_cast(parentObj); + TechDraw::DrawTextLeader* textFeat = dynamic_cast(leader); + + if (parentDV != nullptr) { + QGIView* parentQV = findQViewForDocObj(parentObj); + if (parentQV != nullptr) { + if (textFeat != nullptr) { + textGroup = new QGITextLeader(parentQV, textFeat); + textGroup->updateView(true); + return textGroup; + } else { + leaderGroup = new QGILeaderLine(parentQV, leader); + leaderGroup->updateView(true); //this is different from everybody else, + //but it works. + return leaderGroup; + } + } else { + throw Base::TypeError("QGVP::addViewLeader - parent DV has no QGIV"); + } +// } else if (parentDP != nullptr) { +// leaderGroup = new QGILeaderLine(nullptr,leader); +// ourScene->addItem(leaderGroup); + } else { + //TARFU + throw Base::TypeError("QGVP::addViewLeader - parent obj wrong type"); + } + + return nullptr; +} + //! find the graphic for a DocumentObject QGIView * QGVPage::findQViewForDocObj(App::DocumentObject *obj) const { @@ -497,11 +540,11 @@ QGIView* QGVPage::getQGIVByName(std::string name) QGIView * QGVPage::findParent(QGIView *view) const { const std::vector qviews = getViews(); - TechDraw::DrawView *myView = view->getViewObject(); + TechDraw::DrawView *myFeat = view->getViewObject(); //If type is dimension we check references first TechDraw::DrawViewDimension *dim = 0; - dim = dynamic_cast(myView); + dim = dynamic_cast(myFeat); if(dim) { std::vector objs = dim->References2D.getValues(); @@ -519,7 +562,7 @@ QGIView * QGVPage::findParent(QGIView *view) const //If type is balloon we check references first TechDraw::DrawViewBalloon *balloon = 0; - balloon = dynamic_cast(myView); + balloon = dynamic_cast(myFeat); if(balloon) { App::DocumentObject* obj = balloon->sourceView.getValue(); @@ -544,7 +587,7 @@ QGIView * QGVPage::findParent(QGIView *view) const if(collection) { std::vector objs = collection->Views.getValues(); for( std::vector::iterator it = objs.begin(); it != objs.end(); ++it) { - if(strcmp(myView->getNameInDocument(), (*it)->getNameInDocument()) == 0) + if(strcmp(myFeat->getNameInDocument(), (*it)->getNameInDocument()) == 0) return grp; } @@ -553,7 +596,7 @@ QGIView * QGVPage::findParent(QGIView *view) const } // Not found a parent - return 0; + return nullptr; } void QGVPage::setPageTemplate(TechDraw::DrawTemplate *obj) @@ -832,7 +875,7 @@ void QGVPage::keyPressEvent(QKeyEvent *event) } } } - event->accept(); + QGraphicsView::keyPressEvent(event); } void QGVPage::kbPanScroll(int xMove, int yMove) @@ -856,6 +899,7 @@ void QGVPage::kbPanScroll(int xMove, int yMove) void QGVPage::enterEvent(QEvent *event) { QGraphicsView::enterEvent(event); + setCursor(Qt::ArrowCursor); viewport()->setCursor(Qt::ArrowCursor); } @@ -886,13 +930,19 @@ void QGVPage::leaveEvent(QEvent * event) void QGVPage::mousePressEvent(QMouseEvent *event) { QGraphicsView::mousePressEvent(event); - viewport()->setCursor(Qt::ClosedHandCursor); +// setCursor(Qt::ArrowCursor); +} + +void QGVPage::mouseMoveEvent(QMouseEvent *event) +{ + QGraphicsView::mouseMoveEvent(event); } void QGVPage::mouseReleaseEvent(QMouseEvent *event) { QGraphicsView::mouseReleaseEvent(event); - viewport()->setCursor(Qt::ArrowCursor); +// setCursor(Qt::ArrowCursor); +// viewport()->setCursor(Qt::ArrowCursor); } TechDraw::DrawPage* QGVPage::getDrawPage() diff --git a/src/Mod/TechDraw/Gui/QGVPage.h b/src/Mod/TechDraw/Gui/QGVPage.h index c49673dcb5..310eb8efc4 100644 --- a/src/Mod/TechDraw/Gui/QGVPage.h +++ b/src/Mod/TechDraw/Gui/QGVPage.h @@ -41,8 +41,8 @@ class DrawViewClip; class DrawViewCollection; class DrawViewSpreadsheet; class DrawViewImage; -class DrawViewBalloon; -} +class DrawLeaderLine; +class DrawViewBalloon;} namespace TechDrawGui { @@ -51,6 +51,7 @@ class QGIViewDimension; class QGITemplate; class ViewProviderPage; class QGIViewBalloon; +class QGILeaderLine; class TechDrawGuiExport QGVPage : public QGraphicsView { @@ -77,7 +78,7 @@ public: QGIView * addDrawViewClip(TechDraw::DrawViewClip *view); QGIView * addDrawViewSpreadsheet(TechDraw::DrawViewSpreadsheet *view); QGIView * addDrawViewImage(TechDraw::DrawViewImage *view); - + QGIView * addViewLeader(TechDraw::DrawLeaderLine* view); QGIView* findQViewForDocObj(App::DocumentObject *obj) const; QGIView* getQGIVByName(std::string name); @@ -121,6 +122,7 @@ protected: void enterEvent(QEvent *event) override; void leaveEvent(QEvent *event) override; void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void keyPressEvent(QKeyEvent *event) override; void kbPanScroll(int xMove = 1, int yMove = 1); diff --git a/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc b/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc index 1aa5015dbc..253855f88c 100644 --- a/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc +++ b/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc @@ -60,7 +60,10 @@ icons/actions/techdraw-spreadsheet.svg icons/actions/techdraw-image.svg icons/actions/techdraw-viewdetail.svg - icons/actions/section-up.svg + icons/actions/techdraw-mline.svg + icons/actions/techdraw-textleader.svg + icons/actions/techdraw-point.svg + icons/actions/section-up.svg icons/actions/section-down.svg icons/actions/section-left.svg icons/actions/section-right.svg @@ -72,6 +75,11 @@ icons/arrow-cw.svg icons/techdraw-lock.png icons/cursor-balloon.png + icons/MRTE/menu.svg + icons/MRTE/bgColor.svg + icons/MRTE/fgColor.svg + icons/MRTE/listBullet.svg + icons/MRTE/listNumber.svg translations/TechDraw_af.qm translations/TechDraw_zh-CN.qm translations/TechDraw_zh-TW.qm diff --git a/src/Mod/TechDraw/Gui/Resources/icons/MRTE/bgColor.svg b/src/Mod/TechDraw/Gui/Resources/icons/MRTE/bgColor.svg new file mode 100644 index 0000000000..fe5ed50379 --- /dev/null +++ b/src/Mod/TechDraw/Gui/Resources/icons/MRTE/bgColor.svg @@ -0,0 +1,609 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + [agryson] Alexander Gryson + + + http://agryson.net + + techdraw-view + 2016-01-14 + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + FreeCAD + + + FreeCAD/src/Mod/TechDraw/Gui/Resources/icons/actions/techdraw-view.svg + + + FreeCAD LGPL2+ + + + + + [agryson] Alexander Gryson + + + + + + + + + + + + + + + a + diff --git a/src/Mod/TechDraw/Gui/Resources/icons/MRTE/fgColor.svg b/src/Mod/TechDraw/Gui/Resources/icons/MRTE/fgColor.svg new file mode 100644 index 0000000000..3c49f4a029 --- /dev/null +++ b/src/Mod/TechDraw/Gui/Resources/icons/MRTE/fgColor.svg @@ -0,0 +1,616 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + [agryson] Alexander Gryson + + + http://agryson.net + + techdraw-view + 2016-01-14 + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + FreeCAD + + + FreeCAD/src/Mod/TechDraw/Gui/Resources/icons/actions/techdraw-view.svg + + + FreeCAD LGPL2+ + + + + + [agryson] Alexander Gryson + + + + + + + + + + + + + + + + a + diff --git a/src/Mod/TechDraw/Gui/Resources/icons/MRTE/listBullet.svg b/src/Mod/TechDraw/Gui/Resources/icons/MRTE/listBullet.svg new file mode 100644 index 0000000000..1e94cb87ba --- /dev/null +++ b/src/Mod/TechDraw/Gui/Resources/icons/MRTE/listBullet.svg @@ -0,0 +1,635 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + [agryson] Alexander Gryson + + + http://agryson.net + + techdraw-view + 2016-01-14 + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + FreeCAD + + + FreeCAD/src/Mod/TechDraw/Gui/Resources/icons/actions/techdraw-view.svg + + + FreeCAD LGPL2+ + + + + + [agryson] Alexander Gryson + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/TechDraw/Gui/Resources/icons/MRTE/listNumber.svg b/src/Mod/TechDraw/Gui/Resources/icons/MRTE/listNumber.svg new file mode 100644 index 0000000000..c820b63b12 --- /dev/null +++ b/src/Mod/TechDraw/Gui/Resources/icons/MRTE/listNumber.svg @@ -0,0 +1,649 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + [agryson] Alexander Gryson + + + http://agryson.net + + techdraw-view + 2016-01-14 + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + FreeCAD + + + FreeCAD/src/Mod/TechDraw/Gui/Resources/icons/actions/techdraw-view.svg + + + FreeCAD LGPL2+ + + + + + [agryson] Alexander Gryson + + + + + + + + + + + + + + + + + + 1 + 2 + 3 + diff --git a/src/Mod/TechDraw/Gui/Resources/icons/MRTE/menu.svg b/src/Mod/TechDraw/Gui/Resources/icons/MRTE/menu.svg new file mode 100644 index 0000000000..233bf2175b --- /dev/null +++ b/src/Mod/TechDraw/Gui/Resources/icons/MRTE/menu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/Mod/TechDraw/Gui/Resources/icons/actions/techdraw-mline.svg b/src/Mod/TechDraw/Gui/Resources/icons/actions/techdraw-mline.svg new file mode 100644 index 0000000000..d333c2ed70 --- /dev/null +++ b/src/Mod/TechDraw/Gui/Resources/icons/actions/techdraw-mline.svg @@ -0,0 +1,258 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/TechDraw/Gui/Resources/icons/actions/techdraw-point.svg b/src/Mod/TechDraw/Gui/Resources/icons/actions/techdraw-point.svg new file mode 100644 index 0000000000..13c123c3fd --- /dev/null +++ b/src/Mod/TechDraw/Gui/Resources/icons/actions/techdraw-point.svg @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/Mod/TechDraw/Gui/Resources/icons/actions/techdraw-textleader.svg b/src/Mod/TechDraw/Gui/Resources/icons/actions/techdraw-textleader.svg new file mode 100644 index 0000000000..fad2f78172 --- /dev/null +++ b/src/Mod/TechDraw/Gui/Resources/icons/actions/techdraw-textleader.svg @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/TechDraw/Gui/TaskTextLeader.cpp b/src/Mod/TechDraw/Gui/TaskTextLeader.cpp new file mode 100644 index 0000000000..82259fd971 --- /dev/null +++ b/src/Mod/TechDraw/Gui/TaskTextLeader.cpp @@ -0,0 +1,833 @@ +/*************************************************************************** + * Copyright (c) 2019 Wandererfan +#endif // #ifndef _PreComp_ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "DrawGuiStd.h" +#include "QGVPage.h" +#include "QGIView.h" +#include "QGIPrimPath.h" +#include "MDIViewPage.h" +#include "ViewProviderPage.h" +#include "ViewProviderLeader.h" +#include "QGTracker.h" +#include "QGEPath.h" +#include "QGMText.h" +#include "QGITextLeader.h" +#include "Rez.h" +#include "mrichtextedit.h" +#include "mtextedit.h" + +#include "TaskTextLeader.h" + +using namespace Gui; +using namespace TechDraw; +using namespace TechDrawGui; + +//ctor for edit +TaskTextLeader::TaskTextLeader(int mode, + TechDrawGui::ViewProviderLeader* leadVP) : + ui(new Ui_TaskTextLeader), + m_tracker(nullptr), + m_lineVP(leadVP), + m_textVP(nullptr), + m_baseFeat(nullptr), + m_basePage(nullptr), + m_lineFeat(nullptr), + m_createMode(false), + m_leadLine(nullptr), + m_inProgressLock(false), + m_qgLine(nullptr), + m_qgText(nullptr), + m_textDialog(nullptr), + m_rte(nullptr), + m_mode(mode), + m_pbTrackerState(TRACKEREDIT) +{ + if (m_lineVP == nullptr) { + //should be caught in CMD caller + Base::Console().Error("TaskTextLeader - bad parameters. Can not proceed.\n"); + return; + } + ui->setupUi(this); + + m_lineFeat = m_lineVP->getFeature(); + if (m_mode == TEXTMODE) { + m_textFeat = static_cast(m_lineFeat); + m_textVP = static_cast(m_lineVP); + } + + App::DocumentObject* obj = m_lineFeat->LeaderParent.getValue(); + if ( obj->isDerivedFrom(TechDraw::DrawView::getClassTypeId()) ) { + m_baseFeat = static_cast(m_lineFeat->LeaderParent.getValue()); + } + m_basePage = m_lineFeat->findParentPage(); + + if ( (m_lineFeat == nullptr) || + (m_baseFeat == nullptr) || + (m_basePage == nullptr) ) { + Base::Console().Error("TaskTextLeader - bad parameters (2). Can not proceed.\n"); + return; + } + + setUiEdit(); + + m_mdi = m_lineVP->getMDIViewPage(); + m_scene = m_mdi->m_scene; + m_view = m_mdi->getQGVPage(); + + m_attachPoint = Rez::guiX(Base::Vector3d(m_lineFeat->X.getValue(), + -m_lineFeat->Y.getValue(), + 0.0)); + + connect(ui->pbTracker, SIGNAL(clicked(bool)), + this, SLOT(onTrackerClicked(bool))); + if (m_mode == TEXTMODE) { + connect(ui->pbEditor, SIGNAL(clicked(bool)), + this, SLOT(onEditorClicked(bool))); + } + + m_trackerMode = QGTracker::TrackerMode::Line; +} + +//ctor for creation +TaskTextLeader::TaskTextLeader(int mode, + TechDraw::DrawView* baseFeat, + TechDraw::DrawPage* page) : + ui(new Ui_TaskTextLeader), + m_tracker(nullptr), + m_lineVP(nullptr), + m_baseFeat(baseFeat), + m_basePage(page), + m_lineFeat(nullptr), + m_createMode(true), + m_leadLine(nullptr), + m_inProgressLock(false), + m_qgLine(nullptr), + m_qgText(nullptr), + m_textDialog(nullptr), + m_rte(nullptr), + m_mode(mode), + m_pbTrackerState(TRACKERPICK) +{ + if ( (m_basePage == nullptr) || + (m_baseFeat == nullptr) ) { + //should be caught in CMD caller + Base::Console().Error("TaskTextLeader - bad parameters. Can not proceed.\n"); + return; + } + + ui->setupUi(this); + + Gui::Document* activeGui = Gui::Application::Instance->getDocument(m_basePage->getDocument()); + Gui::ViewProvider* vp = activeGui->getViewProvider(m_basePage); + ViewProviderPage* vpp = static_cast(vp); + m_mdi = vpp->getMDIViewPage(); + m_scene = m_mdi->m_scene; + m_view = m_mdi->getQGVPage(); + + setUiPrimary(); + + connect(ui->pbTracker, SIGNAL(clicked(bool)), + this, SLOT(onTrackerClicked(bool))); + if (mode == TEXTMODE) { + connect(ui->pbEditor, SIGNAL(clicked(bool)), + this, SLOT(onEditorClicked(bool))); + } + + m_trackerMode = QGTracker::TrackerMode::Line; +} + +TaskTextLeader::~TaskTextLeader() +{ + delete ui; +} + +void TaskTextLeader::updateTask() +{ +// blockUpdate = true; + +// blockUpdate = false; +} + +void TaskTextLeader::changeEvent(QEvent *e) +{ + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(this); + } +} + +void TaskTextLeader::setUiPrimary() +{ +// Base::Console().Message("TTL::setUiPrimary() - m_mode: %d\n",m_mode); + enableVPUi(false); + if (m_mode == TEXTMODE) { + setWindowTitle(QObject::tr("New Text Leader")); + enableTextUi(true); + } else { + setWindowTitle(QObject::tr("New Leader Line")); + enableTextUi(false); + } + + if (m_baseFeat != nullptr) { + std::string baseName = m_baseFeat->getNameInDocument(); + ui->leBaseView->setText(Base::Tools::fromStdString(baseName)); + } + ui->pbTracker->setText(QString::fromUtf8("Pick points")); + ui->pbTracker->setEnabled(true); + int aSize = getPrefArrowStyle() + 1; + ui->cboxStartSym->setCurrentIndex(aSize); +} + +void TaskTextLeader::enableTextUi(bool b) +{ + ui->pbEditor->setEnabled(b); + ui->teLeaderText->setEnabled(b); +} + +void TaskTextLeader::enableVPUi(bool b) +{ + ui->cpLineColor->setEnabled(b); + ui->dsbWeight->setEnabled(b); + ui->cboxStyle->setEnabled(b); +} + +void TaskTextLeader::setUiEdit() +{ +// Base::Console().Message("TTL::setUiEdit() - m_mode: %d\n",m_mode); + enableVPUi(true); + if (m_mode == TEXTMODE) { + setWindowTitle(QObject::tr("Edit Text Leader")); + enableTextUi(true); + } else { + setWindowTitle(QObject::tr("Edit Leader Line")); + enableTextUi(false); + } + + if (m_lineFeat != nullptr) { + std::string baseName = m_lineFeat->LeaderParent.getValue()->getNameInDocument(); + ui->leBaseView->setText(Base::Tools::fromStdString(baseName)); + ui->cboxStartSym->setCurrentIndex(m_lineFeat->StartSymbol.getValue() + 1); + ui->cboxEndSym->setCurrentIndex(m_lineFeat->EndSymbol.getValue() + 1); + ui->pbTracker->setText(QString::fromUtf8("Edit points")); + ui->pbTracker->setEnabled(true); + } + + if (m_lineVP != nullptr) { + ui->cpLineColor->setColor(m_lineVP->Color.getValue().asValue()); + ui->dsbWeight->setValue(m_lineVP->LineWidth.getValue()); + ui->cboxStyle->setCurrentIndex(m_lineVP->LineStyle.getValue()); + } + + if (m_textFeat != nullptr) { + ui->teLeaderText->setHtml(QString::fromUtf8(m_textFeat->LeaderText.getValue())); + } +} + +void TaskTextLeader::onEditorClicked(bool b) +{ +// Base::Console().Message("TL::onEditorClicked(%d)\n",b); + Q_UNUSED(b); + m_textDialog = new QDialog(0); + QString leadText = ui->teLeaderText->toHtml(); + m_rte = new MRichTextEdit(m_textDialog, leadText); + //m_rte->setTextWidth(m_lineVP->MaxWidth); + QGridLayout* gl = new QGridLayout(m_textDialog); + gl->addWidget(m_rte,0,0,1,1); + m_textDialog->setWindowTitle(QObject::tr("Leader text editor")); + m_textDialog->setMinimumWidth (400); + m_textDialog->setMinimumHeight(400); + + connect(m_rte, SIGNAL(saveText(QString)), + this, SLOT(onSaveAndExit(QString))); + connect(m_rte, SIGNAL(editorFinished(void)), + this, SLOT(onEditorExit(void))); + + m_textDialog->show(); +} + +void TaskTextLeader::onSaveAndExit(QString qs) +{ + ui->teLeaderText->setHtml(qs); + //dialog clean up should be handled by accept() call in dialog + m_textDialog->accept(); + m_textDialog = nullptr; + m_rte = nullptr; +} + +void TaskTextLeader::onEditorExit(void) +{ + m_textDialog->reject(); + m_textDialog = nullptr; + m_rte = nullptr; +} + +//****************************************************************************** +void TaskTextLeader::createLeaderFeature(std::vector converted) +{ + Base::Console().Message("TTL::createLeaderFeature() - m_mode: %d\n",m_mode); + if (m_mode == TEXTMODE) { + m_leaderName = m_basePage->getDocument()->getUniqueObjectName("DrawTextLeader"); + m_leaderType = "TechDraw::DrawTextLeader"; + } else { + m_leaderName = m_basePage->getDocument()->getUniqueObjectName("DrawLeaderLine"); + m_leaderType = "TechDraw::DrawLeaderLine"; + } + + std::string PageName = m_basePage->getNameInDocument(); + + Gui::Command::openCommand("Create Leader"); + Command::doCommand(Command::Doc,"App.activeDocument().addObject('%s','%s')", + m_leaderType.c_str(),m_leaderName.c_str()); + Command::doCommand(Command::Doc,"App.activeDocument().%s.addView(App.activeDocument().%s)", + PageName.c_str(),m_leaderName.c_str()); + Command::doCommand(Command::Doc,"App.activeDocument().%s.LeaderParent = App.activeDocument().%s", + m_leaderName.c_str(),m_baseFeat->getNameInDocument()); + + App::DocumentObject* obj = m_basePage->getDocument()->getObject(m_leaderName.c_str()); + if (obj == nullptr) { + throw Base::RuntimeError("TaskTextLeader - new markup object not found"); + } + if (obj->isDerivedFrom(TechDraw::DrawTextLeader::getClassTypeId())) { + m_lineFeat = static_cast(obj); + m_textFeat = static_cast(obj); + commonFeatureUpdate(converted); + QPointF qTemp = calcTextStartPos(m_lineFeat->getScale()); + Base::Vector3d vTemp(qTemp.x(), qTemp.y()); + m_textFeat->TextPosition.setValue(Rez::appX(vTemp)); + } else if (obj->isDerivedFrom(TechDraw::DrawLeaderLine::getClassTypeId())) { + m_lineFeat = static_cast(obj); + m_textFeat = nullptr; + commonFeatureUpdate(converted); + } + + Gui::Command::updateActive(); + Gui::Command::commitCommand(); + m_lineFeat->requestPaint(); +} + +void TaskTextLeader::updateLeaderFeature(std::vector converted) +{ +// Base::Console().Message("TTL::updateLeaderFeature(%d) - m_mode: %d\n",converted.size(),m_mode); + Gui::Command::openCommand("Edit Leader"); + commonFeatureUpdate(converted); + App::Color ac; + ac.setValue(ui->cpLineColor->color()); + m_lineVP->Color.setValue(ac); + m_lineVP->LineWidth.setValue(ui->dsbWeight->value()); + m_lineVP->LineStyle.setValue(ui->cboxStyle->currentIndex()); + + Gui::Command::commitCommand(); + m_lineFeat->requestPaint(); +} + +void TaskTextLeader::commonFeatureUpdate(std::vector converted) +{ +// Base::Console().Message("TTL::commonFeatureUpdate()\n"); + m_lineFeat->setPosition(Rez::appX(m_attachPoint.x),Rez::appX(- m_attachPoint.y), true); + if (!converted.empty()) { + m_lineFeat->WayPoints.setValues(converted); + } + int start = ui->cboxStartSym->currentIndex() - 1; + int end = ui->cboxEndSym->currentIndex() - 1; + m_lineFeat->StartSymbol.setValue(start); + m_lineFeat->EndSymbol.setValue(end); + if (m_mode == TEXTMODE) { + m_textFeat->LeaderText.setValue(ui->teLeaderText->toHtml().toUtf8()); + } +} + +void TaskTextLeader::removeFeature(void) +{ +// Base::Console().Message("TTL::removeFeature()\n"); + if (m_lineFeat != nullptr) { + if (m_createMode) { + try { + // this doesn't remove the QGMText item?? + std::string PageName = m_basePage->getNameInDocument(); + Gui::Command::doCommand(Gui::Command::Gui,"App.activeDocument().%s.removeView(App.activeDocument().%s)", + PageName.c_str(),m_lineFeat->getNameInDocument()); + Gui::Command::doCommand(Gui::Command::Gui,"App.activeDocument().removeObject('%s')", + m_lineFeat->getNameInDocument()); + } + catch (...) { + Base::Console().Message("TTL::removeFeature - failed to delete feature\n"); + return; + } + } else { + if (Gui::Command::hasPendingCommand()) { + std::vector undos = Gui::Application::Instance->activeDocument()->getUndoVector(); + Gui::Application::Instance->activeDocument()->undo(1); + } else { + Base::Console().Log("TaskTextLeader: Edit mode - NO command is active\n"); + } + } + } +} + +//we don't know the bounding rect of the text, so we have to calculate a reasonable +//guess at the size of the text block. +QPointF TaskTextLeader::calcTextStartPos(double scale) +{ +// Base::Console().Message("TTL::calcTextStartPos(%.3f) - m_mode: %d\n", scale, m_mode); + double textWidth = 100.0; + double textHeight = 20.0; + double horizGap(20.0); + double tPosX(0.0); + double tPosY(0.0); + + Gui::ViewProvider* vp = QGIView::getViewProvider(m_textFeat); + if (vp != nullptr) { + ViewProviderTextLeader* vpl = dynamic_cast(vp); + if (vpl != nullptr) { + double adjust = 2.0; + double fsize = vpl->Fontsize.getValue(); + textHeight = fsize * adjust; + double width = vpl->MaxWidth.getValue(); + if (width > 0 ) { + textWidth = width; + } + } + } + + if (!m_trackerPoints.empty() ) { + QPointF lastPoint(m_trackerPoints.back().x, m_trackerPoints.back().y); + QPointF firstPoint(m_trackerPoints.front().x, m_trackerPoints.front().y); + QPointF lastOffset = lastPoint; + lastPoint = m_qgParent->mapFromScene(lastPoint) * scale; + firstPoint = m_qgParent->mapFromScene(firstPoint) * scale; + + if (lastPoint.x() < firstPoint.x()) { //last is left of first + tPosX = lastOffset.x() - horizGap - textWidth; //left of last + tPosY = lastOffset.y() - textHeight; + } else { //last is right of first + tPosX = lastOffset.x() + horizGap; //right of last + tPosY = lastOffset.y() - textHeight; + } + } + QPointF result(tPosX, -tPosY); + return result; +} + +//********** Tracker routines ******************************************************************* +void TaskTextLeader::onTrackerClicked(bool b) +{ + Q_UNUSED(b); +// Base::Console().Message("TTL::onTrackerClicked() - m_mode: %d, m_pbTrackerState: %d\n", +// m_mode, m_pbTrackerState); + if (m_pbTrackerState == TRACKERCANCEL) { + removeTracker(); + + m_pbTrackerState = TRACKERPICK; + ui->pbTracker->setText(QString::fromUtf8("Pick Points")); + enableTaskButtons(true); + + setEditCursor(Qt::ArrowCursor); + return; + } else if (m_pbTrackerState == TRACKERCANCELEDIT) { + abandonEditSession(); + + m_pbTrackerState = TRACKEREDIT; + ui->pbTracker->setText(QString::fromUtf8("Edit points")); + enableTaskButtons(true); + + setEditCursor(Qt::ArrowCursor); + return; + } + + if (getCreateMode()) { + m_inProgressLock = true; + m_saveContextPolicy = m_mdi->contextMenuPolicy(); + m_mdi->setContextMenuPolicy(Qt::PreventContextMenu); + m_trackerMode = QGTracker::TrackerMode::Line; + startTracker(); + + QString msg = tr("Pick a starting point for leader line"); + getMainWindow()->statusBar()->show(); + Gui::getMainWindow()->showMessage(msg,3000); + ui->pbTracker->setText(QString::fromUtf8("Escape picking")); + ui->pbTracker->setEnabled(true); + m_pbTrackerState = TRACKERCANCEL; + enableTaskButtons(false); + } else { //edit mode + m_trackerPoints = m_lineFeat->WayPoints.getValues(); + if (!m_trackerPoints.empty()) { //regular edit session + m_inProgressLock = true; + m_saveContextPolicy = m_mdi->contextMenuPolicy(); + m_mdi->setContextMenuPolicy(Qt::PreventContextMenu); + QGVPage* qgvp = m_mdi->getQGVPage(); + QGIView* qgiv = qgvp->findQViewForDocObj(m_lineFeat); + QGILeaderLine* qgLead = dynamic_cast(qgiv); + + if (qgLead == nullptr) { + //tarfu + Base::Console().Error("TaskTextLeader - can't find leader graphic\n"); + //now what? throw will generate "unknown unhandled exception" + } else { + m_qgLine = qgLead; + connect(qgLead, SIGNAL(editComplete(std::vector, QGIView*)), + this, SLOT(onPointEditComplete(std::vector, QGIView*))); + + m_attachPoint = Rez::guiX(Base::Vector3d(m_lineFeat->X.getValue(), //don't need this? + -m_lineFeat->Y.getValue(), + 0.0)); + qgLead->startPathEdit(); + QString msg = tr("Click and drag markers to adjust leader line"); + getMainWindow()->statusBar()->show(); + Gui::getMainWindow()->showMessage(msg,3000); + msg = tr("ESC or RMB to exit"); + getMainWindow()->statusBar()->show(); + Gui::getMainWindow()->showMessage(msg,3000); + ui->pbTracker->setText(QString::fromUtf8("Escape edit")); + ui->pbTracker->setEnabled(true); + m_pbTrackerState = TRACKERCANCELEDIT; + enableTaskButtons(false); + } + } else { // need to recreate leaderline + // same as create mode?? + m_inProgressLock = true; + m_saveContextPolicy = m_mdi->contextMenuPolicy(); + m_mdi->setContextMenuPolicy(Qt::PreventContextMenu); + m_trackerMode = QGTracker::TrackerMode::Line; + startTracker(); + + QString msg = tr("Pick a starting point for leader line"); + getMainWindow()->statusBar()->show(); + Gui::getMainWindow()->showMessage(msg,3000); + ui->pbTracker->setText(QString::fromUtf8("Escape picking")); + ui->pbTracker->setEnabled(true); + m_pbTrackerState = TRACKERCANCEL; + enableTaskButtons(false); + } + } //end edit mode +} + +void TaskTextLeader::startTracker(void) +{ +// Base::Console().Message("TTL::startTracker()\n"); + if (m_trackerMode == QGTracker::TrackerMode::None) { + return; + } + + if (m_tracker == nullptr) { + m_tracker = new QGTracker(m_scene, m_trackerMode); + QObject::connect( + m_tracker, SIGNAL(drawingFinished(std::vector, QGIView*)), + this , SLOT (onTrackerFinished(std::vector, QGIView*)) + ); + } else { + //this is too harsh. but need to avoid restarting process + throw Base::RuntimeError("TechDrawNewLeader - tracker already active\n"); + } + setEditCursor(Qt::CrossCursor); + QString msg = tr("Left click to set a point"); + Gui::getMainWindow()->statusBar()->show(); + Gui::getMainWindow()->showMessage(msg,3000); +} + +void TaskTextLeader::onTrackerFinished(std::vector pts, QGIView* qgParent) +{ +// Base::Console().Message("TTL::onTrackerFinished()\n"); + if (pts.empty()) { + Base::Console().Error("TaskTextLeader - no points available\n"); + return; + } + QGIView* qgiv = dynamic_cast(qgParent); + if (qgiv != nullptr) { + m_qgParent = qgiv; + } + if (m_qgParent != nullptr) { + double scale = m_qgParent->getScale(); + QPointF mapped = m_qgParent->mapFromScene(pts.front()) / scale; + m_attachPoint = Base::Vector3d(mapped.x(), mapped.y(), 0.0); + convertTrackerPoints(pts); + } + + QString msg = tr("Press OK or Cancel to continue"); + getMainWindow()->statusBar()->show(); + Gui::getMainWindow()->showMessage(msg, 3000); + enableTaskButtons(true); + + m_tracker->sleep(true); + m_inProgressLock = false; + ui->pbTracker->setEnabled(false); + enableTaskButtons(true); + setEditCursor(Qt::ArrowCursor); +} + +void TaskTextLeader::removeTracker(void) +{ +// Base::Console().Message("TTL::removeTracker()\n"); + if ( (m_tracker != nullptr) && + (m_tracker->scene() != nullptr) ) { + m_scene->removeItem(m_tracker); + delete m_tracker; + m_tracker = nullptr; + } +} + +void TaskTextLeader::setEditCursor(QCursor c) +{ + if (m_baseFeat != nullptr) { + QGIView* qgivBase = m_view->findQViewForDocObj(m_baseFeat); + qgivBase->setCursor(c); + } +} + +//from 1:1 scale scene QPointF to zero origin Vector3d points +void TaskTextLeader::convertTrackerPoints(std::vector pts) +{ +// Base::Console().Message("TTL::convertTrackerPoints(%d)\n", pts.size()); + m_trackerPoints.clear(); + for (auto& p: pts) { + QPointF mapped = p - pts.front(); + Base::Vector3d convert(mapped.x(),mapped.y(),0.0); + m_trackerPoints.push_back(convert); + } +} + +//****************************************************************************** +void TaskTextLeader::onPointEditComplete(std::vector pts, QGIView* parent) +{ +// Base::Console().Message("TTL::onPointEditComplete(%d)\n", pts.size()); + if (pts.empty()) { + return; + } + QPointF p0 = pts.front(); + + if (parent == nullptr) { +// Base::Console().Message("TTL::onPointEditComplete - passed parent is NULL!\n"); + } else { + m_qgParent = parent; +// double scale = m_qgParent->getScale(); + if ( !(TechDraw::DrawUtil::fpCompare(p0.x(),0.0) && + TechDraw::DrawUtil::fpCompare(p0.y(),0.0)) ) { + //p0 was moved. need to change AttachPoint and intervals from p0 + QPointF mapped = m_qgParent->mapFromItem(m_qgLine,p0); + m_attachPoint = Base::Vector3d(mapped.x(),mapped.y(),0.0); + for (auto& p : pts) { + p -= p0; + } + pts.at(0) = QPointF(0.0,0.0); + } + + convertTrackerPoints(pts); + } + m_inProgressLock = false; + + m_pbTrackerState = TRACKEREDIT; + ui->pbTracker->setText(QString::fromUtf8("Edit points")); + ui->pbTracker->setEnabled(true); + enableTaskButtons(true); +} + +void TaskTextLeader::abandonEditSession(void) +{ + if (m_qgLine != nullptr) { + m_qgLine->abandonEdit(); + } + QString msg = tr("In progress edit abandoned. Start over."); + getMainWindow()->statusBar()->show(); + Gui::getMainWindow()->showMessage(msg,4000); + + m_pbTrackerState = TRACKEREDIT; + ui->pbTracker->setText(QString::fromUtf8("Edit points")); + enableTaskButtons(true); + ui->pbTracker->setEnabled(true); + + setEditCursor(Qt::ArrowCursor); +} + +void TaskTextLeader::saveButtons(QPushButton* btnOK, + QPushButton* btnCancel) +{ + m_btnOK = btnOK; + m_btnCancel = btnCancel; +} + +void TaskTextLeader::enableTaskButtons(bool b) +{ + m_btnOK->setEnabled(b); + m_btnCancel->setEnabled(b); +} + +int TaskTextLeader::getPrefArrowStyle() +{ + Base::Reference hGrp = App::GetApplication().GetUserParameter(). + GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Dimensions"); + int style = hGrp->GetInt("ArrowStyle", 0); + return style; +} + + +//****************************************************************************** + +bool TaskTextLeader::accept() +{ +// Base::Console().Message("TTL::accept() - m_mode: %d\n", m_mode); + if (m_inProgressLock) { +// Base::Console().Message("TTL::accept - edit in progress!!\n"); + abandonEditSession(); + return true; + } + + Gui::Document* doc = Gui::Application::Instance->getDocument(m_basePage->getDocument()); + if (!doc) return false; + + if (!getCreateMode()) { + updateLeaderFeature(m_trackerPoints); + } else { + removeTracker(); + createLeaderFeature(m_trackerPoints); + } + m_mdi->setContextMenuPolicy(m_saveContextPolicy); + m_trackerMode = QGTracker::TrackerMode::None; + Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()"); + + return true; +} + +bool TaskTextLeader::reject() +{ + if (m_inProgressLock) { +// Base::Console().Message("TTL::reject - edit in progress!!\n"); + abandonEditSession(); + removeTracker(); + return false; + } + + Gui::Document* doc = Gui::Application::Instance->getDocument(m_basePage->getDocument()); + if (!doc) return false; + + m_mdi->setContextMenuPolicy(m_saveContextPolicy); + if (getCreateMode() && + (m_lineFeat != nullptr) ) { + removeFeature(); + } + m_trackerMode = QGTracker::TrackerMode::None; + + //make sure any dangling objects are cleaned up + Gui::Command::doCommand(Gui::Command::Gui,"App.activeDocument().recompute()"); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()"); + + return false; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +TaskDlgTextLeader::TaskDlgTextLeader(int mode, + TechDraw::DrawView* baseFeat, + TechDraw::DrawPage* page) + : TaskDialog() +{ + widget = new TaskTextLeader(mode,baseFeat,page); + if (mode == TEXTMODE) { + taskbox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("actions/techdraw-textleader"), + widget->windowTitle(), true, 0); + } else { //if (mode == 1) + taskbox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("actions/techdraw-mline"), + widget->windowTitle(), true, 0); + } + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +TaskDlgTextLeader::TaskDlgTextLeader(int mode, + TechDrawGui::ViewProviderLeader* leadVP) + : TaskDialog() +{ + widget = new TaskTextLeader(mode,leadVP); + if (mode == TEXTMODE) { + taskbox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("actions/techdraw-textleader"), + widget->windowTitle(), true, 0); + } else { //if (mode == 1) + taskbox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("actions/techdraw-mline"), + widget->windowTitle(), true, 0); + } + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +TaskDlgTextLeader::~TaskDlgTextLeader() +{ +} + +void TaskDlgTextLeader::update() +{ +// widget->updateTask(); +} + +void TaskDlgTextLeader::modifyStandardButtons(QDialogButtonBox* box) +{ + QPushButton* btnOK = box->button(QDialogButtonBox::Ok); + QPushButton* btnCancel = box->button(QDialogButtonBox::Cancel); + widget->saveButtons(btnOK, btnCancel); +} + +//==== calls from the TaskView =============================================================== +void TaskDlgTextLeader::open() +{ +} + +void TaskDlgTextLeader::clicked(int) +{ +} + +bool TaskDlgTextLeader::accept() +{ + widget->accept(); + return true; +} + +bool TaskDlgTextLeader::reject() +{ + widget->reject(); + return true; +} + +#include diff --git a/src/Mod/TechDraw/Gui/TaskTextLeader.h b/src/Mod/TechDraw/Gui/TaskTextLeader.h new file mode 100644 index 0000000000..65b33bdb6b --- /dev/null +++ b/src/Mod/TechDraw/Gui/TaskTextLeader.h @@ -0,0 +1,210 @@ +/*************************************************************************** + * Copyright (c) 2019 WandererFan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef TECHDRAWGUI_TASKTEXTLEADER_H +#define TECHDRAWGUI_TASKTEXTLEADER_H + +#include +#include +#include +#include + +#include + +#include "QGTracker.h" + +//TODO: make this a proper enum +#define TRACKERPICK 0 +#define TRACKEREDIT 1 +#define TRACKERCANCEL 2 +#define TRACKERCANCELEDIT 3 + +class MRichTextEdit; + +class Ui_TaskTextLeader; + +namespace App { +class DocumentObject; +} + +namespace TechDraw +{ +class DrawPage; +class DrawView; +class DrawTextLeader; +} + +#define TEXTMODE 0 +#define LINEMODE 1 + +namespace TechDrawGui +{ +class QGVPage; +class QGIView; +class QGIPrimPath; +class MDIViewPage; +class QGTracker; +class QGEPath; +class QGMText; +class QGITextLeader; +class ViewProviderLeader; +class ViewProviderTextLeader; + +class TaskTextLeader : public QWidget +{ + Q_OBJECT + +public: + TaskTextLeader(int mode, + TechDraw::DrawView* baseFeat, + TechDraw::DrawPage* page); + TaskTextLeader(int mode, + TechDrawGui::ViewProviderLeader* leadVP); + ~TaskTextLeader(); + +public Q_SLOTS: + void onTrackerClicked(bool b); + void onTrackerFinished(std::vector pts, QGIView* qgParent); + void onEditorClicked(bool b); +/* void onViewPicked(QPointF pos, QGIView* qgParent);*/ + +public: + virtual bool accept(); + virtual bool reject(); + virtual void setCreateMode(bool b) { m_createMode = b; } + virtual bool getCreateMode(void) { return m_createMode; } + void updateTask(); + void saveButtons(QPushButton* btnOK, + QPushButton* btnCancel); + void enableTaskButtons(bool b); + + +protected Q_SLOTS: + void convertTrackerPoints(std::vector pts); + void onPointEditComplete(std::vector pts, QGIView* parent); + void onSaveAndExit(QString); + void onEditorExit(void); + +protected: + void changeEvent(QEvent *e); + void startTracker(void); + void removeTracker(void); + void abandonEditSession(void); + + void createLeaderFeature(std::vector converted); + void updateLeaderFeature(std::vector converted); + void commonFeatureUpdate(std::vector converted); + void removeFeature(void); + + QPointF calcTextStartPos(double scale); + + void blockButtons(bool b); + void setUiPrimary(void); + void setUiEdit(void); + void enableTextUi(bool b); + void enableVPUi(bool b); + void setEditCursor(QCursor c); + + int getPrefArrowStyle(); + + +private: + Ui_TaskTextLeader * ui; + bool blockUpdate; + + QGTracker* m_tracker; + + MDIViewPage* m_mdi; + QGraphicsScene* m_scene; + QGVPage* m_view; + ViewProviderLeader* m_lineVP; + ViewProviderTextLeader* m_textVP; + TechDraw::DrawView* m_baseFeat; + TechDraw::DrawPage* m_basePage; + TechDraw::DrawTextLeader* m_textFeat; + TechDraw::DrawLeaderLine* m_lineFeat; + std::string m_leaderName; + std::string m_leaderType; + QGIView* m_qgParent; + std::string m_qgParentName; + + std::vector m_trackerPoints; + Base::Vector3d m_attachPoint; + + bool m_createMode; + QGEPath* m_leadLine; + QGMText* m_text; + + QGTracker::TrackerMode m_trackerMode; + Qt::ContextMenuPolicy m_saveContextPolicy; + bool m_inProgressLock; + + QGILeaderLine* m_qgLine; + QGITextLeader* m_qgText; + QPushButton* m_btnOK; + QPushButton* m_btnCancel; + + QDialog* m_textDialog; + MRichTextEdit* m_rte; + int m_mode; + int m_pbTrackerState; +}; + +class TaskDlgTextLeader : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskDlgTextLeader(int mode, + TechDraw::DrawView* baseFeat, + TechDraw::DrawPage* page); + TaskDlgTextLeader(int mode, + TechDrawGui::ViewProviderLeader* leadVP); + ~TaskDlgTextLeader(); + +public: + /// is called the TaskView when the dialog is opened + virtual void open(); + /// is called by the framework if an button is clicked which has no accept or reject role + virtual void clicked(int); + /// is called by the framework if the dialog is accepted (Ok) + virtual bool accept(); + /// is called by the framework if the dialog is rejected (Cancel) + virtual bool reject(); + /// is called by the framework if the user presses the help button + virtual void helpRequested() { return;} + virtual bool isAllowedAlterDocument(void) const + { return false; } + void update(); + + void modifyStandardButtons(QDialogButtonBox* box); + +protected: + +private: + TaskTextLeader * widget; + Gui::TaskView::TaskBox* taskbox; +}; + +} //namespace TechDrawGui + +#endif // #ifndef TECHDRAWGUI_TASKTEXTLEADER_H diff --git a/src/Mod/TechDraw/Gui/TaskTextLeader.ui b/src/Mod/TechDraw/Gui/TaskTextLeader.ui new file mode 100644 index 0000000000..652428e1ba --- /dev/null +++ b/src/Mod/TechDraw/Gui/TaskTextLeader.ui @@ -0,0 +1,381 @@ + + + TechDrawGui::TaskTextLeader + + + + 0 + 0 + 409 + 560 + + + + + 0 + 0 + + + + + 250 + 0 + + + + Text Leader + + + + :/icons/actions/techdraw-textleader.svg:/icons/actions/techdraw-textleader.svg + + + + + + + 0 + 0 + + + + QFrame::Box + + + QFrame::Raised + + + + + + + + + + false + + + false + + + Qt::NoFocus + + + false + + + + + + + Base View + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Select Line Points + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Horizontal + + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Start Symbol + + + + + + + + No Symbol + + + + + Filled Triangle + + + + :/icons/arrowfilled.svg:/icons/arrowfilled.svg + + + + + Open Triangle + + + + :/icons/arrowopen.svg:/icons/arrowopen.svg + + + + + Tick + + + + :/icons/arrowtick.svg:/icons/arrowtick.svg + + + + + Dot + + + + :/icons/arrowdot.svg:/icons/arrowdot.svg + + + + + Open Circle + + + + :/icons/arrowopendot.svg:/icons/arrowopendot.svg + + + + + + + + End Symbol + + + + + + + + No Symbol + + + + + Filled Triangle + + + + :/icons/arrowfilled.svg:/icons/arrowfilled.svg + + + + + Open Triangle + + + + :/icons/arrowopen.svg:/icons/arrowopen.svg + + + + + Tick + + + + :/icons/arrowtick.svg:/icons/arrowtick.svg + + + + + Dot + + + + :/icons/arrowdot.svg:/icons/arrowdot.svg + + + + + Open Circle + + + + :/icons/arrowopendot.svg:/icons/arrowopendot.svg + + + + + + + + Color + + + + + + + + 0 + 0 + 0 + + + + + + + + Weight + + + + + + + 0.100000000000000 + + + 0.500000000000000 + + + + + + + Style + + + + + + + 1 + + + + NoLine + + + + + Solid + + + + + Dash + + + + + Dot + + + + + DashDot + + + + + DashDotDot + + + + + + + + + + Qt::Horizontal + + + + + + + + + + + + + + Leader Text + + + + + + + true + + + Start Editor + + + + + + + + + + + + + + + + Gui::ColorButton + QPushButton +
Gui/Widgets.h
+
+
+ + + + +
diff --git a/src/Mod/TechDraw/Gui/ViewProviderLeader.cpp b/src/Mod/TechDraw/Gui/ViewProviderLeader.cpp new file mode 100644 index 0000000000..bd9e00ab10 --- /dev/null +++ b/src/Mod/TechDraw/Gui/ViewProviderLeader.cpp @@ -0,0 +1,276 @@ +/*************************************************************************** + * Copyright (c) 2004 Jürgen Riegel * + * Copyright (c) 2019 Wanderer Fan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +#endif + +/// Here the FreeCAD includes sorted by Base,App,Gui...... +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "MDIViewPage.h" +#include "QGVPage.h" +#include "QGIView.h" +#include "TaskTextLeader.h" +#include "ViewProviderLeader.h" + +using namespace TechDrawGui; + +PROPERTY_SOURCE(TechDrawGui::ViewProviderLeader, TechDrawGui::ViewProviderDrawingView) + +//************************************************************************** +// Construction/Destruction + +ViewProviderLeader::ViewProviderLeader() +{ + sPixmap = "actions/techdraw-mline"; + + static const char *group = "Line Format"; + + ADD_PROPERTY_TYPE(LineWidth,(getDefLineWeight()) ,group,(App::PropertyType)(App::Prop_None),"Line weight"); + ADD_PROPERTY_TYPE(LineStyle,(1) ,group,(App::PropertyType)(App::Prop_None),"Line style"); + ADD_PROPERTY_TYPE(Color,(getDefLineColor()),group,App::Prop_None,"The color of the Markup"); +} + +ViewProviderLeader::~ViewProviderLeader() +{ +} + +void ViewProviderLeader::attach(App::DocumentObject *pcFeat) +{ + ViewProviderDrawingView::attach(pcFeat); +} + +bool ViewProviderLeader::setEdit(int ModNum) +{ +// Base::Console().Message("VPL::setEdit(%d)\n",ModNum); + if (ModNum == ViewProvider::Default ) { + if (Gui::Control().activeDialog()) { //TaskPanel already open! + return false; + } + // clear the selection (convenience) + Gui::Selection().clearSelection(); + Gui::Control().showDialog(new TaskDlgTextLeader(LINEMODE, this)); + return true; + } else { + return ViewProviderDrawingView::setEdit(ModNum); + } + return true; +} + +void ViewProviderLeader::unsetEdit(int ModNum) +{ + Q_UNUSED(ModNum); + if (ModNum == ViewProvider::Default) { + Gui::Control().closeDialog(); + } + else { + ViewProviderDrawingView::unsetEdit(ModNum); + } +} + +bool ViewProviderLeader::doubleClicked(void) +{ +// Base::Console().Message("VPL::doubleClicked()\n"); + setEdit(ViewProvider::Default); + return true; +} + +void ViewProviderLeader::updateData(const App::Property* p) +{ + ViewProviderDrawingView::updateData(p); +} + +void ViewProviderLeader::onChanged(const App::Property* p) +{ + if ((p == &Color) || + (p == &LineWidth) || + (p == &LineStyle)) { + QGIView* qgiv = getQView(); + if (qgiv) { + qgiv->updateView(true); + } + } + ViewProviderDrawingView::onChanged(p); + +} + +TechDraw::DrawLeaderLine* ViewProviderLeader::getViewObject() const +{ + return dynamic_cast(pcObject); +} + +TechDraw::DrawLeaderLine* ViewProviderLeader::getFeature() const +{ + return dynamic_cast(pcObject); +} + + +double ViewProviderLeader::getDefLineWeight(void) +{ + double result = 0.0; + Base::Reference hGrp = App::GetApplication().GetUserParameter().GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Decorations"); + std::string lgName = hGrp->GetASCII("LineGroup","FC 0.70mm"); + auto lg = TechDraw::LineGroup::lineGroupFactory(lgName); + result = lg->getWeight("Thin"); + delete lg; //Coverity CID 174670 + return result; +} + +App::Color ViewProviderLeader::getDefLineColor(void) +{ + Base::Reference hGrp = App::GetApplication().GetUserParameter(). + GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Markups"); + App::Color result; + result.setPackedValue(hGrp->GetUnsigned("Color", 0x00000000)); + return result; +} + +//****************************************************************************** +PROPERTY_SOURCE(TechDrawGui::ViewProviderTextLeader, TechDrawGui::ViewProviderLeader) + +ViewProviderTextLeader::ViewProviderTextLeader() +{ + sPixmap = "actions/techdraw-textleader"; + + static const char *group = "Text Format"; + + ADD_PROPERTY_TYPE(Font ,(getDefFont().c_str()),group,App::Prop_None, "The name of the font to use"); + ADD_PROPERTY_TYPE(Fontsize,(getDefFontSize()) ,group,(App::PropertyType)(App::Prop_None), + "Text size in internal units"); + ADD_PROPERTY_TYPE(MaxWidth,(-1) ,group,(App::PropertyType)(App::Prop_None), + "Maximum width of text in mm"); + ADD_PROPERTY_TYPE(ShowFrame,(true) ,group,(App::PropertyType)(App::Prop_None), + "Draw a box around text or not"); +} + +ViewProviderTextLeader::~ViewProviderTextLeader() +{ +} + +void ViewProviderTextLeader::attach(App::DocumentObject *pcFeat) +{ + ViewProviderLeader::attach(pcFeat); +} + +bool ViewProviderTextLeader::setEdit(int ModNum) +{ +// Base::Console().Message("VPTL::setEdit(%d)\n",ModNum); + if (ModNum == ViewProvider::Default ) { + if (Gui::Control().activeDialog()) { //TaskPanel already open! + return false; + } + // clear the selection (convenience) + Gui::Selection().clearSelection(); + Gui::Control().showDialog(new TaskDlgTextLeader(TEXTMODE, this)); + return true; + } else { + return ViewProviderLeader::setEdit(ModNum); + } + return true; +} + +void ViewProviderTextLeader::unsetEdit(int ModNum) +{ + Q_UNUSED(ModNum); + if (ModNum == ViewProvider::Default) { + Gui::Control().closeDialog(); + } + else { + ViewProviderLeader::unsetEdit(ModNum); + } +} + +bool ViewProviderTextLeader::doubleClicked(void) +{ +// Base::Console().Message("VPTL::doubleClicked()\n"); + setEdit(ViewProvider::Default); + return true; +} + +void ViewProviderTextLeader::updateData(const App::Property* p) +{ + ViewProviderLeader::updateData(p); +} + +void ViewProviderTextLeader::onChanged(const App::Property* p) +{ + if ((p == &Font) || + (p == &Fontsize) || + (p == &MaxWidth) || + (p == &ShowFrame)) { + QGIView* qgiv = getQView(); + if (qgiv) { + qgiv->updateView(true); + } + } + ViewProviderLeader::onChanged(p); + +} + +TechDraw::DrawTextLeader* ViewProviderTextLeader::getFeature() const +{ + return dynamic_cast(pcObject); +} + +std::string ViewProviderTextLeader::getDefFont(void) const +{ + Base::Reference hGrp = App::GetApplication().GetUserParameter(). + GetGroup("BaseApp")->GetGroup("Preferences")-> + GetGroup("Mod/TechDraw/Labels"); + std::string result = hGrp->GetASCII("LabelFont", "osifont"); + return result; +} + +double ViewProviderTextLeader::getDefFontSize(void) const +{ + Base::Reference hGrp = App::GetApplication().GetUserParameter(). + GetGroup("BaseApp")->GetGroup("Preferences")-> + GetGroup("Mod/TechDraw/Dimensions"); + double result = hGrp->GetFloat("FontSize", 6.0); + return result; +} + + diff --git a/src/Mod/TechDraw/Gui/ViewProviderLeader.h b/src/Mod/TechDraw/Gui/ViewProviderLeader.h new file mode 100644 index 0000000000..5953ad6107 --- /dev/null +++ b/src/Mod/TechDraw/Gui/ViewProviderLeader.h @@ -0,0 +1,107 @@ +/*************************************************************************** + * Copyright (c) 2004 Jürgen Riegel * + * Copyright (c) 2019 Wanderer Fan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef DRAWINGGUI_VIEWPROVIDERLEADER_H +#define DRAWINGGUI_VIEWPROVIDERLEADER_H + +#include + +#include + +#include "ViewProviderDrawingView.h" + +namespace TechDraw { +class DrawTextLeader; +class DrawLeaderLine; +} + +namespace TechDrawGui { + +class TechDrawGuiExport ViewProviderLeader : public ViewProviderDrawingView +{ + PROPERTY_HEADER(TechDrawGui::ViewProviderLeader); + +public: + /// constructor + ViewProviderLeader(); + /// destructor + virtual ~ViewProviderLeader(); + + App::PropertyFloat LineWidth; + App::PropertyInteger LineStyle; + App::PropertyColor Color; + + virtual void attach(App::DocumentObject *); +/* virtual void setDisplayMode(const char* ModeName);*/ + virtual bool useNewSelectionModel(void) const {return false;} +/* virtual std::vector getDisplayModes(void) const;*/ + virtual void updateData(const App::Property*); + virtual void onChanged(const App::Property* p); + virtual bool setEdit(int ModNum); + virtual void unsetEdit(int ModNum); + virtual bool doubleClicked(void); + + virtual TechDraw::DrawLeaderLine* getViewObject() const; + TechDraw::DrawLeaderLine* getFeature() const; + +protected: + double getDefLineWeight(void); + App::Color getDefLineColor(void); +}; + +//****************************************************************************** +class TechDrawGuiExport ViewProviderTextLeader : public ViewProviderLeader +{ + PROPERTY_HEADER(TechDrawGui::ViewProviderTextLeader); + +public: + ViewProviderTextLeader(); + virtual ~ViewProviderTextLeader(); + + App::PropertyFont Font; + App::PropertyLength Fontsize; + App::PropertyFloat MaxWidth; + App::PropertyBool ShowFrame; + + virtual void attach(App::DocumentObject *); + virtual void updateData(const App::Property*); + virtual void onChanged(const App::Property* p); + virtual bool setEdit(int ModNum); + virtual void unsetEdit(int ModNum); + virtual bool doubleClicked(void); + +/* virtual TechDraw::DrawTextLeader* getViewObject() const;*/ + TechDraw::DrawTextLeader* getFeature() const; + +protected: + std::string getDefFont(void) const; + double getDefFontSize(void) const; + +}; + + +} // namespace TechDrawGui + + +#endif // DRAWINGGUI_VIEWPROVIDERLEADER_H diff --git a/src/Mod/TechDraw/Gui/ViewProviderPage.cpp b/src/Mod/TechDraw/Gui/ViewProviderPage.cpp index a4089706d2..ee2302ff08 100644 --- a/src/Mod/TechDraw/Gui/ViewProviderPage.cpp +++ b/src/Mod/TechDraw/Gui/ViewProviderPage.cpp @@ -57,6 +57,7 @@ #include #include #include +#include #include #include @@ -261,6 +262,7 @@ std::vector ViewProviderPage::claimChildren(void) const // for Page, valid children are any View except: DrawProjGroupItem // DrawViewDimension // DrawViewBalloon + // DrawLeader // any FeatuerView in a DrawViewClip // DrawHatch @@ -275,6 +277,7 @@ std::vector ViewProviderPage::claimChildren(void) const docObj->isDerivedFrom(TechDraw::DrawViewDimension::getClassTypeId()) || docObj->isDerivedFrom(TechDraw::DrawHatch::getClassTypeId()) || docObj->isDerivedFrom(TechDraw::DrawViewBalloon::getClassTypeId()) || + docObj->isDerivedFrom(TechDraw::DrawLeaderLine::getClassTypeId()) || (featView && featView->isInClip()) ) continue; else diff --git a/src/Mod/TechDraw/Gui/ViewProviderViewPart.cpp b/src/Mod/TechDraw/Gui/ViewProviderViewPart.cpp index cb23359dd6..72f23e8ff0 100644 --- a/src/Mod/TechDraw/Gui/ViewProviderViewPart.cpp +++ b/src/Mod/TechDraw/Gui/ViewProviderViewPart.cpp @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -160,6 +161,7 @@ std::vector ViewProviderViewPart::claimChildren(void) cons // Collect any child Document Objects and put them in the right place in the Feature tree // valid children of a ViewPart are: // - Dimensions + // - Leaders // - Hatches // - GeomHatches std::vector temp; @@ -186,6 +188,8 @@ std::vector ViewProviderViewPart::claimChildren(void) cons temp.push_back((*it)); } else if ((*it)->getTypeId().isDerivedFrom(TechDraw::DrawViewBalloon::getClassTypeId())) { temp.push_back((*it)); + } else if ((*it)->getTypeId().isDerivedFrom(TechDraw::DrawLeaderLine::getClassTypeId())) { + temp.push_back((*it)); } } return temp; diff --git a/src/Mod/TechDraw/Gui/Workbench.cpp b/src/Mod/TechDraw/Gui/Workbench.cpp index e004df4afb..57b1556bc3 100644 --- a/src/Mod/TechDraw/Gui/Workbench.cpp +++ b/src/Mod/TechDraw/Gui/Workbench.cpp @@ -89,6 +89,8 @@ Gui::MenuItem* Workbench::setupMenuBar() const *draw << "TechDraw_Image"; *draw << "TechDraw_ToggleFrame"; // *decor << "TechDraw_RedrawPage"; + *draw << "TechDraw_LeaderLine"; + *draw << "TechDraw_TextLeader"; return root; } @@ -145,6 +147,8 @@ Gui::ToolBarItem* Workbench::setupToolBars() const *decor << "TechDraw_Image"; *decor << "TechDraw_ToggleFrame"; // *decor << "TechDraw_RedrawPage"; + *decor << "TechDraw_LeaderLine"; + *decor << "TechDraw_TextLeader"; return root; } @@ -199,6 +203,8 @@ Gui::ToolBarItem* Workbench::setupCommandBars() const *decor << "TechDraw_Image"; *decor << "TechDraw_ToggleFrame"; // *decor << "TechDraw_RedrawPage"; + *decor << "TechDraw_LeaderLine"; + *decor << "TechDraw_TextLeader"; return root; } diff --git a/src/Mod/TechDraw/Gui/ZVALUE.h b/src/Mod/TechDraw/Gui/ZVALUE.h index ffe0f19fd3..711450f7df 100644 --- a/src/Mod/TechDraw/Gui/ZVALUE.h +++ b/src/Mod/TechDraw/Gui/ZVALUE.h @@ -17,6 +17,7 @@ namespace ZVALUE { const int SECTIONLINE = 80; //TODO: change to "DECORATION"? section lines, symmetry lines, etc? const int HIGHLIGHT = 80; const int MATTING = 100; + const int TRACKER = 125; const int LOCK = 200; } #endif diff --git a/src/Mod/TechDraw/Gui/mrichtextedit.cpp b/src/Mod/TechDraw/Gui/mrichtextedit.cpp new file mode 100644 index 0000000000..575e1325b9 --- /dev/null +++ b/src/Mod/TechDraw/Gui/mrichtextedit.cpp @@ -0,0 +1,619 @@ +/* +** Copyright (C) 2013 Jiří Procházka (Hobrasoft) +** Contact: http://www.hobrasoft.cz/ +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file is under the terms of the GNU Lesser General Public License +** version 2.1 as published by the Free Software Foundation and appearing +** in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the +** GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mrichtextedit.h" + +MRichTextEdit::MRichTextEdit(QWidget *parent, QString textIn) : QWidget(parent) { + setupUi(this); + m_lastBlockList = 0; + f_textedit->setTabStopWidth(40); + setText(textIn); + + connect(f_save, SIGNAL(clicked()), + this, SLOT(onSave())); + connect(f_exit, SIGNAL(clicked()), + this, SLOT(onExit())); + + connect(f_textedit, SIGNAL(currentCharFormatChanged(QTextCharFormat)), + this, SLOT(slotCurrentCharFormatChanged(QTextCharFormat))); + connect(f_textedit, SIGNAL(cursorPositionChanged()), + this, SLOT(slotCursorPositionChanged())); + + m_fontsize_h1 = 18; + m_fontsize_h2 = 16; + m_fontsize_h3 = 14; + m_fontsize_h4 = 12; + + fontChanged(f_textedit->font()); + bgColorChanged(f_textedit->textColor()); + + // paragraph formatting + + m_paragraphItems << tr("Standard") + << tr("Heading 1") + << tr("Heading 2") + << tr("Heading 3") + << tr("Heading 4") + << tr("Monospace"); + f_paragraph->addItems(m_paragraphItems); + + connect(f_paragraph, SIGNAL(activated(int)), + this, SLOT(textStyle(int))); + + // undo & redo + + f_undo->setShortcut(QKeySequence::Undo); + f_redo->setShortcut(QKeySequence::Redo); + + connect(f_textedit->document(), SIGNAL(undoAvailable(bool)), + f_undo, SLOT(setEnabled(bool))); + connect(f_textedit->document(), SIGNAL(redoAvailable(bool)), + f_redo, SLOT(setEnabled(bool))); + + f_undo->setEnabled(f_textedit->document()->isUndoAvailable()); + f_redo->setEnabled(f_textedit->document()->isRedoAvailable()); + + connect(f_undo, SIGNAL(clicked()), f_textedit, SLOT(undo())); + connect(f_redo, SIGNAL(clicked()), f_textedit, SLOT(redo())); + + // cut, copy & paste + + f_cut->setShortcut(QKeySequence::Cut); + f_copy->setShortcut(QKeySequence::Copy); + f_paste->setShortcut(QKeySequence::Paste); + + f_cut->setEnabled(false); + f_copy->setEnabled(false); + + connect(f_cut, SIGNAL(clicked()), f_textedit, SLOT(cut())); + connect(f_copy, SIGNAL(clicked()), f_textedit, SLOT(copy())); + connect(f_paste, SIGNAL(clicked()), f_textedit, SLOT(paste())); + + connect(f_textedit, SIGNAL(copyAvailable(bool)), f_cut, SLOT(setEnabled(bool))); + connect(f_textedit, SIGNAL(copyAvailable(bool)), f_copy, SLOT(setEnabled(bool))); + +#ifndef QT_NO_CLIPBOARD + connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(slotClipboardDataChanged())); +#endif + + // link + + f_link->setShortcut(Qt::CTRL + Qt::Key_L); + + connect(f_link, SIGNAL(clicked(bool)), this, SLOT(textLink(bool))); + + // bold, italic & underline + + f_bold->setShortcut(Qt::CTRL + Qt::Key_B); + f_italic->setShortcut(Qt::CTRL + Qt::Key_I); + f_underline->setShortcut(Qt::CTRL + Qt::Key_U); + + connect(f_bold, SIGNAL(clicked()), this, SLOT(textBold())); + connect(f_italic, SIGNAL(clicked()), this, SLOT(textItalic())); + connect(f_underline, SIGNAL(clicked()), this, SLOT(textUnderline())); + connect(f_strikeout, SIGNAL(clicked()), this, SLOT(textStrikeout())); + + QAction *removeFormat = new QAction(tr("Remove character formatting"), this); + removeFormat->setShortcut(QKeySequence("CTRL+M")); + connect(removeFormat, SIGNAL(triggered()), this, SLOT(textRemoveFormat())); + f_textedit->addAction(removeFormat); + + QAction *removeAllFormat = new QAction(tr("Remove all formatting"), this); + connect(removeAllFormat, SIGNAL(triggered()), this, SLOT(textRemoveAllFormat())); + f_textedit->addAction(removeAllFormat); + + QAction *textsource = new QAction(tr("Edit document source"), this); + textsource->setShortcut(QKeySequence("CTRL+O")); + connect(textsource, SIGNAL(triggered()), this, SLOT(textSource())); + f_textedit->addAction(textsource); + + QMenu *menu = new QMenu(this); + menu->addAction(removeAllFormat); + menu->addAction(removeFormat); + menu->addAction(textsource); + f_menu->setMenu(menu); + f_menu->setPopupMode(QToolButton::InstantPopup); + + // lists + + f_list_bullet->setShortcut(Qt::CTRL + Qt::Key_Minus); + f_list_ordered->setShortcut(Qt::CTRL + Qt::Key_Equal); + + connect(f_list_bullet, SIGNAL(clicked(bool)), this, SLOT(listBullet(bool))); + connect(f_list_ordered, SIGNAL(clicked(bool)), this, SLOT(listOrdered(bool))); + + // indentation + + f_indent_dec->setShortcut(Qt::CTRL + Qt::Key_Comma); + f_indent_inc->setShortcut(Qt::CTRL + Qt::Key_Period); + + connect(f_indent_inc, SIGNAL(clicked()), this, SLOT(increaseIndentation())); + connect(f_indent_dec, SIGNAL(clicked()), this, SLOT(decreaseIndentation())); + + // font size + + QFontDatabase db; + foreach(int size, db.standardSizes()) + f_fontsize->addItem(QString::number(size)); + + connect(f_fontsize, SIGNAL(activated(QString)), + this, SLOT(textSize(QString))); + f_fontsize->setCurrentIndex(f_fontsize->findText(QString::number(QApplication::font() + .pointSize()))); + + // text foreground color + + QPixmap pix(16, 16); +// pix.fill(QApplication::palette().foreground().color()); +// f_fgcolor->setIcon(pix); + + connect(f_fgcolor, SIGNAL(clicked()), this, SLOT(textFgColor())); + + // text background color + +// pix.fill(QApplication::palette().background().color()); +// f_bgcolor->setIcon(pix); + + connect(f_bgcolor, SIGNAL(clicked()), this, SLOT(textBgColor())); + + // images + connect(f_image, SIGNAL(clicked()), this, SLOT(insertImage())); +} + + +void MRichTextEdit::textSource() { + QDialog *dialog = new QDialog(this); + QPlainTextEdit *pte = new QPlainTextEdit(dialog); + pte->setPlainText( f_textedit->toHtml() ); + QGridLayout *gl = new QGridLayout(dialog); + gl->addWidget(pte,0,0,1,1); + dialog->setWindowTitle(tr("Document source")); + dialog->setMinimumWidth (400); + dialog->setMinimumHeight(600); + dialog->exec(); + + f_textedit->setHtml(pte->toPlainText()); + + delete dialog; +} + + +void MRichTextEdit::textRemoveFormat() { + QTextCharFormat fmt; + fmt.setFontWeight(QFont::Normal); + fmt.setFontUnderline (false); + fmt.setFontStrikeOut (false); + fmt.setFontItalic (false); + fmt.setFontPointSize (9); +// fmt.setFontFamily ("Helvetica"); +// fmt.setFontStyleHint (QFont::SansSerif); +// fmt.setFontFixedPitch (true); + + f_bold ->setChecked(false); + f_underline ->setChecked(false); + f_italic ->setChecked(false); + f_strikeout ->setChecked(false); + f_fontsize ->setCurrentIndex(f_fontsize->findText("9")); + +// QTextBlockFormat bfmt = cursor.blockFormat(); +// bfmt->setIndent(0); + + fmt.clearBackground(); + + mergeFormatOnWordOrSelection(fmt); +} + + +void MRichTextEdit::textRemoveAllFormat() { + f_bold ->setChecked(false); + f_underline ->setChecked(false); + f_italic ->setChecked(false); + f_strikeout ->setChecked(false); + f_fontsize ->setCurrentIndex(f_fontsize->findText("9")); + QString text = f_textedit->toPlainText(); + f_textedit->setPlainText(text); +} + + +void MRichTextEdit::textBold() { + QTextCharFormat fmt; + fmt.setFontWeight(f_bold->isChecked() ? QFont::Bold : QFont::Normal); + mergeFormatOnWordOrSelection(fmt); +} + + +void MRichTextEdit::focusInEvent(QFocusEvent *) { + f_textedit->setFocus(Qt::TabFocusReason); +} + + +void MRichTextEdit::textUnderline() { + QTextCharFormat fmt; + fmt.setFontUnderline(f_underline->isChecked()); + mergeFormatOnWordOrSelection(fmt); +} + +void MRichTextEdit::textItalic() { + QTextCharFormat fmt; + fmt.setFontItalic(f_italic->isChecked()); + mergeFormatOnWordOrSelection(fmt); +} + +void MRichTextEdit::textStrikeout() { + QTextCharFormat fmt; + fmt.setFontStrikeOut(f_strikeout->isChecked()); + mergeFormatOnWordOrSelection(fmt); +} + +void MRichTextEdit::textSize(const QString &p) { + qreal pointSize = p.toFloat(); + if (p.toFloat() > 0) { + QTextCharFormat fmt; + fmt.setFontPointSize(pointSize); + mergeFormatOnWordOrSelection(fmt); + } +} + +void MRichTextEdit::textLink(bool checked) { + bool unlink = false; + QTextCharFormat fmt; + if (checked) { + QString url = f_textedit->currentCharFormat().anchorHref(); + bool ok; + QString newUrl = QInputDialog::getText(this, tr("Create a link"), + tr("Link URL:"), QLineEdit::Normal, + url, + &ok); + if (ok) { + fmt.setAnchor(true); + fmt.setAnchorHref(newUrl); + fmt.setForeground(QApplication::palette().color(QPalette::Link)); + fmt.setFontUnderline(true); + } else { + unlink = true; + } + } else { + unlink = true; + } + if (unlink) { + fmt.setAnchor(false); + fmt.setForeground(QApplication::palette().color(QPalette::Text)); + fmt.setFontUnderline(false); + } + mergeFormatOnWordOrSelection(fmt); +} + +void MRichTextEdit::textStyle(int index) { + QTextCursor cursor = f_textedit->textCursor(); + cursor.beginEditBlock(); + + // standard + if (!cursor.hasSelection()) { + cursor.select(QTextCursor::BlockUnderCursor); + } + QTextCharFormat fmt; + cursor.setCharFormat(fmt); + f_textedit->setCurrentCharFormat(fmt); + + if (index == ParagraphHeading1 + || index == ParagraphHeading2 + || index == ParagraphHeading3 + || index == ParagraphHeading4 ) { + if (index == ParagraphHeading1) { + fmt.setFontPointSize(m_fontsize_h1); + } + if (index == ParagraphHeading2) { + fmt.setFontPointSize(m_fontsize_h2); + } + if (index == ParagraphHeading3) { + fmt.setFontPointSize(m_fontsize_h3); + } + if (index == ParagraphHeading4) { + fmt.setFontPointSize(m_fontsize_h4); + } + if (index == ParagraphHeading2 || index == ParagraphHeading4) { + fmt.setFontItalic(true); + } + + fmt.setFontWeight(QFont::Bold); + } + if (index == ParagraphMonospace) { + fmt = cursor.charFormat(); + fmt.setFontFamily("Monospace"); + fmt.setFontStyleHint(QFont::Monospace); + fmt.setFontFixedPitch(true); + } + cursor.setCharFormat(fmt); + f_textedit->setCurrentCharFormat(fmt); + + cursor.endEditBlock(); +} + +void MRichTextEdit::textFgColor() { + QColor col = QColorDialog::getColor(f_textedit->textColor(), this); + QTextCursor cursor = f_textedit->textCursor(); + if (!cursor.hasSelection()) { + cursor.select(QTextCursor::WordUnderCursor); + } + QTextCharFormat fmt = cursor.charFormat(); + if (col.isValid()) { + fmt.setForeground(col); + } else { + fmt.clearForeground(); + } + cursor.setCharFormat(fmt); + f_textedit->setCurrentCharFormat(fmt); + fgColorChanged(col); +} + +void MRichTextEdit::textBgColor() { + QColor col = QColorDialog::getColor(f_textedit->textBackgroundColor(), this); + QTextCursor cursor = f_textedit->textCursor(); + if (!cursor.hasSelection()) { + cursor.select(QTextCursor::WordUnderCursor); + } + QTextCharFormat fmt = cursor.charFormat(); + if (col.isValid()) { + fmt.setBackground(col); + } else { + fmt.clearBackground(); + } + cursor.setCharFormat(fmt); + f_textedit->setCurrentCharFormat(fmt); + bgColorChanged(col); +} + +void MRichTextEdit::listBullet(bool checked) { + if (checked) { + f_list_ordered->setChecked(false); + } + list(checked, QTextListFormat::ListDisc); +} + +void MRichTextEdit::listOrdered(bool checked) { + if (checked) { + f_list_bullet->setChecked(false); + } + list(checked, QTextListFormat::ListDecimal); +} + +void MRichTextEdit::list(bool checked, QTextListFormat::Style style) { + QTextCursor cursor = f_textedit->textCursor(); + cursor.beginEditBlock(); + if (!checked) { + QTextBlockFormat obfmt = cursor.blockFormat(); + QTextBlockFormat bfmt; + bfmt.setIndent(obfmt.indent()); + cursor.setBlockFormat(bfmt); + } else { + QTextListFormat listFmt; + if (cursor.currentList()) { + listFmt = cursor.currentList()->format(); + } + listFmt.setStyle(style); + cursor.createList(listFmt); + } + cursor.endEditBlock(); +} + +void MRichTextEdit::mergeFormatOnWordOrSelection(const QTextCharFormat &format) { + QTextCursor cursor = f_textedit->textCursor(); + if (!cursor.hasSelection()) { + cursor.select(QTextCursor::WordUnderCursor); + } + cursor.mergeCharFormat(format); + f_textedit->mergeCurrentCharFormat(format); + f_textedit->setFocus(Qt::TabFocusReason); +} + +void MRichTextEdit::slotCursorPositionChanged() { + QTextList *l = f_textedit->textCursor().currentList(); + if (m_lastBlockList && (l == m_lastBlockList || (l != 0 && m_lastBlockList != 0 + && l->format().style() == m_lastBlockList->format().style()))) { + return; + } + m_lastBlockList = l; + if (l) { + QTextListFormat lfmt = l->format(); + if (lfmt.style() == QTextListFormat::ListDisc) { + f_list_bullet->setChecked(true); + f_list_ordered->setChecked(false); + } else if (lfmt.style() == QTextListFormat::ListDecimal) { + f_list_bullet->setChecked(false); + f_list_ordered->setChecked(true); + } else { + f_list_bullet->setChecked(false); + f_list_ordered->setChecked(false); + } + } else { + f_list_bullet->setChecked(false); + f_list_ordered->setChecked(false); + } +} + +void MRichTextEdit::fontChanged(const QFont &f) { + f_fontsize->setCurrentIndex(f_fontsize->findText(QString::number(f.pointSize()))); + f_bold->setChecked(f.bold()); + f_italic->setChecked(f.italic()); + f_underline->setChecked(f.underline()); + f_strikeout->setChecked(f.strikeOut()); + if (f.pointSize() == m_fontsize_h1) { + f_paragraph->setCurrentIndex(ParagraphHeading1); + } else if (f.pointSize() == m_fontsize_h2) { + f_paragraph->setCurrentIndex(ParagraphHeading2); + } else if (f.pointSize() == m_fontsize_h3) { + f_paragraph->setCurrentIndex(ParagraphHeading3); + } else if (f.pointSize() == m_fontsize_h4) { + f_paragraph->setCurrentIndex(ParagraphHeading4); + } else { + if (f.fixedPitch() && f.family() == "Monospace") { + f_paragraph->setCurrentIndex(ParagraphMonospace); + } else { + f_paragraph->setCurrentIndex(ParagraphStandard); + } + } + if (f_textedit->textCursor().currentList()) { + QTextListFormat lfmt = f_textedit->textCursor().currentList()->format(); + if (lfmt.style() == QTextListFormat::ListDisc) { + f_list_bullet->setChecked(true); + f_list_ordered->setChecked(false); + } else if (lfmt.style() == QTextListFormat::ListDecimal) { + f_list_bullet->setChecked(false); + f_list_ordered->setChecked(true); + } else { + f_list_bullet->setChecked(false); + f_list_ordered->setChecked(false); + } + } else { + f_list_bullet->setChecked(false); + f_list_ordered->setChecked(false); + } +} + +void MRichTextEdit::fgColorChanged(const QColor &c) { + QSize iconSize(16,16); + QIcon fgIcon = f_fgcolor->icon(); + QPixmap fgPix = fgIcon.pixmap(iconSize,QIcon::Mode::Normal, QIcon::State::On); + QPixmap filler(iconSize); + if (c.isValid() ) { + filler.fill(c); + filler.setMask(fgPix.createMaskFromColor(Qt::transparent, Qt::MaskInColor) ); + f_fgcolor->setIcon(filler); + } +} + +void MRichTextEdit::bgColorChanged(const QColor &c) { + QSize iconSize(16,16); + QIcon bgIcon = f_bgcolor->icon(); + QPixmap bgPix = bgIcon.pixmap(iconSize,QIcon::Mode::Normal, QIcon::State::On); + QPixmap filler(iconSize); + if (c.isValid() ) { + filler.fill(c); + filler.setMask(bgPix.createMaskFromColor(Qt::transparent, Qt::MaskOutColor) ); + f_bgcolor->setIcon(filler); + } +} + +void MRichTextEdit::slotCurrentCharFormatChanged(const QTextCharFormat &format) { + fontChanged(format.font()); + bgColorChanged((format.background().isOpaque()) ? format.background().color() : QColor()); + fgColorChanged((format.foreground().isOpaque()) ? format.foreground().color() : QColor()); + f_link->setChecked(format.isAnchor()); +} + +void MRichTextEdit::slotClipboardDataChanged() { +#ifndef QT_NO_CLIPBOARD + if (const QMimeData *md = QApplication::clipboard()->mimeData()) + f_paste->setEnabled(md->hasText()); +#endif +} + +QString MRichTextEdit::toHtml() const { + QString s = f_textedit->toHtml(); + // convert emails to links + s = s.replace(QRegExp("(<[^a][^>]+>(?:]+>)?|\\s)([a-zA-Z\\d]+@[a-zA-Z\\d]+\\.[a-zA-Z]+)"), "\\1\\2"); + // convert links + s = s.replace(QRegExp("(<[^a][^>]+>(?:]+>)?|\\s)((?:https?|ftp|file)://[^\\s'\"<>]+)"), "\\1\\2"); + // see also: Utils::linkify() + return s; +} + +void MRichTextEdit::increaseIndentation() { + indent(+1); +} + +void MRichTextEdit::decreaseIndentation() { + indent(-1); +} + +void MRichTextEdit::indent(int delta) { + QTextCursor cursor = f_textedit->textCursor(); + cursor.beginEditBlock(); + QTextBlockFormat bfmt = cursor.blockFormat(); + int ind = bfmt.indent(); + if (ind + delta >= 0) { + bfmt.setIndent(ind + delta); + } + cursor.setBlockFormat(bfmt); + cursor.endEditBlock(); +} + +void MRichTextEdit::setText(const QString& text) { + if (text.isEmpty()) { + setPlainText(text); + return; + } + if (text[0] == '<') { + setHtml(text); + } else { + setPlainText(text); + } +} + +void MRichTextEdit::insertImage() { + QSettings s; + QString attdir = s.value("general/filedialog-path").toString(); + QString file = QFileDialog::getOpenFileName(this, + tr("Select an image"), + attdir, + tr("JPEG (*.jpg);; GIF (*.gif);; PNG (*.png);; BMP (*.bmp);; All (*)")); + QImage image = QImageReader(file).read(); + + f_textedit->dropImage(image, QFileInfo(file).suffix().toUpper().toLocal8Bit().data() ); + +} + +void MRichTextEdit::onSave(void) +{ + QString result = toHtml(); + Q_EMIT saveText(result); +} + +void MRichTextEdit::onExit(void) +{ + Q_EMIT editorFinished(); +} + +#include + diff --git a/src/Mod/TechDraw/Gui/mrichtextedit.h b/src/Mod/TechDraw/Gui/mrichtextedit.h new file mode 100644 index 0000000000..5a7d998672 --- /dev/null +++ b/src/Mod/TechDraw/Gui/mrichtextedit.h @@ -0,0 +1,102 @@ +/* +** Copyright (C) 2013 Jiří Procházka (Hobrasoft) +** Contact: http://www.hobrasoft.cz/ +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file is under the terms of the GNU Lesser General Public License +** version 2.1 as published by the Free Software Foundation and appearing +** in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the +** GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +*/ + +#ifndef _MRICHTEXTEDIT_H_ +#define _MRICHTEXTEDIT_H_ + +#include +#include "ui_mrichtextedit.h" + +/** + * @Brief A simple rich-text editor + */ +class MRichTextEdit : public QWidget, protected Ui::MRichTextEdit { + Q_OBJECT + public: + MRichTextEdit(QWidget *parent = 0, QString textIn = QString() ); + + QString toPlainText() const { return f_textedit->toPlainText(); } + QString toHtml() const; + QTextDocument *document() { return f_textedit->document(); } + QTextCursor textCursor() const { return f_textedit->textCursor(); } + void setTextCursor(const QTextCursor& cursor) { f_textedit->setTextCursor(cursor); } + + public slots: + void setText(const QString &text); + +Q_SIGNALS: + void saveText(QString revText); + void editorFinished(); + + protected slots: + void onSave(void); + void onExit(void); + void setPlainText(const QString &text) { f_textedit->setPlainText(text); } + void setHtml(const QString &text) { f_textedit->setHtml(text); } + void textRemoveFormat(); + void textRemoveAllFormat(); + void textBold(); + void textUnderline(); + void textStrikeout(); + void textItalic(); + void textSize(const QString &p); + void textLink(bool checked); + void textStyle(int index); + void textFgColor(); + void textBgColor(); + void listBullet(bool checked); + void listOrdered(bool checked); + void slotCurrentCharFormatChanged(const QTextCharFormat &format); + void slotCursorPositionChanged(); + void slotClipboardDataChanged(); + void increaseIndentation(); + void decreaseIndentation(); + void insertImage(); + void textSource(); + + protected: + void mergeFormatOnWordOrSelection(const QTextCharFormat &format); + void fontChanged(const QFont &f); + void fgColorChanged(const QColor &c); + void bgColorChanged(const QColor &c); + void list(bool checked, QTextListFormat::Style style); + void indent(int delta); + void focusInEvent(QFocusEvent *event); + + QStringList m_paragraphItems; + int m_fontsize_h1; + int m_fontsize_h2; + int m_fontsize_h3; + int m_fontsize_h4; + + enum ParagraphItems { ParagraphStandard = 0, + ParagraphHeading1, + ParagraphHeading2, + ParagraphHeading3, + ParagraphHeading4, + ParagraphMonospace }; + + QPointer m_lastBlockList; +}; + +#endif diff --git a/src/Mod/TechDraw/Gui/mrichtextedit.ui b/src/Mod/TechDraw/Gui/mrichtextedit.ui new file mode 100644 index 0000000000..2cd49336d4 --- /dev/null +++ b/src/Mod/TechDraw/Gui/mrichtextedit.ui @@ -0,0 +1,657 @@ + + + MRichTextEdit + + + + 0 + 0 + 879 + 312 + + + + + + + + 1 + + + 1 + + + + + + 2 + + + 0 + + + + + Save changes + + + + + + + + + + + + + + + Close editor + + + + + + + + + + + + + + + Qt::Vertical + + + + + + + Qt::ClickFocus + + + Paragraph formatting + + + true + + + + + + + Qt::Vertical + + + + + + + false + + + Qt::ClickFocus + + + Undo (CTRL+Z) + + + Undo + + + + + + + + + 16 + 16 + + + + + + + + false + + + Qt::ClickFocus + + + Redo + + + Redo + + + + + + + + + 16 + 16 + + + + + + + + Qt::ClickFocus + + + Cut (CTRL+X) + + + Cut + + + + + + + + + 16 + 16 + + + + + + + + Qt::ClickFocus + + + Copy (CTRL+C) + + + Copy + + + + + + + + + 16 + 16 + + + + + + + + Qt::ClickFocus + + + Paste (CTRL+V) + + + Paste + + + + + + + + + 16 + 16 + + + + + + + + Qt::Vertical + + + + + + + Qt::ClickFocus + + + Link (CTRL+L) + + + Link + + + + + + + + + 16 + 16 + + + + true + + + + + + + Qt::Vertical + + + + + + + Qt::ClickFocus + + + Bold (CTRL+B) + + + Bold + + + + + + + + + 16 + 16 + + + + true + + + + + + + Qt::ClickFocus + + + Italic (CTRL+I) + + + Italic + + + + + + + + + 16 + 16 + + + + true + + + + + + + Qt::ClickFocus + + + Underline (CTRL+U) + + + Underline + + + + + + + + + 16 + 16 + + + + true + + + + + + + Strikethrough + + + Strike Out + + + + + + + + + 16 + 16 + + + + true + + + + + + + Qt::Vertical + + + + + + + Qt::ClickFocus + + + Bullet list (CTRL+-) + + + + + + + :/icons/MRTE/listBullet.svg:/icons/MRTE/listBullet.svg + + + + 16 + 16 + + + + true + + + + + + + Qt::ClickFocus + + + Ordered list (CTRL+=) + + + + + + + :/icons/MRTE/listNumber.svg:/icons/MRTE/listNumber.svg + + + + 16 + 16 + + + + true + + + + + + + Qt::ClickFocus + + + Decrease indentation (CTRL+,) + + + Decrease indentation + + + + + + + + + 16 + 16 + + + + + + + + Qt::ClickFocus + + + Increase indentation (CTRL+.) + + + Increase indentation + + + + + + + + + 16 + 16 + + + + + + + + Qt::Vertical + + + + + + + + 0 + 0 + + + + Qt::ClickFocus + + + Text foreground color + + + + + + + :/icons/MRTE/fgColor.svg:/icons/MRTE/fgColor.svg + + + + 16 + 16 + + + + + + + + Qt::ClickFocus + + + Text background color + + + Background + + + + :/icons/MRTE/bgColor.svg:/icons/MRTE/bgColor.svg + + + + 16 + 16 + + + + Qt::ToolButtonIconOnly + + + Qt::NoArrow + + + + + + + Qt::ClickFocus + + + Font size + + + true + + + + + + + Qt::Vertical + + + + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + More functions + + + + + + + :/icons/MRTE/menu.svg:/icons/MRTE/menu.svg + + + + + f_paragraph + line_4 + f_undo + f_redo + f_cut + f_copy + f_paste + line + f_link + line_3 + f_italic + f_underline + line_2 + f_fontsize + line_5 + f_list_bullet + f_list_ordered + f_indent_dec + f_indent_inc + f_bold + f_bgcolor + f_strikeout + f_image + line_6 + f_menu + f_fgcolor + f_save + f_exit + line_7 + + + + + + More functions + + + QTextEdit::AutoNone + + + true + + + + + + + + MTextEdit + QTextEdit +
mtextedit.h
+
+
+ + f_textedit + f_strikeout + f_image + f_menu + + + + + + +
diff --git a/src/Mod/TechDraw/Gui/mtextedit.cpp b/src/Mod/TechDraw/Gui/mtextedit.cpp new file mode 100644 index 0000000000..aaf5eba9ca --- /dev/null +++ b/src/Mod/TechDraw/Gui/mtextedit.cpp @@ -0,0 +1,78 @@ +#include "mtextedit.h" +#include +#include +#include +#include +#include +#include + + +MTextEdit::MTextEdit(QWidget *parent) : QTextEdit(parent) { +} + + +bool MTextEdit::canInsertFromMimeData(const QMimeData *source) const { + return source->hasImage() || QTextEdit::canInsertFromMimeData(source); +} + + +void MTextEdit::insertFromMimeData(const QMimeData *source) { + if (source->hasImage()) { + QStringList formats = source->formats(); + QString format; + for (int i=0; i(source->imageData()), format); + dropImage(qvariant_cast(source->imageData()), "JPG"); // Sorry, ale cokoli jiného dlouho trvá + return; + } + } + QTextEdit::insertFromMimeData(source); +} + + +QMimeData *MTextEdit::createMimeDataFromSelection() const { + return QTextEdit::createMimeDataFromSelection(); +} + + +void MTextEdit::dropImage(const QImage& image, const QString& format) { + QByteArray bytes; + QBuffer buffer(&bytes); + buffer.open(QIODevice::WriteOnly); + image.save(&buffer, format.toLocal8Bit().data()); + buffer.close(); + QByteArray base64 = bytes.toBase64(); + QByteArray base64l; + for (int i=0; i + diff --git a/src/Mod/TechDraw/Gui/mtextedit.h b/src/Mod/TechDraw/Gui/mtextedit.h new file mode 100644 index 0000000000..be63253c91 --- /dev/null +++ b/src/Mod/TechDraw/Gui/mtextedit.h @@ -0,0 +1,22 @@ +#ifndef _MTEXTEDIT_H_ +#define _MTEXTEDIT_H_ + +#include +#include +#include + +class MTextEdit : public QTextEdit { + Q_OBJECT + public: + MTextEdit(QWidget *parent); + + void dropImage(const QImage& image, const QString& format); + + protected: + bool canInsertFromMimeData(const QMimeData *source) const; + void insertFromMimeData(const QMimeData *source); + QMimeData *createMimeDataFromSelection() const; + +}; + +#endif