From 565f2b35b4132f05d12a3f9e2bcd2c597ef5943c Mon Sep 17 00:00:00 2001 From: vocx-fc Date: Wed, 3 Jun 2020 22:32:56 -0500 Subject: [PATCH] Draft: move make_text function to its own module Also perform several improvements such as PEP8 cleanup, write complete docstring, type checking of the input arguments, accepting a full placement to modify the position, and deprecating the older call. Update the Gui Command as well. --- src/Mod/Draft/CMakeLists.txt | 1 + src/Mod/Draft/Draft.py | 15 +- src/Mod/Draft/draftguitools/gui_texts.py | 41 +++-- src/Mod/Draft/draftmake/make_text.py | 155 ++++++++++++++++++ src/Mod/Draft/draftobjects/text.py | 125 ++++---------- src/Mod/Draft/draftviewproviders/view_text.py | 4 + 6 files changed, 228 insertions(+), 113 deletions(-) create mode 100644 src/Mod/Draft/draftmake/make_text.py diff --git a/src/Mod/Draft/CMakeLists.txt b/src/Mod/Draft/CMakeLists.txt index 5151a2af15..7531beba66 100644 --- a/src/Mod/Draft/CMakeLists.txt +++ b/src/Mod/Draft/CMakeLists.txt @@ -124,6 +124,7 @@ SET(Draft_make_functions draftmake/make_shape2dview.py draftmake/make_shapestring.py draftmake/make_sketch.py + draftmake/make_text.py draftmake/make_wire.py draftmake/make_wpproxy.py draftmake/README.md diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 527fd6121c..148fa0a96e 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -409,13 +409,14 @@ if gui: ViewProviderDraftLabel = ViewProviderLabel -from draftobjects.text import make_text -from draftobjects.text import Text -makeText = make_text -DraftText = Text +from draftobjects.text import (Text, + DraftText) -if gui: - from draftviewproviders.view_text import ViewProviderText - ViewProviderDraftText = ViewProviderText +from draftmake.make_text import (make_text, + makeText) + +if FreeCAD.GuiUp: + from draftviewproviders.view_text import (ViewProviderText, + ViewProviderDraftText) ## @} diff --git a/src/Mod/Draft/draftguitools/gui_texts.py b/src/Mod/Draft/draftguitools/gui_texts.py index 734a8c3a92..8d0964e392 100644 --- a/src/Mod/Draft/draftguitools/gui_texts.py +++ b/src/Mod/Draft/draftguitools/gui_texts.py @@ -39,6 +39,7 @@ import Draft_rc import DraftVecUtils import draftguitools.gui_base_original as gui_base_original import draftguitools.gui_tool_utils as gui_tool_utils + from draftutils.translate import translate from draftutils.messages import _msg @@ -84,26 +85,32 @@ class Text(gui_base_original.Creator): def createObject(self): """Create the actual object in the current document.""" - txt = '[' - for line in self.text: - if len(txt) > 1: - txt += ', ' - if sys.version_info.major < 3: - # Python2, string needs to be converted to unicode - line = unicode(line) - txt += '"' + str(line.encode("utf8")) + '"' - else: - # Python3, string is already unicode - txt += '"' + line + '"' - txt += ']' + text_list = self.text + + # If the last element is an empty string "" we remove it + if not text_list[-1]: + text_list.pop() + + # For Python 2 we convert the string to unicode, + # Python 3 nothing needs to be done + if sys.version_info.major < 3: + u_list = [unicode(line) for line in text_list] + t_list = ['"' + str(line.encode("utf8")) + '"' for line in u_list] + else: + t_list = ['"' + line + '"' for line in text_list] + + list_as_text = ", ".join(t_list) + + string = '[' + list_as_text + ']' + Gui.addModule("Draft") - _cmd = 'Draft.makeText' + _cmd = 'Draft.make_text' _cmd += '(' - _cmd += txt + ', ' - _cmd += 'point=' + DraftVecUtils.toString(self.node[0]) + _cmd += string + ', ' + _cmd += 'placement=' + DraftVecUtils.toString(self.node[0]) _cmd += ')' - _cmd_list = ['text = ' + _cmd, - 'Draft.autogroup(text)', + _cmd_list = ['_text_ = ' + _cmd, + 'Draft.autogroup(_text_)', 'FreeCAD.ActiveDocument.recompute()'] self.commit(translate("draft", "Create Text"), _cmd_list) diff --git a/src/Mod/Draft/draftmake/make_text.py b/src/Mod/Draft/draftmake/make_text.py new file mode 100644 index 0000000000..adf25796b7 --- /dev/null +++ b/src/Mod/Draft/draftmake/make_text.py @@ -0,0 +1,155 @@ +# *************************************************************************** +# * Copyright (c) 2009, 2010 Yorik van Havre * +# * Copyright (c) 2009, 2010 Ken Cline * +# * Copyright (c) 2020 Eliud Cabrera Castillo * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * FreeCAD 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 FreeCAD; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** +"""Provides the make function to create Draft Text objects.""" +## @package make_text +# \ingroup DRAFT +# \brief Provides the make function to create Draft Text objects. + +import FreeCAD as App +import draftutils.utils as utils +import draftutils.gui_utils as gui_utils + +from draftutils.messages import _msg, _err +from draftutils.translate import _tr +from draftobjects.text import Text + +if App.GuiUp: + from draftviewproviders.view_text import ViewProviderText + + +def make_text(string, placement=None, screen=False): + """Create a Text object containing the given list of strings. + + The current color and text height and font specified in preferences + are used. + + Parameters + ---------- + string: str, or list of str + String to display on screen. + + If it is a list, each element in the list should be a string. + In this case each element will be printed in its own line, that is, + a newline will be added at the end of each string. + + If an empty string is passed `''` this won't cause an error + but the text `'Label'` will be displayed in the 3D view. + + placement: Base::Placement, Base::Vector3, or Base::Rotation, optional + It defaults to `None`. + If it is provided, it is the placement of the new text. + The input could be a full placement, just a vector indicating + the translation, or just a rotation. + + screen: bool, optional + It defaults to `False`, in which case the text is placed in 3D space + oriented like any other object, on top of a given plane, + by the default the XY plane. + If it is `True`, the text will always face perpendicularly + to the camera direction, that is, it will be flat on the screen. + + Returns + ------- + App::FeaturePython + A scripted object of type `'Text'`. + This object does not have a `Shape` attribute, as the text is created + on screen by Coin (pivy). + + None + If there is a problem it will return `None`. + """ + _name = "make_text" + utils.print_header(_name, "Text") + + found, doc = utils.find_doc(App.activeDocument()) + if not found: + _err(_tr("No active document. Aborting.")) + return None + + _msg("string: {}".format(string)) + try: + utils.type_check([(string, (str, list))]) + except TypeError: + _err(_tr("Wrong input: must be a list of strings " + "or a single string.")) + return None + + if not all(isinstance(element, str) for element in string): + _err(_tr("Wrong input: must be a list of strings " + "or a single string.")) + return None + + if isinstance(string, str): + string = [string] + + _msg("placement: {}".format(placement)) + if not placement: + placement = App.Placement() + try: + utils.type_check([(placement, (App.Placement, + App.Vector, + App.Rotation))], name=_name) + except TypeError: + _err(_tr("Wrong input: must be a placement, a vector, " + "or a rotation.")) + return None + + # Convert the vector or rotation to a full placement + if isinstance(placement, App.Vector): + placement = App.Placement(placement, App.Rotation()) + elif isinstance(placement, App.Rotation): + placement = App.Placement(App.Vector(), placement) + + new_obj = doc.addObject("App::FeaturePython", + "Text") + Text(new_obj) + new_obj.Text = string + new_obj.Placement = placement + + if App.GuiUp: + ViewProviderText(new_obj.ViewObject) + + h = utils.get_param("textheight", 0.20) + + if screen: + _msg("screen: {}".format(screen)) + new_obj.ViewObject.DisplayMode = "3D text" + h = h*10 + + new_obj.ViewObject.FontSize = h + new_obj.ViewObject.FontName = utils.get_param("textfont", "") + new_obj.ViewObject.LineSpacing = 1 + + gui_utils.format_object(new_obj) + gui_utils.select(new_obj) + + return new_obj + + +def makeText(stringlist, point=App.Vector(0, 0, 0), screen=False): + """Create Text. DEPRECATED. Use 'make_text'.""" + utils.use_instead("make_text") + + return make_text(stringlist, point, screen) diff --git a/src/Mod/Draft/draftobjects/text.py b/src/Mod/Draft/draftobjects/text.py index 46744c05bc..42c258c7cb 100644 --- a/src/Mod/Draft/draftobjects/text.py +++ b/src/Mod/Draft/draftobjects/text.py @@ -21,112 +21,59 @@ # * USA * # * * # *************************************************************************** - -"""This module provides the object code for Draft Text. -""" +"""Provide the object code for Draft Text objects.""" ## @package text # \ingroup DRAFT -# \brief This module provides the object code for Draft Text. +# \brief Provide the object code for Draft Text objects. + +from PySide.QtCore import QT_TRANSLATE_NOOP import FreeCAD as App -import math -from PySide.QtCore import QT_TRANSLATE_NOOP -import DraftGeomUtils -import draftutils.gui_utils as gui_utils -import draftutils.utils as utils + from draftobjects.draft_annotation import DraftAnnotation -if App.GuiUp: - from draftviewproviders.view_text import ViewProviderText - - - -def make_text(stringslist, point=App.Vector(0,0,0), screen=False): - """makeText(strings, point, screen) - - Creates a Text object containing the given strings. - The current color and text height and font - specified in preferences are used. - - Parameters - ---------- - stringlist : List - Given list of strings, one string by line (strings can also - be one single string) - - point : App::Vector - insert point of the text - - screen : Bool - If screen is True, the text always faces the view direction. - - """ - - if not App.ActiveDocument: - App.Console.PrintError("No active document. Aborting\n") - return - - utils.type_check([(point, App.Vector)], "makeText") - if not isinstance(stringslist,list): stringslist = [stringslist] - - obj = App.ActiveDocument.addObject("App::FeaturePython","Text") - Text(obj) - obj.Text = stringslist - obj.Placement.Base = point - - if App.GuiUp: - ViewProviderText(obj.ViewObject) - if screen: - obj.ViewObject.DisplayMode = "3D text" - h = utils.get_param("textheight",0.20) - if screen: - h = h*10 - obj.ViewObject.FontSize = h - obj.ViewObject.FontName = utils.get_param("textfont","") - obj.ViewObject.LineSpacing = 1 - gui_utils.format_object(obj) - gui_utils.select(obj) - - return obj - class Text(DraftAnnotation): - """The Draft Text object""" + """The Draft Text object.""" def __init__(self, obj): - super(Text, self).__init__(obj, "Text") - - self.init_properties(obj) - + self.set_properties(obj) obj.Proxy = self - - def init_properties(self, obj): - """Add Text specific properties to the object and set them""" + def set_properties(self, obj): + """Add properties to the object and set them.""" + properties = obj.PropertiesList - obj.addProperty("App::PropertyPlacement", - "Placement", - "Base", - QT_TRANSLATE_NOOP("App::Property", - "The placement of this object")) + if "Placement" not in properties: + _tip = QT_TRANSLATE_NOOP("App::Property", + "The placement of the base point " + "of the first line") + obj.addProperty("App::PropertyPlacement", + "Placement", + "Base", + _tip) + obj.Placement = App.Placement() - obj.addProperty("App::PropertyStringList", - "Text", - "Base", - QT_TRANSLATE_NOOP("App::Property", - "The text displayed by this object")) + if "Text" not in properties: + _tip = QT_TRANSLATE_NOOP("App::Property", + "The text displayed by this object.\n" + "It is a list of strings; each element " + "in the list will be displayed " + "in its own line.") + obj.addProperty("App::PropertyStringList", + "Text", + "Base", + _tip) + obj.Text = [] def onDocumentRestored(self, obj): + """Execute code when the document is restored. + + It calls the parent class to add missing annotation properties. + """ super(Text, self).onDocumentRestored(obj) - def execute(self,obj): - '''Do something when recompute object''' - return - - - def onChanged(self,obj,prop): - '''Do something when a property has changed''' - - return +# Alias for compatibility with v0.18 and earlier +DraftText = Text diff --git a/src/Mod/Draft/draftviewproviders/view_text.py b/src/Mod/Draft/draftviewproviders/view_text.py index e442b1689e..6cb5115dcf 100644 --- a/src/Mod/Draft/draftviewproviders/view_text.py +++ b/src/Mod/Draft/draftviewproviders/view_text.py @@ -180,3 +180,7 @@ class ViewProviderText(ViewProviderDraftAnnotation): if "LineSpacing" in vobj.PropertiesList: self.text2d.spacing = vobj.LineSpacing self.text3d.spacing = vobj.LineSpacing + + +# Alias for compatibility with v0.18 and earlier +ViewProviderDraftText = ViewProviderText