Draft: clean up ViewProviderText class

Various improvements in style, PEP8, spacing, docstrings.

The list of strings is set to empty before being assigned again.
This solves a problem of the text not being updated correctly.

In the past some `try-except` blocks were there to catch and
ignore certain exceptions that apparently were caused by a
race condition, where certain properties are not assigned
to the object before they are used. These errors
don't seem to occur in v0.19, so we removed the exception
handling. We leave comments mentioning the issue
in case it re-appears.

The `DisplayMode` is swapped, so now `'2D text'` means that the
text always faces the camera, and `'3D text'` means that the
text can be positioned in different orientations in the 3D space.
This is consistent with the `Draft Label` behavior.

A function `draftutils.gui_utils.migrate_text_display_mode`
is provided to help migrate older objects of type `Text`
or `DraftText` to the new display mode.
This commit is contained in:
vocx-fc
2020-06-19 16:11:37 -05:00
committed by Yorik van Havre
parent de6f251f75
commit 22e9cf8921
3 changed files with 124 additions and 91 deletions

View File

@@ -131,12 +131,13 @@ def make_text(string, placement=None, screen=False):
if App.GuiUp:
ViewProviderText(new_obj.ViewObject)
h = utils.get_param("textheight", 0.20)
h = utils.get_param("textheight", 2)
new_obj.ViewObject.DisplayMode = "3D text"
if screen:
_msg("screen: {}".format(screen))
new_obj.ViewObject.DisplayMode = "3D text"
h = h*10
new_obj.ViewObject.DisplayMode = "2D text"
h = h * 10
new_obj.ViewObject.FontSize = h
new_obj.ViewObject.FontName = utils.get_param("textfont", "")

View File

