support multi-state text blocks; also show IME candidate strings in DirectEntry fields

This commit is contained in:
David Rose 2004-04-08 01:17:50 +00:00
parent fd4e0879b8
commit 5d121b8ed9
29 changed files with 4330 additions and 2311 deletions

View File

@ -73,11 +73,10 @@ class DirectEntry(DirectFrame):
scale = 1,
# Don't get rid of the text node
mayChange = 1)
# We want to keep this sucker frozen since its not
# in the scene graph
self.onscreenText.freeze()
# We can also get rid of the node path since we're just using the
# onscreenText as an easy way to access a text node as a component
# We can get rid of the node path since we're just using the
# onscreenText as an easy way to access a text node as a
# component
self.onscreenText.removeNode()
# Bind command function

View File

@ -90,12 +90,12 @@ def printEntryText(text):
# CALL de1.get() and de1.set('new text') to get and set entry contents
de1 = DirectEntry(initialText = 'Hello, how are you?',
image = 'models/maps/noise.rgb',
#image = 'phase_3/maps/toowntown-logo.jpg',
image_pos = (4.55, 0, -1.65),
image_scale = (5.5, 1, 2.55),
image_pos = (4.55, 0, -2.55),
image_scale = (5.5, 1, 4),
command = printEntryText,
pos = (-1.1875, 0, 0.879167),
scale = 0.0707855,
cursorKeys = 1,
)
# DIRECT DIALOG EXAMPLE

View File

@ -157,8 +157,6 @@ class OnscreenText(PandaObject, NodePath):
if font == None:
font = DirectGuiGlobals.getDefaultFont()
# Freeze the node while we set all the properties
textNode.freeze()
textNode.setFont(font)
textNode.setTextColor(fg[0], fg[1], fg[2], fg[3])
textNode.setAlign(align)
@ -202,12 +200,9 @@ class OnscreenText(PandaObject, NodePath):
self.mayChange = mayChange
# Ok, now update the node.
if self.mayChange:
# If we might change the text later, we have to keep the
# TextNode around.
textNode.thaw()
else:
# Otherwise, we can throw it away.
if not self.mayChange:
# If we aren't going to change the text later, we can
# throw away the TextNode.
self.textNode = textNode.generate()
self.isClean = 0
@ -225,10 +220,10 @@ class OnscreenText(PandaObject, NodePath):
self.cleanup()
def freeze(self):
self.textNode.freeze()
pass
def thaw(self):
self.textNode.thaw()
pass
# Allow changing of several of the parameters after the text has
# been created. These should be used with caution; it is better
@ -237,9 +232,6 @@ class OnscreenText(PandaObject, NodePath):
# text, and for those rare occasions when you actually want to
# change a text's property after it has been created.
# If you need to change several properties at the same time at
# runtime, you should call freeze() first and thaw() afterward.
def setFont(self, font):
self.textNode.setFont(font)
@ -321,7 +313,6 @@ class OnscreenText(PandaObject, NodePath):
self.textNode.setTextColor(fg[0], fg[1], fg[2], fg[3])
def setBg(self, bg):
self.textNode.freeze()
if bg[3] != 0:
# If we have a background color, create a card.
self.textNode.setCardColor(bg[0], bg[1], bg[2], bg[3])
@ -329,10 +320,8 @@ class OnscreenText(PandaObject, NodePath):
else:
# Otherwise, remove the card.
self.textNode.clearCard()
self.textNode.thaw()
def setShadow(self, shadow):
self.textNode.freeze()
if shadow[3] != 0:
# If we have a shadow color, create a shadow.
self.textNode.setShadowColor(shadow[0], shadow[1], shadow[2], shadow[3])
@ -340,10 +329,8 @@ class OnscreenText(PandaObject, NodePath):
else:
# Otherwise, remove the shadow.
self.textNode.clearShadow()
self.textNode.thaw()
def setFrame(self, frame):
self.textNode.freeze()
if frame[3] != 0:
# If we have a frame color, create a frame.
self.textNode.setFrameColor(frame[0], frame[1], frame[2], frame[3])
@ -351,15 +338,12 @@ class OnscreenText(PandaObject, NodePath):
else:
# Otherwise, remove the frame.
self.textNode.clearFrame()
self.textNode.thaw()
def configure(self, option=None, **kw):
# These is for compatability with DirectGui functions
if not self.mayChange:
print 'OnscreenText.configure: mayChange == 0'
return
# Freeze text node prior to making changes
self.freeze()
for option, value in kw.items():
# Use option string to access setter function
try:
@ -371,7 +355,6 @@ class OnscreenText(PandaObject, NodePath):
setter(value)
except AttributeError:
print 'OnscreenText.configure: invalid option:', option
self.thaw()
# Allow index style references
def __setitem__(self, key, value):

View File

@ -3988,13 +3988,11 @@ class LevelStyleManager:
for i in range (numItems):
# Create a text node--just a card, really--of the right color.
tn = TextNode('colorChip')
tn.freeze()
tn.setFont(getDefaultFont())
tn.setTransform(Mat4.scaleMat(0.07, 0.07, 0.07 * aspectRatio))
tn.setCardColor(colorList[i])
tn.setCardActual(0, 1.1111, 0, 0.8333)
tn.setText(' ')
tn.thaw()
# Reposition it
card = tn.getCardTransformed()
@ -4113,14 +4111,12 @@ class LevelStyleManager:
# Create text node for each item
if (textList[i] != None):
tn = TextNode('TextItem')
tn.freeze()
tn.setFont(getDefaultFont())
tn.setTransform(Mat4.scaleMat(0.07, 0.07, 0.07 * aspectRatio))
tn.setTextColor(0, 0, 0, 1)
tn.setCardColor(1, 1, 1, 1)
tn.setCardAsMargin(0.1, 0.1, 0.1, 0.1)
tn.setText(str(textList[i]))
tn.thaw()
# Reposition it
card = tn.getCardTransformed()

View File

@ -138,14 +138,12 @@ class TextPieMenu(PieMenu):
# Create text node for each item
if (textList[i] != None):
tn = TextNode('TextItem')
tn.freeze()
tn.setFont(getDefaultFont())
tn.setTransform(Mat4.scaleMat(0.07, 0.07, 0.07 * aspectRatio))
tn.setTextColor(0, 0, 0, 1)
tn.setCardColor(1, 1, 1, 1)
tn.setCardAsMargin(0.1, 0.1, 0.1, 0.1)
tn.setText(str(textList[i]))
tn.thaw()
# Reposition it
card = tn.getCardTransformed()

View File

