historical/toontown-classic.git/panda/include/textNode.I
2024-01-16 11:20:27 -06:00

1223 lines
30 KiB
Text

/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file textNode.I
* @author drose
* @date 2002-03-13
*/
/**
* Returns the number of units high each line of text is. This is based on
* the font. Note that it is possible for the text to include nested font
* change commands, in which case the value of this method is questionable.
*/
INLINE PN_stdfloat TextNode::
get_line_height() const {
TextFont *font = get_font();
if (font == nullptr) {
return 0.0f;
}
return font->get_line_height();
}
/**
* Sets the maximum number of rows that may be formatted by the TextNode. If
* more text than this is attempted, it will be truncated and has_overflow()
* will return true.
*/
INLINE void TextNode::
set_max_rows(int max_rows) {
MutexHolder holder(_lock);
_max_rows = max_rows;
invalidate_with_measure();
}
/**
* Resets the TextNode's default behavior of not limiting the number of rows
* of text.
*/
INLINE void TextNode::
clear_max_rows() {
MutexHolder holder(_lock);
_max_rows = 0;
invalidate_with_measure();
}
/**
* Returns true if a limit on the height of the TextNode has been set via
* set_max_rows(), false otherwise.
*/
INLINE bool TextNode::
has_max_rows() const {
MutexHolder holder(_lock);
return _max_rows > 0;
}
/**
* Returns the limit on the height of the TextNode specified by
* set_max_rows().
*/
INLINE int TextNode::
get_max_rows() const {
MutexHolder holder(_lock);
return _max_rows;
}
/**
* Returns true if the last text set on the text node exceeded the max_rows
* constraint, or false if it all fit.
*/
INLINE bool TextNode::
has_overflow() const {
MutexHolder holder(_lock);
check_measure();
return (_flags & F_has_overflow) != 0;
}
/**
*
*/
INLINE void TextNode::
set_frame_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a) {
set_frame_color(LColor(r, g, b, a));
}
/**
*
*/
INLINE void TextNode::
set_frame_color(const LColor &frame_color) {
MutexHolder holder(_lock);
if (_frame_color != frame_color) {
_frame_color = frame_color;
invalidate_no_measure();
}
}
/**
*
*/
INLINE LColor TextNode::
get_frame_color() const {
MutexHolder holder(_lock);
return _frame_color;
}
/**
*
*/
INLINE void TextNode::
set_card_border(PN_stdfloat size, PN_stdfloat uv_portion) {
MutexHolder holder(_lock);
if ((_flags & F_has_card_border) == 0 || _card_border_size != size || _card_border_uv_portion != uv_portion) {
_flags |= F_has_card_border;
_card_border_size = size;
_card_border_uv_portion = uv_portion;
invalidate_no_measure();
}
}
/**
*
*/
INLINE void TextNode::
clear_card_border() {
MutexHolder holder(_lock);
if (_flags & F_has_card_border) {
_flags &= ~F_has_card_border;
invalidate_no_measure();
}
}
/**
*
*/
INLINE PN_stdfloat TextNode::
get_card_border_size() const {
MutexHolder holder(_lock);
return _card_border_size;
}
/**
*
*/
INLINE PN_stdfloat TextNode::
get_card_border_uv_portion() const {
MutexHolder holder(_lock);
return _card_border_uv_portion;
}
/**
*
*/
INLINE bool TextNode::
has_card_border() const {
MutexHolder holder(_lock);
return (_flags & F_has_card_border) != 0;
}
/**
*
*/
INLINE void TextNode::
set_card_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a) {
set_card_color(LColor(r, g, b, a));
}
/**
*
*/
INLINE void TextNode::
set_card_color(const LColor &card_color) {
MutexHolder holder(_lock);
if (_card_color != card_color) {
_card_color = card_color;
invalidate_no_measure();
}
}
/**
*
*/
INLINE LColor TextNode::
get_card_color() const {
MutexHolder holder(_lock);
return _card_color;
}
/**
*
*/
INLINE void TextNode::
set_card_texture(Texture *card_texture) {
if (card_texture == nullptr) {
clear_card_texture();
} else {
MutexHolder holder(_lock);
if ((_flags & F_has_card_texture) == 0 || _card_texture != card_texture) {
_flags |= F_has_card_texture;
_card_texture = card_texture;
invalidate_no_measure();
}
}
}
/**
*
*/
INLINE void TextNode::
clear_card_texture() {
MutexHolder holder(_lock);
if (_flags & F_has_card_texture) {
_flags &= ~F_has_card_texture;
_card_texture = nullptr;
invalidate_no_measure();
}
}
/**
*
*/
INLINE bool TextNode::
has_card_texture() const {
MutexHolder holder(_lock);
return (_flags & F_has_card_texture) != 0;
}
/**
*
*/
INLINE Texture *TextNode::
get_card_texture() const {
MutexHolder holder(_lock);
return _card_texture;
}
/**
* Specifies that a border will be drawn around the text when it is next
* created. The parameters are the amount of additional padding to insert
* between the frame and the text in each dimension, and all should generally
* be positive.
*/
INLINE void TextNode::
set_frame_as_margin(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top) {
MutexHolder holder(_lock);
_flags |= (F_has_frame | F_frame_as_margin);
_frame_ul.set(left, top);
_frame_lr.set(right, bottom);
invalidate_no_measure();
}
/**
* Similar to set_frame_as_margin, except the frame is specified in actual
* coordinate units (relative to the text's origin), irrespective of the size
* of the text. The left and bottom coordinates should generally be negative,
* while the right and top coordinates should generally be positive.
*/
INLINE void TextNode::
set_frame_actual(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top) {
MutexHolder holder(_lock);
_flags |= F_has_frame;
_flags &= ~F_frame_as_margin;
_frame_ul.set(left, top);
_frame_lr.set(right, bottom);
invalidate_no_measure();
}
/**
* Specifies that a border will not be drawn around the text.
*/
INLINE void TextNode::
clear_frame() {
MutexHolder holder(_lock);
_flags &= ~F_has_frame;
invalidate_no_measure();
}
/**
*
*/
INLINE bool TextNode::
has_frame() const {
MutexHolder holder(_lock);
return (_flags & F_has_frame) != 0;
}
/**
* If this is true, the frame was set via a call to set_frame_as_margin(), and
* the dimension of the frame as returned by get_frame_as_set() represent a
* margin all around the text. If false, then the frame was set via a call to
* set_frame_actual(), and the dimensions of the frame as returned by
* get_frame_as_set() are relative to the text's origin.
*/
INLINE bool TextNode::
is_frame_as_margin() const {
MutexHolder holder(_lock);
nassertr((_flags & F_has_frame) != 0, false);
return (_flags & F_frame_as_margin) != 0;
}
/**
* Returns the dimensions of the frame as set by set_frame_as_margin() or
* set_frame_actual(). Use is_frame_actual() to determine how to interpret
* the values returned by this function. It is an error to call this if
* has_frame() is false.
*/
INLINE LVecBase4 TextNode::
get_frame_as_set() const {
MutexHolder holder(_lock);
nassertr((_flags & F_has_frame) != 0, LVecBase4(0.0, 0.0, 0.0, 0.0));
return LVecBase4(_frame_ul[0], _frame_lr[0], _frame_lr[1], _frame_ul[1]);
}
/**
* Returns the actual dimensions of the frame around the text. If the frame
* was set via set_frame_as_margin(), the result returned by this function
* reflects the size of the current text; if the frame was set via
* set_frame_actual(), this returns the values actually set.
*
* If the text has no frame at all, this returns the dimensions of the text
* itself, as if the frame were set with a margin of 0, 0, 0, 0.
*/
INLINE LVecBase4 TextNode::
get_frame_actual() const {
MutexHolder holder(_lock);
if (_flags & F_has_frame) {
if (_flags & F_frame_as_margin) {
check_measure();
return LVecBase4(_text_ul[0] - _frame_ul[0],
_text_lr[0] + _frame_lr[0],
_text_lr[1] - _frame_lr[1],
_text_ul[1] + _frame_ul[1]);
} else {
return LVecBase4(_frame_ul[0], _frame_lr[0], _frame_lr[1], _frame_ul[1]);
}
} else {
check_measure();
return LVecBase4(_text_ul[0], _text_lr[0], _text_lr[1], _text_ul[1]);
}
}
/**
* Specifies the thickness of the lines that will be used to draw the frame.
*/
INLINE void TextNode::
set_frame_line_width(PN_stdfloat frame_width) {
MutexHolder holder(_lock);
_frame_width = frame_width;
invalidate_no_measure();
}
/**
* Returns the thickness of the lines that will be used to draw the frame.
*/
INLINE PN_stdfloat TextNode::
get_frame_line_width() const {
MutexHolder holder(_lock);
return _frame_width;
}
/**
* Enables or disables the drawing of corners for the frame. These are extra
* points drawn at each of the four corners, to soften the ugly edges
* generated when the line width is greater than one.
*/
INLINE void TextNode::
set_frame_corners(bool corners) {
MutexHolder holder(_lock);
if (corners) {
_flags |= F_frame_corners;
} else {
_flags &= ~F_frame_corners;
}
invalidate_no_measure();
}
/**
*
*/
INLINE bool TextNode::
get_frame_corners() const {
MutexHolder holder(_lock);
return (_flags & F_frame_corners) != 0;
}
/**
* Specifies that a (possibly opaque or semitransparent) card will be held
* behind the text when it is next created. Like set_frame_as_margin, the
* parameters are the amount of additional padding to insert around the text
* in each dimension, and all should generally be positive.
*/
INLINE void TextNode::
set_card_as_margin(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top) {
MutexHolder holder(_lock);
_flags |= (F_has_card | F_card_as_margin);
_card_ul.set(left, top);
_card_lr.set(right, bottom);
invalidate_no_measure();
}
/**
* Similar to set_card_as_margin, except the card is specified in actual
* coordinate units (relative to the text's origin), irrespective of the size
* of the text. The left and bottom coordinates should generally be negative,
* while the right and top coordinates should generally be positive.
*/
INLINE void TextNode::
set_card_actual(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top) {
MutexHolder holder(_lock);
_flags |= F_has_card;
_flags &= ~F_card_as_margin;
_card_ul.set(left, top);
_card_lr.set(right, bottom);
invalidate_no_measure();
}
/**
* Sets the card_decal flag. When this is true, the text is decalled onto the
* card, which is necessary if the TextNode is to be rendered in the 3-d world
* without putting it in a bin.
*/
INLINE void TextNode::
set_card_decal(bool card_decal) {
MutexHolder holder(_lock);
if (card_decal) {
_flags |= F_card_decal;
} else {
_flags &= ~F_card_decal;
}
invalidate_no_measure();
}
/**
* Specifies that a card will not be drawn behind the text.
*/
INLINE void TextNode::
clear_card() {
MutexHolder holder(_lock);
_flags &= ~F_has_card;
invalidate_no_measure();
}
/**
*
*/
INLINE bool TextNode::
has_card() const {
MutexHolder holder(_lock);
return (_flags & F_has_card) != 0;
}
/**
* Returns the card_decal flag. See set_card_decal().
*/
INLINE bool TextNode::
get_card_decal() const {
MutexHolder holder(_lock);
return (_flags & F_card_decal) != 0;
}
/**
* If this is true, the card was set via a call to set_card_as_margin(), and
* the dimension of the card as returned by get_card_as_set() represent a
* margin all around the text. If false, then the card was set via a call to
* set_card_actual(), and the dimensions of the card as returned by
* get_card_as_set() are relative to the text's origin.
*/
INLINE bool TextNode::
is_card_as_margin() const {
MutexHolder holder(_lock);
nassertr((_flags & F_has_card) != 0, false);
return (_flags & F_card_as_margin) != 0;
}
/**
* Returns the dimensions of the card as set by set_card_as_margin() or
* set_card_actual(). Use is_card_actual() to determine how to interpret the
* values returned by this function. It is an error to call this if
* has_card() is false.
*/
INLINE LVecBase4 TextNode::
get_card_as_set() const {
MutexHolder holder(_lock);
nassertr((_flags & F_has_card) != 0, LVecBase4(0.0, 0.0, 0.0, 0.0));
return LVecBase4(_card_ul[0], _card_lr[0], _card_lr[1], _card_ul[1]);
}
/**
* Returns the actual dimensions of the card around the text. If the card was
* set via set_card_as_margin(), the result returned by this function reflects
* the size of the current text; if the card was set via set_card_actual(),
* this returns the values actually set.
*
* If the text has no card at all, this returns the dimensions of the text
* itself, as if the card were set with a margin of 0, 0, 0, 0.
*/
INLINE LVecBase4 TextNode::
get_card_actual() const {
MutexHolder holder(_lock);
if (_flags & F_has_card) {
if (_flags & F_card_as_margin) {
check_measure();
return LVecBase4(_text_ul[0] - _card_ul[0],
_text_lr[0] + _card_lr[0],
_text_lr[1] - _card_lr[1],
_text_ul[1] + _card_ul[1]);
} else {
return LVecBase4(_card_ul[0], _card_lr[0], _card_lr[1], _card_ul[1]);
}
} else {
check_measure();
return LVecBase4(_text_ul[0], _text_lr[0], _text_lr[1], _text_ul[1]);
}
}
/**
* Returns the actual card dimensions, transformed by the matrix set by
* set_transform(). This returns the card dimensions in actual coordinates as
* seen by the rest of the world. Also see get_upper_left_3d() and
* get_lower_right_3d().
*/
INLINE LVecBase4 TextNode::
get_card_transformed() const {
LVecBase4 card = get_card_actual();
MutexHolder holder(_lock);
LPoint3 ul = LPoint3(card[0], 0.0, card[3]) * _transform;
LPoint3 lr = LPoint3(card[1], 0.0, card[2]) * _transform;
return LVecBase4(ul[0], lr[0], lr[2], ul[2]);
}
/**
* Sets an additional transform that is applied to the entire text paragraph.
*/
INLINE void TextNode::
set_transform(const LMatrix4 &transform) {
MutexHolder holder(_lock);
_transform = transform;
invalidate_with_measure();
}
/**
*
*/
INLINE LMatrix4 TextNode::
get_transform() const {
MutexHolder holder(_lock);
return _transform;
}
/**
* Specifies the coordinate system in which the text will be generated.
*/
INLINE void TextNode::
set_coordinate_system(CoordinateSystem coordinate_system) {
MutexHolder holder(_lock);
_coordinate_system = coordinate_system;
invalidate_with_measure();
}
/**
*
*/
INLINE CoordinateSystem TextNode::
get_coordinate_system() const {
MutexHolder holder(_lock);
return _coordinate_system;
}
/**
* Specifies the UsageHint that will be applied to generated geometry. The
* default is UH_static, which is probably the right setting, but if you know
* the TextNode's geometry will have a short lifespan, it may be better to set
* it to UH_stream. See geomEnums.h.
*/
INLINE void TextNode::
set_usage_hint(Geom::UsageHint usage_hint) {
MutexHolder holder(_lock);
_usage_hint = usage_hint;
invalidate_no_measure();
}
/**
* Returns the UsageHint that will be applied to generated geometry. See
* set_usage_hint().
*/
INLINE Geom::UsageHint TextNode::
get_usage_hint() const {
MutexHolder holder(_lock);
return _usage_hint;
}
/**
* Sets the flatten flags. This should be a union of the
* TextNode::FlattenFlags options. This controls the degree of flattening
* performed on the TextNode's internal geometry (i.e. the scene graph
* returned by generate()) each time the text is changed. In general, more
* flattening means a more optimal result, but it will take more time to
* generate.
*
* The choice may be any of these three:
*
* FF_none - No flatten operation is called. The letters are left as
* independent Geoms.
*
* FF_light - A flatten_light() operation is called. The attributes are
* applied to the vertices, but no nodes are removed.
*
* FF_medium - A flatten_medium() operation is called. The attributes are
* applied to the vertices, and a few trivial nodes are removed.
*
* FF_strong - A flatten_strong() operation is called. The attributes are
* applied to the vertices, and the resulting nodes are aggressively combined
* into as few nodes as possible.
*
* In addition to the above choices, you may optionally include the following
* flag:
*
* FF_dynamic_merge - Copy the geoms into a single GeomVertexData as we go,
* instead of relying on the flatten operation at the end. This pre-flattens
* the text considerably, and may obviate the need for flatten altogether; it
* also tends to improve performance considerably even if you do call flatten.
* However, it is not as fast as not calling flatten at all.
*
* The default is taken from the text-flatten and text-dynamic-merge config
* variables.
*/
INLINE void TextNode::
set_flatten_flags(int flatten_flags) {
MutexHolder holder(_lock);
_flatten_flags = flatten_flags;
}
/**
* Returns the flatten flags. See set_flatten_flags().
*/
INLINE int TextNode::
get_flatten_flags() const {
MutexHolder holder(_lock);
return _flatten_flags;
}
/**
* Sets the font that will be used when making text. If this is set to NULL,
* the default font will be used, which can be set via set_default_font().
*/
INLINE void TextNode::
set_font(TextFont *font) {
MutexHolder holder(_lock);
TextProperties::set_font(font);
invalidate_with_measure();
}
/**
* Resets the font to the default font.
*/
INLINE void TextNode::
clear_font() {
MutexHolder holder(_lock);
TextProperties::clear_font();
invalidate_with_measure();
}
/**
* Sets the small_caps flag. When this is set, lowercase letters are
* generated as scaled-down versions of their uppercase equivalents. This is
* particularly useful to set for fonts that do not have lowercase letters.
*
* It is also a good idea to set this for a (dynamic) font that has already
* implemented lowercase letters as scaled-down versions of their uppercase
* equivalents, since without this flag the texture memory may needlessly
* duplicate equivalent glyphs for upper and lowercase letters. Setting this
* flag causes the texture memory to share the mixed-case letters.
*
* The amount by which the lowercase letters are scaled is specified by
* set_small_caps_scale().
*/
INLINE void TextNode::
set_small_caps(bool small_caps) {
MutexHolder holder(_lock);
TextProperties::set_small_caps(small_caps);
invalidate_with_measure();
}
/**
*
*/
INLINE void TextNode::
clear_small_caps() {
MutexHolder holder(_lock);
TextProperties::clear_small_caps();
invalidate_with_measure();
}
/**
* Sets the scale factor applied to lowercase letters from their uppercase
* equivalents, when the small_caps flag is in effect. See set_small_caps().
* Normally, this will be a number less than one.
*/
INLINE void TextNode::
set_small_caps_scale(PN_stdfloat small_caps_scale) {
MutexHolder holder(_lock);
TextProperties::set_small_caps_scale(small_caps_scale);
invalidate_with_measure();
}
/**
*
*/
INLINE void TextNode::
clear_small_caps_scale() {
MutexHolder holder(_lock);
TextProperties::clear_small_caps_scale();
invalidate_with_measure();
}
/**
*
*/
INLINE void TextNode::
set_slant(PN_stdfloat slant) {
MutexHolder holder(_lock);
TextProperties::set_slant(slant);
invalidate_with_measure();
}
/**
*
*/
INLINE void TextNode::
clear_slant() {
MutexHolder holder(_lock);
TextProperties::clear_slant();
invalidate_with_measure();
}
/**
*
*/
INLINE void TextNode::
set_align(TextNode::Alignment align_type) {
MutexHolder holder(_lock);
TextProperties::set_align(align_type);
invalidate_with_measure();
}
/**
*
*/
INLINE void TextNode::
clear_align() {
MutexHolder holder(_lock);
TextProperties::clear_align();
invalidate_with_measure();
}
/**
* Specifies the amount of extra space that is inserted before the first
* character of each line. This can be thought of as a left margin.
*/
INLINE void TextNode::
set_indent(PN_stdfloat indent) {
MutexHolder holder(_lock);
TextProperties::set_indent(indent);
invalidate_with_measure();
}
/**
*
*/
INLINE void TextNode::
clear_indent() {
MutexHolder holder(_lock);
TextProperties::clear_indent();
invalidate_with_measure();
}
/**
* Sets the text up to automatically wordwrap when it exceeds the indicated
* width. This can be thought of as a right margin or margin width.
*/
INLINE void TextNode::
set_wordwrap(PN_stdfloat wordwrap) {
MutexHolder holder(_lock);
TextProperties::set_wordwrap(wordwrap);
invalidate_with_measure();
}
/**
* Removes the wordwrap setting from the TextNode. Text will be as wide as it
* is.
*/
INLINE void TextNode::
clear_wordwrap() {
MutexHolder holder(_lock);
TextProperties::clear_wordwrap();
invalidate_with_measure();
}
/**
*
*/
INLINE void TextNode::
set_text_color(const LColor &text_color) {
MutexHolder holder(_lock);
TextProperties::set_text_color(text_color);
invalidate_no_measure();
}
/**
*
*/
INLINE void TextNode::
set_text_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a) {
set_text_color(LColor(r, g, b, a));
}
/**
* Removes the text color specification; the text will be colored whatever it
* was in the source font file.
*/
INLINE void TextNode::
clear_text_color() {
MutexHolder holder(_lock);
TextProperties::clear_text_color();
invalidate_no_measure();
}
/**
*
*/
INLINE void TextNode::
set_shadow_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a) {
set_shadow_color(LColor(r, g, b, a));
}
/**
*
*/
INLINE void TextNode::
set_shadow_color(const LColor &shadow_color) {
MutexHolder holder(_lock);
TextProperties::set_shadow_color(shadow_color);
invalidate_no_measure();
}
/**
*
*/
INLINE void TextNode::
clear_shadow_color() {
MutexHolder holder(_lock);
TextProperties::clear_shadow_color();
invalidate_with_measure();
}
/**
* Specifies that the text should be drawn with a shadow, by creating a second
* copy of the text and offsetting it slightly behind the first.
*/
INLINE void TextNode::
set_shadow(PN_stdfloat xoffset, PN_stdfloat yoffset) {
set_shadow(LVecBase2(xoffset, yoffset));
}
/**
* Specifies that the text should be drawn with a shadow, by creating a second
* copy of the text and offsetting it slightly behind the first.
*/
INLINE void TextNode::
set_shadow(const LVecBase2 &shadow_offset) {
MutexHolder holder(_lock);
TextProperties::set_shadow(shadow_offset);
invalidate_no_measure();
}
/**
* Specifies that a shadow will not be drawn behind the text.
*/
INLINE void TextNode::
clear_shadow() {
MutexHolder holder(_lock);
TextProperties::clear_shadow();
invalidate_no_measure();
}
/**
* Names the GeomBin that the TextNode geometry should be assigned to. If
* this is set, then a GeomBinTransition will be created to explicitly place
* each component in the named bin.
*
* The draw_order value will also be passed to each GeomBinTransition as
* appropriate; this is particularly useful if this names a GeomBinFixed, e.g.
* "fixed".
*/
INLINE void TextNode::
set_bin(const std::string &bin) {
MutexHolder holder(_lock);
TextProperties::set_bin(bin);
invalidate_no_measure();
}
/**
* Removes the effect of a previous call to set_bin(). Text will be drawn in
* whatever bin it would like to be drawn in, with no explicit ordering.
*/
INLINE void TextNode::
clear_bin() {
MutexHolder holder(_lock);
TextProperties::clear_bin();
invalidate_no_measure();
}
/**
* Sets the drawing order of text created by the TextMaker. This is actually
* the draw order of the card and frame. The shadow is drawn at
* _draw_order+1, and the text at _draw_order+2.
*
* This affects the sorting order assigned to the arcs as they are created,
* and also is passed to whatever bin may be assigned via set_bin().
*
* The return value is the first unused draw_order number, e.g. _draw_order +
* 3.
*/
INLINE int TextNode::
set_draw_order(int draw_order) {
MutexHolder holder(_lock);
invalidate_no_measure();
return TextProperties::set_draw_order(draw_order);
}
/**
*
*/
INLINE void TextNode::
clear_draw_order() {
MutexHolder holder(_lock);
TextProperties::clear_draw_order();
invalidate_with_measure();
}
/**
* Sets the width of each tab stop, in screen units. A tab character embedded
* in the text will advance the horizontal position to the next tab stop.
*/
INLINE void TextNode::
set_tab_width(PN_stdfloat tab_width) {
MutexHolder holder(_lock);
TextProperties::set_tab_width(tab_width);
invalidate_with_measure();
}
/**
*
*/
INLINE void TextNode::
clear_tab_width() {
MutexHolder holder(_lock);
TextProperties::clear_tab_width();
invalidate_with_measure();
}
/**
* Specifies the factor by which to scale each letter of the text as it is
* placed. This can be used (possibly in conjunction with set_glyph_shift())
* to implement superscripting or subscripting.
*/
INLINE void TextNode::
set_glyph_scale(PN_stdfloat glyph_scale) {
MutexHolder holder(_lock);
TextProperties::set_glyph_scale(glyph_scale);
invalidate_with_measure();
}
/**
*
*/
INLINE void TextNode::
clear_glyph_scale() {
MutexHolder holder(_lock);
TextProperties::clear_glyph_scale();
invalidate_with_measure();
}
/**
* Specifies a vertical amount to shift each letter of the text as it is
* placed. This can be used (possibly in conjunction with set_glyph_scale())
* to implement superscripting or subscripting.
*/
INLINE void TextNode::
set_glyph_shift(PN_stdfloat glyph_shift) {
MutexHolder holder(_lock);
TextProperties::set_glyph_shift(glyph_shift);
invalidate_with_measure();
}
/**
*
*/
INLINE void TextNode::
clear_glyph_shift() {
MutexHolder holder(_lock);
TextProperties::clear_glyph_shift();
invalidate_with_measure();
}
/**
* Returns a string that represents the contents of the text, as it has been
* formatted by wordwrap rules.
*
* In earlier versions, this did not contain any embedded special characters
* like \1 or \3; now it does.
*/
INLINE std::string TextNode::
get_wordwrapped_text() const {
return encode_wtext(get_wordwrapped_wtext());
}
/**
* Returns the width of a line of text of arbitrary characters. The line
* should not include the newline character.
*/
INLINE PN_stdfloat TextNode::
calc_width(const std::string &line) const {
return calc_width(decode_text(line));
}
/**
* Returns a wstring that represents the contents of the text, as it has been
* formatted by wordwrap rules.
*
* In earlier versions, this did not contain any embedded special characters
* like \1 or \3; now it does.
*/
INLINE std::wstring TextNode::
get_wordwrapped_wtext() const {
MutexHolder holder(_lock);
check_measure();
return _wordwrapped_wtext;
}
/**
* Returns the leftmost extent of the text in local 2-d coordinates,
* unmodified by the set_transform() matrix.
*/
INLINE PN_stdfloat TextNode::
get_left() const {
MutexHolder holder(_lock);
check_measure();
return _text_ul[0];
}
/**
* Returns the rightmost extent of the text in local 2-d coordinates,
* unmodified by the set_transform() matrix.
*/
INLINE PN_stdfloat TextNode::
get_right() const {
MutexHolder holder(_lock);
check_measure();
return _text_lr[0];
}
/**
* Returns the bottommost extent of the text in local 2-d coordinates,
* unmodified by the set_transform() matrix.
*/
INLINE PN_stdfloat TextNode::
get_bottom() const {
MutexHolder holder(_lock);
check_measure();
return _text_lr[1];
}
/**
* Returns the topmost extent of the text in local 2-d coordinates, unmodified
* by the set_transform() matrix.
*/
INLINE PN_stdfloat TextNode::
get_top() const {
MutexHolder holder(_lock);
check_measure();
return _text_ul[1];
}
/**
* Returns the net height of the text in local 2-d coordinates.
*/
INLINE PN_stdfloat TextNode::
get_height() const {
MutexHolder holder(_lock);
check_measure();
return _text_ul[1] - _text_lr[1];
}
/**
* Returns the net width of the text in local 2-d coordinates.
*/
INLINE PN_stdfloat TextNode::
get_width() const {
MutexHolder holder(_lock);
check_measure();
return _text_lr[0] - _text_ul[0];
}
/**
* Returns the upper-left extent of the text object, after it has been
* transformed into 3-d space by applying the set_transform() matrix.
*/
INLINE LPoint3 TextNode::
get_upper_left_3d() const {
MutexHolder holder(_lock);
check_measure();
return _ul3d;
}
/**
* Returns the lower-right extent of the text object, after it has been
* transformed into 3-d space by applying the set_transform() matrix.
*/
INLINE LPoint3 TextNode::
get_lower_right_3d() const {
MutexHolder holder(_lock);
check_measure();
return _lr3d;
}
/**
* Returns the number of rows of text that were generated. This counts word-
* wrapped rows as well as rows generated due to embedded newlines.
*/
INLINE int TextNode::
get_num_rows() const {
MutexHolder holder(_lock);
check_measure();
return _num_rows;
}
/**
* Generates the text, according to the parameters indicated within the
* TextNode, and returns a Node that may be parented within the tree to
* represent it.
*/
PT(PandaNode) TextNode::
generate() {
MutexHolder holder(_lock);
return do_generate();
}
/**
* Can be called after the TextNode has been fully configured, to force the
* node to recompute its text immediately, rather than waiting for it to be
* drawn. This call is optional.
*/
INLINE void TextNode::
update() {
MutexHolder holder(_lock);
check_rebuild();
}
/**
* Forces the TextNode to recompute itself now, even if it believes nothing
* has changed. Normally, this should not need to be called, but it may be
* useful if some properties change outside of the TextNode's knowledge (for
* instance, within the font).
*/
INLINE void TextNode::
force_update() {
MutexHolder holder(_lock);
mark_internal_bounds_stale();
do_rebuild();
}
/**
* Called internally whenever some state on the TextNode changes, requiring
* the internal geometry to be recomputed, but which will not result in a
* change in the size or shape of the text (for instance, the text color
* changes).
*/
INLINE void TextNode::
invalidate_no_measure() {
_flags |= F_needs_rebuild;
}
/**
* Called internally whenever some state on the TextNode changes, requiring
* the internal geometry to be recomputed, and which will may result in a
* change in the size or shape of the text (for instance, the text scale
* changes).
*/
INLINE void TextNode::
invalidate_with_measure() {
_flags |= (F_needs_rebuild | F_needs_measure);
mark_internal_bounds_stale();
}
/**
* Called internally to call do_rebuild() if necessary (that is, if the
* internal geometry has changed recently).
*/
INLINE void TextNode::
check_rebuild() const {
if ((_flags & F_needs_rebuild) != 0) {
((TextNode *)this)->do_rebuild();
}
}
/**
* Called internally to call do_measure() if necessary; this will remeasure
* the text without necessarily rebuilding it.
*/
INLINE void TextNode::
check_measure() const {
if ((_flags & F_needs_measure) != 0) {
((TextNode *)this)->do_measure();
}
}