PGEntry should use wstring internally

This commit is contained in:
David Rose 2002-02-16 19:37:06 +00:00
parent 79c241b0d9
commit 64ddb25aed
7 changed files with 208 additions and 103 deletions

View File

@ -21,25 +21,30 @@
// Function: PGEntry::set_text
// Access: Published
// Description: Changes the text currently displayed within the
// entry.
// entry. This uses the Unicode encoding currently
// specified for the "focus" TextNode; therefore, the
// TextNode must exist before calling set_text().
////////////////////////////////////////////////////////////////////
INLINE void PGEntry::
set_text(const string &text) {
_text = text;
_text_geom_stale = true;
_cursor_stale = true;
_blink_start = ClockObject::get_global_clock()->get_frame_time();
TextNode *text_node = get_text_def(S_focus);
nassertv(text_node != (TextNode *)NULL);
set_wtext(text_node->decode_text(text));
}
////////////////////////////////////////////////////////////////////
// Function: PGEntry::get_text
// Access: Published
// Description: Returns the text currently displayed within the
// entry.
// entry. This uses the Unicode encoding currently
// specified for the "focus" TextNode; therefore, the
// TextNode must exist before calling get_text().
////////////////////////////////////////////////////////////////////
INLINE const string &PGEntry::
INLINE string PGEntry::
get_text() const {
return _text;
TextNode *text_node = get_text_def(S_focus);
nassertr(text_node != (TextNode *)NULL, string());
return text_node->encode_wtext(get_wtext());
}
////////////////////////////////////////////////////////////////////
@ -352,3 +357,28 @@ INLINE string PGEntry::
get_erase_event() const {
return "erase-" + get_id();
}
////////////////////////////////////////////////////////////////////
// Function: PGEntry::set_wtext
// Access: Public
// Description: Changes the text currently displayed within the
// entry.
////////////////////////////////////////////////////////////////////
INLINE void PGEntry::
set_wtext(const wstring &wtext) {
_wtext = wtext;
_text_geom_stale = true;
_cursor_stale = true;
_blink_start = ClockObject::get_global_clock()->get_frame_time();
}
////////////////////////////////////////////////////////////////////
// Function: PGEntry::get_wtext
// Access: Public
// Description: Returns the text currently displayed within the
// entry.
////////////////////////////////////////////////////////////////////
INLINE const wstring &PGEntry::
get_wtext() const {
return _wtext;
}

View File