@ -310,20 +310,6 @@ process_events() {
case KeyPress:
handle_keystroke(event.xkey);
handle_keypress(event.xkey);
/*
// Temp hack for testing. We pretend that we have received a
// candidate string every type the user types the backslash key.
{
KeySym key = XLookupKeysym(&event.xkey, 0);
if (key == XK_backslash) {
cerr << "Pressed backslash, sending candidate\n";
wstring candidate_string = TextEncoder::decode_text("This is a candidate string", TextEncoder::get_default_encoding());
_input_devices[0].candidate(candidate_string, 5, 7);
}
}
*/
break;
case KeyRelease:

View File

@ -265,6 +265,70 @@ get_obscure_mode() const {
return _obscure_mode;
}
////////////////////////////////////////////////////////////////////
// Function: PGEntry::set_candidate_active
// Access: Published
// Description: Specifies the name of the TextProperties structure
// added to the TextPropertiesManager that will be used
// to render candidate strings from the IME, used for
// typing characters in east Asian languages. Each
// candidate string represents one possible way to
// interpret the sequence of keys the user has just
// entered; it should not be considered typed yet, but
// it is important for the user to be able to see what
// he is considering entering.
//
// This particular method sets the properties for the
// subset of the current candidate string that the user
// can actively scroll through.
////////////////////////////////////////////////////////////////////
INLINE void PGEntry::
set_candidate_active(const string &candidate_active) {
_candidate_active = candidate_active;
}
////////////////////////////////////////////////////////////////////
// Function: PGEntry::get_candidate_active
// Access: Published
// Description: See set_candidate_active().
////////////////////////////////////////////////////////////////////
INLINE const string &PGEntry::
get_candidate_active() const {
return _candidate_active;
}
////////////////////////////////////////////////////////////////////
// Function: PGEntry::set_candidate_inactive
// Access: Published
// Description: Specifies the name of the TextProperties structure
// added to the TextPropertiesManager that will be used
// to render candidate strings from the IME, used for
// typing characters in east Asian languages. Each
// candidate string represents one possible way to
// interpret the sequence of keys the user has just
// entered; it should not be considered typed yet, but
// it is important for the user to be able to see what
// he is considering entering.
//
// This particular method sets the properties for the
// subset of the current candidate string that the user
// is not actively scrolling through.
////////////////////////////////////////////////////////////////////
INLINE void PGEntry::
set_candidate_inactive(const string &candidate_inactive) {
_candidate_inactive = candidate_inactive;
}
////////////////////////////////////////////////////////////////////
// Function: PGEntry::get_candidate_inactive
// Access: Published
// Description: See set_candidate_inactive().
////////////////////////////////////////////////////////////////////
INLINE const string &PGEntry::
get_candidate_inactive() const {
return _candidate_inactive;
}
////////////////////////////////////////////////////////////////////
// Function: PGEntry::get_accept_prefix
// Access: Published, Static

View File

@ -28,6 +28,7 @@
#include "mouseButton.h"
#include "lineSegs.h"
#include "textEncoder.h"
#include "config_text.h"
#include <math.h>
@ -44,6 +45,8 @@ PGEntry(const string &name) :
{
_cursor_position = 0;
_cursor_stale = true;
_candidate_highlight_start = 0;
_candidate_highlight_end = 0;
_max_chars = 0;
_max_width = 0.0f;
_num_lines = 1;
@ -56,6 +59,12 @@ PGEntry(const string &name) :
_cursor_def = _text_render_root.attach_new_node("cursor");
_cursor_visible = true;
// These strings are used to specify the TextProperties to apply to
// candidate strings generated from the IME (for entering text in an
// east Asian language).
_candidate_active = "candidate_active";
_candidate_inactive = "candidate_inactive";
_cursor_keys_active = true;
_obscure_mode = false;
@ -178,6 +187,11 @@ press(const MouseWatcherParameter &param, bool background) {
} else if ((!background && get_focus()) ||
(background && get_background_focus())) {
// Keyboard button.
if (!_candidate_wtext.empty()) {
_candidate_wtext.clear();
_text_geom_stale = true;
}
_cursor_position = min(_cursor_position, (int)_wtext.length());
_blink_start = ClockObject::get_global_clock()->get_frame_time();
if (button == KeyboardButton::enter()) {
@ -266,53 +280,42 @@ press(const MouseWatcherParameter &param, bool background) {
bool too_long = false;
if (_max_width > 0.0f) {
TextNode *text_node = get_text_def(S_focus);
if (_num_lines <= 1) {
// If we have only one line, we can check the length
// by simply measuring the width of the text.
too_long = (text_node->calc_width(measure_text) > _max_width);
text_node->set_wtext(measure_text);
text_node->set_wordwrap(_max_width);
text_node->set_preserve_trailing_whitespace(true);
text_node->set_max_rows(_num_lines);
} else {
// If we have multiple lines, we have to check the
// length by wordwrapping it and counting up the
// number of lines.
wstring ww_text = text_node->wordwrap_to(measure_text, _max_width, true);
int num_lines = 1;
size_t last_line_start = 0;
for (size_t p = 0;
p < ww_text.length() && !too_long;
++p) {
if (ww_text[p] == '\n') {
last_line_start = p + 1;
num_lines++;
too_long = (num_lines > _num_lines);
}
too_long = text_node->has_overflow();
if (!too_long) {
// We must also ensure that the last line is not too
// long (it might be, because of additional
// whitespace on the end).
wstring ww_text = text_node->get_wordwrapped_wtext();
size_t last_line_start = ww_text.rfind('\n');
if (last_line_start == string::npos) {
last_line_start = 0;
}
if (!too_long) {
// We must also ensure that the last line is not too
// long (it might be, because of additional
// whitespace on the end).
wstring last_line = ww_text.substr(last_line_start);
float last_line_width = text_node->calc_width(last_line);
if (num_lines == _num_lines) {
// Mainly we only care about this if we're on
// the very last line.
too_long = (last_line_width > _max_width);
} else {
// If we're not on the very last line, the width
// is still important, just so we don't allow an
// infinite number of spaces to accumulate.
// However, we must allow at least *one* space
// on the end of a line.
if (_wtext.length() >= 1 &&
_wtext[_wtext.length() - 1] == ' ') {
if (last_line_width > _max_width) {
// In this case, however, it's not exactly
// an overflow; we just want to reject the
// space.
return;
}
wstring last_line = ww_text.substr(last_line_start);
float last_line_width = text_node->calc_width(last_line);
if (text_node->get_num_rows() == _num_lines) {
// Mainly we only care about this if we're on
// the very last line.
too_long = (last_line_width > _max_width);
} else {
// If we're not on the very last line, the width
// is still important, just so we don't allow an
// infinite number of spaces to accumulate.
// However, we must allow at least *one* space
// on the end of a line.
if (_wtext.length() >= 1 &&
_wtext[_wtext.length() - 1] == ' ') {
if (last_line_width > _max_width) {
// In this case, however, it's not exactly
// an overflow; we just want to reject the
// space.
return;
}
}
}
@ -355,9 +358,14 @@ keystroke(const MouseWatcherParameter &param, bool background) {
int keycode = param.get_keycode();
if (use_keystrokes) {
if (!isascii(keycode) || isprint(keycode)) {
// A normal visible character. Add a new character to the
// text entry, if there's room.
if (!_candidate_wtext.empty()) {
_candidate_wtext.clear();
_text_geom_stale = true;
}
wstring new_char(1, (wchar_t)keycode);
if (get_max_chars() > 0 && (int)_wtext.length() >= get_max_chars()) {
@ -382,53 +390,42 @@ keystroke(const MouseWatcherParameter &param, bool background) {
bool too_long = false;
if (_max_width > 0.0f) {
TextNode *text_node = get_text_def(S_focus);
if (_num_lines <= 1) {
// If we have only one line, we can check the length
// by simply measuring the width of the text.
too_long = (text_node->calc_width(measure_text) > _max_width);
} else {
// If we have multiple lines, we have to check the
// length by wordwrapping it and counting up the
// number of lines.
wstring ww_text = text_node->wordwrap_to(measure_text, _max_width, true);
int num_lines = 1;
size_t last_line_start = 0;
for (size_t p = 0;
p < ww_text.length() && !too_long;
++p) {
if (ww_text[p] == '\n') {
last_line_start = p + 1;
num_lines++;
too_long = (num_lines > _num_lines);
}
text_node->set_wtext(measure_text);
text_node->set_wordwrap(_max_width);
text_node->set_preserve_trailing_whitespace(true);
text_node->set_max_rows(_num_lines);
too_long = text_node->has_overflow();
if (!too_long) {
// We must also ensure that the last line is not too
// long (it might be, because of additional
// whitespace on the end).
wstring ww_text = text_node->get_wordwrapped_wtext();
size_t last_line_start = ww_text.rfind('\n');
if (last_line_start == string::npos) {
last_line_start = 0;
}
if (!too_long) {
// We must also ensure that the last line is not too
// long (it might be, because of additional
// whitespace on the end).
wstring last_line = ww_text.substr(last_line_start);
float last_line_width = text_node->calc_width(last_line);
if (num_lines == _num_lines) {
// Mainly we only care about this if we're on
// the very last line.
too_long = (last_line_width > _max_width);
} else {
// If we're not on the very last line, the width
// is still important, just so we don't allow an
// infinite number of spaces to accumulate.
// However, we must allow at least *one* space
// on the end of a line.
if (_wtext.length() >= 1 &&
_wtext[_wtext.length() - 1] == ' ') {
if (last_line_width > _max_width) {
// In this case, however, it's not exactly
// an overflow; we just want to reject the
// space.
return;
}
wstring last_line = ww_text.substr(last_line_start);
float last_line_width = text_node->calc_width(last_line);
if (text_node->get_num_rows() == _num_lines) {
// Mainly we only care about this if we're on
// the very last line.
too_long = (last_line_width > _max_width);
} else {
// If we're not on the very last line, the width
// is still important, just so we don't allow an
// infinite number of spaces to accumulate.
// However, we must allow at least *one* space
// on the end of a line.
if (_wtext.length() >= 1 &&
_wtext[_wtext.length() - 1] == ' ') {
if (last_line_width > _max_width) {
// In this case, however, it's not exactly
// an overflow; we just want to reject the
// space.
return;
}
}
}
@ -467,18 +464,11 @@ void PGEntry::
candidate(const MouseWatcherParameter &param, bool background) {
if (get_active()) {
if (param.has_candidate()) {
// Do something with the candidate string.
TextEncoder te;
const wstring &cs = param.get_candidate_string();
size_t hs = param.get_highlight_start();
size_t he = param.get_highlight_end();
pgui_cat.info()
<< "Candidate: "
<< te.encode_wtext(cs.substr(0, hs))
<< " (" << te.encode_wtext(cs.substr(hs, he - hs)) << ") "
<< te.encode_wtext(cs.substr(he))
<< "\n";
// Save the candidate string so it can be displayed.
_candidate_wtext = param.get_candidate_string();
_candidate_highlight_start = param.get_highlight_start();
_candidate_highlight_end = param.get_highlight_end();
_text_geom_stale = true;
}
}
PGItem::candidate(param, background);
@ -563,7 +553,7 @@ setup(float width, int num_lines) {
TextNode *text_node = get_text_def(S_focus);
float line_height = text_node->get_line_height();
// Define determine the four corners of the frame.
// Determine the four corners of the frame.
LPoint3f ll(0.0f, 0.0f, -0.3f * line_height - (line_height * (num_lines - 1)));
LPoint3f ur(width, 0.0f, line_height);
LPoint3f lr(ur[0], 0.0f, ll[2]);
@ -640,11 +630,6 @@ setup(float width, int num_lines) {
// indicated state. The default if nothing is specified
// is the same TextNode returned by
// PGItem::get_text_node().
//
// It is the responsibility of the user to ensure that
// this TextNode has been frozen by a call to freeze().
// Passing in an unfrozen TextNode will result in
// needless work.
////////////////////////////////////////////////////////////////////
void PGEntry::
set_text_def(int state, TextNode *node) {
@ -726,7 +711,7 @@ get_display_wtext() {
return _obscured_wtext;
} else {
// In normal, non-obscure mode, we display the actual text.
// In normal, non-obscure mode, we display the actual text
return _wtext;
}
}
@ -756,38 +741,54 @@ update_text() {
nassertv(node != (TextNode *)NULL);
if (_text_geom_stale || node != _last_text_def) {
const wstring &display_wtext = get_display_wtext();
wstring display_wtext;
if (_candidate_wtext.empty() || _obscure_mode) {
// If we're not trying to display a candidate string, it's easy:
// just display the current text contents.
display_wtext = get_display_wtext();
} else {
// Insert the complex sequence of characters required to show
// the candidate string in a different color. This gets
// inserted at the current cursor position.
wstring source_wtext = get_display_wtext();
display_wtext = source_wtext.substr(0, _cursor_position);
display_wtext += wstring(1, text_push_properties_key);
display_wtext += node->decode_text(_candidate_inactive);
display_wtext += wstring(1, text_push_properties_key);
display_wtext += _candidate_wtext.substr(0, _candidate_highlight_start);
display_wtext += wstring(1, text_push_properties_key);
display_wtext += node->decode_text(_candidate_active);
display_wtext += wstring(1, text_push_properties_key);
display_wtext += _candidate_wtext.substr(_candidate_highlight_start,
_candidate_highlight_end - _candidate_highlight_start);
display_wtext += wstring(1, text_pop_properties_key);
display_wtext += _candidate_wtext.substr(_candidate_highlight_end);
display_wtext += wstring(1, text_pop_properties_key);
display_wtext += source_wtext.substr(_cursor_position);
}
// We need to regenerate.
_last_text_def = node;
_last_text_def->set_wtext(display_wtext);
_last_text_def->set_wordwrap(_max_width);
_last_text_def->set_preserve_trailing_whitespace(true);
_last_text_def->set_max_rows(_num_lines);
if (_max_width > 0.0f && _num_lines > 1) {
// Fold the text into multiple lines.
wstring ww_text =
_last_text_def->wordwrap_to(display_wtext, _max_width, true);
// Check for multiple lines.
wstring ww_text = _last_text_def->get_wordwrapped_wtext();
// And chop the lines up into pieces.
_ww_lines.clear();
size_t p = 0;
size_t q = ww_text.find((wchar_t)'\n');
while (q != string::npos) {
_ww_lines.push_back(WWLine());
WWLine &line = _ww_lines.back();
line._str = ww_text.substr(p, q - p);
// Get the left edge of the text at this line.
line._left = 0.0f;
if (_last_text_def->get_align() != TextNode::A_left) {
_last_text_def->set_wtext(line._str);
line._left = _last_text_def->get_left();
}
p = q + 1;
q = ww_text.find('\n', p);
}
// And chop the lines up into pieces.
_ww_lines.clear();
size_t p = 0;
size_t q = ww_text.find((wchar_t)'\n');
while (q != string::npos) {
_ww_lines.push_back(WWLine());
WWLine &line = _ww_lines.back();
line._str = ww_text.substr(p);
line._str = ww_text.substr(p, q - p);
// Get the left edge of the text at this line.
line._left = 0.0f;
@ -795,17 +796,18 @@ update_text() {
_last_text_def->set_wtext(line._str);
line._left = _last_text_def->get_left();
}
_last_text_def->set_wtext(ww_text);
} else {
// Only one line.
_ww_lines.clear();
_ww_lines.push_back(WWLine());
WWLine &line = _ww_lines.back();
line._str = display_wtext;
_last_text_def->set_wtext(display_wtext);
p = q + 1;
q = ww_text.find('\n', p);
}
_ww_lines.push_back(WWLine());
WWLine &line = _ww_lines.back();
line._str = ww_text.substr(p);
// Get the left edge of the text at this line.
line._left = 0.0f;
if (_last_text_def->get_align() != TextNode::A_left) {
_last_text_def->set_wtext(line._str);
line._left = _last_text_def->get_left();
}
@ -844,7 +846,11 @@ update_cursor() {
}
nassertv(row >= 0 && row < (int)_ww_lines.size());
nassertv(column >= 0 && column <= (int)_ww_lines[row]._str.length());
// It is possible for this to become untrue legitimately, if due
// to a candidate string we have wordwrapped down the last part of
// the line containing the cursor.
//nassertv(column >= 0 && column <= (int)_ww_lines[row]._str.length());
float width =
_last_text_def->calc_width(_ww_lines[row]._str.substr(0, column));

View File

@ -98,6 +98,12 @@ PUBLISHED:
INLINE void set_obscure_mode(bool flag);
INLINE bool get_obscure_mode() const;
INLINE void set_candidate_active(const string &candidate_active);
INLINE const string &get_candidate_active() const;
INLINE void set_candidate_inactive(const string &candidate_inactive);
INLINE const string &get_candidate_inactive() const;
void set_text_def(int state, TextNode *node);
TextNode *get_text_def(int state) const;
@ -133,10 +139,17 @@ private:
bool _cursor_stale;
bool _cursor_visible;
wstring _candidate_wtext;
size_t _candidate_highlight_start;
size_t _candidate_highlight_end;
int _max_chars;
float _max_width;
int _num_lines;
string _candidate_active;
string _candidate_inactive;
typedef pvector< PT(TextNode) > TextDefs;
TextDefs _text_defs;

View File

@ -9,7 +9,7 @@
putil gobj pgraph linmath \
pnmtext pnmimage gsgbase mathutil
#define COMBINED_SOURCES $[TARGET]_composite1.cxx
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
#define SOURCES \
config_text.h \
@ -20,9 +20,12 @@
fontPool.I fontPool.h \
geomTextGlyph.I geomTextGlyph.h \
staticTextFont.I staticTextFont.h \
textAssembler.I textAssembler.h \
textFont.I textFont.h \
textGlyph.I textGlyph.h \
textNode.I textNode.h textNode.cxx
textNode.I textNode.h \
textProperties.I textProperties.h \
textPropertiesManager.I textPropertiesManager.h
#define INCLUDED_SOURCES \
config_text.cxx \
@ -33,7 +36,11 @@
fontPool.cxx \
geomTextGlyph.cxx \
staticTextFont.cxx \
textFont.cxx textGlyph.cxx
textAssembler.cxx \
textFont.cxx textGlyph.cxx \
textNode.cxx \
textProperties.cxx \
textPropertiesManager.cxx
#define INSTALL_HEADERS \
config_text.h \
@ -43,9 +50,12 @@
fontPool.I fontPool.h \
geomTextGlyph.I geomTextGlyph.h \
staticTextFont.I staticTextFont.h \
textAssembler.I textAssembler.h \
textFont.I textFont.h \
textGlyph.I textGlyph.h \
textNode.I textNode.h
textNode.I textNode.h \
textProperties.I textProperties.h \
textPropertiesManager.I textPropertiesManager.h
#define IGATESCAN all

View File

@ -20,6 +20,7 @@
#include "staticTextFont.h"
#include "textFont.h"
#include "textNode.h"
#include "textProperties.h"
#include "dynamicTextFont.h"
#include "dynamicTextPage.h"
#include "geomTextGlyph.h"
@ -48,6 +49,16 @@ const string text_default_font = config_text.GetString("text-default-font", "");
const float text_tab_width = config_text.GetFloat("text-tab-width", 5.0f);
// This is the decimal character number that, embedded in a string, is
// used to bracket the name of a TextProperties structure added to the
// TextPropertiesManager object, to control the appearance of
// subsequent text.
const int text_push_properties_key = config_text.GetInt("text-push-properties-key", 1);
// This is the decimal character number that undoes the effect of a
// previous appearance of text_push_properties_key.
const int text_pop_properties_key = config_text.GetInt("text-pop-properties-key", 2);
// This is the decimal character number that, embedded in a string, is
// identified as the soft-hyphen character.
const int text_soft_hyphen_key = config_text.GetInt("text-soft-hyphen-key", 3);
@ -98,6 +109,7 @@ init_libtext() {
StaticTextFont::init_type();
TextFont::init_type();
TextNode::init_type();
TextProperties::init_type();
#ifdef HAVE_FREETYPE
DynamicTextFont::init_type();

View File

@ -38,6 +38,8 @@ extern const bool text_small_caps;
extern const float text_small_caps_scale;
extern const string text_default_font;
extern const float text_tab_width;
extern const int text_push_properties_key;
extern const int text_pop_properties_key;
extern const int text_soft_hyphen_key;
extern const int text_soft_break_key;
extern wstring *text_soft_hyphen_output;

View File

@ -17,6 +17,8 @@
////////////////////////////////////////////////////////////////////
#include "fontPool.h"
#include "staticTextFont.h"
#include "dynamicTextFont.h"
#include "config_util.h"
#include "config_express.h"
#include "virtualFileSystem.h"

View File

@ -0,0 +1,91 @@
// Filename: textAssembler.I
// Created by: drose (06Apr04)
//
////////////////////////////////////////////////////////////////////
//
// 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: TextAssembler::get_ul
// Access: Public
// Description: Returns the upper-left corner of the assembled text,
// in 2-d text coordinates.
////////////////////////////////////////////////////////////////////
INLINE const LVector2f &TextAssembler::
get_ul() const {
return _ul;
}
////////////////////////////////////////////////////////////////////
// Function: TextAssembler::get_lr
// Access: Public
// Description: Returns the lower-right corner of the assembled text,
// in 2-d text coordinates.
////////////////////////////////////////////////////////////////////
INLINE const LVector2f &TextAssembler::
get_lr() const {
return _lr;
}
////////////////////////////////////////////////////////////////////
// Function: TextAssembler::get_num_rows
// Access: Public
// Description: Returns the number of rows of text after it has all
// been wordwrapped and assembled.
////////////////////////////////////////////////////////////////////
INLINE int TextAssembler::
get_num_rows() const {
return _num_rows;
}
////////////////////////////////////////////////////////////////////
// Function: TextAssembler::calc_width
// Access: Private, Static
// Description: Returns the width of a single character, according to
// its associated font.
////////////////////////////////////////////////////////////////////
INLINE float TextAssembler::
calc_width(const TextCharacter &tch) {
return calc_width(tch._character, *tch._properties);
}
////////////////////////////////////////////////////////////////////
// Function: TextAssembler::TextCharacter::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE TextAssembler::TextCharacter::
TextCharacter(wchar_t character, const TextProperties *properties) :
_character(character),
_properties(properties)
{
}
////////////////////////////////////////////////////////////////////
// Function: TextAssembler::GlyphPlacement::add_piece
// Access: Public
// Description: Adds a piece of the glyph, consisting of a single
// Geom and an associated RenderState. Typically, a
// glyph will have exactly one piece; there will only be
// multiple pieces in the case of cheesy accent marks or
// ligatures.
////////////////////////////////////////////////////////////////////
INLINE void TextAssembler::GlyphPlacement::
add_piece(Geom *geom, const RenderState *state) {
Piece piece;
piece._geom = geom;
piece._state = state;
_pieces.push_back(piece);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,188 @@
// Filename: textAssembler.h
// Created by: drose (06Apr04)
//
////////////////////////////////////////////////////////////////////
//
// 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 TEXTASSEMBLER_H
#define TEXTASSEMBLER_H
#ifndef CPPPARSER // interrogate has a bit of trouble with wstring.
#include "pandabase.h"
#include "textProperties.h"
#include "textFont.h"
#include "unicodeLatinMap.h"
#include "geomNode.h"
#include "pointerTo.h"
class TextEncoder;
////////////////////////////////////////////////////////////////////
// Class : TextAssembler
// Description : This class is not intended to be used directly by
// user code, but is used by the TextNode to lay out a
// block of text and convert it into rows of Geoms
// according to the TextProperties.
//
// It is not exported from the DLL since it is not
// intended to be used outside of this module.
////////////////////////////////////////////////////////////////////
class TextAssembler {
public:
TextAssembler(TextEncoder *encoder);
~TextAssembler();
void clear();
bool set_wtext(const wstring &wtext, const TextProperties &properties,
int max_rows = 0);
INLINE int get_num_rows() const;
wstring get_wordwrapped_wtext() const;
PT(PandaNode) assemble_text();
INLINE const LVector2f &get_ul() const;
INLINE const LVector2f &get_lr() const;
static float calc_width(wchar_t character, const TextProperties &properties);
private:
// These structures are built up and operated on by scan_wtext() and
// wordwrap_text(). It represents the unrolling of the embedded \1
// .. \2 sequences embedded in the string into a TextProperties
// pointer associated with each character.
typedef pvector<TextProperties *> PropertiesList;
class TextCharacter {
public:
INLINE TextCharacter(wchar_t character, const TextProperties *properties);
wchar_t _character;
const TextProperties *_properties;
};
typedef pvector<TextCharacter> TextString;
PropertiesList _properties_list;
TextString _wordwrapped_string;
int _num_rows;
void scan_wtext(wstring::const_iterator &si,
const wstring::const_iterator &send,
const TextProperties *current_properties,
TextString &text_string);
bool wordwrap_text(const TextAssembler::TextString &text,
TextAssembler::TextString &output_text,
int max_rows);
INLINE static float calc_width(const TextCharacter &tch);
static float calc_hyphen_width(const TextCharacter &tch);
// These structures are built up by assemble_paragraph() and
// assemble_row(). They represent the actual Geoms as laid out in a
// paragraph.
class Piece {
public:
PT(Geom) _geom;
CPT(RenderState) _state;
};
typedef pvector<Piece> Pieces;
class GlyphPlacement {
public:
INLINE void add_piece(Geom *geom, const RenderState *state);
void calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
bool &found_any) 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;
Pieces _pieces;
LMatrix4f _xform;
const TextProperties *_properties;
};
typedef pvector<GlyphPlacement *> PlacedGlyphs;
void assemble_paragraph(TextString::const_iterator si,
const TextString::const_iterator &send,
PlacedGlyphs &placed_glyphs);
void assemble_row(TextString::const_iterator &si,
const TextString::const_iterator &send,
PlacedGlyphs &row_placed_glyphs,
float &row_width, float &line_height,
TextProperties::Alignment &align);
// These interfaces are for implementing cheesy accent marks and
// ligatures when the font doesn't support them.
enum CheesyPosition {
CP_above,
CP_below,
CP_top,
CP_bottom,
CP_within,
};
enum CheesyTransform {
CT_none,
CT_mirror_x,
CT_mirror_y,
CT_rotate_90,
CT_rotate_180,
CT_rotate_270,
CT_squash,
CT_squash_mirror_y,
CT_squash_mirror_diag,
CT_small_squash,
CT_small_squash_mirror_y,
CT_small,
CT_small_rotate_270,
CT_tiny,
CT_tiny_mirror_x,
CT_tiny_rotate_270,
};
static void
get_character_glyphs(int character, const TextProperties *properties,
bool &got_glyph, const TextGlyph *&glyph,
const TextGlyph *&second_glyph,
UnicodeLatinMap::AccentType &accent_type,
int &additional_flags,
float &glyph_scale, float &advance_scale);
static void
tack_on_accent(UnicodeLatinMap::AccentType accent_type,
const LPoint3f &min_vert, const LPoint3f &max_vert,
const LPoint3f &centroid,
const TextProperties *properties, GlyphPlacement *placement);
static bool
tack_on_accent(char accent_mark, CheesyPosition position,
CheesyTransform transform,
const LPoint3f &min_vert, const LPoint3f &max_vert,
const LPoint3f &centroid,
const TextProperties *properties, GlyphPlacement *placement);
// These are filled in by assemble_paragraph().
LVector2f _ul;
LVector2f _lr;
TextEncoder *_encoder;
};
#include "textAssembler.I"
#endif // CPPPARSER
#endif

View File

@ -22,29 +22,6 @@
TypeHandle TextFont::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: isbreakpoint
// Description: An internal function, similar to isspace(), except it
// does not consider newlines to be whitespace. It also
// includes the soft-hyphen character.
////////////////////////////////////////////////////////////////////
static INLINE bool
isbreakpoint(unsigned int ch) {
return (ch == ' ' || ch == '\t' ||
ch == (unsigned int)text_soft_hyphen_key ||
ch == (unsigned int)text_soft_break_key);
}
////////////////////////////////////////////////////////////////////
// Function: isspacew
// Description: An internal function that works like isspace() but is
// safe to call for a wide character.
////////////////////////////////////////////////////////////////////
static INLINE bool
isspacew(unsigned int ch) {
return isascii(ch) && isspace(ch);
}
////////////////////////////////////////////////////////////////////
// Function: TextFont::Constructor
// Access: Public
@ -66,81 +43,6 @@ TextFont::
~TextFont() {
}
////////////////////////////////////////////////////////////////////
// Function: TextFont::calc_width
// Access: Published
// Description: Returns the width of a single character of the font,
// or 0.0 if the character is not known.
////////////////////////////////////////////////////////////////////
float TextFont::
calc_width(int character) {
if (character == ' ') {
// A space is a special case.
return _space_advance;
}
const TextGlyph *glyph;
get_glyph(character, glyph);
if (glyph == (TextGlyph *)NULL) {
// Unknown character.
return 0.0f;
}
return glyph->get_advance();
}
////////////////////////////////////////////////////////////////////
// Function: TextFont::calc_width
// Access: Published
// Description: Returns the width of a line of text of arbitrary
// characters. The line should not include the newline
// character.
////////////////////////////////////////////////////////////////////
float TextFont::
calc_width(const string &line) {
float width = 0.0f;
string::const_iterator si;
for (si = line.begin(); si != line.end(); ++si) {
width += calc_width(*si);
}
return width;
}
////////////////////////////////////////////////////////////////////
// Function: TextFont::wordwrap_to
// Access: Published
// Description: Inserts newlines into the given text at the
// appropriate places in order to make each line be the
// longest possible line that is not longer than
// wordwrap_width (and does not break any words, if
// possible). Returns the new string.
////////////////////////////////////////////////////////////////////
string TextFont::
wordwrap_to(const string &text, float wordwrap_width,
bool preserve_trailing_whitespace) {
// Elevate the string to a wstring for this operation.
wstring wtext;
wtext.reserve(text.size());
for (string::const_iterator ti = text.begin(); ti != text.end(); ++ti) {
wtext += (unsigned int)(*ti);
}
wtext = wordwrap_to(wtext, wordwrap_width, preserve_trailing_whitespace);
// Back down from wstring to string.
string result;
result.reserve(wtext.size());
for (wstring::const_iterator wi = wtext.begin();
wi != wtext.end();
++wi) {
result += (char)(*wi);
}
return result;
}
////////////////////////////////////////////////////////////////////
// Function: TextFont::write
// Access: Published, Virtual
@ -151,215 +53,3 @@ write(ostream &out, int indent_level) const {
indent(out, indent_level)
<< "TextFont " << get_name() << "\n";
}
////////////////////////////////////////////////////////////////////
// Function: TextFont::calc_width (wide char)
// Access: Public
// Description: Returns the width of a line of text of arbitrary
// characters. The line should not include the newline
// character.
////////////////////////////////////////////////////////////////////
float TextFont::
calc_width(const wstring &line) {
float width = 0.0f;
wstring::const_iterator si;
for (si = line.begin(); si != line.end(); ++si) {
width += calc_width(*si);
}
return width;
}
////////////////////////////////////////////////////////////////////
// Function: TextFont::wordwrap_to (wide char)
// Access: Public
// Description: Inserts newlines into the given text at the
// appropriate places in order to make each line be the
// longest possible line that is not longer than
// wordwrap_width (and does not break any words, if
// possible). Returns the new string.
////////////////////////////////////////////////////////////////////
wstring TextFont::
wordwrap_to(const wstring &text, float wordwrap_width,
bool preserve_trailing_whitespace) {
wstring output_text;
size_t p = 0;
// Preserve any initial whitespace and newlines.
float initial_width = 0.0f;
while (p < text.length() && isspacew(text[p])) {
if (text[p] == '\n') {
initial_width = 0.0f;
} else {
initial_width += calc_width(text[p]);
}
output_text += text[p];
p++;
}
bool needs_newline = false;
while (p < text.length()) {
nassertr(!isspacew(text[p]), wstring());
// Scan the next n characters, until the end of the string or an
// embedded newline character, or we exceed wordwrap_width.
size_t q = p;
bool any_spaces = false;
size_t last_space = 0;
float last_space_width = 0.0f;
bool any_hyphens = false;
size_t last_hyphen = 0;
bool output_hyphen = false;
bool overflow = false;
bool last_was_space = false;
float hyphen_width = calc_width(*text_soft_hyphen_output);
float width = initial_width;
while (q < text.length() && text[q] != '\n') {
if (isspacew(text[q]) || text[q] == text_soft_break_key) {
if (!last_was_space) {
any_spaces = true;
// We only care about logging whether there is a soft-hyphen
// character to the right of the rightmost space. Each time
// we encounter a space, we reset this counter.
any_hyphens = false;
last_space = q;
last_space_width = width;
last_was_space = true;
}
} else {
last_was_space = false;
}
// A soft hyphen character is not printed, but marks a point
// at which we might hyphenate a word if we need to.
if (text[q] == text_soft_hyphen_key) {
// We only consider this as a possible hyphenation point if
// (a) it is not the very first character, and (b) there is
// enough room for a hyphen character to be printed following
// it.
if (q != p && width + hyphen_width <= wordwrap_width) {
any_hyphens = true;
last_hyphen = q;
}
} else if (text[q] != text_soft_break_key) {
// Some normal, printable character.
width += calc_width(text[q]);
}
q++;
if (width > wordwrap_width) {
// Oops, too many.
q--;
overflow = true;
break;
}
}
if (overflow) {
// If we stopped because we exceeded the wordwrap width, then
// try to find an appropriate place to wrap the line or to
// hyphenate, if necessary.
if (any_spaces && last_space_width / wordwrap_width >= text_hyphen_ratio) {
// If we have a space that ended up within our safety margin,
// don't use any soft-hyphen characters.
any_hyphens = false;
}
if (any_hyphens) {
// If we still have a soft-hyphen character, use it.
q = last_hyphen;
output_hyphen = true;
} else if (any_spaces) {
// Otherwise, break at a space if we can.
q = last_space;
} else {
// Otherwise, this is a forced break. Accept the longest line
// we can that does not leave the next line beginning with one
// of our forbidden characters.
size_t i = 0;
while ((int)i < text_max_never_break && q - i > p &&
text_never_break_before->find(text[q - i]) != wstring::npos) {
i++;
}
if ((int)i < text_max_never_break) {
q -= i;
}
}
}
// Skip additional whitespace between the lines.
size_t next_start = q;
while (next_start < text.length() && isbreakpoint(text[next_start])) {
next_start++;
}
// Trim off any more blanks on the end.
while (q > p && isspacew(text[q - 1])) {
q--;
}
if (next_start == p) {
// No characters got in at all. This could only happen if the
// wordwrap width is narrower than a single character, or if we
// have a substantial number of leading spaces in a line.
q++;
next_start++;
while (next_start < text.length() && isbreakpoint(text[next_start])) {
next_start++;
}
}
if (needs_newline) {
output_text += '\n';
}
needs_newline = true;
if (preserve_trailing_whitespace) {
q = next_start;
}
for (size_t pi = p; pi < q; pi++) {
if (text[pi] != text_soft_hyphen_key &&
text[pi] != text_soft_break_key) {
output_text += text[pi];
}
}
if (output_hyphen) {
output_text += *text_soft_hyphen_output;
}
// Now prepare to wrap the next line.
if (next_start < text.length() && text[next_start] == '\n') {
// Preserve a single embedded newline.
output_text += '\n';
next_start++;
needs_newline = false;
}
p = next_start;
// Preserve any initial whitespace and newlines.
initial_width = 0.0f;
while (p < text.length() && isspacew(text[p])) {
if (text[p] == '\n') {
initial_width = 0.0f;
} else {
initial_width += calc_width(text[p]);
}
output_text += text[p];
p++;
}
}
return output_text;
}

View File

@ -53,15 +53,9 @@ PUBLISHED:
INLINE float get_space_advance() const;
INLINE void set_space_advance(float space_advance);
float calc_width(int character);
float calc_width(const string &line);
string wordwrap_to(const string &text, float wordwrap_width,
bool preserve_trailing_whitespace);
virtual void write(ostream &out, int indent_level) const;
public:
float calc_width(const wstring &line);
wstring wordwrap_to(const wstring &text, float wordwrap_width,
bool preserve_trailing_whitespace);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -23,13 +23,12 @@
#include "config_text.h"
#include "textEncoder.h"
#include "textProperties.h"
#include "textFont.h"
#include "unicodeLatinMap.h"
#include "textAssembler.h"
#include "pandaNode.h"
#include "luse.h"
class StringDecoder;
////////////////////////////////////////////////////////////////////
// Class : TextNode
// Description : The primary interface to this module. This class
@ -53,49 +52,19 @@ class StringDecoder;
// you may use however you like. Each time you call
// generate() a new node is returned.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA TextNode : public PandaNode, public TextEncoder {
class EXPCL_PANDA TextNode : public PandaNode, public TextEncoder, public TextProperties {
PUBLISHED:
TextNode(const string &name);
TextNode(const string &name, const TextProperties &copy);
~TextNode();
enum Alignment {
A_left,
A_right,
A_center,
};
INLINE int freeze();
INLINE int thaw();
INLINE void set_font(TextFont *font);
INLINE TextFont *get_font() const;
INLINE static void set_default_font(TextFont *);
INLINE static TextFont *get_default_font();
INLINE float get_line_height() const;
INLINE void set_small_caps(bool small_caps);
INLINE bool get_small_caps() const;
INLINE void set_small_caps_scale(float small_caps_scale);
INLINE float get_small_caps_scale() const;
INLINE void set_slant(float slant);
INLINE float get_slant() const;
INLINE void set_align(Alignment align_type);
INLINE Alignment get_align() const;
INLINE void set_wordwrap(float width);
INLINE void clear_wordwrap();
INLINE bool has_wordwrap() const;
INLINE float get_wordwrap() const;
INLINE void set_text_color(float r, float g, float b, float a);
INLINE void set_text_color(const Colorf &text_color);
INLINE void clear_text_color();
INLINE bool has_text_color() const;
INLINE Colorf get_text_color() const;
INLINE void set_max_rows(int max_rows);
INLINE void clear_max_rows();
INLINE bool has_max_rows() const;
INLINE int get_max_rows() const;
INLINE bool has_overflow() const;
INLINE void set_frame_color(float r, float g, float b, float a);
INLINE void set_frame_color(const Colorf &frame_color);
@ -116,10 +85,6 @@ PUBLISHED:
INLINE bool has_card_texture() const;
INLINE Texture *get_card_texture() const;
INLINE void set_shadow_color(float r, float g, float b, float a);
INLINE void set_shadow_color(const Colorf &shadow_color);
INLINE Colorf get_shadow_color() const;
INLINE void set_frame_as_margin(float left, float right,
float bottom, float top);
INLINE void set_frame_actual(float left, float right,
@ -146,28 +111,64 @@ PUBLISHED:
INLINE LVecBase4f get_card_actual() const;
INLINE LVecBase4f get_card_transformed() const;
INLINE void set_shadow(float xoffset, float yoffset);
INLINE void clear_shadow();
INLINE bool has_shadow() const;
INLINE LVecBase2f get_shadow() const;
INLINE void set_bin(const string &bin);
INLINE void clear_bin();
INLINE bool has_bin() const;
INLINE const string &get_bin() const;
INLINE int set_draw_order(int draw_order);
INLINE int get_draw_order() const;
INLINE void set_tab_width(float tab_width);
INLINE float get_tab_width() const;
INLINE void set_transform(const LMatrix4f &transform);
INLINE LMatrix4f get_transform() const;
INLINE void set_coordinate_system(CoordinateSystem cs);
INLINE CoordinateSystem get_coordinate_system() const;
// These methods are inherited from TextProperties, but we override
// here so we can flag the TextNode as dirty when they have been
// change.
INLINE void set_font(TextFont *font);
INLINE void clear_font();
INLINE void set_small_caps(bool small_caps);
INLINE void clear_small_caps();
INLINE void set_small_caps_scale(float small_caps_scale);
INLINE void clear_small_caps_scale();
INLINE void set_slant(float slant);
INLINE void clear_slant();
INLINE void set_align(Alignment align_type);
INLINE void clear_align();
INLINE void set_indent(float indent);
INLINE void clear_indent();
INLINE void set_wordwrap(float wordwrap);
INLINE void clear_wordwrap();
INLINE void set_text_color(float r, float g, float b, float a);
INLINE void set_text_color(const Colorf &text_color);
INLINE void clear_text_color();
INLINE void set_shadow_color(float r, float g, float b, float a);
INLINE void set_shadow_color(const Colorf &shadow_color);
INLINE void clear_shadow_color();
INLINE void set_shadow(float xoffset, float yoffset);
INLINE void set_shadow(const LVecBase2f &shadow_offset);
INLINE void clear_shadow();
INLINE void set_bin(const string &bin);
INLINE void clear_bin();
INLINE int set_draw_order(int draw_order);
INLINE void clear_draw_order();
INLINE void set_tab_width(float tab_width);
INLINE void clear_tab_width();
INLINE void set_glyph_scale(float glyph_scale);
INLINE void clear_glyph_scale();
INLINE void set_glyph_shift(float glyph_shift);
INLINE void clear_glyph_shift();
// These methods are inherited from TextEncoder, but we override
// here so we can flag the TextNode as dirty when they have been
// change.
@ -177,10 +178,14 @@ PUBLISHED:
INLINE void append_text(const string &text);
INLINE void append_unicode_char(int character);
INLINE float calc_width(int character) const;
// After the text has been set, you can query this to determine how
// it will be wordwrapped.
INLINE string get_wordwrapped_text() const;
// These methods calculate the width of a single character or a line
// of text in the current font.
float calc_width(int character) const;
INLINE float calc_width(const string &line) const;
string wordwrap_to(const string &text, float wordwrap_width,
bool preserve_trailing_whitespace) const;
virtual void write(ostream &out, int indent_level = 0) const;
@ -207,9 +212,8 @@ public:
INLINE void set_wtext(const wstring &wtext);
INLINE void append_wtext(const wstring &text);
INLINE float calc_width(const wstring &line) const;
INLINE wstring wordwrap_to(const wstring &wtext, float wordwrap_width,
bool preserve_trailing_whitespace) const;
INLINE wstring get_wordwrapped_wtext() const;
float calc_width(const wstring &line) const;
// From parent class PandaNode
virtual int get_unsafe_to_apply_attribs() const;
@ -235,123 +239,47 @@ private:
void do_rebuild();
void do_measure();
#ifndef CPPPARSER // interrogate has a bit of trouble with wstring.
float assemble_row(wstring::iterator &si, const wstring::iterator &send,
TextFont *font, GeomNode *dest, const LMatrix4f &mat);
PT(PandaNode) assemble_text(wstring::iterator si, const wstring::iterator &send,
TextFont *font,
LVector2f &ul, LVector2f &lr, int &num_rows);
float measure_row(wstring::iterator &si, const wstring::iterator &send,
TextFont *font);
void measure_text(wstring::iterator si, const wstring::iterator &send,
TextFont *font,
LVector2f &ul, LVector2f &lr, int &num_rows);
#endif // CPPPARSER
enum CheesyPlacement {
CP_above,
CP_below,
CP_top,
CP_bottom,
CP_within,
};
enum CheesyTransform {
CT_none,
CT_mirror_x,
CT_mirror_y,
CT_rotate_90,
CT_rotate_180,
CT_rotate_270,
CT_squash,
CT_squash_mirror_y,
CT_squash_mirror_diag,
CT_small_squash,
CT_small_squash_mirror_y,
CT_small,
CT_small_rotate_270,
CT_tiny,
CT_tiny_mirror_x,
CT_tiny_rotate_270,
};
void get_character_glyphs(int character, TextFont *font,
bool &got_glyph, const TextGlyph *&glyph,
const TextGlyph *&second_glyph,
UnicodeLatinMap::AccentType &accent_type,
int &additional_flags,
float &glyph_scale, float &advance_scale);
void tack_on_accent(UnicodeLatinMap::AccentType accent_type,
const LPoint3f &min_vert, const LPoint3f &max_vert,
const LPoint3f &centroid,
TextFont *font, GeomNode *dest,
Geom *geom_array[], int &num_geoms);
bool tack_on_accent(char accent_mark, CheesyPlacement placement,
CheesyTransform transform,
const LPoint3f &min_vert, const LPoint3f &max_vert,
const LPoint3f &centroid,
TextFont *font, GeomNode *dest,
Geom *geom_array[], int &num_geoms);
PT(PandaNode) make_frame();
PT(PandaNode) make_card();
PT(PandaNode) make_card_with_border();
static void load_default_font();
PT(TextFont) _font;
PT(PandaNode) _internal_geom;
float _slant;
PT(Texture) _card_texture;
Colorf _text_color;
Colorf _shadow_color;
Colorf _frame_color;
Colorf _card_color;
enum Flags {
F_has_text_color = 0x00000001,
F_has_wordwrap = 0x00000002,
F_has_frame = 0x00000004,
F_frame_as_margin = 0x00000008,
F_has_card = 0x00000010,
F_card_as_margin = 0x00000020,
F_has_card_texture = 0x00000040,
F_has_shadow = 0x00000080,
F_frame_corners = 0x00000100,
F_card_transp = 0x00000200,
F_has_card_border = 0x00000400,
F_needs_rebuild = 0x00004000,
F_needs_measure = 0x00008000,
F_small_caps = 0x00010000,
F_has_frame = 0x0001,
F_frame_as_margin = 0x0002,
F_has_card = 0x0004,
F_card_as_margin = 0x0008,
F_has_card_texture = 0x0010,
F_frame_corners = 0x0020,
F_card_transp = 0x0040,
F_has_card_border = 0x0080,
F_needs_rebuild = 0x0100,
F_needs_measure = 0x0200,
F_has_overflow = 0x0400,
};
int _flags;
Alignment _align;
float _wordwrap_width;
int _max_rows;
float _frame_width;
float _card_border_size;
float _card_border_uv_portion;
float _small_caps_scale;
LVector2f _frame_ul, _frame_lr;
LVector2f _card_ul, _card_lr;
LVector2f _shadow_offset;
string _bin;
int _draw_order;
float _tab_width;
LMatrix4f _transform;
CoordinateSystem _coordinate_system;
LPoint2f _ul2d, _lr2d;
LPoint3f _ul3d, _lr3d;
int _num_rows;
static PT(TextFont) _default_font;
static bool _loaded_default_font;
#ifndef CPPPARSER
TextAssembler _assembler;
#endif
public:
static TypeHandle get_class_type() {
@ -359,9 +287,12 @@ public:
}
static void init_type() {
PandaNode::init_type();
TextEncoder::init_type();
TextProperties::init_type();
register_type(_type_handle, "TextNode",
PandaNode::get_class_type(),
TextEncoder::get_class_type());
TextEncoder::get_class_type(),
TextProperties::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();

View File

@ -0,0 +1,842 @@
// Filename: textProperties.I
// Created by: drose (06Apr04)
//
////////////////////////////////////////////////////////////////////
//
// 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: TextProperties::is_any_specified
// Access: Published
// Description: Returns true if any properties have been specified,
// false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool TextProperties::
is_any_specified() const {
return (_specified != 0);
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::set_default_font
// Access: Published, Static
// Description: Specifies the default font to be used for any
// TextNode whose font is uninitialized or NULL. See
// set_font().
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
set_default_font(TextFont *font) {
// If the user overrides the default, we don't need to try to load
// whatever it would have been.
_loaded_default_font = true;
_default_font = font;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::get_default_font
// Access: Published, Static
// Description: Specifies the default font to be used for any
// TextNode whose font is uninitialized or NULL. See
// set_font().
////////////////////////////////////////////////////////////////////
INLINE TextFont *TextProperties::
get_default_font() {
if (!_loaded_default_font) {
load_default_font();
}
return _default_font;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::set_font
// Access: Published
// Description: 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 TextProperties::
set_font(TextFont *font) {
_font = font;
_specified |= F_has_font;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::clear_font
// Access: Published
// Description: Restores the default font to the text.
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
clear_font() {
_font.clear();
_specified &= ~F_has_font;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::has_font
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool TextProperties::
has_font() const {
return (_specified & F_has_font) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::get_font
// Access: Published
// Description: Returns the font currently in use, if any. If no
// font is in use, this returns the default font.
////////////////////////////////////////////////////////////////////
INLINE TextFont *TextProperties::
get_font() const {
return has_font() ? _font.p() : get_default_font();
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::set_small_caps
// Access: Published
// Description: 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 TextProperties::
set_small_caps(bool small_caps) {
_small_caps = small_caps;
_specified |= F_has_small_caps;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::clear_small_caps
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
clear_small_caps() {
_small_caps = false;
_specified &= ~F_has_small_caps;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::has_small_caps
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool TextProperties::
has_small_caps() const {
return (_specified & F_has_small_caps) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::get_small_caps
// Access: Published
// Description: Returns the small_caps flag. See set_small_caps().
////////////////////////////////////////////////////////////////////
INLINE bool TextProperties::
get_small_caps() const {
return _small_caps;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::set_small_caps_scale
// Access: Published
// Description: 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 TextProperties::
set_small_caps_scale(float small_caps_scale) {
_small_caps_scale = small_caps_scale;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::clear_small_caps_scale
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
clear_small_caps_scale() {
_small_caps_scale = text_small_caps_scale;
_specified &= ~F_has_small_caps_scale;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::has_small_caps_scale
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool TextProperties::
has_small_caps_scale() const {
return (_specified & F_has_small_caps_scale) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::get_small_caps_scale
// Access: Published
// Description: Returns the scale factor applied to lowercase letters
// from their uppercase equivalents, when the small_caps
// flag is in effect. See set_small_caps() and
// set_small_caps_scale().
////////////////////////////////////////////////////////////////////
INLINE float TextProperties::
get_small_caps_scale() const {
return _small_caps_scale;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::set_slant
// Access: Published
// Description: Specifies the factor by which the text slants to the
// right.
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
set_slant(float slant) {
_slant = slant;
_specified |= F_has_slant;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::clear_slant
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
clear_slant() {
_slant = 0.0f;
_specified &= ~F_has_slant;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::has_slant
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool TextProperties::
has_slant() const {
return (_specified & F_has_slant) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::get_slant
// Access: Published
// Description: Returns the factor by which the text is specified to
// slant to the right.
////////////////////////////////////////////////////////////////////
INLINE float TextProperties::
get_slant() const {
return _slant;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::set_align
// Access: Published
// Description: Specifies the alignment of the text within its
// margins.
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
set_align(TextProperties::Alignment align_type) {
_align = align_type;
_specified |= F_has_align;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::clear_align
// Access: Published
// Description: Restores the default alignment of the text.
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
clear_align() {
_align = A_left;
_specified &= ~F_has_align;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::has_align
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool TextProperties::
has_align() const {
return (_specified & F_has_align) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::get_align
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE TextProperties::Alignment TextProperties::
get_align() const {
return _align;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::set_indent
// Access: Published
// Description: 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 TextProperties::
set_indent(float indent) {
_indent_width = indent;
_specified |= F_has_indent;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::clear_indent
// Access: Published
// Description: Removes the indent setting from the text. Text
// will be as wide as it is.
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
clear_indent() {
_indent_width = 0.0f;
_specified &= ~F_has_indent;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::has_indent
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool TextProperties::
has_indent() const {
return (_specified & F_has_indent) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::get_indent
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE float TextProperties::
get_indent() const {
return _indent_width;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::set_wordwrap
// Access: Published
// Description: 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 TextProperties::
set_wordwrap(float wordwrap) {
_wordwrap_width = wordwrap;
_specified |= F_has_wordwrap;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::clear_wordwrap
// Access: Published
// Description: Removes the wordwrap setting from the text. Text
// will be as wide as it is.
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
clear_wordwrap() {
_wordwrap_width = 0.0f;
_specified &= ~F_has_wordwrap;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::has_wordwrap
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool TextProperties::
has_wordwrap() const {
return (_specified & F_has_wordwrap) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::get_wordwrap
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE float TextProperties::
get_wordwrap() const {
return _wordwrap_width;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::set_preserve_trailing_whitespace
// Access: Published
// Description: Sets the preserve_trailing_whitespace flag. When
// this is set, trailing whitespace at the end of the
// line is not stripped when the text is wordwrapped (it
// is stripped by default). Since the trailing
// whitespace is invisible, this is important primarily
// for determining the proper width of a frame or card
// behind the text.
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
set_preserve_trailing_whitespace(bool preserve_trailing_whitespace) {
_preserve_trailing_whitespace = preserve_trailing_whitespace;
_specified |= F_has_preserve_trailing_whitespace;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::clear_preserve_trailing_whitespace
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
clear_preserve_trailing_whitespace() {
_preserve_trailing_whitespace = false;
_specified &= ~F_has_preserve_trailing_whitespace;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::has_preserve_trailing_whitespace
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool TextProperties::
has_preserve_trailing_whitespace() const {
return (_specified & F_has_preserve_trailing_whitespace) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::get_preserve_trailing_whitespace
// Access: Published
// Description: Returns the preserve_trailing_whitespace flag. See
// set_preserve_trailing_whitespace().
////////////////////////////////////////////////////////////////////
INLINE bool TextProperties::
get_preserve_trailing_whitespace() const {
return _preserve_trailing_whitespace;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::set_text_color
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
set_text_color(float r, float g, float b, float a) {
set_text_color(Colorf(r, g, b, a));
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::set_text_color
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
set_text_color(const Colorf &text_color) {
_text_color = text_color;
_specified |= F_has_text_color;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::clear_text_color
// Access: Published
// Description: Removes the text color specification; the text will
// be colored whatever it was in the source font file.
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
clear_text_color() {
_text_color.set(1.0f, 1.0f, 1.0f, 1.0f);
_specified &= ~F_has_text_color;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::has_text_color
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool TextProperties::
has_text_color() const {
return (_specified & F_has_text_color) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::get_text_color
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE Colorf TextProperties::
get_text_color() const {
return _text_color;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::set_shadow_color
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
set_shadow_color(float r, float g, float b, float a) {
set_shadow_color(Colorf(r, g, b, a));
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::set_shadow_color
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
set_shadow_color(const Colorf &shadow_color) {
_shadow_color = shadow_color;
_specified |= F_has_shadow_color;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::clear_shadow_color
// Access: Published
// Description: Removes the shadow color specification.
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
clear_shadow_color() {
_shadow_color.set(0.0f, 0.0f, 0.0f, 1.0f);
_specified &= ~F_has_shadow_color;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::has_shadow_color
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool TextProperties::
has_shadow_color() const {
return (_specified & F_has_shadow_color) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::get_shadow_color
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE Colorf TextProperties::
get_shadow_color() const {
return _shadow_color;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::set_shadow
// Access: Published
// Description: 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 TextProperties::
set_shadow(float xoffset, float yoffset) {
set_shadow(LVecBase2f(xoffset, yoffset));
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::set_shadow
// Access: Published
// Description: 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 TextProperties::
set_shadow(const LVecBase2f &shadow_offset) {
_shadow_offset = shadow_offset;
_specified |= F_has_shadow;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::clear_shadow
// Access: Published
// Description: Specifies that a shadow will not be drawn behind the
// text.
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
clear_shadow() {
_specified &= ~F_has_shadow;
_shadow_offset.set(0.0f, 0.0f);
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::has_shadow
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool TextProperties::
has_shadow() const {
return (_specified & F_has_shadow) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::get_shadow
// Access: Published
// Description: Returns the offset of the shadow as set by
// set_shadow(). It is an error to call this if
// has_shadow() is false.
////////////////////////////////////////////////////////////////////
INLINE LVector2f TextProperties::
get_shadow() const {
return _shadow_offset;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::set_bin
// Access: Published
// Description: Names the CullBin that the text geometry should be
// assigned to. If this is set, then a CullBinAttrib
// will be created to explicitly place each component in
// the named bin.
//
// The draw_order value will also be passed to each
// CullBinAttrib as appropriate; this is particularly
// useful if this names a CullBinFixed, e.g. "fixed".
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
set_bin(const string &bin) {
_bin = bin;
_specified |= F_has_bin;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::clear_bin
// Access: Published
// Description: 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 TextProperties::
clear_bin() {
_bin = string();
_specified &= ~F_has_bin;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::has_bin
// Access: Published
// Description: Returns true if an explicit drawing bin has been
// set via set_bin(), false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool TextProperties::
has_bin() const {
return (_specified & F_has_bin) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::get_bin
// Access: Published
// Description: Returns the drawing bin set with set_bin(), or empty
// string if no bin has been set.
////////////////////////////////////////////////////////////////////
INLINE const string &TextProperties::
get_bin() const {
return _bin;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::set_draw_order
// Access: Published
// Description: Sets the drawing order of text created by the
// TextNode. 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 nodes
// 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 TextProperties::
set_draw_order(int draw_order) {
_draw_order = draw_order;
_specified |= F_has_draw_order;
return _draw_order + 3;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::clear_draw_order
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
clear_draw_order() {
_draw_order = 1;
_specified &= ~F_has_draw_order;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::has_draw_order
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool TextProperties::
has_draw_order() const {
return (_specified & F_has_draw_order) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::get_draw_order
// Access: Published
// Description: Returns the drawing order set with set_draw_order().
////////////////////////////////////////////////////////////////////
INLINE int TextProperties::
get_draw_order() const {
return _draw_order;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::set_tab_width
// Access: Published
// Description: 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 TextProperties::
set_tab_width(float tab_width) {
_tab_width = tab_width;
_specified |= F_has_tab_width;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::clear_tab_width
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
clear_tab_width() {
_tab_width = text_tab_width;
_specified &= ~F_has_tab_width;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::has_tab_width
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool TextProperties::
has_tab_width() const {
return (_specified & F_has_tab_width) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::get_tab_width
// Access: Published
// Description: Returns the width set via set_tab_width().
////////////////////////////////////////////////////////////////////
INLINE float TextProperties::
get_tab_width() const {
return _tab_width;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::set_glyph_scale
// Access: Published
// Description: 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 TextProperties::
set_glyph_scale(float glyph_scale) {
_glyph_scale = glyph_scale;
_specified |= F_has_glyph_scale;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::clear_glyph_scale
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
clear_glyph_scale() {
_specified &= ~F_has_glyph_scale;
_glyph_scale = 0.0f;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::has_glyph_scale
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool TextProperties::
has_glyph_scale() const {
return (_specified & F_has_glyph_scale) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::get_glyph_scale
// Access: Published
// Description: Returns the scale factor of each letter as specified
// by set_glyph_scale().
////////////////////////////////////////////////////////////////////
INLINE float TextProperties::
get_glyph_scale() const {
return _glyph_scale;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::set_glyph_shift
// Access: Published
// Description: 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 TextProperties::
set_glyph_shift(float glyph_shift) {
_glyph_shift = glyph_shift;
_specified |= F_has_glyph_shift;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::clear_glyph_shift
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void TextProperties::
clear_glyph_shift() {
_specified &= ~F_has_glyph_shift;
_glyph_shift = 0.0f;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::has_glyph_shift
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool TextProperties::
has_glyph_shift() const {
return (_specified & F_has_glyph_shift) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::get_glyph_shift
// Access: Published
// Description: Returns the vertical shift of each letter as
// specified by set_glyph_shift().
////////////////////////////////////////////////////////////////////
INLINE float TextProperties::
get_glyph_shift() const {
return _glyph_shift;
}

View File

@ -0,0 +1,318 @@
// Filename: textProperties.cxx
// Created by: drose (06Apr04)
//
////////////////////////////////////////////////////////////////////
//
// 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 "textProperties.h"
#include "config_text.h"
#include "default_font.h"
#include "dynamicTextFont.h"
#include "staticTextFont.h"
#include "bamFile.h"
#include "fontPool.h"
PT(TextFont) TextProperties::_default_font;
bool TextProperties::_loaded_default_font = false;
TypeHandle TextProperties::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: TextProperties::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
TextProperties::
TextProperties() {
_specified = 0;
_small_caps = false;
_small_caps_scale = text_small_caps_scale;
_slant = 0.0f;
_align = A_left;
_indent_width = 0.0f;
_wordwrap_width = 0.0f;
_preserve_trailing_whitespace = false;
_text_color.set(1.0f, 1.0f, 1.0f, 1.0f);
_shadow_color.set(1.0f, 1.0f, 1.0f, 1.0f);
_shadow_offset.set(0.0f, 0.0f);
_draw_order = 1;
_tab_width = text_tab_width;
_glyph_scale = 1.0f;
_glyph_shift = 0.0f;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::Copy Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
TextProperties::
TextProperties(const TextProperties &copy) {
(*this) = copy;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::Copy Assignment Operator
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
void TextProperties::
operator = (const TextProperties &copy) {
_specified = copy._specified;
_font = copy._font;
_small_caps = copy._small_caps;
_small_caps_scale = copy._small_caps_scale;
_slant = copy._slant;
_align = copy._align;
_indent_width = copy._indent_width;
_wordwrap_width = copy._wordwrap_width;
_preserve_trailing_whitespace = copy._preserve_trailing_whitespace;
_text_color = copy._text_color;
_shadow_color = copy._shadow_color;
_shadow_offset = copy._shadow_offset;
_bin = copy._bin;
_draw_order = copy._draw_order;
_tab_width = copy._tab_width;
_glyph_scale = copy._glyph_scale;
_glyph_shift = copy._glyph_shift;
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::clear
// Access: Published
// Description: Unsets all properties that have been specified so
// far, and resets the TextProperties structure to its
// initial empty state.
////////////////////////////////////////////////////////////////////
void TextProperties::
clear() {
(*this) = TextProperties();
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::add_properties
// Access: Published
// Description: Sets any properties that are explicitly specified in
// other on this object. Leaves other properties
// unchanged.
////////////////////////////////////////////////////////////////////
void TextProperties::
add_properties(const TextProperties &other) {
if (other.has_font()) {
set_font(other.get_font());
}
if (other.has_small_caps()) {
set_small_caps(other.get_small_caps());
set_small_caps_scale(other.get_small_caps_scale());
}
if (other.has_slant()) {
set_slant(other.get_slant());
}
if (other.has_align()) {
set_align(other.get_align());
}
if (other.has_indent()) {
set_indent(other.get_indent());
}
if (other.has_wordwrap()) {
set_wordwrap(other.get_wordwrap());
}
if (other.has_text_color()) {
set_text_color(other.get_text_color());
}
if (other.has_shadow_color()) {
set_shadow_color(other.get_shadow_color());
}
if (other.has_shadow()) {
set_shadow(other.get_shadow());
}
if (other.has_bin()) {
set_bin(other.get_bin());
}
if (other.has_draw_order()) {
set_draw_order(other.get_draw_order());
}
if (other.has_tab_width()) {
set_tab_width(other.get_tab_width());
}
// The glyph scale and shift are a special case: rather than
// replacing the previous value, they modify it.
if (other.has_glyph_shift()) {
set_glyph_shift(other.get_glyph_shift() * get_glyph_scale() + get_glyph_shift());
}
if (other.has_glyph_scale()) {
set_glyph_scale(other.get_glyph_scale() * get_glyph_scale());
}
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::write
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
void TextProperties::
write(ostream &out, int indent_level) const {
if (!is_any_specified()) {
indent(out, indent_level)
<< "default properties\n";
}
if (has_font()) {
if (get_font() != (TextFont *)NULL) {
indent(out, indent_level)
<< "with font " << _font->get_name() << "\n";
} else {
indent(out, indent_level)
<< "with NULL font\n";
}
}
if (has_small_caps()) {
indent(out, indent_level)
<< "small caps = " << get_small_caps() << "\n";
}
if (has_small_caps_scale()) {
indent(out, indent_level)
<< "small caps scale = " << get_small_caps_scale() << "\n";
}
if (has_slant()) {
indent(out, indent_level)
<< "slant = " << get_slant() << "\n";
}
if (has_align()) {
indent(out, indent_level)
<< "alignment is ";
switch (get_align()) {
case A_left:
out << "A_left\n";
break;
case A_right:
out << "A_right\n";
break;
case A_center:
out << "A_center\n";
break;
}
}
if (has_indent()) {
indent(out, indent_level)
<< "indent at " << get_indent() << " units.\n";
}
if (has_wordwrap()) {
indent(out, indent_level)
<< "word-wrapping at " << get_wordwrap() << " units.\n";
}
if (has_text_color()) {
indent(out, indent_level)
<< "text color is " << get_text_color() << "\n";
}
if (has_shadow()) {
indent(out, indent_level)
<< "shadow at " << get_shadow() << "\n";
}
if (has_shadow_color()) {
indent(out, indent_level)
<< "shadow color is " << get_shadow_color() << "\n";
}
if (has_bin()) {
indent(out, indent_level)
<< "bin is " << get_bin() << "\n";
}
if (has_draw_order()) {
indent(out, indent_level)
<< "draw order is " << get_draw_order() << "\n";
}
if (has_tab_width()) {
indent(out, indent_level)
<< "tab width is " << get_tab_width() << "\n";
}
if (has_glyph_scale()) {
indent(out, indent_level)
<< "glyph scale is " << get_glyph_scale() << "\n";
}
if (has_glyph_shift()) {
indent(out, indent_level)
<< "glyph shift is " << get_glyph_shift() << "\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: TextProperties::load_default_font
// Access: Private, Static
// Description: This function is called once (or never), the first
// time someone attempts to render a TextNode using the
// default font. It should attempt to load the default
// font, using the compiled-in version if it is
// available, or whatever system file may be named in
// Configrc.
////////////////////////////////////////////////////////////////////
void TextProperties::
load_default_font() {
_loaded_default_font = true;
if (!text_default_font.empty()) {
// First, attempt to load the user-specified filename.
_default_font = FontPool::load_font(text_default_font);
if (_default_font->is_valid()) {
return;
}
}
// Then, attempt to load the compiled-in font, if we have one.
#ifdef COMPILE_IN_DEFAULT_FONT
#ifdef HAVE_FREETYPE
// Loading the compiled-in FreeType font is relatively easy.
_default_font = new DynamicTextFont((const char *)default_font_data,
default_font_size, 0);
#else
// The compiled-in Bam font requires creating a BamFile object to
// decode it.
string data((const char *)default_font_data, default_font_size);
#ifdef HAVE_ZLIB
// The font data is stored compressed; decompress it on-the-fly.
istringstream inz(data);
IDecompressStream in(&inz, false);
#else
// The font data is stored uncompressed, so just load it.
istringstream in(data);
#endif // HAVE_ZLIB
BamFile bam_file;
if (bam_file.open_read(in, "default font stream")) {
PT(PandaNode) node = bam_file.read_node();
if (node != (PandaNode *)NULL) {
_default_font = new StaticTextFont(node);
}
}
#endif // HAVE_FREETYPE
#endif // COMPILE_IN_DEFAULT_FONT
}

View File

@ -0,0 +1,213 @@
// Filename: textProperties.h
// Created by: drose (06Apr04)
//
////////////////////////////////////////////////////////////////////
//
// 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 TEXTPROPERTIES_H
#define TEXTPROPERTIES_H
#include "pandabase.h"
#include "config_text.h"
#include "luse.h"
#include "textFont.h"
#include "pointerTo.h"
////////////////////////////////////////////////////////////////////
// Class : TextProperties
// Description : This defines the set of visual properties that may be
// assigned to the individual characters of the text.
// (Properties which affect the overall block of text
// can only be specified on the TextNode directly).
//
// Typically, there is just one set of properties on a
// given block of text, which is set directly on the
// TextNode (TextNode inherits from TextProperties).
// That makes all of the text within a particular block
// have the same appearance.
//
// This separate class exists in order to implement
// multiple different kinds of text appearing within one
// block. The text string itself may reference a
// TextProperties structure by name using the \1 and \2
// tokens embedded within the string; each nested
// TextProperties structure modifies the appearance of
// subsequent text within the block.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA TextProperties {
PUBLISHED:
enum Alignment {
A_left,
A_right,
A_center,
};
TextProperties();
TextProperties(const TextProperties &copy);
void operator = (const TextProperties &copy);
void clear();
INLINE bool is_any_specified() const;
INLINE static void set_default_font(TextFont *);
INLINE static TextFont *get_default_font();
INLINE void set_font(TextFont *font);
INLINE void clear_font();
INLINE bool has_font() const;
INLINE TextFont *get_font() const;
INLINE void set_small_caps(bool small_caps);
INLINE void clear_small_caps();
INLINE bool has_small_caps() const;
INLINE bool get_small_caps() const;
INLINE void set_small_caps_scale(float small_caps_scale);
INLINE void clear_small_caps_scale();
INLINE bool has_small_caps_scale() const;
INLINE float get_small_caps_scale() const;
INLINE void set_slant(float slant);
INLINE void clear_slant();
INLINE bool has_slant() const;
INLINE float get_slant() const;
INLINE void set_align(Alignment align_type);
INLINE void clear_align();
INLINE bool has_align() const;
INLINE Alignment get_align() const;
INLINE void set_indent(float indent);
INLINE void clear_indent();
INLINE bool has_indent() const;
INLINE float get_indent() const;
INLINE void set_wordwrap(float wordwrap);
INLINE void clear_wordwrap();
INLINE bool has_wordwrap() const;
INLINE float get_wordwrap() const;
INLINE void set_preserve_trailing_whitespace(bool preserve_trailing_whitespace);
INLINE void clear_preserve_trailing_whitespace();
INLINE bool has_preserve_trailing_whitespace() const;
INLINE bool get_preserve_trailing_whitespace() const;
INLINE void set_text_color(float r, float g, float b, float a);
INLINE void set_text_color(const Colorf &text_color);
INLINE void clear_text_color();
INLINE bool has_text_color() const;
INLINE Colorf get_text_color() const;
INLINE void set_shadow_color(float r, float g, float b, float a);
INLINE void set_shadow_color(const Colorf &shadow_color);
INLINE void clear_shadow_color();
INLINE bool has_shadow_color() const;
INLINE Colorf get_shadow_color() const;
INLINE void set_shadow(float xoffset, float yoffset);
INLINE void set_shadow(const LVecBase2f &shadow_offset);
INLINE void clear_shadow();
INLINE bool has_shadow() const;
INLINE LVector2f get_shadow() const;
INLINE void set_bin(const string &bin);
INLINE void clear_bin();
INLINE bool has_bin() const;
INLINE const string &get_bin() const;
INLINE int set_draw_order(int draw_order);
INLINE void clear_draw_order();
INLINE bool has_draw_order() const;
INLINE int get_draw_order() const;
INLINE void set_tab_width(float tab_width);
INLINE void clear_tab_width();
INLINE bool has_tab_width() const;
INLINE float get_tab_width() const;
INLINE void set_glyph_scale(float glyph_scale);
INLINE void clear_glyph_scale();
INLINE bool has_glyph_scale() const;
INLINE float get_glyph_scale() const;
INLINE void set_glyph_shift(float glyph_shift);
INLINE void clear_glyph_shift();
INLINE bool has_glyph_shift() const;
INLINE float get_glyph_shift() const;
void add_properties(const TextProperties &other);
void write(ostream &out, int indent_level = 0) const;
private:
static void load_default_font();
enum Flags {
F_has_font = 0x0001,
F_has_small_caps = 0x0002,
F_has_small_caps_scale = 0x0004,
F_has_slant = 0x0008,
F_has_align = 0x0010,
F_has_indent = 0x0020,
F_has_wordwrap = 0x0040,
F_has_preserve_trailing_whitespace = 0x0080,
F_has_text_color = 0x0100,
F_has_shadow_color = 0x0200,
F_has_shadow = 0x0400,
F_has_bin = 0x0800,
F_has_draw_order = 0x1000,
F_has_tab_width = 0x2000,
F_has_glyph_scale = 0x4000,
F_has_glyph_shift = 0x8000,
};
int _specified;
PT(TextFont) _font;
bool _small_caps;
float _small_caps_scale;
float _slant;
Alignment _align;
float _indent_width;
float _wordwrap_width;
bool _preserve_trailing_whitespace;
Colorf _text_color;
Colorf _shadow_color;
LVector2f _shadow_offset;
string _bin;
int _draw_order;
float _tab_width;
float _glyph_scale;
float _glyph_shift;
static PT(TextFont) _default_font;
static bool _loaded_default_font;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
register_type(_type_handle, "TextProperties");
}
private:
static TypeHandle _type_handle;
};
#include "textProperties.I"
#endif

View File

@ -0,0 +1,18 @@
// Filename: textPropertiesManager.I
// Created by: drose (07Apr04)
//
////////////////////////////////////////////////////////////////////
//
// 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 .
//
////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,148 @@
// Filename: textPropertiesManager.cxx
// Created by: drose (07Apr04)
//
////////////////////////////////////////////////////////////////////
//
// 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 "textPropertiesManager.h"
#include "indent.h"
TextPropertiesManager *TextPropertiesManager::_global_ptr = (TextPropertiesManager *)NULL;
////////////////////////////////////////////////////////////////////
// Function: TextPropertiesManager::Constructor
// Access: Protected
// Description: The constructor is not intended to be called
// directly; there is only one TextPropertiesManager and
// it constructs itself. This could have been a private
// constructor, but gcc issues a spurious warning if the
// constructor is private and the class has no friends.
////////////////////////////////////////////////////////////////////
TextPropertiesManager::
TextPropertiesManager() {
}
////////////////////////////////////////////////////////////////////
// Function: TextPropertiesManager::Destructor
// Access: Protected
// Description: Don't call the destructor.
////////////////////////////////////////////////////////////////////
TextPropertiesManager::
~TextPropertiesManager() {
}
////////////////////////////////////////////////////////////////////
// Function: TextPropertiesManager::set_properties
// Access: Published
// Description: Defines the TextProperties associated with the
// indicated name. When the name is subsequently
// encountered in text embedded between \1 characters in
// a TextNode string, the following text will be
// rendered with these properties.
//
// If there was already a TextProperties structure
// associated with this name, it is quietly replaced
// with the new definition.
////////////////////////////////////////////////////////////////////
void TextPropertiesManager::
set_properties(const string &name, const TextProperties &properties) {
_properties[name] = properties;
}
////////////////////////////////////////////////////////////////////
// Function: TextPropertiesManager::get_properties
// Access: Published
// Description: Returns the TextProperties associated with the
// indicated name. If there was not previously a
// TextProperties associated with this name, a warning
// is printed and then a default TextProperties
// structure is associated with the name, and returned.
//
// Call has_properties() instead to check whether a
// particular name has been defined.
////////////////////////////////////////////////////////////////////
TextProperties TextPropertiesManager::
get_properties(const string &name) {
Properties::const_iterator pi;
pi = _properties.find(name);
if (pi != _properties.end()) {
return (*pi).second;
}
text_cat.warning()
<< "Creating default TextProperties for name '" << name << "'\n";
TextProperties default_properties;
_properties[name] = default_properties;
return default_properties;
}
////////////////////////////////////////////////////////////////////
// Function: TextPropertiesManager::has_properties
// Access: Published
// Description: Returns true if a TextProperties structure has been
// associated with the indicated name, false otherwise.
// Normally this means set_properties() has been called
// with this name, but because get_properties() will
// implicitly create a default TextProperties structure,
// it may also mean simply that get_properties() has
// been called with the indicated name.
////////////////////////////////////////////////////////////////////
bool TextPropertiesManager::
has_properties(const string &name) const {
Properties::const_iterator pi;
pi = _properties.find(name);
return (pi != _properties.end());
}
////////////////////////////////////////////////////////////////////
// Function: TextPropertiesManager::clear_properties
// Access: Published
// Description: Removes the named TextProperties structure from the
// manager.
////////////////////////////////////////////////////////////////////
void TextPropertiesManager::
clear_properties(const string &name) {
_properties.erase(name);
}
////////////////////////////////////////////////////////////////////
// Function: TextPropertiesManager::write
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
void TextPropertiesManager::
write(ostream &out, int indent_level) const {
Properties::const_iterator pi;
for (pi = _properties.begin(); pi != _properties.end(); ++pi) {
indent(out, indent_level)
<< "TextProperties " << (*pi).first << ":\n";
(*pi).second.write(out, indent_level + 2);
}
}
////////////////////////////////////////////////////////////////////
// Function: TextPropertiesManager::get_global_ptr
// Access: Published, Static
// Description: Returns the pointer to the global TextPropertiesManager
// object.
////////////////////////////////////////////////////////////////////
TextPropertiesManager *TextPropertiesManager::
get_global_ptr() {
if (_global_ptr == (TextPropertiesManager *)NULL) {
_global_ptr = new TextPropertiesManager;
}
return _global_ptr;
}

View File

@ -0,0 +1,72 @@
// Filename: textPropertiesManager.h
// Created by: drose (07Apr04)
//
////////////////////////////////////////////////////////////////////
//
// 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 TEXTPROPERTIESMANAGER_H
#define TEXTPROPERTIESMANAGER_H
#include "pandabase.h"
#include "config_text.h"
#include "textProperties.h"
////////////////////////////////////////////////////////////////////
// Class : TextPropertiesManager
// Description : This defines all of the TextProperties structures
// that might be referenced by name from an embedded
// text string.
//
// A text string, as rendered by a TextNode, can contain
// embedded references to one of the TextProperties
// defined here, by enclosing the name between \1 (ASCII
// 0x01) characters; this causes a "push" to the named
// state. All text following the closing \1 character
// will then be rendered in the new state. The next \2
// (ASCII 0x02) character will then restore the previous
// state for subsequent text.
//
// For instance, "x\1up\1n\2 + y" indicates that the
// character "x" will be rendered in the normal state,
// the character "n" will be rendered in the "up" state,
// and then " + y" will be rendered in the normal state
// again.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA TextPropertiesManager {
protected:
TextPropertiesManager();
~TextPropertiesManager();
PUBLISHED:
void set_properties(const string &name, const TextProperties &properties);
TextProperties get_properties(const string &name);
bool has_properties(const string &name) const;
void clear_properties(const string &name);
void write(ostream &out, int indent_level = 0) const;
static TextPropertiesManager *get_global_ptr();
private:
typedef pmap<string, TextProperties> Properties;
Properties _properties;
static TextPropertiesManager *_global_ptr;
};
#include "textPropertiesManager.I"
#endif

View File

@ -6,5 +6,3 @@
#include "fontPool.cxx"
#include "geomTextGlyph.cxx"
#include "staticTextFont.cxx"
#include "textFont.cxx"
#include "textGlyph.cxx"

View File

@ -0,0 +1,6 @@
#include "textAssembler.cxx"
#include "textFont.cxx"
#include "textGlyph.cxx"
#include "textNode.cxx"
#include "textProperties.cxx"
#include "textPropertiesManager.cxx"