support multi-state text blocks; also show IME candidate strings in DirectEntry fields
This commit is contained in:
parent
fd4e0879b8
commit
5d121b8ed9
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ¶m, 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 ¶m, 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 ¶m, 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 ¶m, 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 ¶m, 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));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "fontPool.h"
|
||||
#include "staticTextFont.h"
|
||||
#include "dynamicTextFont.h"
|
||||
#include "config_util.h"
|
||||
#include "config_express.h"
|
||||
#include "virtualFileSystem.h"
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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 ¢roid,
|
||||
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 ¢roid,
|
||||
const TextProperties *properties, GlyphPlacement *placement);
|
||||
|
||||
// These are filled in by assemble_paragraph().
|
||||
LVector2f _ul;
|
||||
LVector2f _lr;
|
||||
|
||||
TextEncoder *_encoder;
|
||||
};
|
||||
|
||||
#include "textAssembler.I"
|
||||
|
||||
#endif // CPPPARSER
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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 ©);
|
||||
~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 ¢roid,
|
||||
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 ¢roid,
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 ©) {
|
||||
(*this) = copy;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TextProperties::Copy Assignment Operator
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TextProperties::
|
||||
operator = (const TextProperties ©) {
|
||||
_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
|
||||
}
|
||||
|
|
@ -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 ©);
|
||||
void operator = (const TextProperties ©);
|
||||
|
||||
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
|
||||
|
|
@ -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 .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -6,5 +6,3 @@
|
|||
#include "fontPool.cxx"
|
||||
#include "geomTextGlyph.cxx"
|
||||
#include "staticTextFont.cxx"
|
||||
#include "textFont.cxx"
|
||||
#include "textGlyph.cxx"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
#include "textAssembler.cxx"
|
||||
#include "textFont.cxx"
|
||||
#include "textGlyph.cxx"
|
||||
#include "textNode.cxx"
|
||||
#include "textProperties.cxx"
|
||||
#include "textPropertiesManager.cxx"
|
||||
Loading…
Reference in New Issue