mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -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));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
// Access: Published
|
||||
@ -47,6 +64,61 @@ get_text() const {
|
||||
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
|
||||
// Access: Published
|
||||
@ -431,11 +503,25 @@ get_erase_event() const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PGEntry::
|
||||
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;
|
||||
_cursor_stale = true;
|
||||
_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
|
||||
// entry.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const wstring &PGEntry::
|
||||
INLINE wstring PGEntry::
|
||||
get_wtext() const {
|
||||
return _wtext;
|
||||
return _text.get_wtext();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -41,7 +41,9 @@ TypeHandle PGEntry::_type_handle;
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PGEntry::
|
||||
PGEntry(const string &name) :
|
||||
PGItem(name)
|
||||
PGItem(name),
|
||||
_text(get_text_node()),
|
||||
_obscure_text(get_text_node())
|
||||
{
|
||||
set_cull_callback();
|
||||
|
||||
@ -53,6 +55,7 @@ PGEntry(const string &name) :
|
||||
_max_chars = 0;
|
||||
_max_width = 0.0f;
|
||||
_num_lines = 1;
|
||||
_accept_enabled = true;
|
||||
_last_text_def = (TextNode *)NULL;
|
||||
_text_geom_stale = true;
|
||||
_blink_start = 0.0f;
|
||||
@ -93,8 +96,8 @@ PGEntry::
|
||||
PGEntry::
|
||||
PGEntry(const PGEntry ©) :
|
||||
PGItem(copy),
|
||||
_wtext(copy._wtext),
|
||||
_obscured_wtext(copy._obscured_wtext),
|
||||
_text(copy._text),
|
||||
_obscure_text(copy._obscure_text),
|
||||
_cursor_position(copy._cursor_position),
|
||||
_max_chars(copy._max_chars),
|
||||
_max_width(copy._max_width),
|
||||
@ -203,7 +206,7 @@ press(const MouseWatcherParameter ¶m, bool background) {
|
||||
_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();
|
||||
if (button == KeyboardButton::enter()) {
|
||||
// Enter. Accept the entry.
|
||||
@ -214,10 +217,7 @@ press(const MouseWatcherParameter ¶m, bool background) {
|
||||
} else if (button == KeyboardButton::backspace()) {
|
||||
// Backspace. Remove the character to the left of the cursor.
|
||||
if (_cursor_position > 0) {
|
||||
if (_obscure_mode && _obscured_wtext.length() == _wtext.length()) {
|
||||
_obscured_wtext.erase(_obscured_wtext.begin() + _obscured_wtext.length() - 1);
|
||||
}
|
||||
_wtext.erase(_wtext.begin() + _cursor_position - 1);
|
||||
_text.set_wsubstr(wstring(), _cursor_position - 1, 1);
|
||||
_cursor_position--;
|
||||
_cursor_stale = true;
|
||||
_text_geom_stale = true;
|
||||
@ -226,11 +226,8 @@ press(const MouseWatcherParameter ¶m, bool background) {
|
||||
|
||||
} else if (button == KeyboardButton::del()) {
|
||||
// Delete. Remove the character to the right of the cursor.
|
||||
if (_cursor_position < (int)_wtext.length()) {
|
||||
if (_obscure_mode && _obscured_wtext.length() == _wtext.length()) {
|
||||
_obscured_wtext.erase(_obscured_wtext.begin() + _obscured_wtext.length() - 1);
|
||||
}
|
||||
_wtext.erase(_wtext.begin() + _cursor_position);
|
||||
if (_cursor_position < _text.get_num_characters()) {
|
||||
_text.set_wsubstr(wstring(), _cursor_position, 1);
|
||||
_text_geom_stale = true;
|
||||
erase(param);
|
||||
}
|
||||
@ -245,7 +242,7 @@ press(const MouseWatcherParameter ¶m, bool background) {
|
||||
} else if (button == KeyboardButton::right()) {
|
||||
if (_cursor_keys_active) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -259,7 +256,7 @@ press(const MouseWatcherParameter ¶m, bool background) {
|
||||
} else if (button == KeyboardButton::end()) {
|
||||
if (_cursor_keys_active) {
|
||||
// End. Move the cursor position to the end.
|
||||
_cursor_position = _wtext.length();
|
||||
_cursor_position = _text.get_num_characters();
|
||||
_cursor_stale = true;
|
||||
}
|
||||
}
|
||||
@ -290,52 +287,27 @@ keystroke(const MouseWatcherParameter ¶m, bool background) {
|
||||
}
|
||||
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
|
||||
// have exceeded a fixed number of characters, irrespective
|
||||
// of the formatted width of those characters.
|
||||
overflow(param);
|
||||
|
||||
} else {
|
||||
_cursor_position = min(_cursor_position, (int)_wtext.length());
|
||||
wstring new_text =
|
||||
_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;
|
||||
_cursor_position = min(_cursor_position, _text.get_num_characters());
|
||||
bool too_long = !_text.set_wsubstr(new_char, _cursor_position, 0);
|
||||
if (_obscure_mode) {
|
||||
measure_text = get_display_wtext() + (wchar_t)'*';
|
||||
too_long = !_obscure_text.set_wtext(wstring(_text.get_num_characters(), '*'));
|
||||
} else {
|
||||
measure_text = new_text;
|
||||
}
|
||||
|
||||
// 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 (!too_long && (_text.get_num_rows() == _num_lines)) {
|
||||
// If we've filled up all of the available lines, 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;
|
||||
}
|
||||
wstring last_line = ww_text.substr(last_line_start);
|
||||
float last_line_width = text_node->calc_width(last_line);
|
||||
|
||||
int r = _num_lines - 1;
|
||||
int c = _text.get_num_cols(r);
|
||||
float last_line_width =
|
||||
_text.get_xpos(r, c) - _text.get_xpos(r, 0);
|
||||
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
|
||||
// exceed the maximum width, just so we don't allow an
|
||||
// infinite number of spaces to accumulate.
|
||||
|
||||
// First, we need to figure out our current position
|
||||
// within the wordwrapped text, by skipping past the
|
||||
// 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') {
|
||||
int r, c;
|
||||
_text.calc_r_c(r, c, _cursor_position);
|
||||
if (_text.get_num_cols(r) == c + 1) {
|
||||
// The user is typing at the end of the line. But we
|
||||
// must allow at least one space at the end of the
|
||||
// line, so we only make any of the following checks
|
||||
// if there are already multiple spaces at the end of
|
||||
// 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
|
||||
// end of a line; we need to make sure the line does
|
||||
// not grow too wide. Get the beginning of the line
|
||||
// and measure its width.
|
||||
int q = current_pos;
|
||||
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);
|
||||
|
||||
// not grow too wide. Measure the line's width.
|
||||
float current_line_width =
|
||||
_text.get_xpos(r, c + 1) - _text.get_xpos(r, 0);
|
||||
if (current_line_width > _max_width) {
|
||||
// We have to reject the space, but we don't treat
|
||||
// it as an overflow condition.
|
||||
|
||||
_text.set_wsubstr(wstring(), _cursor_position, 1);
|
||||
// If the user is typing over existing space
|
||||
// characters, we act as if the right-arrow key
|
||||
// were pressed instead, and advance the cursor to
|
||||
// the next position. Otherwise, we just quietly
|
||||
// eat the space character.
|
||||
if (_cursor_position < (int)_wtext.length() &&
|
||||
_wtext[_cursor_position] == ' ') {
|
||||
if (_cursor_position < _text.get_num_characters() &&
|
||||
_text.get_character(_cursor_position) == ' ') {
|
||||
_cursor_position++;
|
||||
_cursor_stale = true;
|
||||
}
|
||||
@ -409,14 +353,10 @@ keystroke(const MouseWatcherParameter ¶m, bool background) {
|
||||
}
|
||||
|
||||
if (too_long) {
|
||||
_text.set_wsubstr(wstring(), _cursor_position, 1);
|
||||
overflow(param);
|
||||
|
||||
} else {
|
||||
_wtext = new_text;
|
||||
if (_obscure_mode) {
|
||||
_obscured_wtext = measure_text;
|
||||
}
|
||||
|
||||
_cursor_position += new_char.length();
|
||||
_cursor_stale = true;
|
||||
_text_geom_stale = true;
|
||||
@ -445,10 +385,11 @@ candidate(const MouseWatcherParameter ¶m, bool background) {
|
||||
_candidate_highlight_end = param.get_highlight_end();
|
||||
_candidate_cursor_pos = param.get_cursor_pos();
|
||||
_text_geom_stale = true;
|
||||
if (!_candidate_wtext.empty())
|
||||
if (!_candidate_wtext.empty()) {
|
||||
type(param);
|
||||
}
|
||||
}
|
||||
}
|
||||
PGItem::candidate(param, background);
|
||||
}
|
||||
|
||||
@ -678,9 +619,9 @@ set_focus(bool focus) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PGEntry::
|
||||
is_wtext() const {
|
||||
wstring::const_iterator ti;
|
||||
for (ti = _wtext.begin(); ti != _wtext.end(); ++ti) {
|
||||
if (((*ti) & ~0x7f) != 0) {
|
||||
for (int i = 0; i < _text.get_num_characters(); ++i) {
|
||||
wchar_t ch = _text.get_character(i);
|
||||
if ((ch & ~0x7f) != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -688,34 +629,6 @@ is_wtext() const {
|
||||
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
|
||||
// Access: Private
|
||||
@ -741,89 +654,56 @@ update_text() {
|
||||
nassertv(node != (TextNode *)NULL);
|
||||
|
||||
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:
|
||||
// just display the current text contents.
|
||||
display_wtext = get_display_wtext();
|
||||
assembled = _text.assemble_text();
|
||||
|
||||
} 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();
|
||||
TextPropertiesManager *tp_mgr = TextPropertiesManager::get_global_ptr();
|
||||
TextProperties inactive = tp_mgr->get_properties(_candidate_inactive);
|
||||
TextProperties active = tp_mgr->get_properties(_candidate_active);
|
||||
|
||||
display_wtext = source_wtext.substr(0, _cursor_position);
|
||||
display_wtext += wstring(1, (wchar_t)text_push_properties_key);
|
||||
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);
|
||||
// Create a special TextAssembler to insert the candidate string
|
||||
// in its own special colors.
|
||||
|
||||
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);
|
||||
|
||||
// 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();
|
||||
TextAssembler ctext(_text);
|
||||
ctext.set_wsubstr(_candidate_wtext.substr(_candidate_highlight_end),
|
||||
_cursor_position, 0, inactive);
|
||||
ctext.set_wsubstr(_candidate_wtext.substr(_candidate_highlight_start,
|
||||
_candidate_highlight_end - _candidate_highlight_start),
|
||||
_cursor_position, 0, active);
|
||||
ctext.set_wsubstr(_candidate_wtext.substr(0, _candidate_highlight_start),
|
||||
_cursor_position, 0, inactive);
|
||||
assembled = ctext.assemble_text();
|
||||
}
|
||||
|
||||
if (!_current_text.is_empty()) {
|
||||
_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 =
|
||||
_text_render_root.attach_new_node(_last_text_def->generate());
|
||||
_text_render_root.attach_new_node(assembled);
|
||||
_text_geom_stale = false;
|
||||
_cursor_stale = true;
|
||||
}
|
||||
@ -844,32 +724,23 @@ update_cursor() {
|
||||
if (_cursor_stale || node != _last_text_def) {
|
||||
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());
|
||||
|
||||
// Determine the row and column of the cursor.
|
||||
int row = 0;
|
||||
int column = _cursor_position + _candidate_cursor_pos;
|
||||
while (row + 1 < (int)_ww_lines.size() &&
|
||||
column > (int)_ww_lines[row]._str.length()) {
|
||||
column -= _ww_lines[row]._str.length();
|
||||
row++;
|
||||
int row, column;
|
||||
float xpos, ypos;
|
||||
if (_obscure_mode) {
|
||||
_obscure_text.calc_r_c(row, column, _cursor_position + _candidate_cursor_pos);
|
||||
xpos = _obscure_text.get_xpos(row, column);
|
||||
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());
|
||||
|
||||
// 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_def.set_pos(xpos, 0.0f, ypos);
|
||||
_cursor_stale = false;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "pointerTo.h"
|
||||
#include "pvector.h"
|
||||
#include "clockObject.h"
|
||||
#include "textAssembler.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : PGEntry
|
||||
@ -74,8 +75,14 @@ PUBLISHED:
|
||||
void setup(float width, int num_lines);
|
||||
|
||||
INLINE void set_text(const string &text);
|
||||
INLINE string get_plain_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 int get_cursor_position() const;
|
||||
|
||||
@ -121,21 +128,21 @@ PUBLISHED:
|
||||
INLINE string get_erase_event() const;
|
||||
|
||||
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);
|
||||
bool is_wtext() const;
|
||||
|
||||
|
||||
private:
|
||||
const wstring &get_display_wtext();
|
||||
void slot_text_def(int state);
|
||||
void update_text();
|
||||
void update_cursor();
|
||||
void show_hide_cursor(bool visible);
|
||||
void update_state();
|
||||
|
||||
wstring _wtext;
|
||||
wstring _obscured_wtext;
|
||||
TextAssembler _text;
|
||||
TextAssembler _obscure_text;
|
||||
int _cursor_position;
|
||||
bool _cursor_stale;
|
||||
bool _cursor_visible;
|
||||
@ -166,17 +173,6 @@ private:
|
||||
TextNode *_last_text_def;
|
||||
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
|
||||
// attached to the above node, and is transformed around and/or
|
||||
// hidden according to the cursor's position and blink state.
|
||||
|
@ -43,9 +43,61 @@ get_usage_hint() const {
|
||||
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
|
||||
// Access: Public
|
||||
// Access: Published
|
||||
// Description: Returns the upper-left corner of the assembled text,
|
||||
// in 2-d text coordinates.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -56,7 +108,7 @@ get_ul() const {
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TextAssembler::get_lr
|
||||
// Access: Public
|
||||
// Access: Published
|
||||
// Description: Returns the lower-right corner of the assembled text,
|
||||
// in 2-d text coordinates.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -65,15 +117,212 @@ get_lr() const {
|
||||
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
|
||||
// Access: Public
|
||||
// Access: Published
|
||||
// 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;
|
||||
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::
|
||||
calc_width(const TextCharacter &tch) {
|
||||
if (tch._graphic != (TextGraphic *)NULL) {
|
||||
return calc_width(tch._graphic, *tch._properties);
|
||||
return calc_width(tch._graphic, tch._cprops->_properties);
|
||||
} 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:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE TextAssembler::TextCharacter::
|
||||
TextCharacter(wchar_t character, const TextProperties *properties) :
|
||||
TextCharacter(wchar_t character,
|
||||
TextAssembler::ComputedProperties *cprops) :
|
||||
_character(character),
|
||||
_graphic(NULL),
|
||||
_properties(properties)
|
||||
_cprops(cprops)
|
||||
{
|
||||
}
|
||||
|
||||
@ -110,13 +360,126 @@ TextCharacter(wchar_t character, const TextProperties *properties) :
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE TextAssembler::TextCharacter::
|
||||
TextCharacter(const TextGraphic *graphic, const TextProperties *properties) :
|
||||
TextCharacter(const TextGraphic *graphic, const wstring &graphic_wname,
|
||||
TextAssembler::ComputedProperties *cprops) :
|
||||
_character(0),
|
||||
_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
|
||||
// Access: Public
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -19,8 +19,6 @@
|
||||
#ifndef TEXTASSEMBLER_H
|
||||
#define TEXTASSEMBLER_H
|
||||
|
||||
#ifndef CPPPARSER // interrogate has a bit of trouble with wstring iterators.
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "textProperties.h"
|
||||
@ -29,23 +27,27 @@
|
||||
#include "geomNode.h"
|
||||
#include "pointerTo.h"
|
||||
#include "geom.h"
|
||||
#include "textPropertiesManager.h"
|
||||
#include "textEncoder.h"
|
||||
|
||||
class TextEncoder;
|
||||
class TextGraphic;
|
||||
class TextAssembler;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 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.
|
||||
// Description : This class is not normally 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. However, user code may take
|
||||
// advantage of it, if desired, for very low-level text
|
||||
// operations.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class TextAssembler {
|
||||
public:
|
||||
class EXPCL_PANDA TextAssembler {
|
||||
PUBLISHED:
|
||||
TextAssembler(TextEncoder *encoder);
|
||||
TextAssembler(const TextAssembler ©);
|
||||
void operator = (const TextAssembler ©);
|
||||
~TextAssembler();
|
||||
|
||||
void clear();
|
||||
@ -53,11 +55,41 @@ public:
|
||||
INLINE void set_usage_hint(Geom::UsageHint usage_hint);
|
||||
INLINE Geom::UsageHint get_usage_hint() const;
|
||||
|
||||
bool set_wtext(const wstring &wtext, const TextProperties &properties,
|
||||
int max_rows = 0);
|
||||
INLINE int get_num_rows() const;
|
||||
INLINE bool set_max_rows(int max_rows);
|
||||
INLINE int get_max_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;
|
||||
|
||||
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();
|
||||
|
||||
INLINE const LVector2f &get_ul() const;
|
||||
@ -67,33 +99,69 @@ public:
|
||||
static float calc_width(const TextGraphic *graphic, const TextProperties &properties);
|
||||
|
||||
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
|
||||
// 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);
|
||||
INLINE TextCharacter(const TextGraphic *graphic, const TextProperties *properties);
|
||||
INLINE TextCharacter(wchar_t character, ComputedProperties *cprops);
|
||||
INLINE TextCharacter(const TextGraphic *graphic,
|
||||
const wstring &graphic_wname,
|
||||
ComputedProperties *cprops);
|
||||
INLINE TextCharacter(const TextCharacter ©);
|
||||
INLINE void operator = (const TextCharacter ©);
|
||||
|
||||
wchar_t _character;
|
||||
const TextGraphic *_graphic;
|
||||
const TextProperties *_properties;
|
||||
wstring _graphic_wname;
|
||||
PT(ComputedProperties) _cprops;
|
||||
};
|
||||
typedef pvector<TextCharacter> TextString;
|
||||
|
||||
PropertiesList _properties_list;
|
||||
TextString _wordwrapped_string;
|
||||
int _num_rows;
|
||||
class TextRow {
|
||||
public:
|
||||
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 TextProperties *current_properties,
|
||||
TextString &text_string);
|
||||
bool wordwrap_text(const TextAssembler::TextString &text,
|
||||
TextAssembler::TextString &output_text,
|
||||
int max_rows);
|
||||
ComputedProperties *current_cprops);
|
||||
#endif // CPPPARSER
|
||||
|
||||
bool wordwrap_text();
|
||||
|
||||
INLINE static float calc_width(const TextCharacter &tch);
|
||||
static float calc_hyphen_width(const TextCharacter &tch);
|
||||
@ -127,11 +195,8 @@ private:
|
||||
};
|
||||
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,
|
||||
void assemble_paragraph(PlacedGlyphs &placed_glyphs);
|
||||
void assemble_row(TextRow &row,
|
||||
PlacedGlyphs &row_placed_glyphs,
|
||||
float &row_width, float &line_height,
|
||||
TextProperties::Alignment &align);
|
||||
@ -188,14 +253,14 @@ private:
|
||||
// These are filled in by assemble_paragraph().
|
||||
LVector2f _ul;
|
||||
LVector2f _lr;
|
||||
float _next_row_ypos;
|
||||
|
||||
TextEncoder *_encoder;
|
||||
Geom::UsageHint _usage_hint;
|
||||
int _max_rows;
|
||||
};
|
||||
|
||||
#include "textAssembler.I"
|
||||
|
||||
#endif // CPPPARSER
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -47,6 +47,7 @@ get_line_height() const {
|
||||
INLINE void TextNode::
|
||||
set_max_rows(int max_rows) {
|
||||
_max_rows = max_rows;
|
||||
_assembler.set_max_rows(_max_rows);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
|
||||
@ -59,6 +60,7 @@ set_max_rows(int max_rows) {
|
||||
INLINE void TextNode::
|
||||
clear_max_rows() {
|
||||
_max_rows = 0;
|
||||
_assembler.set_max_rows(_max_rows);
|
||||
invalidate_with_measure();
|
||||
}
|
||||
|
||||
@ -1183,8 +1185,10 @@ append_unicode_char(int character) {
|
||||
// Access: Public
|
||||
// Description: Returns a string that represents the contents of the
|
||||
// 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::
|
||||
get_wordwrapped_text() const {
|
||||
@ -1234,8 +1238,10 @@ append_wtext(const wstring &wtext) {
|
||||
// Access: Published
|
||||
// Description: Returns a wstring that represents the contents of the
|
||||
// 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::
|
||||
get_wordwrapped_wtext() const {
|
||||
|
@ -302,7 +302,8 @@ generate() {
|
||||
wstring wtext = get_wtext();
|
||||
|
||||
// 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) {
|
||||
// No overflow.
|
||||
_flags &= ~F_has_overflow;
|
||||
|
@ -296,9 +296,7 @@ private:
|
||||
|
||||
LPoint3f _ul3d, _lr3d;
|
||||
|
||||
#ifndef CPPPARSER
|
||||
TextAssembler _assembler;
|
||||
#endif
|
||||
|
||||
public:
|
||||
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
|
||||
// Access: Published
|
||||
|
@ -91,6 +91,71 @@ operator = (const TextProperties ©) {
|
||||
_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
|
||||
// Access: Published
|
||||
|
@ -59,6 +59,9 @@ PUBLISHED:
|
||||
TextProperties(const TextProperties ©);
|
||||
void operator = (const TextProperties ©);
|
||||
|
||||
bool operator == (const TextProperties &other) const;
|
||||
INLINE bool operator != (const TextProperties &other) const;
|
||||
|
||||
void clear();
|
||||
INLINE bool is_any_specified() const;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user