diff --git a/panda/src/express/textEncoder.I b/panda/src/express/textEncoder.I index 8251dbb8ab..f015d3e059 100644 --- a/panda/src/express/textEncoder.I +++ b/panda/src/express/textEncoder.I @@ -32,6 +32,20 @@ TextEncoder() { _flags = (F_got_text | F_got_wtext); } +//////////////////////////////////////////////////////////////////// +// Function: TextEncoder::Copy Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE TextEncoder:: +TextEncoder(const TextEncoder ©) : + _flags(copy._flags), + _encoding(copy._encoding), + _text(copy._text), + _wtext(copy._wtext) +{ +} + //////////////////////////////////////////////////////////////////// // Function: TextEncoder::set_encoding // Access: Published diff --git a/panda/src/express/textEncoder.h b/panda/src/express/textEncoder.h index e666bf06a5..9f5ba8bf36 100644 --- a/panda/src/express/textEncoder.h +++ b/panda/src/express/textEncoder.h @@ -47,6 +47,7 @@ PUBLISHED: }; INLINE TextEncoder(); + INLINE TextEncoder(const TextEncoder ©); INLINE void set_encoding(Encoding encoding); INLINE Encoding get_encoding() const; diff --git a/panda/src/pgui/pgButton.cxx b/panda/src/pgui/pgButton.cxx index f936e03a29..8384dcd1a6 100644 --- a/panda/src/pgui/pgButton.cxx +++ b/panda/src/pgui/pgButton.cxx @@ -57,7 +57,8 @@ PGButton:: //////////////////////////////////////////////////////////////////// PGButton:: PGButton(const PGButton ©) : - PGItem(copy) + PGItem(copy), + _click_buttons(copy._click_buttons) { _button_down = false; } diff --git a/panda/src/pgui/pgItem.I b/panda/src/pgui/pgItem.I index ed37b0dda4..6877b9e436 100644 --- a/panda/src/pgui/pgItem.I +++ b/panda/src/pgui/pgItem.I @@ -552,3 +552,14 @@ compare_largest(const LVecBase4f *&largest, float &largest_area, largest_area = new_area; } } + +//////////////////////////////////////////////////////////////////// +// Function: PGItem::StateDef::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PGItem::StateDef:: +StateDef() : + _frame_stale(true) +{ +} diff --git a/panda/src/pgui/pgItem.cxx b/panda/src/pgui/pgItem.cxx index 27ad5dbcfd..932a5d5831 100644 --- a/panda/src/pgui/pgItem.cxx +++ b/panda/src/pgui/pgItem.cxx @@ -100,10 +100,34 @@ PGItem(const PGItem ©) : _has_frame(copy._has_frame), _frame(copy._frame), _state(copy._state), - _flags(copy._flags) + _flags(copy._flags), + _sounds(copy._sounds) { _notify = NULL; _region = new PGMouseWatcherRegion(this); + + // We give our region the same name as the region for the PGItem + // we're copying--so that this PGItem will generate the same event + // names when the user interacts with it. + _region->set_name(copy._region->get_name()); + + // Make a deep copy of all of the original PGItem's StateDefs. + size_t num_state_defs = copy._state_defs.size(); + _state_defs.reserve(num_state_defs); + for (size_t i = 0; i < num_state_defs; ++i) { + // We cheat and cast away the const, because the frame is just a + // cache. But we have to get the frame out of the source before we + // can safely copy it. + StateDef &old_sd = (StateDef &)(copy._state_defs[i]); + old_sd._frame.remove_node(); + old_sd._frame_stale = true; + + StateDef new_sd; + new_sd._root = old_sd._root.copy_to(NodePath()); + new_sd._frame_style = old_sd._frame_style; + + _state_defs.push_back(new_sd); + } } //////////////////////////////////////////////////////////////////// @@ -1135,9 +1159,7 @@ frame_changed() { void PGItem:: slot_state_def(int state) { while (state >= (int)_state_defs.size()) { - StateDef def; - def._frame_stale = true; - _state_defs.push_back(def); + _state_defs.push_back(StateDef()); } } diff --git a/panda/src/pgui/pgItem.h b/panda/src/pgui/pgItem.h index cc34b6a38d..a672d9cdd2 100644 --- a/panda/src/pgui/pgItem.h +++ b/panda/src/pgui/pgItem.h @@ -207,6 +207,7 @@ private: class StateDef { public: + INLINE StateDef(); NodePath _root; PGFrameStyle _frame_style; NodePath _frame; diff --git a/panda/src/text/Sources.pp b/panda/src/text/Sources.pp index c9e9de00cb..402904733f 100644 --- a/panda/src/text/Sources.pp +++ b/panda/src/text/Sources.pp @@ -23,6 +23,7 @@ textAssembler.I textAssembler.h \ textFont.I textFont.h \ textGlyph.I textGlyph.h \ + textGraphic.I textGraphic.h \ textNode.I textNode.h \ textProperties.I textProperties.h \ textPropertiesManager.I textPropertiesManager.h @@ -38,6 +39,7 @@ staticTextFont.cxx \ textAssembler.cxx \ textFont.cxx textGlyph.cxx \ + textGraphic.cxx \ textNode.cxx \ textProperties.cxx \ textPropertiesManager.cxx @@ -53,6 +55,7 @@ textAssembler.I textAssembler.h \ textFont.I textFont.h \ textGlyph.I textGlyph.h \ + textGraphic.I textGraphic.h \ textNode.I textNode.h \ textProperties.I textProperties.h \ textPropertiesManager.I textPropertiesManager.h diff --git a/panda/src/text/config_text.cxx b/panda/src/text/config_text.cxx index 521abc708e..b0a66b1bdc 100644 --- a/panda/src/text/config_text.cxx +++ b/panda/src/text/config_text.cxx @@ -118,6 +118,13 @@ ConfigVariableInt text_soft_break_key "when it is used as a break point, no character is " "introduced in its place.")); +ConfigVariableInt text_embed_graphic_key +("text-embed-graphic-key", 5, + PRC_DESC("This is the decimal character number that, embedded in " + "a string, is used to bracket the name of a model " + "added to the TextPropertiesManager object, to " + "embed an arbitrary graphic image within a paragraph.")); + wstring get_text_soft_hyphen_output() { static wstring *text_soft_hyphen_output = NULL; diff --git a/panda/src/text/config_text.h b/panda/src/text/config_text.h index 6f2de921ca..c7b44a418b 100644 --- a/panda/src/text/config_text.h +++ b/panda/src/text/config_text.h @@ -45,6 +45,7 @@ extern ConfigVariableInt text_push_properties_key; extern ConfigVariableInt text_pop_properties_key; extern ConfigVariableInt text_soft_hyphen_key; extern ConfigVariableInt text_soft_break_key; +extern ConfigVariableInt text_embed_graphic_key; extern wstring get_text_soft_hyphen_output(); extern ConfigVariableDouble text_hyphen_ratio; extern wstring get_text_never_break_before(); diff --git a/panda/src/text/textAssembler.I b/panda/src/text/textAssembler.I index ab950d4bb2..673b52f578 100644 --- a/panda/src/text/textAssembler.I +++ b/panda/src/text/textAssembler.I @@ -84,7 +84,11 @@ get_num_rows() const { //////////////////////////////////////////////////////////////////// INLINE float TextAssembler:: calc_width(const TextCharacter &tch) { - return calc_width(tch._character, *tch._properties); + if (tch._graphic != (TextGraphic *)NULL) { + return calc_width(tch._graphic, *tch._properties); + } else { + return calc_width(tch._character, *tch._properties); + } } //////////////////////////////////////////////////////////////////// @@ -95,6 +99,20 @@ calc_width(const TextCharacter &tch) { INLINE TextAssembler::TextCharacter:: TextCharacter(wchar_t character, const TextProperties *properties) : _character(character), + _graphic(NULL), + _properties(properties) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: TextAssembler::TextCharacter::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE TextAssembler::TextCharacter:: +TextCharacter(const TextGraphic *graphic, const TextProperties *properties) : + _character(0), + _graphic(graphic), _properties(properties) { } diff --git a/panda/src/text/textAssembler.cxx b/panda/src/text/textAssembler.cxx index 800d5a80d8..893089abda 100644 --- a/panda/src/text/textAssembler.cxx +++ b/panda/src/text/textAssembler.cxx @@ -177,7 +177,9 @@ get_wordwrapped_wtext() const { for (ti = _wordwrapped_string.begin(); ti != _wordwrapped_string.end(); ++ti) { - wtext += (*ti)._character; + if ((*ti)._graphic != (TextGraphic *)NULL) { + wtext += (*ti)._character; + } } return wtext; @@ -203,8 +205,13 @@ assemble_text() { // and put them under a common node. PT(PandaNode) parent_node = new PandaNode("common"); - PT(GeomNode) shadow_node = new GeomNode("shadow"); - PT(GeomNode) text_node = new GeomNode("text"); + PT(PandaNode) shadow_node = new PandaNode("shadow"); + PT(GeomNode) shadow_geom_node = new GeomNode("shadow_geom"); + shadow_node->add_child(shadow_geom_node); + + PT(PandaNode) text_node = new PandaNode("text"); + PT(GeomNode) text_geom_node = new GeomNode("text_geom"); + text_node->add_child(text_geom_node); const TextProperties *properties = NULL; CPT(RenderState) text_state; @@ -256,16 +263,18 @@ assemble_text() { // goes, while the place-text function just stomps on the // vertices. if (properties->has_shadow()) { - placement->assign_copy_to(shadow_node, shadow_state, shadow_xform); + placement->assign_copy_to(shadow_geom_node, shadow_state, shadow_xform); + placement->copy_graphic_to(shadow_node, shadow_state, shadow_xform); any_shadow = true; } - placement->assign_to(text_node, text_state); + placement->assign_to(text_geom_node, text_state); + placement->copy_graphic_to(text_node, text_state, LMatrix4f::ident_mat()); delete placement; } placed_glyphs.clear(); if (any_shadow) { - // The shadow_node must appear first to guarantee the correct + // The shadow_geom_node must appear first to guarantee the correct // rendering order. parent_node->add_child(shadow_node); } @@ -316,6 +325,17 @@ calc_width(wchar_t character, const TextProperties &properties) { return advance * glyph_scale; } +//////////////////////////////////////////////////////////////////// +// Function: TextAssembler::calc_width +// Access: Private, Static +// Description: Returns the width of a single TextGraphic image. +//////////////////////////////////////////////////////////////////// +float TextAssembler:: +calc_width(const TextGraphic *graphic, const TextProperties &properties) { + LVecBase4f frame = graphic->get_frame(); + return (frame[1] - frame[0]) * properties.get_glyph_scale(); +} + //////////////////////////////////////////////////////////////////// // Function: TextAssembler::scan_wtext // Access: Private @@ -368,7 +388,13 @@ scan_wtext(wstring::const_iterator &si, // Define the new properties by extending the current properties. TextProperties *new_properties = new TextProperties(*current_properties); - new_properties->add_properties(manager->get_properties(name)); + const TextProperties *named_props = manager->get_properties_ptr(name); + if (named_props != (TextProperties *)NULL) { + new_properties->add_properties(*named_props); + } else { + text_cat.warning() + << "Unknown TextProperties: " << name << "\n"; + } _properties_list.push_back(new_properties); // And recursively scan with the nested properties. @@ -390,6 +416,45 @@ scan_wtext(wstring::const_iterator &si, ++si; return; + } else if ((*si) == text_embed_graphic_key) { + // This indicates an embedded graphic. Pull off the name of the + // TextGraphic structure, which is everything until the next + // text_embed_graphic_key. + + wstring wname; + ++si; + while (si != send && (*si) != text_embed_graphic_key) { + wname += (*si); + ++si; + } + + if (si == send) { + // We didn't close the text_embed_graphic_key. That's an + // error. + text_cat.warning() + << "Unclosed embed_graphic in text.\n"; + return; + } + + ++si; + + // Now we have to encode the wstring into a string, for lookup + // in the TextPropertiesManager. + string name = _encoder->encode_wtext(wname); + + TextPropertiesManager *manager = + TextPropertiesManager::get_global_ptr(); + + // Get the graphic image. + const TextGraphic *named_graphic = manager->get_graphic_ptr(name); + if (named_graphic != (TextGraphic *)NULL) { + text_string.push_back(TextCharacter(named_graphic, current_properties)); + + } else { + text_cat.warning() + << "Unknown TextGraphic: " << name << "\n"; + } + } else { // A normal character. Apply it. text_string.push_back(TextCharacter(*si, current_properties)); @@ -771,6 +836,7 @@ assemble_row(TextAssembler::TextString::const_iterator &si, while (si != send) { wchar_t character = (*si)._character; + const TextGraphic *graphic = (*si)._graphic; const TextProperties *properties = (*si)._properties; TextFont *font = properties->get_font(); @@ -782,7 +848,12 @@ assemble_row(TextAssembler::TextString::const_iterator &si, // And the height of the row is the maximum of all the fonts used // within the row. - line_height = max(line_height, font->get_line_height()); + if (graphic != (TextGraphic *)NULL) { + LVecBase4f frame = graphic->get_frame(); + line_height = max(line_height, frame[3] - frame[2]); + } else { + line_height = max(line_height, font->get_line_height()); + } if (character == '\n') { // The newline character marks the end of the row. @@ -803,6 +874,38 @@ assemble_row(TextAssembler::TextString::const_iterator &si, } else if (character == text_soft_hyphen_key) { // And so is the 'soft-hyphen' key character. + } else if (graphic != (TextGraphic *)NULL) { + // A special embedded graphic. + GlyphPlacement *placement = new GlyphPlacement; + row_placed_glyphs.push_back(placement); + + placement->_graphic_model = graphic->get_model().node(); + + LVecBase4f frame = graphic->get_frame(); + float glyph_scale = properties->get_glyph_scale(); + + float advance = (frame[1] - frame[0]); + + // Now compute the matrix that will transform the glyph (or + // glyphs) into position. + LMatrix4f glyph_xform = LMatrix4f::scale_mat(glyph_scale); + + glyph_xform(3, 0) += (xpos - frame[0]); + glyph_xform(3, 2) += (properties->get_glyph_shift() - frame[2]); + + if (properties->has_slant()) { + LMatrix4f shear(1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + properties->get_slant(), 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + glyph_xform = shear * glyph_xform; + } + + placement->_xform = glyph_xform; + placement->_properties = properties; + + xpos += advance * glyph_scale; + } else { // A printable character. bool got_glyph; @@ -1482,5 +1585,27 @@ assign_copy_to(GeomNode *geom_node, const RenderState *state, } } +//////////////////////////////////////////////////////////////////// +// Function: TextAssembler::GlyphPlacement::copy_graphic_to +// Access: Private +// Description: If the GlyphPlacement includes a special graphic, +// copies it to the indicated node. +//////////////////////////////////////////////////////////////////// +void TextAssembler::GlyphPlacement:: +copy_graphic_to(PandaNode *node, const RenderState *state, + const LMatrix4f &extra_xform) const { + if (_graphic_model != (PandaNode *)NULL) { + LMatrix4f new_xform = _xform * extra_xform; + + // We need an intermediate node to hold the transform and state. + PT(PandaNode) intermediate_node = new PandaNode(""); + node->add_child(intermediate_node); + + intermediate_node->set_transform(TransformState::make_mat(new_xform)); + intermediate_node->set_state(state); + intermediate_node->add_child(_graphic_model->copy_subgraph()); + } +} + #endif // CPPPARSER diff --git a/panda/src/text/textAssembler.h b/panda/src/text/textAssembler.h index c2144bd5fe..4b66d9d0c8 100644 --- a/panda/src/text/textAssembler.h +++ b/panda/src/text/textAssembler.h @@ -31,6 +31,7 @@ #include "geom.h" class TextEncoder; +class TextGraphic; //////////////////////////////////////////////////////////////////// // Class : TextAssembler @@ -63,6 +64,7 @@ public: INLINE const LVector2f &get_lr() const; static float calc_width(wchar_t character, const TextProperties &properties); + static float calc_width(const TextGraphic *graphic, const TextProperties &properties); private: // These structures are built up and operated on by scan_wtext() and @@ -74,7 +76,9 @@ private: class TextCharacter { public: INLINE TextCharacter(wchar_t character, const TextProperties *properties); + INLINE TextCharacter(const TextGraphic *graphic, const TextProperties *properties); wchar_t _character; + const TextGraphic *_graphic; const TextProperties *_properties; }; typedef pvector TextString; @@ -112,9 +116,12 @@ private: bool &found_any, Thread *current_thread) const; void assign_to(GeomNode *geom_node, const RenderState *state) const; void assign_copy_to(GeomNode *geom_node, const RenderState *state, - const LMatrix4f &xform) const; + const LMatrix4f &extra_xform) const; + void copy_graphic_to(PandaNode *node, const RenderState *state, + const LMatrix4f &extra_xform) const; Pieces _pieces; + PT(PandaNode) _graphic_model; LMatrix4f _xform; const TextProperties *_properties; }; diff --git a/panda/src/text/textGraphic.I b/panda/src/text/textGraphic.I new file mode 100644 index 0000000000..217263fd9e --- /dev/null +++ b/panda/src/text/textGraphic.I @@ -0,0 +1,116 @@ +// Filename: textGraphic.I +// Created by: drose (18Aug06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: TextGraphic::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE TextGraphic:: +TextGraphic() { + _frame = LVecBase4f::zero(); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextGraphic::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE TextGraphic:: +TextGraphic(const NodePath &model, const LVecBase4f &frame) : + _model(model), + _frame(frame) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: TextGraphic::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE TextGraphic:: +TextGraphic(const NodePath &model, float left, float right, float bottom, float top) : + _model(model), + _frame(left, right, bottom, top) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: TextGraphic::get_model +// Access: Published +// Description: Returns the NodePath associated with the graphic, +// that renders the desired image. +//////////////////////////////////////////////////////////////////// +INLINE NodePath TextGraphic:: +get_model() const { + return _model; +} + +//////////////////////////////////////////////////////////////////// +// Function: TextGraphic::set_model +// Access: Published +// Description: Changes the NodePath associated with the graphic. +// This NodePath should contain geometry that will +// render the desired graphic image. +//////////////////////////////////////////////////////////////////// +INLINE void TextGraphic:: +set_model(const NodePath &model) { + _model = model; +} + +//////////////////////////////////////////////////////////////////// +// Function: TextGraphic::get_frame +// Access: Published +// Description: Returns the frame specified for the graphic. This is +// the amount of space that will be reserved for the +// graphic when it is embedded in a text paragraph, in +// the form (left, right, bottom, top). +// +// The actual graphic, as rendered by the NodePath +// specified via set_model(), should more or less fit +// within this rectangle. It is not required to fit +// completely within it, but if it does not, it may +// visually overlap with nearby text. +//////////////////////////////////////////////////////////////////// +INLINE LVecBase4f TextGraphic:: +get_frame() const { + return _frame; +} + +//////////////////////////////////////////////////////////////////// +// Function: TextGraphic::set_frame +// Access: Published +// Description: Specifies the (left, right, bottom, top) bounding +// frame for the graphic. See get_frame(). +//////////////////////////////////////////////////////////////////// +INLINE void TextGraphic:: +set_frame(const LVecBase4f &frame) { + _frame = frame; +} + +//////////////////////////////////////////////////////////////////// +// Function: TextGraphic::set_frame +// Access: Published +// Description: Specifies the (left, right, bottom, top) bounding +// frame for the graphic. See get_frame(). +//////////////////////////////////////////////////////////////////// +INLINE void TextGraphic:: +set_frame(float left, float right, float bottom, float top) { + _frame.set(left, right, bottom, top); +} diff --git a/panda/src/text/textGraphic.cxx b/panda/src/text/textGraphic.cxx new file mode 100644 index 0000000000..f3c6b58b75 --- /dev/null +++ b/panda/src/text/textGraphic.cxx @@ -0,0 +1,19 @@ +// Filename: textGraphic.cxx +// Created by: drose (18Aug06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "textGraphic.h" diff --git a/panda/src/text/textGraphic.h b/panda/src/text/textGraphic.h new file mode 100644 index 0000000000..0b84ae0d97 --- /dev/null +++ b/panda/src/text/textGraphic.h @@ -0,0 +1,67 @@ +// Filename: textGraphic.h +// Created by: drose (18Aug06) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef TEXTGRAPHIC_H +#define TEXTGRAPHIC_H + +#include "pandabase.h" + +#include "config_text.h" +#include "nodePath.h" + +//////////////////////////////////////////////////////////////////// +// Class : TextGraphic +// Description : This defines a special model that has been +// constructed for the purposes of embedding an +// arbitrary graphic image within a text paragraph. +// +// It can be any arbitrary model, though it should be +// built along the same scale as the text, and it should +// probably be at least mostly two-dimensional. +// Typically, this means it should be constructed in the +// X-Z plane, and it should have a maximum vertical (Z) +// height of 1.0. +// +// The frame specifies an arbitrary bounding volume in +// the form (left, right, bottom, top). This indicates +// the amount of space that will be reserved within the +// paragraph. The actual model is not actually required +// to fit within this rectangle, but if it does not, it +// may visually overlap with nearby text. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA TextGraphic { +PUBLISHED: + INLINE TextGraphic(); + INLINE TextGraphic(const NodePath &model, const LVecBase4f &frame); + INLINE TextGraphic(const NodePath &model, float left, float right, float bottom, float top); + + INLINE NodePath get_model() const; + INLINE void set_model(const NodePath &model); + + INLINE LVecBase4f get_frame() const; + INLINE void set_frame(const LVecBase4f &frame); + INLINE void set_frame(float left, float right, float bottom, float top); + +private: + NodePath _model; + LVecBase4f _frame; +}; + +#include "textGraphic.I" + +#endif diff --git a/panda/src/text/textNode.cxx b/panda/src/text/textNode.cxx index ddf6229ecc..e37437abba 100644 --- a/panda/src/text/textNode.cxx +++ b/panda/src/text/textNode.cxx @@ -120,6 +120,50 @@ TextNode(const string &name, const TextProperties ©) : _lr3d.set(0.0f, 0.0f, 0.0f); } +//////////////////////////////////////////////////////////////////// +// Function: TextNode::Copy Constructor +// Access: Published +// Description: OK, this is a true copy constructor. +//////////////////////////////////////////////////////////////////// +TextNode:: +TextNode(const TextNode ©) : + PandaNode(copy), + TextEncoder(copy), + TextProperties(copy), + _card_texture(copy._card_texture), + _frame_color(copy._frame_color), + _card_color(copy._card_color), + _flags(copy._flags), + _max_rows(copy._max_rows), + _frame_width(copy._frame_width), + _card_border_size(copy._card_border_size), + _card_border_uv_portion(copy._card_border_uv_portion), + _frame_ul(copy._frame_ul), + _frame_lr(copy._frame_lr), + _card_ul(copy._card_ul), + _card_lr(copy._card_lr), + _transform(copy._transform), + _coordinate_system(copy._coordinate_system), + _ul3d(copy._ul3d), + _lr3d(copy._lr3d), + _assembler(this) +{ + invalidate_with_measure(); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextNode::make_copy +// Access: Protected, Virtual +// Description: Returns a newly-allocated Node that is a shallow copy +// of this one. It will be a different Node pointer, +// but its internal data may or may not be shared with +// that of the original Node. +//////////////////////////////////////////////////////////////////// +PandaNode *TextNode:: +make_copy() const { + return new TextNode(*this); +} + //////////////////////////////////////////////////////////////////// // Function: TextNode::Destructor // Access: Published @@ -267,8 +311,7 @@ generate() { PT(PandaNode) text_root = _assembler.assemble_text(); - // Parent the text in. We create an intermediate node so we can - // choose to reinstance the text_root as the shadow, below. + // Parent the text in. PT(PandaNode) text = new PandaNode("text"); root->add_child(text, get_draw_order() + 2); text->add_child(text_root); diff --git a/panda/src/text/textNode.h b/panda/src/text/textNode.h index 4639b4e007..1682b78d50 100644 --- a/panda/src/text/textNode.h +++ b/panda/src/text/textNode.h @@ -57,6 +57,11 @@ class EXPCL_PANDA TextNode : public PandaNode, public TextEncoder, public TextPr PUBLISHED: TextNode(const string &name); TextNode(const string &name, const TextProperties ©); +protected: + TextNode(const TextNode ©); + virtual PandaNode *make_copy() const; + +PUBLISHED: ~TextNode(); INLINE float get_line_height() const; diff --git a/panda/src/text/textPropertiesManager.cxx b/panda/src/text/textPropertiesManager.cxx index 234e3d1e81..b9d5ca80e5 100644 --- a/panda/src/text/textPropertiesManager.cxx +++ b/panda/src/text/textPropertiesManager.cxx @@ -118,6 +118,105 @@ clear_properties(const string &name) { _properties.erase(name); } +//////////////////////////////////////////////////////////////////// +// Function: TextPropertiesManager::set_graphic +// Access: Published +// Description: Defines the TextGraphic associated with the +// indicated name. When the name is subsequently +// encountered in text embedded between \5 characters in +// a TextNode string, the specified graphic will be +// embedded in the text at that point. +// +// If there was already a TextGraphic structure +// associated with this name, it is quietly replaced +// with the new definition. +//////////////////////////////////////////////////////////////////// +void TextPropertiesManager:: +set_graphic(const string &name, const TextGraphic &graphic) { + _graphics[name] = graphic; +} + +//////////////////////////////////////////////////////////////////// +// Function: TextPropertiesManager::set_graphic +// Access: Published +// Description: This flavor of set_graphic implicitly creates a frame +// for the model using the model's actual computed +// bounding volume, as derived from +// NodePath::calc_tight_bounds(). Create a TextGraphic +// object first if you want to have explicit control of +// the frame. +//////////////////////////////////////////////////////////////////// +void TextPropertiesManager:: +set_graphic(const string &name, const NodePath &model) { + LPoint3f min_point, max_point; + model.calc_tight_bounds(min_point, max_point); + + TextGraphic graphic(model, + min_point.dot(LVector3f::right()), + max_point.dot(LVector3f::right()), + min_point.dot(LVector3f::up()), + max_point.dot(LVector3f::up())); + + _graphics[name] = graphic; +} + +//////////////////////////////////////////////////////////////////// +// Function: TextPropertiesManager::get_graphic +// Access: Published +// Description: Returns the TextGraphic associated with the +// indicated name. If there was not previously a +// TextGraphic associated with this name, a warning +// is printed and then a default TextGraphic +// structure is associated with the name, and returned. +// +// Call has_graphic() instead to check whether a +// particular name has been defined. +//////////////////////////////////////////////////////////////////// +TextGraphic TextPropertiesManager:: +get_graphic(const string &name) { + Graphics::const_iterator pi; + pi = _graphics.find(name); + if (pi != _graphics.end()) { + return (*pi).second; + } + + text_cat.warning() + << "Creating default TextGraphic for name '" << name << "'\n"; + + TextGraphic default_graphic; + _graphics[name] = default_graphic; + return default_graphic; +} + +//////////////////////////////////////////////////////////////////// +// Function: TextPropertiesManager::has_graphic +// Access: Published +// Description: Returns true if a TextGraphic structure has been +// associated with the indicated name, false otherwise. +// Normally this means set_graphic() has been called +// with this name, but because get_graphic() will +// implicitly create a default TextGraphic structure, +// it may also mean simply that get_graphic() has +// been called with the indicated name. +//////////////////////////////////////////////////////////////////// +bool TextPropertiesManager:: +has_graphic(const string &name) const { + Graphics::const_iterator pi; + pi = _graphics.find(name); + return (pi != _graphics.end()); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextPropertiesManager::clear_graphic +// Access: Published +// Description: Removes the named TextGraphic structure from the +// manager. +//////////////////////////////////////////////////////////////////// +void TextPropertiesManager:: +clear_graphic(const string &name) { + _graphics.erase(name); +} + //////////////////////////////////////////////////////////////////// // Function: TextPropertiesManager::write // Access: Published @@ -146,3 +245,37 @@ get_global_ptr() { } return _global_ptr; } + +//////////////////////////////////////////////////////////////////// +// Function: TextPropertiesManager::get_properties_ptr +// Access: Public +// Description: Returns a pointer to the TextProperties with the +// indicated name, or NULL if there is no properties +// with that name. +//////////////////////////////////////////////////////////////////// +const TextProperties *TextPropertiesManager:: +get_properties_ptr(const string &name) { + Properties::const_iterator pi; + pi = _properties.find(name); + if (pi != _properties.end()) { + return &(*pi).second; + } + return NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: TextPropertiesManager::get_graphic_ptr +// Access: Public +// Description: Returns a pointer to the TextGraphic with the +// indicated name, or NULL if there is no graphic +// with that name. +//////////////////////////////////////////////////////////////////// +const TextGraphic *TextPropertiesManager:: +get_graphic_ptr(const string &name) { + Graphics::const_iterator pi; + pi = _graphics.find(name); + if (pi != _graphics.end()) { + return &(*pi).second; + } + return NULL; +} diff --git a/panda/src/text/textPropertiesManager.h b/panda/src/text/textPropertiesManager.h index 2055d23301..e9dd5bad34 100644 --- a/panda/src/text/textPropertiesManager.h +++ b/panda/src/text/textPropertiesManager.h @@ -23,6 +23,7 @@ #include "config_text.h" #include "textProperties.h" +#include "textGraphic.h" //////////////////////////////////////////////////////////////////// // Class : TextPropertiesManager @@ -44,6 +45,14 @@ // the character "n" will be rendered in the "up" state, // and then " + y" will be rendered in the normal state // again. +// +// This can also be used to define arbitrary models that +// can serve as embedded graphic images in a text +// paragraph. This works similarly; the convention is +// to create a TextGraphic that describes the graphic +// image, and then associate it here via the +// set_graphic() call. Then "\5name\5" will embed the +// named graphic. //////////////////////////////////////////////////////////////////// class EXPCL_PANDA TextPropertiesManager { protected: @@ -56,14 +65,27 @@ PUBLISHED: bool has_properties(const string &name) const; void clear_properties(const string &name); + void set_graphic(const string &name, const TextGraphic &graphic); + void set_graphic(const string &name, const NodePath &model); + TextGraphic get_graphic(const string &name); + bool has_graphic(const string &name) const; + void clear_graphic(const string &name); + void write(ostream &out, int indent_level = 0) const; static TextPropertiesManager *get_global_ptr(); +public: + const TextProperties *get_properties_ptr(const string &name); + const TextGraphic *get_graphic_ptr(const string &name); + private: typedef pmap Properties; Properties _properties; + typedef pmap Graphics; + Graphics _graphics; + static TextPropertiesManager *_global_ptr; }; diff --git a/panda/src/text/text_composite2.cxx b/panda/src/text/text_composite2.cxx index 208f6e33f1..4e0021e810 100644 --- a/panda/src/text/text_composite2.cxx +++ b/panda/src/text/text_composite2.cxx @@ -1,6 +1,7 @@ #include "textAssembler.cxx" #include "textFont.cxx" #include "textGlyph.cxx" +#include "textGraphic.cxx" #include "textNode.cxx" #include "textProperties.cxx" #include "textPropertiesManager.cxx"