@@ -39,9 +39,9 @@ import os
import six
import FreeCAD as App
import draftutils.utils as utils
from draftutils.messages import _msg, _wrn
from draftutils.utils import getParam
from draftutils.utils import get_type
from draftutils.translate import _tr, translate
if App.GuiUp:
@@ -141,19 +141,19 @@ def autogroup(obj):
App.Console.PrintMessage(err)
return
inverse_placement = App.Placement(matrix.inverse())
if get_type(obj) == 'Point':
if utils.get_type(obj) == 'Point':
point_vector = App.Vector(obj.X, obj.Y, obj.Z)
real_point = inverse_placement.multVec(point_vector)
obj.X = real_point.x
obj.Y = real_point.y
obj.Z = real_point.z
elif get_type(obj) in ["Dimension", "LinearDimension"]:
elif utils.get_type(obj) in ["Dimension", "LinearDimension"]:
obj.Start = inverse_placement.multVec(obj.Start)
obj.End = inverse_placement.multVec(obj.End)
obj.Dimline = inverse_placement.multVec(obj.Dimline)
obj.Normal = inverse_placement.Rotation.multVec(obj.Normal)
obj.Direction = inverse_placement.Rotation.multVec(obj.Direction)
elif get_type(obj) in ["Label"]:
elif utils.get_type(obj) in ["Label"]:
obj.Placement = App.Placement(inverse_placement.multiply(obj.Placement))
obj.TargetPoint = inverse_placement.multVec(obj.TargetPoint)
elif hasattr(obj,"Placement"):
@@ -193,7 +193,7 @@ def dim_symbol(symbol=None, invert=False):
that will be used as a dimension symbol.
"""
if symbol is None:
symbol = getParam("dimsymbol", 0)
symbol = utils.get_param("dimsymbol", 0)
if symbol == 0:
return coin.SoSphere()
@@ -340,7 +340,7 @@ def format_object(target, origin=None):
doc = App.ActiveDocument
if ui.isConstructionMode():
col = fcol = ui.getDefaultColor("constr")
gname = getParam("constructiongroupname", "Construction")
gname = utils.get_param("constructiongroupname", "Construction")
grp = doc.getObject(gname)
if not grp:
grp = doc.addObject("App::DocumentObjectGroup", gname)
@@ -655,3 +655,13 @@ def load_texture(filename, size=None, gui=App.GuiUp):
loadTexture = load_texture
def migrate_text_display_mode(obj_type="Text", mode="3D text", doc=None):
"""Migrate the display mode of objects of certain type."""
if not doc:
doc = App.activeDocument()
for obj in doc.Objects:
if utils.get_type(obj) == obj_type:
obj.ViewObject.DisplayMode = mode

View File

@@ -1,6 +1,7 @@
# ***************************************************************************
# * Copyright (c) 2009, 2010 Yorik van Havre <yorik@uncreated.net> *
# * Copyright (c) 2009, 2010 Ken Cline <cline@frii.com> *
# * Copyright (c) 2020 Eliud Cabrera Castillo <e.cabrera-castillo@tum.de> *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
@@ -21,28 +22,28 @@
# * USA *
# * *
# ***************************************************************************
"""This module provides the Draft Text view provider classes
"""
## @package text
"""Provides the Draft Text viewprovider class."""
## @package view_text
# \ingroup DRAFT
# \brief This module provides the view provider code for Draft Text.
# \brief Provides the Draft Text viewprovider class.
import pivy.coin as coin
import sys
from PySide.QtCore import QT_TRANSLATE_NOOP
import FreeCAD as App
import DraftVecUtils, DraftGeomUtils
import math, sys
from pivy import coin
from PySide.QtCore import QT_TRANSLATE_NOOP
import draftutils.utils as utils
import draftutils.gui_utils as gui_utils
from draftviewproviders.view_draft_annotation import ViewProviderDraftAnnotation
from draftviewproviders.view_draft_annotation \
import ViewProviderDraftAnnotation
param = App.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
class ViewProviderText(ViewProviderDraftAnnotation):
"""A View Provider for the Draft Text annotation"""
"""Viewprovider for the Draft Text annotation."""
def __init__(self,vobj):
def __init__(self, vobj):
super(ViewProviderText, self).__init__(vobj)
self.set_properties(vobj)
@@ -98,66 +99,76 @@ class ViewProviderText(ViewProviderDraftAnnotation):
_tip)
def getIcon(self):
"""Return the path to the icon used by the view provider."""
return ":/icons/Draft_Text.svg"
def claimChildren(self):
"""Return objects that will be placed under it in the tree view."""
return []
def attach(self,vobj):
'''Setup the scene sub-graph of the view provider'''
# backwards compatibility
self.ScaleMultiplier = 1.00
def attach(self, vobj):
"""Set up the scene sub-graph of the view provider."""
# Main attributes of the Coin scenegraph
self.mattext = coin.SoMaterial()
textdrawstyle = coin.SoDrawStyle()
textdrawstyle.style = coin.SoDrawStyle.FILLED
self.trans = coin.SoTransform()
self.font = coin.SoFont()
self.text2d = coin.SoAsciiText()
self.text3d = coin.SoText2()
self.text2d.string = self.text3d.string = "Label" # need to init with something, otherwise, crash!
self.text2d.justification = coin.SoAsciiText.LEFT
self.text3d.justification = coin.SoText2.LEFT
self.text2d = coin.SoText2() # Faces the camera always
self.text3d = coin.SoAsciiText() # Can be oriented in 3D space
textdrawstyle = coin.SoDrawStyle()
textdrawstyle.style = coin.SoDrawStyle.FILLED
# The text string needs to be initialized to something,
# otherwise it may crash
self.text2d.string = self.text3d.string = "Label"
self.text2d.justification = coin.SoText2.LEFT
self.text3d.justification = coin.SoAsciiText.LEFT
self.node2d = coin.SoGroup()
self.node2d.addChild(self.trans)
self.node2d.addChild(self.mattext)
self.node2d.addChild(textdrawstyle)
self.node2d.addChild(self.font)
self.node2d.addChild(self.text2d)
self.node3d = coin.SoGroup()
self.node3d.addChild(self.trans)
self.node3d.addChild(self.mattext)
self.node3d.addChild(textdrawstyle)
self.node3d.addChild(self.font)
self.node3d.addChild(self.text3d)
vobj.addDisplayMode(self.node2d,"2D text")
vobj.addDisplayMode(self.node3d,"3D text")
self.onChanged(vobj,"TextColor")
self.onChanged(vobj,"FontSize")
self.onChanged(vobj,"FontName")
self.onChanged(vobj,"Justification")
self.onChanged(vobj,"LineSpacing")
def getDisplayModes(self,vobj):
return ["2D text","3D text"]
vobj.addDisplayMode(self.node2d, "2D text")
vobj.addDisplayMode(self.node3d, "3D text")
self.onChanged(vobj, "TextColor")
self.onChanged(vobj, "FontSize")
self.onChanged(vobj, "FontName")
self.onChanged(vobj, "Justification")
self.onChanged(vobj, "LineSpacing")
self.onChanged(vobj, "ScaleMultiplier")
def getDisplayModes(self, vobj):
"""Return the display modes that this viewprovider supports."""
return ["2D text", "3D text"]
def setDisplayMode(self,mode):
def setDisplayMode(self, mode):
"""Return the saved display mode."""
return mode
def updateData(self, obj, prop):
"""Execute when a property from the Proxy class is changed."""
if prop == "Text" and obj.Text:
self.text2d.string.setValue("")
self.text3d.string.setValue("")
if sys.version_info.major >= 3:
_list = [l for l in obj.Text if l]
else:
_list = [l.encode("utf8") for l in obj.Text if l]
self.text2d.string.setValues(_list)
self.text3d.string.setValues(_list)
def updateData(self,obj,prop):
if prop == "Text":
if obj.Text:
if sys.version_info.major >= 3:
self.text2d.string.setValues([l for l in obj.Text if l])
self.text3d.string.setValues([l for l in obj.Text if l])
else:
self.text2d.string.setValues([l.encode("utf8") for l in obj.Text if l])
self.text3d.string.setValues([l.encode("utf8") for l in obj.Text if l])
elif prop == "Placement":
self.trans.translation.setValue(obj.Placement.Base)
self.trans.rotation.setValue(obj.Placement.Rotation.Q)
@@ -166,40 +177,51 @@ class ViewProviderText(ViewProviderDraftAnnotation):
"""Execute when a view property is changed."""
super(ViewProviderText, self).onChanged(vobj, prop)
if prop == "ScaleMultiplier":
if "ScaleMultiplier" in vobj.PropertiesList:
if vobj.ScaleMultiplier:
self.ScaleMultiplier = vobj.ScaleMultiplier
if "FontSize" in vobj.PropertiesList:
self.font.size = vobj.FontSize.Value * self.ScaleMultiplier
elif prop == "TextColor":
if "TextColor" in vobj.PropertiesList:
l = vobj.TextColor
self.mattext.diffuseColor.setValue([l[0],l[1],l[2]])
elif (prop == "FontName"):
if "FontName" in vobj.PropertiesList:
self.font.name = vobj.FontName.encode("utf8")
elif prop == "FontSize":
if "FontSize" in vobj.PropertiesList:
self.font.size = vobj.FontSize.Value * self.ScaleMultiplier
elif prop == "Justification":
try:
if getattr(vobj, "Justification", None) is not None:
if vobj.Justification == "Left":
self.text2d.justification = coin.SoAsciiText.LEFT
self.text3d.justification = coin.SoText2.LEFT
elif vobj.Justification == "Right":
self.text2d.justification = coin.SoAsciiText.RIGHT
self.text3d.justification = coin.SoText2.RIGHT
else:
self.text2d.justification = coin.SoAsciiText.CENTER
self.text3d.justification = coin.SoText2.CENTER
except AssertionError:
pass # Race condition - Justification enum has not been set yet
elif prop == "LineSpacing":
if "LineSpacing" in vobj.PropertiesList:
self.text2d.spacing = vobj.LineSpacing
self.text3d.spacing = vobj.LineSpacing
properties = vobj.PropertiesList
if (prop == "ScaleMultiplier" and "ScaleMultiplier" in properties
and vobj.ScaleMultiplier):
if "FontSize" in properties:
self.font.size = vobj.FontSize.Value * vobj.ScaleMultiplier
elif prop == "TextColor" and "TextColor" in properties:
col = vobj.TextColor
self.mattext.diffuseColor.setValue([col[0], col[1], col[2]])
elif prop == "FontName" and "FontName" in properties:
self.font.name = vobj.FontName.encode("utf8")
elif (prop == "FontSize" and "FontSize" in properties
and "ScaleMultiplier" in properties and vobj.ScaleMultiplier):
# In v0.19 this code causes an `AttributeError` exception
# during loading of the document as `ScaleMultiplier`
# apparently isn't set immediately when the document loads.
# So the if condition tests for the existance
# of `ScaleMultiplier` before even changing the font size.
# A try-except block may be used as well to catch and ignore
# this error.
self.font.size = vobj.FontSize.Value * vobj.ScaleMultiplier
elif prop == "Justification" and "Justification" in properties:
# This code was surrounded by a try-except block in order to catch
# and ignore an `AssertionError` exception. This was the result
# of a race condition that would result in the `Justification`
# property not being set at the time that this code is invoked.
# However, in v0.19 this problem doesn't seem to exist any more
# so we removed the try-except block.
if vobj.Justification == "Left":
self.text2d.justification = coin.SoText2.LEFT
self.text3d.justification = coin.SoAsciiText.LEFT
elif vobj.Justification == "Right":
self.text2d.justification = coin.SoText2.RIGHT
self.text3d.justification = coin.SoAsciiText.RIGHT
else:
self.text2d.justification = coin.SoText2.CENTER
self.text3d.justification = coin.SoAsciiText.CENTER
elif prop == "LineSpacing" and "LineSpacing" in properties:
self.text2d.spacing = vobj.LineSpacing
self.text3d.spacing = vobj.LineSpacing
# Alias for compatibility with v0.18 and earlier