@ -82,8 +82,8 @@ PGEntry::
PGEntry::
PGEntry(const PGEntry &copy) :
PGItem(copy),
_text(copy._text),
_obscured_text(copy._obscured_text),
_wtext(copy._wtext),
_obscured_wtext(copy._obscured_wtext),
_cursor_position(copy._cursor_position),
_max_chars(copy._max_chars),
_max_width(copy._max_width),
@ -106,8 +106,8 @@ PGEntry(const PGEntry &copy) :
void PGEntry::
operator = (const PGEntry &copy) {
PGItem::operator = (copy);
_text = copy._text;
_obscured_text = copy._obscured_text;
_wtext = copy._wtext;
_obscured_wtext = copy._obscured_wtext;
_cursor_position = copy._cursor_position;
_max_chars = copy._max_chars;
_max_width = copy._max_width;
@ -179,7 +179,7 @@ press(const MouseWatcherParameter &param, bool background) {
} else if ((!background && get_focus()) ||
(background && get_background_focus())) {
// Keyboard button.
_cursor_position = min(_cursor_position, (int)_text.length());
_cursor_position = min(_cursor_position, (int)_wtext.length());
_blink_start = ClockObject::get_global_clock()->get_frame_time();
if (button == KeyboardButton::enter()) {
// Enter. Accept the entry.
@ -188,10 +188,10 @@ press(const MouseWatcherParameter &param, 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_text.length() == _text.length()) {
_obscured_text.erase(_obscured_text.begin() + _obscured_text.length() - 1);
if (_obscure_mode && _obscured_wtext.length() == _wtext.length()) {
_obscured_wtext.erase(_obscured_wtext.begin() + _obscured_wtext.length() - 1);
}
_text.erase(_text.begin() + _cursor_position - 1);
_wtext.erase(_wtext.begin() + _cursor_position - 1);
_cursor_position--;
_cursor_stale = true;
_text_geom_stale = true;
@ -200,11 +200,11 @@ press(const MouseWatcherParameter &param, bool background) {
} else if (button == KeyboardButton::del()) {
// Delete. Remove the character to the right of the cursor.
if (_cursor_position < (int)_text.length()) {
if (_obscure_mode && _obscured_text.length() == _text.length()) {
_obscured_text.erase(_obscured_text.begin() + _obscured_text.length() - 1);
if (_cursor_position < (int)_wtext.length()) {
if (_obscure_mode && _obscured_wtext.length() == _wtext.length()) {
_obscured_wtext.erase(_obscured_wtext.begin() + _obscured_wtext.length() - 1);
}
_text.erase(_text.begin() + _cursor_position);
_wtext.erase(_wtext.begin() + _cursor_position);
_text_geom_stale = true;
erase(param);
}
@ -219,7 +219,7 @@ press(const MouseWatcherParameter &param, 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)_text.length());
_cursor_position = min(_cursor_position + 1, (int)_wtext.length());
_cursor_stale = true;
}
@ -233,29 +233,32 @@ press(const MouseWatcherParameter &param, bool background) {
} else if (button == KeyboardButton::end()) {
if (_cursor_keys_active) {
// End. Move the cursor position to the end.
_cursor_position = _text.length();
_cursor_position = _wtext.length();
_cursor_stale = true;
}
} else if (!use_keystrokes && button.has_ascii_equivalent()) {
char key = button.get_ascii_equivalent();
// This part of the code is deprecated and will be removed
// soon. It only supports the old button up/down method of
// sending keystrokes, instead of the new keystroke method.
wchar_t key = button.get_ascii_equivalent();
if (isprint(key)) {
// A normal visible character. Add a new character to the
// text entry, if there's room.
if (get_max_chars() > 0 && (int)_text.length() >= get_max_chars()) {
if (get_max_chars() > 0 && (int)_wtext.length() >= get_max_chars()) {
overflow(param);
} else {
string new_text =
_text.substr(0, _cursor_position) + key +
_text.substr(_cursor_position);
wstring new_text =
_wtext.substr(0, _cursor_position) + key +
_wtext.substr(_cursor_position);
// Get a string to measure its length. In normal mode,
// we measure the text itself. In obscure mode, we
// measure a string of n asterisks.
string measure_text;
wstring measure_text;
if (_obscure_mode) {
measure_text = get_display_text() + '*';
measure_text = get_display_wtext() + (wchar_t)'*';
} else {
measure_text = new_text;
}
@ -273,7 +276,7 @@ press(const MouseWatcherParameter &param, bool background) {
// If we have multiple lines, we have to check the
// length by wordwrapping it and counting up the
// number of lines.
string ww_text = text_node->wordwrap_to(measure_text, _max_width, true);
wstring ww_text = text_node->wordwrap_to(measure_text, _max_width, true);
int num_lines = 1;
size_t last_line_start = 0;
for (size_t p = 0;
@ -290,7 +293,7 @@ press(const MouseWatcherParameter &param, bool background) {
// We must also ensure that the last line is not too
// long (it might be, because of additional
// whitespace on the end).
string last_line = ww_text.substr(last_line_start);
wstring last_line = ww_text.substr(last_line_start);
float last_line_width = text_node->calc_width(last_line);
if (num_lines == _num_lines) {
// Mainly we only care about this if we're on
@ -303,8 +306,8 @@ press(const MouseWatcherParameter &param, bool background) {
// infinite number of spaces to accumulate.
// However, we must allow at least *one* space
// on the end of a line.
if (_text.length() >= 1 &&
_text[_text.length() - 1] == ' ') {
if (_wtext.length() >= 1 &&
_wtext[_wtext.length() - 1] == ' ') {
if (last_line_width > _max_width) {
// In this case, however, it's not exactly
// an overflow; we just want to reject the
@ -321,9 +324,9 @@ press(const MouseWatcherParameter &param, bool background) {
overflow(param);
} else {
_text = new_text;
_wtext = new_text;
if (_obscure_mode) {
_obscured_text = measure_text;
_obscured_wtext = measure_text;
}
_cursor_position++;
@ -356,26 +359,22 @@ keystroke(const MouseWatcherParameter &param, bool background) {
if (!isascii(keycode) || isprint(keycode)) {
// A normal visible character. Add a new character to the
// text entry, if there's room.
wstring new_char(1, (wchar_t)keycode);
// Encode the character. This might expand it to two or
// three bytes, or it might remain a one-byte character.
TextNode *text_node = get_text_def(S_focus);
string new_char = text_node->encode_wchar(keycode);
if (get_max_chars() > 0 && (int)_text.length() >= get_max_chars()) {
if (get_max_chars() > 0 && (int)_wtext.length() >= get_max_chars()) {
overflow(param);
} else {
_cursor_position = min(_cursor_position, (int)_text.length());
string new_text =
_text.substr(0, _cursor_position) + new_char +
_text.substr(_cursor_position);
_cursor_position = min(_cursor_position, (int)_wtext.length());
wstring new_text =
_wtext.substr(0, _cursor_position) + new_char +
_wtext.substr(_cursor_position);
// Get a string to measure its length. In normal mode,
// we measure the text itself. In obscure mode, we
// measure a string of n asterisks.
string measure_text;
wstring measure_text;
if (_obscure_mode) {
measure_text = get_display_text() + '*';
measure_text = get_display_wtext() + (wchar_t)'*';
} else {
measure_text = new_text;
}
@ -393,7 +392,7 @@ keystroke(const MouseWatcherParameter &param, bool background) {
// If we have multiple lines, we have to check the
// length by wordwrapping it and counting up the
// number of lines.
string ww_text = text_node->wordwrap_to(measure_text, _max_width, true);
wstring ww_text = text_node->wordwrap_to(measure_text, _max_width, true);
int num_lines = 1;
size_t last_line_start = 0;
for (size_t p = 0;
@ -410,7 +409,7 @@ keystroke(const MouseWatcherParameter &param, bool background) {
// We must also ensure that the last line is not too
// long (it might be, because of additional
// whitespace on the end).
string last_line = ww_text.substr(last_line_start);
wstring last_line = ww_text.substr(last_line_start);
float last_line_width = text_node->calc_width(last_line);
if (num_lines == _num_lines) {
// Mainly we only care about this if we're on
@ -423,8 +422,8 @@ keystroke(const MouseWatcherParameter &param, bool background) {
// infinite number of spaces to accumulate.
// However, we must allow at least *one* space
// on the end of a line.
if (_text.length() >= 1 &&
_text[_text.length() - 1] == ' ') {
if (_wtext.length() >= 1 &&
_wtext[_wtext.length() - 1] == ' ') {
if (last_line_width > _max_width) {
// In this case, however, it's not exactly
// an overflow; we just want to reject the
@ -441,9 +440,9 @@ keystroke(const MouseWatcherParameter &param, bool background) {
overflow(param);
} else {
_text = new_text;
_wtext = new_text;
if (_obscure_mode) {
_obscured_text = measure_text;
_obscured_wtext = measure_text;
}
_cursor_position += new_char.length();
@ -561,16 +560,16 @@ setup(float width, int num_lines) {
frame[3] = max(max(ll[2], ur[2]), max(lr[2], ul[2]));
switch (text_node->get_align()) {
case TM_ALIGN_LEFT:
case TextNode::A_left:
// The default case.
break;
case TM_ALIGN_CENTER:
case TextNode::A_center:
frame[0] = -width / 2.0;
frame[1] = width / 2.0;
break;
case TM_ALIGN_RIGHT:
case TextNode::A_right:
frame[0] = -width;
frame[1] = 0.0f;
break;
@ -676,30 +675,30 @@ set_focus(bool focus) {
}
////////////////////////////////////////////////////////////////////
// Function: PGEntry::get_display_text
// Function: PGEntry::get_display_wtext
// Access: Private
// Description: Returns the string that should be displayed within
// the entry. This is normally _text, but it may be
// _obscured_text.
// the entry. This is normally _wtext, but it may be
// _obscured_wtext.
////////////////////////////////////////////////////////////////////
const string &PGEntry::
get_display_text() {
const wstring &PGEntry::
get_display_wtext() {
if (_obscure_mode) {
// If obscure mode is enabled, we should just display a bunch of
// asterisks.
if (_obscured_text.length() != _text.length()) {
_obscured_text = "";
string::const_iterator ti;
for (ti = _text.begin(); ti != _text.end(); ++ti) {
_obscured_text += '*';
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_text;
return _obscured_wtext;
} else {
// In normal, non-obscure mode, we display the actual text.
return _text;
return _wtext;
}
}
@ -728,20 +727,20 @@ update_text() {
nassertv(node != (TextNode *)NULL);
if (_text_geom_stale || node != _last_text_def) {
const string &display_text = get_display_text();
const wstring &display_wtext = get_display_wtext();
// We need to regenerate.
_last_text_def = node;
if (_max_width > 0.0f && _num_lines > 1) {
// Fold the text into multiple lines.
string ww_text =
_last_text_def->wordwrap_to(display_text, _max_width, true);
wstring ww_text =
_last_text_def->wordwrap_to(display_wtext, _max_width, true);
// And chop the lines up into pieces.
_ww_lines.clear();
size_t p = 0;
size_t q = ww_text.find('\n');
size_t q = ww_text.find((wchar_t)'\n');
while (q != string::npos) {
_ww_lines.push_back(WWLine());
WWLine &line = _ww_lines.back();
@ -749,8 +748,8 @@ update_text() {
// Get the left edge of the text at this line.
line._left = 0.0f;
if (_last_text_def->get_align() != TM_ALIGN_LEFT) {
_last_text_def->set_text(line._str);
if (_last_text_def->get_align() != TextNode::A_left) {
_last_text_def->set_wtext(line._str);
line._left = _last_text_def->get_left();
}
@ -763,21 +762,21 @@ update_text() {
// Get the left edge of the text at this line.
line._left = 0.0f;
if (_last_text_def->get_align() != TM_ALIGN_LEFT) {
_last_text_def->set_text(line._str);
if (_last_text_def->get_align() != TextNode::A_left) {
_last_text_def->set_wtext(line._str);
line._left = _last_text_def->get_left();
}
_last_text_def->set_text(ww_text);
_last_text_def->set_wtext(ww_text);
} else {
// Only one line.
_ww_lines.clear();
_ww_lines.push_back(WWLine());
WWLine &line = _ww_lines.back();
line._str = display_text;
line._str = display_wtext;
_last_text_def->set_text(display_text);
_last_text_def->set_wtext(display_wtext);
line._left = _last_text_def->get_left();
}
@ -804,7 +803,7 @@ update_cursor() {
if (_cursor_stale || node != _last_text_def) {
update_text();
_cursor_position = min(_cursor_position, (int)_text.length());
_cursor_position = min(_cursor_position, (int)_wtext.length());
// Determine the row and column of the cursor.
int row = 0;

View File

@ -33,6 +33,14 @@
// Description : This is a particular kind of PGItem that handles
// simple one-line text entries, of the sort where the
// user can type any string.
//
// A PGEntry does all of its internal manipulation on a
// wide string, so it can store the full Unicode
// character set. The interface can support either the
// wide string getters and setters, or the normal 8-bit
// string getters and setters, which use whatever
// encoding method is specified by the associated
// TextNode.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA PGEntry : public PGItem {
PUBLISHED:
@ -66,7 +74,7 @@ PUBLISHED:
void setup(float width, int num_lines);
INLINE void set_text(const string &text);
INLINE const string &get_text() const;
INLINE string get_text() const;
INLINE void set_cursor_position(int position);
INLINE int get_cursor_position() const;
@ -106,16 +114,21 @@ PUBLISHED:
INLINE string get_type_event() const;
INLINE string get_erase_event() const;
public:
INLINE void set_wtext(const wstring &wtext);
INLINE const wstring &get_wtext() const;
private:
const string &get_display_text();
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();
string _text;
string _obscured_text;
wstring _wtext;
wstring _obscured_wtext;
int _cursor_position;
bool _cursor_stale;
bool _cursor_visible;
@ -142,7 +155,7 @@ private:
// to compute the correct cursor position.
class WWLine {
public:
string _str;
wstring _str;
float _left;
};
typedef pvector<WWLine> WWLines;

View File

@ -56,7 +56,7 @@ ConfigureFn(config_text) {
const bool text_flatten = config_text.GetBool("text-flatten", true);
const bool text_update_cleared_glyphs = config_text.GetBool("text-update-cleared-glyphs", false);
const bool text_mipmap = config_text.GetBool("text-mipmap", true);
const bool text_mipmap = config_text.GetBool("text-mipmap", false);
const int text_anisotropic_degree = config_text.GetInt("text-anisotropic-degree", 1);
const int text_texture_margin = config_text.GetInt("text-texture-margin", 2);
const float text_poly_margin = config_text.GetFloat("text-poly-margin", 1.0f);

View File

@ -1022,6 +1022,19 @@ get_coordinate_system() const {
return _coordinate_system;
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::set_text
// Access: Published
// Description: Changes the text that is displayed under the
// TextNode.
////////////////////////////////////////////////////////////////////
INLINE void TextNode::
set_text(const string &text) {
_text = text;
_wtext = decode_text(text);
rebuild(true);
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::clear_text
// Access: Published
@ -1225,3 +1238,58 @@ INLINE int TextNode::
get_num_rows() const {
return _num_rows;
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::set_wtext
// Access: Public
// Description: Changes the text that is displayed under the
// TextNode, with a wide text. This automatically sets
// the string reported by get_text() to the 8-bit
// encoded version of the same string.
////////////////////////////////////////////////////////////////////
INLINE void TextNode::
set_wtext(const wstring &wtext) {
_wtext = wtext;
_text = encode_wtext(wtext);
rebuild(true);
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::get_wtext
// Access: Public
// Description: Returns the text associated with the TextNode, as a
// wide-character string.
////////////////////////////////////////////////////////////////////
INLINE const wstring &TextNode::
get_wtext() const {
return _wtext;
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::calc_width
// Access: Published
// Description: Returns the width of a line of text of arbitrary
// characters. The line should not include the newline
// character.
////////////////////////////////////////////////////////////////////
INLINE float TextNode::
calc_width(const wstring &line) const {
nassertr(_font != (TextFont *)NULL, 0.0);
return _font->calc_width(line);
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::wordwrap_to
// Access: Published
// Description: Inserts newlines into the given text at the
// appropriate places in order to make each line be the
// longest possible line that is not longer than
// wordwrap_width (and does not break any words, if
// possible). Returns the new string.
////////////////////////////////////////////////////////////////////
wstring TextNode::
wordwrap_to(const wstring &wtext, float wordwrap_width,
bool preserve_trailing_whitespace) const {
nassertr(_font != (TextFont *)NULL, wtext);
return _font->wordwrap_to(wtext, wordwrap_width, preserve_trailing_whitespace);
}

View File

@ -92,19 +92,6 @@ TextNode::
~TextNode() {
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::set_text
// Access: Published
// Description: Changes the text that is displayed under the
// TextNode.
////////////////////////////////////////////////////////////////////
void TextNode::
set_text(const string &text) {
_text = text;
_wtext = decode_text(text);
rebuild(true);
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::wordwrap_to
// Access: Published
@ -439,10 +426,10 @@ encode_wchar(wchar_t ch) const {
// accoding to the current encoding.
////////////////////////////////////////////////////////////////////
string TextNode::
encode_wtext(const wstring &text) const {
encode_wtext(const wstring &wtext) const {
string result;
for (wstring::const_iterator pi = text.begin(); pi != text.end(); ++pi) {
for (wstring::const_iterator pi = wtext.begin(); pi != wtext.end(); ++pi) {
result += encode_wchar(*pi);
}

View File

@ -186,7 +186,7 @@ PUBLISHED:
INLINE void set_coordinate_system(CoordinateSystem cs);
INLINE CoordinateSystem get_coordinate_system() const;
void set_text(const string &str);
INLINE void set_text(const string &text);
INLINE void clear_text();
INLINE bool has_text() const;
INLINE string get_text() const;
@ -218,8 +218,16 @@ PUBLISHED:
PT_Node generate();
public:
// Direct support for wide-character strings.
INLINE void set_wtext(const wstring &wtext);
INLINE const wstring &get_wtext() const;
INLINE float calc_width(const wstring &line) const;
INLINE wstring wordwrap_to(const wstring &wtext, float wordwrap_width,
bool preserve_trailing_whitespace) const;
string encode_wchar(wchar_t ch) const;
string encode_wtext(const wstring &text) const;
string encode_wtext(const wstring &wtext) const;
wstring decode_text(const string &text) const;
private: