mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-15 08:16:11 -04:00
PGEntry supports embedded mode changes
This commit is contained in:
parent
504df9ac3c
commit
278fe85c1a
@ -32,6 +32,23 @@ set_text(const string &text) {
|
|||||||
set_wtext(text_node->decode_text(text));
|
set_wtext(text_node->decode_text(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PGEntry::get_plain_text
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the text currently displayed within the
|
||||||
|
// entry, without any embedded properties characters.
|
||||||
|
//
|
||||||
|
// This uses the Unicode encoding currently specified
|
||||||
|
// for the "focus" TextNode; therefore, the TextNode
|
||||||
|
// must exist before calling get_text().
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE string PGEntry::
|
||||||
|
get_plain_text() const {
|
||||||
|
TextNode *text_node = get_text_def(S_focus);
|
||||||
|
nassertr(text_node != (TextNode *)NULL, string());
|
||||||
|
return text_node->encode_wtext(get_plain_wtext());
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: PGEntry::get_text
|
// Function: PGEntry::get_text
|
||||||
// Access: Published
|
// Access: Published
|
||||||
@ -47,6 +64,61 @@ get_text() const {
|
|||||||
return text_node->encode_wtext(get_wtext());
|
return text_node->encode_wtext(get_wtext());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PGEntry::get_num_characters
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the number of characters of text in the
|
||||||
|
// entry. This is the actual number of visible
|
||||||
|
// characters, not counting implicit newlines due to
|
||||||
|
// wordwrapping, or formatted characters for text
|
||||||
|
// properties changes. If there is an embedded
|
||||||
|
// TextGraphic object, it counts as one character.
|
||||||
|
//
|
||||||
|
// This is also the length of the string returned by
|
||||||
|
// get_plain_text().
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE int PGEntry::
|
||||||
|
get_num_characters() const {
|
||||||
|
return _text.get_num_characters();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PGEntry::get_character
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the character at the indicated position in
|
||||||
|
// the entry. If the object at this position is a
|
||||||
|
// graphic object instead of a character, returns 0.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE wchar_t PGEntry::
|
||||||
|
get_character(int n) const {
|
||||||
|
return _text.get_character(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PGEntry::get_graphic
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the graphic object at the indicated position
|
||||||
|
// in the pre-wordwrapped string. If the object at this
|
||||||
|
// position is a character instead of a graphic object,
|
||||||
|
// returns NULL.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE const TextGraphic *PGEntry::
|
||||||
|
get_graphic(int n) const {
|
||||||
|
return _text.get_graphic(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PGEntry::get_properties
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the TextProperties in effect for the object
|
||||||
|
// at the indicated position in the pre-wordwrapped
|
||||||
|
// string.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE const TextProperties &PGEntry::
|
||||||
|
get_properties(int n) const {
|
||||||
|
return _text.get_properties(n);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: PGEntry::set_cursor_position
|
// Function: PGEntry::set_cursor_position
|
||||||
// Access: Published
|
// Access: Published
|
||||||
@ -431,11 +503,25 @@ get_erase_event() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE void PGEntry::
|
INLINE void PGEntry::
|
||||||
set_wtext(const wstring &wtext) {
|
set_wtext(const wstring &wtext) {
|
||||||
_wtext = wtext;
|
_text.set_wtext(wtext);
|
||||||
|
if (_obscure_mode) {
|
||||||
|
_obscure_text.set_wtext(wstring(_text.get_num_characters(), '*'));
|
||||||
|
}
|
||||||
_text_geom_stale = true;
|
_text_geom_stale = true;
|
||||||
_cursor_stale = true;
|
_cursor_stale = true;
|
||||||
_blink_start = ClockObject::get_global_clock()->get_frame_time();
|
_blink_start = ClockObject::get_global_clock()->get_frame_time();
|
||||||
set_cursor_position(_wtext.size());
|
set_cursor_position(_text.get_num_characters());
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PGEntry::get_plain_wtext
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the text currently displayed within the
|
||||||
|
// entry, without any embedded properties characters.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE wstring PGEntry::
|
||||||
|
get_plain_wtext() const {
|
||||||
|
return _text.get_plain_wtext();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -444,9 +530,9 @@ set_wtext(const wstring &wtext) {
|
|||||||
// Description: Returns the text currently displayed within the
|
// Description: Returns the text currently displayed within the
|
||||||
// entry.
|
// entry.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE const wstring &PGEntry::
|
INLINE wstring PGEntry::
|
||||||
get_wtext() const {
|
get_wtext() const {
|
||||||
return _wtext;
|
return _text.get_wtext();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
@ -41,7 +41,9 @@ TypeHandle PGEntry::_type_handle;
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
PGEntry::
|
PGEntry::
|
||||||
PGEntry(const string &name) :
|
PGEntry(const string &name) :
|
||||||
PGItem(name)
|
PGItem(name),
|
||||||
|
_text(get_text_node()),
|
||||||
|
_obscure_text(get_text_node())
|
||||||
{
|
{
|
||||||
set_cull_callback();
|
set_cull_callback();
|
||||||
|
|
||||||
@ -53,6 +55,7 @@ PGEntry(const string &name) :
|
|||||||
_max_chars = 0;
|
_max_chars = 0;
|
||||||
_max_width = 0.0f;
|
_max_width = 0.0f;
|
||||||
_num_lines = 1;
|
_num_lines = 1;
|
||||||
|
_accept_enabled = true;
|
||||||
_last_text_def = (TextNode *)NULL;
|
_last_text_def = (TextNode *)NULL;
|
||||||
_text_geom_stale = true;
|
_text_geom_stale = true;
|
||||||
_blink_start = 0.0f;
|
_blink_start = 0.0f;
|
||||||
@ -93,8 +96,8 @@ PGEntry::
|
|||||||
PGEntry::
|
PGEntry::
|
||||||
PGEntry(const PGEntry ©) :
|
PGEntry(const PGEntry ©) :
|
||||||
PGItem(copy),
|
PGItem(copy),
|
||||||
_wtext(copy._wtext),
|
_text(copy._text),
|
||||||
_obscured_wtext(copy._obscured_wtext),
|
_obscure_text(copy._obscure_text),
|
||||||
_cursor_position(copy._cursor_position),
|
_cursor_position(copy._cursor_position),
|
||||||
_max_chars(copy._max_chars),
|
_max_chars(copy._max_chars),
|
||||||
_max_width(copy._max_width),
|
_max_width(copy._max_width),
|
||||||
@ -203,7 +206,7 @@ press(const MouseWatcherParameter ¶m, bool background) {
|
|||||||
_text_geom_stale = true;
|
_text_geom_stale = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_cursor_position = min(_cursor_position, (int)_wtext.length());
|
_cursor_position = min(_cursor_position, _text.get_num_characters());
|
||||||
_blink_start = ClockObject::get_global_clock()->get_frame_time();
|
_blink_start = ClockObject::get_global_clock()->get_frame_time();
|
||||||
if (button == KeyboardButton::enter()) {
|
if (button == KeyboardButton::enter()) {
|
||||||
// Enter. Accept the entry.
|
// Enter. Accept the entry.
|
||||||
@ -214,10 +217,7 @@ press(const MouseWatcherParameter ¶m, bool background) {
|
|||||||
} else if (button == KeyboardButton::backspace()) {
|
} else if (button == KeyboardButton::backspace()) {
|
||||||
// Backspace. Remove the character to the left of the cursor.
|
// Backspace. Remove the character to the left of the cursor.
|
||||||
if (_cursor_position > 0) {
|
if (_cursor_position > 0) {
|
||||||
if (_obscure_mode && _obscured_wtext.length() == _wtext.length()) {
|
_text.set_wsubstr(wstring(), _cursor_position - 1, 1);
|
||||||
_obscured_wtext.erase(_obscured_wtext.begin() + _obscured_wtext.length() - 1);
|
|
||||||
}
|
|
||||||
_wtext.erase(_wtext.begin() + _cursor_position - 1);
|
|
||||||
_cursor_position--;
|
_cursor_position--;
|
||||||
_cursor_stale = true;
|
_cursor_stale = true;
|
||||||
_text_geom_stale = true;
|
_text_geom_stale = true;
|
||||||
@ -226,11 +226,8 @@ press(const MouseWatcherParameter ¶m, bool background) {
|
|||||||
|
|
||||||
} else if (button == KeyboardButton::del()) {
|
} else if (button == KeyboardButton::del()) {
|
||||||
// Delete. Remove the character to the right of the cursor.
|
// Delete. Remove the character to the right of the cursor.
|
||||||
if (_cursor_position < (int)_wtext.length()) {
|
if (_cursor_position < _text.get_num_characters()) {
|
||||||
if (_obscure_mode && _obscured_wtext.length() == _wtext.length()) {
|
_text.set_wsubstr(wstring(), _cursor_position, 1);
|
||||||
_obscured_wtext.erase(_obscured_wtext.begin() + _obscured_wtext.length() - 1);
|
|
||||||
}
|
|
||||||
_wtext.erase(_wtext.begin() + _cursor_position);
|
|
||||||
_text_geom_stale = true;
|
_text_geom_stale = true;
|
||||||
erase(param);
|
erase(param);
|
||||||
}
|
}
|
||||||
@ -245,7 +242,7 @@ press(const MouseWatcherParameter ¶m, bool background) {
|
|||||||
} else if (button == KeyboardButton::right()) {
|
} else if (button == KeyboardButton::right()) {
|
||||||
if (_cursor_keys_active) {
|
if (_cursor_keys_active) {
|
||||||
// Right arrow. Move the cursor position to the right.
|
// Right arrow. Move the cursor position to the right.
|
||||||
_cursor_position = min(_cursor_position + 1, (int)_wtext.length());
|
_cursor_position = min(_cursor_position + 1, _text.get_num_characters());
|
||||||
_cursor_stale = true;
|
_cursor_stale = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,7 +256,7 @@ press(const MouseWatcherParameter ¶m, bool background) {
|
|||||||
} else if (button == KeyboardButton::end()) {
|
} else if (button == KeyboardButton::end()) {
|
||||||
if (_cursor_keys_active) {
|
if (_cursor_keys_active) {
|
||||||
// End. Move the cursor position to the end.
|
// End. Move the cursor position to the end.
|
||||||
_cursor_position = _wtext.length();
|
_cursor_position = _text.get_num_characters();
|
||||||
_cursor_stale = true;
|
_cursor_stale = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -290,52 +287,27 @@ keystroke(const MouseWatcherParameter ¶m, bool background) {
|
|||||||
}
|
}
|
||||||
wstring new_char(1, (wchar_t)keycode);
|
wstring new_char(1, (wchar_t)keycode);
|
||||||
|
|
||||||
if (get_max_chars() > 0 && (int)_wtext.length() >= get_max_chars()) {
|
if (get_max_chars() > 0 && _text.get_num_characters() >= get_max_chars()) {
|
||||||
// In max_chars mode, we consider it an overflow after we
|
// In max_chars mode, we consider it an overflow after we
|
||||||
// have exceeded a fixed number of characters, irrespective
|
// have exceeded a fixed number of characters, irrespective
|
||||||
// of the formatted width of those characters.
|
// of the formatted width of those characters.
|
||||||
overflow(param);
|
overflow(param);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
_cursor_position = min(_cursor_position, (int)_wtext.length());
|
_cursor_position = min(_cursor_position, _text.get_num_characters());
|
||||||
wstring new_text =
|
bool too_long = !_text.set_wsubstr(new_char, _cursor_position, 0);
|
||||||
_wtext.substr(0, _cursor_position) + new_char +
|
|
||||||
_wtext.substr(_cursor_position);
|
|
||||||
|
|
||||||
// Get the new string to measure its length. In normal
|
|
||||||
// mode, we measure the text itself. In obscure mode, we
|
|
||||||
// measure a string of n asterisks.
|
|
||||||
wstring measure_text;
|
|
||||||
if (_obscure_mode) {
|
if (_obscure_mode) {
|
||||||
measure_text = get_display_wtext() + (wchar_t)'*';
|
too_long = !_obscure_text.set_wtext(wstring(_text.get_num_characters(), '*'));
|
||||||
} else {
|
} else {
|
||||||
measure_text = new_text;
|
if (!too_long && (_text.get_num_rows() == _num_lines)) {
|
||||||
}
|
|
||||||
|
|
||||||
// Now check the length.
|
|
||||||
bool too_long = false;
|
|
||||||
if (_max_width > 0.0f) {
|
|
||||||
TextNode *text_node = get_text_def(S_focus);
|
|
||||||
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 && (text_node->get_num_rows() == _num_lines)) {
|
|
||||||
// If we've filled up all of the available lines, we
|
// If we've filled up all of the available lines, we
|
||||||
// must also ensure that the last line is not too long
|
// must also ensure that the last line is not too long
|
||||||
// (it might be, because of additional whitespace on
|
// (it might be, because of additional whitespace on
|
||||||
// the end).
|
// the end).
|
||||||
wstring ww_text = text_node->get_wordwrapped_wtext();
|
int r = _num_lines - 1;
|
||||||
size_t last_line_start = ww_text.rfind('\n');
|
int c = _text.get_num_cols(r);
|
||||||
if (last_line_start == string::npos) {
|
float last_line_width =
|
||||||
last_line_start = 0;
|
_text.get_xpos(r, c) - _text.get_xpos(r, 0);
|
||||||
}
|
|
||||||
wstring last_line = ww_text.substr(last_line_start);
|
|
||||||
float last_line_width = text_node->calc_width(last_line);
|
|
||||||
|
|
||||||
too_long = (last_line_width > _max_width);
|
too_long = (last_line_width > _max_width);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,59 +317,31 @@ keystroke(const MouseWatcherParameter ¶m, bool background) {
|
|||||||
// end of the current line if it would make that line
|
// end of the current line if it would make that line
|
||||||
// exceed the maximum width, just so we don't allow an
|
// exceed the maximum width, just so we don't allow an
|
||||||
// infinite number of spaces to accumulate.
|
// infinite number of spaces to accumulate.
|
||||||
|
int r, c;
|
||||||
// First, we need to figure out our current position
|
_text.calc_r_c(r, c, _cursor_position);
|
||||||
// within the wordwrapped text, by skipping past the
|
if (_text.get_num_cols(r) == c + 1) {
|
||||||
// newlines.
|
|
||||||
wstring ww_text = text_node->get_wordwrapped_wtext();
|
|
||||||
int i = 0;
|
|
||||||
int current_pos = 0;
|
|
||||||
while (i < _cursor_position) {
|
|
||||||
nassertv(current_pos < (int)ww_text.length());
|
|
||||||
if (ww_text[current_pos] != '\n') {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
current_pos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is the user typing at the end of the line? Scan for
|
|
||||||
// the next character that's not a space following the
|
|
||||||
// current position.
|
|
||||||
int p = current_pos + 1;
|
|
||||||
while (p < (int)ww_text.length() && ww_text[p] == ' ') {
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p >= (int)ww_text.length() || ww_text[p] == '\n') {
|
|
||||||
// The user is typing at the end of the line. But we
|
// The user is typing at the end of the line. But we
|
||||||
// must allow at least one space at the end of the
|
// must allow at least one space at the end of the
|
||||||
// line, so we only make any of the following checks
|
// line, so we only make any of the following checks
|
||||||
// if there are already multiple spaces at the end of
|
// if there are already multiple spaces at the end of
|
||||||
// the line.
|
// the line.
|
||||||
if (p - 2 >= 0 && ww_text[p - 2] == ' ') {
|
if (c - 1 >= 0 && _text.get_character(r, c - 1) == ' ') {
|
||||||
// Ok, the user is putting multiple spaces on the
|
// Ok, the user is putting multiple spaces on the
|
||||||
// end of a line; we need to make sure the line does
|
// end of a line; we need to make sure the line does
|
||||||
// not grow too wide. Get the beginning of the line
|
// not grow too wide. Measure the line's width.
|
||||||
// and measure its width.
|
float current_line_width =
|
||||||
int q = current_pos;
|
_text.get_xpos(r, c + 1) - _text.get_xpos(r, 0);
|
||||||
while (q >= 0 && ww_text[q] != '\n') {
|
|
||||||
q--;
|
|
||||||
}
|
|
||||||
|
|
||||||
wstring current_line = ww_text.substr(q + 1, p - (q + 1));
|
|
||||||
float current_line_width = text_node->calc_width(current_line);
|
|
||||||
|
|
||||||
if (current_line_width > _max_width) {
|
if (current_line_width > _max_width) {
|
||||||
// We have to reject the space, but we don't treat
|
// We have to reject the space, but we don't treat
|
||||||
// it as an overflow condition.
|
// it as an overflow condition.
|
||||||
|
_text.set_wsubstr(wstring(), _cursor_position, 1);
|
||||||
// If the user is typing over existing space
|
// If the user is typing over existing space
|
||||||
// characters, we act as if the right-arrow key
|
// characters, we act as if the right-arrow key
|
||||||
// were pressed instead, and advance the cursor to
|
// were pressed instead, and advance the cursor to
|
||||||
// the next position. Otherwise, we just quietly
|
// the next position. Otherwise, we just quietly
|
||||||
// eat the space character.
|
// eat the space character.
|
||||||
if (_cursor_position < (int)_wtext.length() &&
|
if (_cursor_position < _text.get_num_characters() &&
|
||||||
_wtext[_cursor_position] == ' ') {
|
_text.get_character(_cursor_position) == ' ') {
|
||||||
_cursor_position++;
|
_cursor_position++;
|
||||||
_cursor_stale = true;
|
_cursor_stale = true;
|
||||||
}
|
}
|
||||||
@ -409,14 +353,10 @@ keystroke(const MouseWatcherParameter ¶m, bool background) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (too_long) {
|
if (too_long) {
|
||||||
|
_text.set_wsubstr(wstring(), _cursor_position, 1);
|
||||||
overflow(param);
|
overflow(param);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
_wtext = new_text;
|
|
||||||
if (_obscure_mode) {
|
|
||||||
_obscured_wtext = measure_text;
|
|
||||||
}
|
|
||||||
|
|
||||||
_cursor_position += new_char.length();
|
_cursor_position += new_char.length();
|
||||||
_cursor_stale = true;
|
_cursor_stale = true;
|
||||||
_text_geom_stale = true;
|
_text_geom_stale = true;
|
||||||
@ -445,8 +385,9 @@ candidate(const MouseWatcherParameter ¶m, bool background) {
|
|||||||
_candidate_highlight_end = param.get_highlight_end();
|
_candidate_highlight_end = param.get_highlight_end();
|
||||||
_candidate_cursor_pos = param.get_cursor_pos();
|
_candidate_cursor_pos = param.get_cursor_pos();
|
||||||
_text_geom_stale = true;
|
_text_geom_stale = true;
|
||||||
if (!_candidate_wtext.empty())
|
if (!_candidate_wtext.empty()) {
|
||||||
type(param);
|
type(param);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PGItem::candidate(param, background);
|
PGItem::candidate(param, background);
|
||||||
@ -678,9 +619,9 @@ set_focus(bool focus) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool PGEntry::
|
bool PGEntry::
|
||||||
is_wtext() const {
|
is_wtext() const {
|
||||||
wstring::const_iterator ti;
|
for (int i = 0; i < _text.get_num_characters(); ++i) {
|
||||||
for (ti = _wtext.begin(); ti != _wtext.end(); ++ti) {
|
wchar_t ch = _text.get_character(i);
|
||||||
if (((*ti) & ~0x7f) != 0) {
|
if ((ch & ~0x7f) != 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -688,34 +629,6 @@ is_wtext() const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: PGEntry::get_display_wtext
|
|
||||||
// Access: Private
|
|
||||||
// Description: Returns the string that should be displayed within
|
|
||||||
// the entry. This is normally _wtext, but it may be
|
|
||||||
// _obscured_wtext.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
const wstring &PGEntry::
|
|
||||||
get_display_wtext() {
|
|
||||||
if (_obscure_mode) {
|
|
||||||
// If obscure mode is enabled, we should just display a bunch of
|
|
||||||
// asterisks.
|
|
||||||
if (_obscured_wtext.length() != _wtext.length()) {
|
|
||||||
_obscured_wtext = wstring();
|
|
||||||
wstring::const_iterator ti;
|
|
||||||
for (ti = _wtext.begin(); ti != _wtext.end(); ++ti) {
|
|
||||||
_obscured_wtext += (wchar_t)'*';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return _obscured_wtext;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// In normal, non-obscure mode, we display the actual text
|
|
||||||
return _wtext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: PGEntry::slot_text_def
|
// Function: PGEntry::slot_text_def
|
||||||
// Access: Private
|
// Access: Private
|
||||||
@ -741,89 +654,56 @@ update_text() {
|
|||||||
nassertv(node != (TextNode *)NULL);
|
nassertv(node != (TextNode *)NULL);
|
||||||
|
|
||||||
if (_text_geom_stale || node != _last_text_def) {
|
if (_text_geom_stale || node != _last_text_def) {
|
||||||
wstring display_wtext;
|
TextProperties props = *node;
|
||||||
|
props.set_wordwrap(_max_width);
|
||||||
|
props.set_preserve_trailing_whitespace(true);
|
||||||
|
_text.set_properties(props);
|
||||||
|
_text.set_max_rows(_num_lines);
|
||||||
|
|
||||||
if (_candidate_wtext.empty() || _obscure_mode) {
|
if (node != _last_text_def) {
|
||||||
|
// Make sure the default properties are applied to all the
|
||||||
|
// characters in the text.
|
||||||
|
_text.set_wtext(_text.get_wtext());
|
||||||
|
_last_text_def = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
PT(PandaNode) assembled;
|
||||||
|
if (_obscure_mode) {
|
||||||
|
_obscure_text.set_properties(props);
|
||||||
|
_obscure_text.set_max_rows(_num_lines);
|
||||||
|
_obscure_text.set_wtext(wstring(_text.get_num_characters(), '*'));
|
||||||
|
assembled = _obscure_text.assemble_text();
|
||||||
|
|
||||||
|
} else if (_candidate_wtext.empty()) {
|
||||||
// If we're not trying to display a candidate string, it's easy:
|
// If we're not trying to display a candidate string, it's easy:
|
||||||
// just display the current text contents.
|
// just display the current text contents.
|
||||||
display_wtext = get_display_wtext();
|
assembled = _text.assemble_text();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Insert the complex sequence of characters required to show
|
TextPropertiesManager *tp_mgr = TextPropertiesManager::get_global_ptr();
|
||||||
// the candidate string in a different color. This gets
|
TextProperties inactive = tp_mgr->get_properties(_candidate_inactive);
|
||||||
// inserted at the current cursor position.
|
TextProperties active = tp_mgr->get_properties(_candidate_active);
|
||||||
wstring source_wtext = get_display_wtext();
|
|
||||||
|
|
||||||
display_wtext = source_wtext.substr(0, _cursor_position);
|
// Create a special TextAssembler to insert the candidate string
|
||||||
display_wtext += wstring(1, (wchar_t)text_push_properties_key);
|
// in its own special colors.
|
||||||
display_wtext += node->decode_text(_candidate_inactive);
|
|
||||||
display_wtext += wstring(1, (wchar_t)text_push_properties_key);
|
|
||||||
display_wtext += _candidate_wtext.substr(0, _candidate_highlight_start);
|
|
||||||
display_wtext += wstring(1, (wchar_t)text_push_properties_key);
|
|
||||||
display_wtext += node->decode_text(_candidate_active);
|
|
||||||
display_wtext += wstring(1, (wchar_t)text_push_properties_key);
|
|
||||||
display_wtext += _candidate_wtext.substr(_candidate_highlight_start,
|
|
||||||
_candidate_highlight_end - _candidate_highlight_start);
|
|
||||||
display_wtext += wstring(1, (wchar_t)text_pop_properties_key);
|
|
||||||
display_wtext += _candidate_wtext.substr(_candidate_highlight_end);
|
|
||||||
display_wtext += wstring(1, (wchar_t)text_pop_properties_key);
|
|
||||||
|
|
||||||
display_wtext += source_wtext.substr(_cursor_position);
|
TextAssembler ctext(_text);
|
||||||
}
|
ctext.set_wsubstr(_candidate_wtext.substr(_candidate_highlight_end),
|
||||||
|
_cursor_position, 0, inactive);
|
||||||
// We need to regenerate.
|
ctext.set_wsubstr(_candidate_wtext.substr(_candidate_highlight_start,
|
||||||
_last_text_def = node;
|
_candidate_highlight_end - _candidate_highlight_start),
|
||||||
_last_text_def->set_wtext(display_wtext);
|
_cursor_position, 0, active);
|
||||||
_last_text_def->set_wordwrap(_max_width);
|
ctext.set_wsubstr(_candidate_wtext.substr(0, _candidate_highlight_start),
|
||||||
_last_text_def->set_preserve_trailing_whitespace(true);
|
_cursor_position, 0, inactive);
|
||||||
_last_text_def->set_max_rows(_num_lines);
|
assembled = ctext.assemble_text();
|
||||||
|
|
||||||
// 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) {
|
|
||||||
// Temporarily set this line's text in the TextNode, just so
|
|
||||||
// we can measure the left margin. (If align is A_left, we
|
|
||||||
// know that the left margin is 0.0, so we don't need to do
|
|
||||||
// this.)
|
|
||||||
_last_text_def->set_wtext(line._str);
|
|
||||||
line._left = _last_text_def->get_left();
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_current_text.is_empty()) {
|
if (!_current_text.is_empty()) {
|
||||||
_current_text.remove_node();
|
_current_text.remove_node();
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to reset the text, since we might have changed it
|
|
||||||
// temporarily in the above when align is not A_left.
|
|
||||||
_last_text_def->set_wtext(display_wtext);
|
|
||||||
_current_text =
|
_current_text =
|
||||||
_text_render_root.attach_new_node(_last_text_def->generate());
|
_text_render_root.attach_new_node(assembled);
|
||||||
_text_geom_stale = false;
|
_text_geom_stale = false;
|
||||||
_cursor_stale = true;
|
_cursor_stale = true;
|
||||||
}
|
}
|
||||||
@ -844,32 +724,23 @@ update_cursor() {
|
|||||||
if (_cursor_stale || node != _last_text_def) {
|
if (_cursor_stale || node != _last_text_def) {
|
||||||
update_text();
|
update_text();
|
||||||
|
|
||||||
_cursor_position = min(_cursor_position, (int)_wtext.length());
|
_cursor_position = min(_cursor_position, _text.get_num_characters());
|
||||||
_candidate_cursor_pos = min(_candidate_cursor_pos, _candidate_wtext.length());
|
_candidate_cursor_pos = min(_candidate_cursor_pos, _candidate_wtext.length());
|
||||||
|
|
||||||
// Determine the row and column of the cursor.
|
// Determine the row and column of the cursor.
|
||||||
int row = 0;
|
int row, column;
|
||||||
int column = _cursor_position + _candidate_cursor_pos;
|
float xpos, ypos;
|
||||||
while (row + 1 < (int)_ww_lines.size() &&
|
if (_obscure_mode) {
|
||||||
column > (int)_ww_lines[row]._str.length()) {
|
_obscure_text.calc_r_c(row, column, _cursor_position + _candidate_cursor_pos);
|
||||||
column -= _ww_lines[row]._str.length();
|
xpos = _obscure_text.get_xpos(row, column);
|
||||||
row++;
|
ypos = _obscure_text.get_ypos(row, column);
|
||||||
|
} else {
|
||||||
|
_text.calc_r_c(row, column, _cursor_position + _candidate_cursor_pos);
|
||||||
|
xpos = _text.get_xpos(row, column);
|
||||||
|
ypos = _text.get_ypos(row, column);
|
||||||
}
|
}
|
||||||
|
|
||||||
nassertv(row >= 0 && row < (int)_ww_lines.size());
|
_cursor_def.set_pos(xpos, 0.0f, ypos);
|
||||||
|
|
||||||
// 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));
|
|
||||||
float line_height = _last_text_def->get_line_height();
|
|
||||||
|
|
||||||
LVecBase3f trans(_ww_lines[row]._left + width, 0.0f, -line_height * row);
|
|
||||||
_cursor_def.set_pos(trans);
|
|
||||||
|
|
||||||
_cursor_stale = false;
|
_cursor_stale = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "pointerTo.h"
|
#include "pointerTo.h"
|
||||||
#include "pvector.h"
|
#include "pvector.h"
|
||||||
#include "clockObject.h"
|
#include "clockObject.h"
|
||||||
|
#include "textAssembler.h"
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Class : PGEntry
|
// Class : PGEntry
|
||||||
@ -74,8 +75,14 @@ PUBLISHED:
|
|||||||
void setup(float width, int num_lines);
|
void setup(float width, int num_lines);
|
||||||
|
|
||||||
INLINE void set_text(const string &text);
|
INLINE void set_text(const string &text);
|
||||||
|
INLINE string get_plain_text() const;
|
||||||
INLINE string get_text() const;
|
INLINE string get_text() const;
|
||||||
|
|
||||||
|
INLINE int get_num_characters() const;
|
||||||
|
INLINE wchar_t get_character(int n) const;
|
||||||
|
INLINE const TextGraphic *get_graphic(int n) const;
|
||||||
|
INLINE const TextProperties &get_properties(int n) const;
|
||||||
|
|
||||||
INLINE void set_cursor_position(int position);
|
INLINE void set_cursor_position(int position);
|
||||||
INLINE int get_cursor_position() const;
|
INLINE int get_cursor_position() const;
|
||||||
|
|
||||||
@ -121,21 +128,21 @@ PUBLISHED:
|
|||||||
INLINE string get_erase_event() const;
|
INLINE string get_erase_event() const;
|
||||||
|
|
||||||
INLINE void set_wtext(const wstring &wtext);
|
INLINE void set_wtext(const wstring &wtext);
|
||||||
INLINE const wstring &get_wtext() const;
|
INLINE wstring get_plain_wtext() const;
|
||||||
|
INLINE wstring get_wtext() const;
|
||||||
INLINE void set_accept_enabled(bool enabled);
|
INLINE void set_accept_enabled(bool enabled);
|
||||||
bool is_wtext() const;
|
bool is_wtext() const;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const wstring &get_display_wtext();
|
|
||||||
void slot_text_def(int state);
|
void slot_text_def(int state);
|
||||||
void update_text();
|
void update_text();
|
||||||
void update_cursor();
|
void update_cursor();
|
||||||
void show_hide_cursor(bool visible);
|
void show_hide_cursor(bool visible);
|
||||||
void update_state();
|
void update_state();
|
||||||
|
|
||||||
wstring _wtext;
|
TextAssembler _text;
|
||||||
wstring _obscured_wtext;
|
TextAssembler _obscure_text;
|
||||||
int _cursor_position;
|
int _cursor_position;
|
||||||
bool _cursor_stale;
|
bool _cursor_stale;
|
||||||
bool _cursor_visible;
|
bool _cursor_visible;
|
||||||
@ -166,17 +173,6 @@ private:
|
|||||||
TextNode *_last_text_def;
|
TextNode *_last_text_def;
|
||||||
bool _text_geom_stale;
|
bool _text_geom_stale;
|
||||||
|
|
||||||
// This is a list of each row of text in the entry, after it has
|
|
||||||
// been wordwrapped by update_text(). It's used by update_cursor()
|
|
||||||
// to compute the correct cursor position.
|
|
||||||
class WWLine {
|
|
||||||
public:
|
|
||||||
wstring _str;
|
|
||||||
float _left;
|
|
||||||
};
|
|
||||||
typedef pvector<WWLine> WWLines;
|
|
||||||
WWLines _ww_lines;
|
|
||||||
|
|
||||||
// This is the node that represents the cursor geometry. It is also
|
// This is the node that represents the cursor geometry. It is also
|
||||||
// attached to the above node, and is transformed around and/or
|
// attached to the above node, and is transformed around and/or
|
||||||
// hidden according to the cursor's position and blink state.
|
// hidden according to the cursor's position and blink state.
|
||||||
|
@ -43,9 +43,61 @@ get_usage_hint() const {
|
|||||||
return _usage_hint;
|
return _usage_hint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::set_max_rows
|
||||||
|
// Access: Published
|
||||||
|
// Description: If max_rows is greater than zero, no more than
|
||||||
|
// max_rows will be accepted. Text beyond that will be
|
||||||
|
// truncated.
|
||||||
|
//
|
||||||
|
// The return value is true if all the text is accepted,
|
||||||
|
// or false if some was truncated.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE bool TextAssembler::
|
||||||
|
set_max_rows(int max_rows) {
|
||||||
|
_max_rows = max_rows;
|
||||||
|
return wordwrap_text();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::get_max_rows
|
||||||
|
// Access: Published
|
||||||
|
// Description: If max_rows is greater than zero, no more than
|
||||||
|
// max_rows will be accepted. Text beyond that will be
|
||||||
|
// truncated.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE int TextAssembler::
|
||||||
|
get_max_rows() const {
|
||||||
|
return _max_rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::set_properties
|
||||||
|
// Access: Published
|
||||||
|
// Description: Specifies the default TextProperties that are applied
|
||||||
|
// to the text in the absence of any nested property
|
||||||
|
// change sequences.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE void TextAssembler::
|
||||||
|
set_properties(const TextProperties &properties) {
|
||||||
|
_initial_cprops = new ComputedProperties(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::get_properties
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the default TextProperties that are applied
|
||||||
|
// to the text in the absence of any nested property
|
||||||
|
// change sequences.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE const TextProperties &TextAssembler::
|
||||||
|
get_properties() const {
|
||||||
|
return _initial_cprops->_properties;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: TextAssembler::get_ul
|
// Function: TextAssembler::get_ul
|
||||||
// Access: Public
|
// Access: Published
|
||||||
// Description: Returns the upper-left corner of the assembled text,
|
// Description: Returns the upper-left corner of the assembled text,
|
||||||
// in 2-d text coordinates.
|
// in 2-d text coordinates.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -56,7 +108,7 @@ get_ul() const {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: TextAssembler::get_lr
|
// Function: TextAssembler::get_lr
|
||||||
// Access: Public
|
// Access: Published
|
||||||
// Description: Returns the lower-right corner of the assembled text,
|
// Description: Returns the lower-right corner of the assembled text,
|
||||||
// in 2-d text coordinates.
|
// in 2-d text coordinates.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -65,15 +117,212 @@ get_lr() const {
|
|||||||
return _lr;
|
return _lr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::calc_r
|
||||||
|
// Access: Published
|
||||||
|
// Description: Computes the row index of the nth character or
|
||||||
|
// graphic object in the text and returns it.
|
||||||
|
//
|
||||||
|
// If the nth character is not a normal printable
|
||||||
|
// character with a position in the wordwrapped string,
|
||||||
|
// returns -1 (for instance, a soft-hyphen character, or
|
||||||
|
// a newline character, may not have a corresponding
|
||||||
|
// position).
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
int TextAssembler::
|
||||||
|
calc_r(int n) const {
|
||||||
|
int r, c;
|
||||||
|
if (calc_r_c(r, c, n)) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::calc_c
|
||||||
|
// Access: Published
|
||||||
|
// Description: Computes the column index of the nth character or
|
||||||
|
// graphic object in the text and returns it.
|
||||||
|
//
|
||||||
|
// If the nth character is not a normal printable
|
||||||
|
// character with a position in the wordwrapped string,
|
||||||
|
// returns -1 (for instance, a soft-hyphen character, or
|
||||||
|
// a newline character, may not have a corresponding
|
||||||
|
// position).
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
int TextAssembler::
|
||||||
|
calc_c(int n) const {
|
||||||
|
int r, c;
|
||||||
|
if (calc_r_c(r, c, n)) {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::get_num_characters
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the number of characters of text, before
|
||||||
|
// wordwrapping.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE int TextAssembler::
|
||||||
|
get_num_characters() const {
|
||||||
|
return _text_string.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::get_character
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the character at the indicated position in
|
||||||
|
// the pre-wordwrapped string. If the object at this
|
||||||
|
// position is a graphic object instead of a character,
|
||||||
|
// returns 0.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE wchar_t TextAssembler::
|
||||||
|
get_character(int n) const {
|
||||||
|
nassertr(n >= 0 && n < (int)_text_string.size(), 0);
|
||||||
|
return _text_string[n]._character;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::get_graphic
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the graphic object at the indicated position
|
||||||
|
// in the pre-wordwrapped string. If the object at this
|
||||||
|
// position is a character instead of a graphic object,
|
||||||
|
// returns NULL.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE const TextGraphic *TextAssembler::
|
||||||
|
get_graphic(int n) const {
|
||||||
|
nassertr(n >= 0 && n < (int)_text_string.size(), 0);
|
||||||
|
return _text_string[n]._graphic;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::get_properties
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the TextProperties in effect for the object
|
||||||
|
// at the indicated position in the pre-wordwrapped
|
||||||
|
// string.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE const TextProperties &TextAssembler::
|
||||||
|
get_properties(int n) const {
|
||||||
|
nassertr(n >= 0 && n < (int)_text_string.size(), *(new TextProperties()));
|
||||||
|
return _text_string[n]._cprops->_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::get_width
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the width of the character or object at the
|
||||||
|
// indicated position in the pre-wordwrapped string.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE float TextAssembler::
|
||||||
|
get_width(int n) const {
|
||||||
|
nassertr(n >= 0 && n < (int)_text_string.size(), 0.0f);
|
||||||
|
|
||||||
|
return calc_width(_text_string[n]);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: TextAssembler::get_num_rows
|
// Function: TextAssembler::get_num_rows
|
||||||
// Access: Public
|
// Access: Published
|
||||||
// Description: Returns the number of rows of text after it has all
|
// Description: Returns the number of rows of text after it has all
|
||||||
// been wordwrapped and assembled.
|
// been wordwrapped and assembled.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE int TextAssembler::
|
INLINE int TextAssembler::
|
||||||
get_num_rows() const {
|
get_num_rows() const {
|
||||||
return _num_rows;
|
return _text_block.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::get_num_cols
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the number of characters and/or graphic
|
||||||
|
// objects in the nth row.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE int TextAssembler::
|
||||||
|
get_num_cols(int r) const {
|
||||||
|
nassertr(r >= 0 && r <= (int)_text_block.size(), 0);
|
||||||
|
if (r == _text_block.size()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return _text_block[r]._string.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::get_character
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the character at the indicated position in
|
||||||
|
// the indicated row. If the object at this position is
|
||||||
|
// a graphic object instead of a character, returns 0.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE wchar_t TextAssembler::
|
||||||
|
get_character(int r, int c) const {
|
||||||
|
nassertr(r >= 0 && r < (int)_text_block.size(), 0);
|
||||||
|
nassertr(c >= 0 && c < (int)_text_block[r]._string.size(), 0);
|
||||||
|
return _text_block[r]._string[c]._character;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::get_graphic
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the graphic object at the indicated position
|
||||||
|
// in the indicated row. If the object at this position
|
||||||
|
// is a character instead of a graphic object, returns
|
||||||
|
// NULL.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE const TextGraphic *TextAssembler::
|
||||||
|
get_graphic(int r, int c) const {
|
||||||
|
nassertr(r >= 0 && r < (int)_text_block.size(), 0);
|
||||||
|
nassertr(c >= 0 && c < (int)_text_block[r]._string.size(), 0);
|
||||||
|
return _text_block[r]._string[c]._graphic;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::get_properties
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the TextProperties in effect for the object
|
||||||
|
// at the indicated position in the indicated row.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE const TextProperties &TextAssembler::
|
||||||
|
get_properties(int r, int c) const {
|
||||||
|
nassertr(r >= 0 && r < (int)_text_block.size(), *(new TextProperties()));
|
||||||
|
nassertr(c >= 0 && c < (int)_text_block[r]._string.size(), *(new TextProperties()));
|
||||||
|
return _text_block[r]._string[c]._cprops->_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::get_width
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the width of the character or object at the
|
||||||
|
// indicated position in the indicated row.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE float TextAssembler::
|
||||||
|
get_width(int r, int c) const {
|
||||||
|
nassertr(r >= 0 && r < (int)_text_block.size(), 0.0f);
|
||||||
|
nassertr(c >= 0 && c < (int)_text_block[r]._string.size(), 0.0f);
|
||||||
|
|
||||||
|
return calc_width(_text_block[r]._string[c]);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::get_ypos
|
||||||
|
// Access: Published
|
||||||
|
// Description: Returns the y position of the origin of all of the
|
||||||
|
// characters or graphic objects in the indicated row.
|
||||||
|
//
|
||||||
|
// It is legal for r to exceed the index number of the
|
||||||
|
// last row by 1. The value of c is presently ignored.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE float TextAssembler::
|
||||||
|
get_ypos(int r, int) const {
|
||||||
|
nassertr(r >= 0 && r <= (int)_text_block.size(), 0.0f);
|
||||||
|
if (r == _text_block.size()) {
|
||||||
|
return _next_row_ypos;
|
||||||
|
} else {
|
||||||
|
return _text_block[r]._ypos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -85,9 +334,9 @@ get_num_rows() const {
|
|||||||
INLINE float TextAssembler::
|
INLINE float TextAssembler::
|
||||||
calc_width(const TextCharacter &tch) {
|
calc_width(const TextCharacter &tch) {
|
||||||
if (tch._graphic != (TextGraphic *)NULL) {
|
if (tch._graphic != (TextGraphic *)NULL) {
|
||||||
return calc_width(tch._graphic, *tch._properties);
|
return calc_width(tch._graphic, tch._cprops->_properties);
|
||||||
} else {
|
} else {
|
||||||
return calc_width(tch._character, *tch._properties);
|
return calc_width(tch._character, tch._cprops->_properties);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,10 +346,11 @@ calc_width(const TextCharacter &tch) {
|
|||||||
// Description:
|
// Description:
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE TextAssembler::TextCharacter::
|
INLINE TextAssembler::TextCharacter::
|
||||||
TextCharacter(wchar_t character, const TextProperties *properties) :
|
TextCharacter(wchar_t character,
|
||||||
|
TextAssembler::ComputedProperties *cprops) :
|
||||||
_character(character),
|
_character(character),
|
||||||
_graphic(NULL),
|
_graphic(NULL),
|
||||||
_properties(properties)
|
_cprops(cprops)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,13 +360,126 @@ TextCharacter(wchar_t character, const TextProperties *properties) :
|
|||||||
// Description:
|
// Description:
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE TextAssembler::TextCharacter::
|
INLINE TextAssembler::TextCharacter::
|
||||||
TextCharacter(const TextGraphic *graphic, const TextProperties *properties) :
|
TextCharacter(const TextGraphic *graphic, const wstring &graphic_wname,
|
||||||
|
TextAssembler::ComputedProperties *cprops) :
|
||||||
_character(0),
|
_character(0),
|
||||||
_graphic(graphic),
|
_graphic(graphic),
|
||||||
_properties(properties)
|
_graphic_wname(graphic_wname),
|
||||||
|
_cprops(cprops)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::TextCharacter::Copy Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE TextAssembler::TextCharacter::
|
||||||
|
TextCharacter(const TextAssembler::TextCharacter ©) :
|
||||||
|
_character(copy._character),
|
||||||
|
_graphic(copy._graphic),
|
||||||
|
_graphic_wname(copy._graphic_wname),
|
||||||
|
_cprops(copy._cprops)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::TextCharacter::Copy Assignment
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE void TextAssembler::TextCharacter::
|
||||||
|
operator = (const TextAssembler::TextCharacter ©) {
|
||||||
|
_character = copy._character;
|
||||||
|
_graphic = copy._graphic;
|
||||||
|
_graphic_wname = copy._graphic_wname;
|
||||||
|
_cprops = copy._cprops;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::TextRow::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE TextAssembler::TextRow::
|
||||||
|
TextRow(int row_start) :
|
||||||
|
_row_start(row_start),
|
||||||
|
_got_soft_hyphens(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::TextRow::Copy Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE TextAssembler::TextRow::
|
||||||
|
TextRow(const TextAssembler::TextRow ©) :
|
||||||
|
_string(copy._string),
|
||||||
|
_row_start(copy._row_start),
|
||||||
|
_got_soft_hyphens(copy._got_soft_hyphens),
|
||||||
|
_xpos(copy._xpos),
|
||||||
|
_ypos(copy._ypos)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::TextRow::Copy Assignment
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE void TextAssembler::TextRow::
|
||||||
|
operator = (const TextAssembler::TextRow ©) {
|
||||||
|
_string = copy._string;
|
||||||
|
_row_start = copy._row_start;
|
||||||
|
_got_soft_hyphens = copy._got_soft_hyphens;
|
||||||
|
_xpos = copy._xpos;
|
||||||
|
_ypos = copy._ypos;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::ComputedProperties::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE TextAssembler::ComputedProperties::
|
||||||
|
ComputedProperties(const TextProperties &orig_properties) :
|
||||||
|
_based_on(NULL),
|
||||||
|
_depth(0),
|
||||||
|
_properties(orig_properties)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextAssembler::ComputedProperties::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE TextAssembler::ComputedProperties::
|
||||||
|
ComputedProperties(ComputedProperties *based_on, const wstring &wname,
|
||||||
|
TextEncoder *encoder) :
|
||||||
|
_based_on(based_on),
|
||||||
|
_depth(_based_on->_depth + 1),
|
||||||
|
_wname(wname),
|
||||||
|
_properties(based_on->_properties)
|
||||||
|
{
|
||||||
|
TextPropertiesManager *manager =
|
||||||
|
TextPropertiesManager::get_global_ptr();
|
||||||
|
|
||||||
|
// Now we have to encode the wstring into a string, for lookup
|
||||||
|
// in the TextPropertiesManager.
|
||||||
|
string name = encoder->encode_wtext(wname);
|
||||||
|
|
||||||
|
const TextProperties *named_props = manager->get_properties_ptr(name);
|
||||||
|
if (named_props != (TextProperties *)NULL) {
|
||||||
|
_properties.add_properties(*named_props);
|
||||||
|
} else {
|
||||||
|
text_cat.warning()
|
||||||
|
<< "Unknown TextProperties: " << name << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: TextAssembler::GlyphPlacement::add_piece
|
// Function: TextAssembler::GlyphPlacement::add_piece
|
||||||
// Access: Public
|
// Access: Public
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -19,8 +19,6 @@
|
|||||||
#ifndef TEXTASSEMBLER_H
|
#ifndef TEXTASSEMBLER_H
|
||||||
#define TEXTASSEMBLER_H
|
#define TEXTASSEMBLER_H
|
||||||
|
|
||||||
#ifndef CPPPARSER // interrogate has a bit of trouble with wstring iterators.
|
|
||||||
|
|
||||||
#include "pandabase.h"
|
#include "pandabase.h"
|
||||||
|
|
||||||
#include "textProperties.h"
|
#include "textProperties.h"
|
||||||
@ -29,23 +27,27 @@
|
|||||||
#include "geomNode.h"
|
#include "geomNode.h"
|
||||||
#include "pointerTo.h"
|
#include "pointerTo.h"
|
||||||
#include "geom.h"
|
#include "geom.h"
|
||||||
|
#include "textPropertiesManager.h"
|
||||||
|
#include "textEncoder.h"
|
||||||
|
|
||||||
class TextEncoder;
|
class TextEncoder;
|
||||||
class TextGraphic;
|
class TextGraphic;
|
||||||
|
class TextAssembler;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Class : TextAssembler
|
// Class : TextAssembler
|
||||||
// Description : This class is not intended to be used directly by
|
// Description : This class is not normally used directly by user
|
||||||
// user code, but is used by the TextNode to lay out a
|
// code, but is used by the TextNode to lay out a block
|
||||||
// block of text and convert it into rows of Geoms
|
// of text and convert it into rows of Geoms according
|
||||||
// according to the TextProperties.
|
// to the TextProperties. However, user code may take
|
||||||
//
|
// advantage of it, if desired, for very low-level text
|
||||||
// It is not exported from the DLL since it is not
|
// operations.
|
||||||
// intended to be used outside of this module.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
class TextAssembler {
|
class EXPCL_PANDA TextAssembler {
|
||||||
public:
|
PUBLISHED:
|
||||||
TextAssembler(TextEncoder *encoder);
|
TextAssembler(TextEncoder *encoder);
|
||||||
|
TextAssembler(const TextAssembler ©);
|
||||||
|
void operator = (const TextAssembler ©);
|
||||||
~TextAssembler();
|
~TextAssembler();
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
@ -53,11 +55,41 @@ public:
|
|||||||
INLINE void set_usage_hint(Geom::UsageHint usage_hint);
|
INLINE void set_usage_hint(Geom::UsageHint usage_hint);
|
||||||
INLINE Geom::UsageHint get_usage_hint() const;
|
INLINE Geom::UsageHint get_usage_hint() const;
|
||||||
|
|
||||||
bool set_wtext(const wstring &wtext, const TextProperties &properties,
|
INLINE bool set_max_rows(int max_rows);
|
||||||
int max_rows = 0);
|
INLINE int get_max_rows() const;
|
||||||
INLINE int get_num_rows() const;
|
|
||||||
|
INLINE void set_properties(const TextProperties &properties);
|
||||||
|
INLINE const TextProperties &get_properties() const;
|
||||||
|
|
||||||
|
bool set_wtext(const wstring &wtext);
|
||||||
|
bool set_wsubstr(const wstring &wtext, int start, int count,
|
||||||
|
const TextProperties &properties = TextProperties());
|
||||||
|
|
||||||
|
wstring get_plain_wtext() const;
|
||||||
|
wstring get_wordwrapped_plain_wtext() const;
|
||||||
|
wstring get_wtext() const;
|
||||||
wstring get_wordwrapped_wtext() const;
|
wstring get_wordwrapped_wtext() const;
|
||||||
|
|
||||||
|
bool calc_r_c(int &r, int &c, int n) const;
|
||||||
|
INLINE int calc_r(int n) const;
|
||||||
|
INLINE int calc_c(int n) const;
|
||||||
|
int calc_index(int r, int c) const;
|
||||||
|
|
||||||
|
INLINE int get_num_characters() const;
|
||||||
|
INLINE wchar_t get_character(int n) const;
|
||||||
|
INLINE const TextGraphic *get_graphic(int n) const;
|
||||||
|
INLINE const TextProperties &get_properties(int n) const;
|
||||||
|
INLINE float get_width(int n) const;
|
||||||
|
|
||||||
|
INLINE int get_num_rows() const;
|
||||||
|
INLINE int get_num_cols(int r) const;
|
||||||
|
INLINE wchar_t get_character(int r, int c) const;
|
||||||
|
INLINE const TextGraphic *get_graphic(int r, int c) const;
|
||||||
|
INLINE const TextProperties &get_properties(int r, int c) const;
|
||||||
|
INLINE float get_width(int r, int c) const;
|
||||||
|
float get_xpos(int r, int c) const;
|
||||||
|
INLINE float get_ypos(int r, int c) const;
|
||||||
|
|
||||||
PT(PandaNode) assemble_text();
|
PT(PandaNode) assemble_text();
|
||||||
|
|
||||||
INLINE const LVector2f &get_ul() const;
|
INLINE const LVector2f &get_ul() const;
|
||||||
@ -67,33 +99,69 @@ public:
|
|||||||
static float calc_width(const TextGraphic *graphic, const TextProperties &properties);
|
static float calc_width(const TextGraphic *graphic, const TextProperties &properties);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class ComputedProperties : public ReferenceCount {
|
||||||
|
public:
|
||||||
|
INLINE ComputedProperties(const TextProperties &orig_properties);
|
||||||
|
INLINE ComputedProperties(ComputedProperties *based_on,
|
||||||
|
const wstring &wname, TextEncoder *encoder);
|
||||||
|
void append_delta(wstring &wtext, ComputedProperties *other);
|
||||||
|
|
||||||
|
PT(ComputedProperties) _based_on;
|
||||||
|
int _depth;
|
||||||
|
wstring _wname;
|
||||||
|
TextProperties _properties;
|
||||||
|
};
|
||||||
|
|
||||||
// These structures are built up and operated on by scan_wtext() and
|
// These structures are built up and operated on by scan_wtext() and
|
||||||
// wordwrap_text(). It represents the unrolling of the embedded \1
|
// wordwrap_text(). It represents the unrolling of the embedded \1
|
||||||
// .. \2 sequences embedded in the string into a TextProperties
|
// .. \2 sequences embedded in the string into a TextProperties
|
||||||
// pointer associated with each character.
|
// pointer associated with each character.
|
||||||
typedef pvector<TextProperties *> PropertiesList;
|
|
||||||
|
|
||||||
class TextCharacter {
|
class TextCharacter {
|
||||||
public:
|
public:
|
||||||
INLINE TextCharacter(wchar_t character, const TextProperties *properties);
|
INLINE TextCharacter(wchar_t character, ComputedProperties *cprops);
|
||||||
INLINE TextCharacter(const TextGraphic *graphic, const TextProperties *properties);
|
INLINE TextCharacter(const TextGraphic *graphic,
|
||||||
|
const wstring &graphic_wname,
|
||||||
|
ComputedProperties *cprops);
|
||||||
|
INLINE TextCharacter(const TextCharacter ©);
|
||||||
|
INLINE void operator = (const TextCharacter ©);
|
||||||
|
|
||||||
wchar_t _character;
|
wchar_t _character;
|
||||||
const TextGraphic *_graphic;
|
const TextGraphic *_graphic;
|
||||||
const TextProperties *_properties;
|
wstring _graphic_wname;
|
||||||
|
PT(ComputedProperties) _cprops;
|
||||||
};
|
};
|
||||||
typedef pvector<TextCharacter> TextString;
|
typedef pvector<TextCharacter> TextString;
|
||||||
|
|
||||||
PropertiesList _properties_list;
|
class TextRow {
|
||||||
TextString _wordwrapped_string;
|
public:
|
||||||
int _num_rows;
|
INLINE TextRow(int row_start);
|
||||||
|
INLINE TextRow(const TextRow ©);
|
||||||
|
INLINE void operator = (const TextRow ©);
|
||||||
|
|
||||||
void scan_wtext(wstring::const_iterator &si,
|
TextString _string;
|
||||||
|
int _row_start;
|
||||||
|
bool _got_soft_hyphens;
|
||||||
|
float _xpos;
|
||||||
|
float _ypos;
|
||||||
|
};
|
||||||
|
typedef pvector<TextRow> TextBlock;
|
||||||
|
|
||||||
|
PT(ComputedProperties) _initial_cprops;
|
||||||
|
|
||||||
|
// This is the string, unwordwrapped.
|
||||||
|
TextString _text_string;
|
||||||
|
|
||||||
|
// And here it is, wordwrapped.
|
||||||
|
TextBlock _text_block;
|
||||||
|
|
||||||
|
#ifndef CPPPARSER // interrogate has a bit of trouble with wstring iterators.
|
||||||
|
void scan_wtext(TextString &output_string,
|
||||||
|
wstring::const_iterator &si,
|
||||||
const wstring::const_iterator &send,
|
const wstring::const_iterator &send,
|
||||||
const TextProperties *current_properties,
|
ComputedProperties *current_cprops);
|
||||||
TextString &text_string);
|
#endif // CPPPARSER
|
||||||
bool wordwrap_text(const TextAssembler::TextString &text,
|
|
||||||
TextAssembler::TextString &output_text,
|
bool wordwrap_text();
|
||||||
int max_rows);
|
|
||||||
|
|
||||||
INLINE static float calc_width(const TextCharacter &tch);
|
INLINE static float calc_width(const TextCharacter &tch);
|
||||||
static float calc_hyphen_width(const TextCharacter &tch);
|
static float calc_hyphen_width(const TextCharacter &tch);
|
||||||
@ -127,11 +195,8 @@ private:
|
|||||||
};
|
};
|
||||||
typedef pvector<GlyphPlacement *> PlacedGlyphs;
|
typedef pvector<GlyphPlacement *> PlacedGlyphs;
|
||||||
|
|
||||||
void assemble_paragraph(TextString::const_iterator si,
|
void assemble_paragraph(PlacedGlyphs &placed_glyphs);
|
||||||
const TextString::const_iterator &send,
|
void assemble_row(TextRow &row,
|
||||||
PlacedGlyphs &placed_glyphs);
|
|
||||||
void assemble_row(TextString::const_iterator &si,
|
|
||||||
const TextString::const_iterator &send,
|
|
||||||
PlacedGlyphs &row_placed_glyphs,
|
PlacedGlyphs &row_placed_glyphs,
|
||||||
float &row_width, float &line_height,
|
float &row_width, float &line_height,
|
||||||
TextProperties::Alignment &align);
|
TextProperties::Alignment &align);
|
||||||
@ -188,14 +253,14 @@ private:
|
|||||||
// These are filled in by assemble_paragraph().
|
// These are filled in by assemble_paragraph().
|
||||||
LVector2f _ul;
|
LVector2f _ul;
|
||||||
LVector2f _lr;
|
LVector2f _lr;
|
||||||
|
float _next_row_ypos;
|
||||||
|
|
||||||
TextEncoder *_encoder;
|
TextEncoder *_encoder;
|
||||||
Geom::UsageHint _usage_hint;
|
Geom::UsageHint _usage_hint;
|
||||||
|
int _max_rows;
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "textAssembler.I"
|
#include "textAssembler.I"
|
||||||
|
|
||||||
#endif // CPPPARSER
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ get_line_height() const {
|
|||||||
INLINE void TextNode::
|
INLINE void TextNode::
|
||||||
set_max_rows(int max_rows) {
|
set_max_rows(int max_rows) {
|
||||||
_max_rows = max_rows;
|
_max_rows = max_rows;
|
||||||
|
_assembler.set_max_rows(_max_rows);
|
||||||
invalidate_with_measure();
|
invalidate_with_measure();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,6 +60,7 @@ set_max_rows(int max_rows) {
|
|||||||
INLINE void TextNode::
|
INLINE void TextNode::
|
||||||
clear_max_rows() {
|
clear_max_rows() {
|
||||||
_max_rows = 0;
|
_max_rows = 0;
|
||||||
|
_assembler.set_max_rows(_max_rows);
|
||||||
invalidate_with_measure();
|
invalidate_with_measure();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1183,8 +1185,10 @@ append_unicode_char(int character) {
|
|||||||
// Access: Public
|
// Access: Public
|
||||||
// Description: Returns a string that represents the contents of the
|
// Description: Returns a string that represents the contents of the
|
||||||
// text, as it has been formatted by wordwrap rules.
|
// text, as it has been formatted by wordwrap rules.
|
||||||
// This will not contain any embedded special characters
|
//
|
||||||
// like \1 or \3.
|
// In earlier versions, this did not contain any
|
||||||
|
// embedded special characters like \1 or \3; now it
|
||||||
|
// does.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE string TextNode::
|
INLINE string TextNode::
|
||||||
get_wordwrapped_text() const {
|
get_wordwrapped_text() const {
|
||||||
@ -1234,8 +1238,10 @@ append_wtext(const wstring &wtext) {
|
|||||||
// Access: Published
|
// Access: Published
|
||||||
// Description: Returns a wstring that represents the contents of the
|
// Description: Returns a wstring that represents the contents of the
|
||||||
// text, as it has been formatted by wordwrap rules.
|
// text, as it has been formatted by wordwrap rules.
|
||||||
// This will not contain any embedded special characters
|
//
|
||||||
// like \1 or \3.
|
// In earlier versions, this did not contain any
|
||||||
|
// embedded special characters like \1 or \3; now it
|
||||||
|
// does.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE wstring TextNode::
|
INLINE wstring TextNode::
|
||||||
get_wordwrapped_wtext() const {
|
get_wordwrapped_wtext() const {
|
||||||
|
@ -302,7 +302,8 @@ generate() {
|
|||||||
wstring wtext = get_wtext();
|
wstring wtext = get_wtext();
|
||||||
|
|
||||||
// Assemble the text.
|
// Assemble the text.
|
||||||
bool all_set = _assembler.set_wtext(wtext, *this, _max_rows);
|
_assembler.set_properties(*this);
|
||||||
|
bool all_set = _assembler.set_wtext(wtext);
|
||||||
if (all_set) {
|
if (all_set) {
|
||||||
// No overflow.
|
// No overflow.
|
||||||
_flags &= ~F_has_overflow;
|
_flags &= ~F_has_overflow;
|
||||||
|
@ -296,9 +296,7 @@ private:
|
|||||||
|
|
||||||
LPoint3f _ul3d, _lr3d;
|
LPoint3f _ul3d, _lr3d;
|
||||||
|
|
||||||
#ifndef CPPPARSER
|
|
||||||
TextAssembler _assembler;
|
TextAssembler _assembler;
|
||||||
#endif
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static TypeHandle get_class_type() {
|
static TypeHandle get_class_type() {
|
||||||
|
@ -17,6 +17,16 @@
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextProperties::operator !=
|
||||||
|
// Access: Published
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE bool TextProperties::
|
||||||
|
operator != (const TextProperties &other) const {
|
||||||
|
return !operator == (other);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: TextProperties::is_any_specified
|
// Function: TextProperties::is_any_specified
|
||||||
// Access: Published
|
// Access: Published
|
||||||
|
@ -91,6 +91,71 @@ operator = (const TextProperties ©) {
|
|||||||
_glyph_shift = copy._glyph_shift;
|
_glyph_shift = copy._glyph_shift;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TextProperties::operator ==
|
||||||
|
// Access: Published
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool TextProperties::
|
||||||
|
operator == (const TextProperties &other) const {
|
||||||
|
if (_specified != other._specified) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((_specified & F_has_font) && _font != other._font) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((_specified & F_has_small_caps) && _small_caps != other._small_caps) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((_specified & F_has_small_caps_scale) && _small_caps_scale != other._small_caps_scale) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((_specified & F_has_slant) && _slant != other._slant) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((_specified & F_has_align) && _align != other._align) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((_specified & F_has_indent) && _indent_width != other._indent_width) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((_specified & F_has_wordwrap) && _wordwrap_width != other._wordwrap_width) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((_specified & F_has_preserve_trailing_whitespace) && _preserve_trailing_whitespace != other._preserve_trailing_whitespace) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((_specified & F_has_text_color) && _text_color != other._text_color) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((_specified & F_has_text_color) && _text_color != other._text_color) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((_specified & F_has_shadow_color) && _shadow_color != other._shadow_color) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((_specified & F_has_shadow) && _shadow_offset != other._shadow_offset) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((_specified & F_has_bin) && _bin != other._bin) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((_specified & F_has_draw_order) && _draw_order != other._draw_order) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((_specified & F_has_tab_width) && _tab_width != other._tab_width) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((_specified & F_has_glyph_scale) && _glyph_scale != other._glyph_scale) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((_specified & F_has_glyph_shift) && _glyph_shift != other._glyph_shift) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: TextProperties::clear
|
// Function: TextProperties::clear
|
||||||
// Access: Published
|
// Access: Published
|
||||||
|
@ -59,6 +59,9 @@ PUBLISHED:
|
|||||||
TextProperties(const TextProperties ©);
|
TextProperties(const TextProperties ©);
|
||||||
void operator = (const TextProperties ©);
|
void operator = (const TextProperties ©);
|
||||||
|
|
||||||
|
bool operator == (const TextProperties &other) const;
|
||||||
|
INLINE bool operator != (const TextProperties &other) const;
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
INLINE bool is_any_specified() const;
|
INLINE bool is_any_specified() const;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user