From f7f4af2e49486814f1b76d3c040317972e54f827 Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 6 Nov 2001 02:34:02 +0000 Subject: [PATCH] add obscured mode --- panda/src/pgui/pgEntry.I | 33 ++++++++++++++++++ panda/src/pgui/pgEntry.cxx | 71 ++++++++++++++++++++++++++++++++++---- panda/src/pgui/pgEntry.h | 6 ++++ 3 files changed, 103 insertions(+), 7 deletions(-) diff --git a/panda/src/pgui/pgEntry.I b/panda/src/pgui/pgEntry.I index 3a18fe51ff..d73c0c96f2 100644 --- a/panda/src/pgui/pgEntry.I +++ b/panda/src/pgui/pgEntry.I @@ -226,6 +226,39 @@ get_cursor_keys_active() const { return _cursor_keys_active; } +//////////////////////////////////////////////////////////////////// +// Function: PGEntry::set_obscure_mode +// Access: Published +// Description: Specifies whether obscure mode should be enabled. In +// obscure mode, a string of asterisks is displayed +// instead of the literal text, e.g. for entering +// passwords. +// +// In obscure mode, the width of the text is computed +// based on the width of the string of asterisks, not on +// the width of the actual text. This has implications +// on the maximum length of text that may be entered if +// max_width is in effect. +//////////////////////////////////////////////////////////////////// +INLINE void PGEntry:: +set_obscure_mode(bool flag) { + if (_obscure_mode != flag) { + _obscure_mode = flag; + _text_geom_stale = true; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PGEntry::get_obscure_mode +// Access: Published +// Description: Specifies whether obscure mode is enabled. See +// set_obscure_mode(). +//////////////////////////////////////////////////////////////////// +INLINE bool PGEntry:: +get_obscure_mode() const { + return _obscure_mode; +} + //////////////////////////////////////////////////////////////////// // Function: PGEntry::get_accept_prefix // Access: Published, Static diff --git a/panda/src/pgui/pgEntry.cxx b/panda/src/pgui/pgEntry.cxx index e0e30f4faf..b61568f755 100644 --- a/panda/src/pgui/pgEntry.cxx +++ b/panda/src/pgui/pgEntry.cxx @@ -59,6 +59,7 @@ PGEntry(const string &name) : PGItem(name) _cursor_visible = true; _cursor_keys_active = true; + _obscure_mode = false; set_active(true); update_state(); @@ -82,12 +83,15 @@ PGEntry:: PGEntry(const PGEntry ©) : PGItem(copy), _text(copy._text), + _obscured_text(copy._obscured_text), _cursor_position(copy._cursor_position), _max_chars(copy._max_chars), _max_width(copy._max_width), _text_defs(copy._text_defs), _blink_start(copy._blink_start), - _blink_rate(copy._blink_rate) + _blink_rate(copy._blink_rate), + _cursor_keys_active(copy._cursor_keys_active), + _obscure_mode(copy._obscure_mode) { _cursor_stale = true; _last_text_def = (TextNode *)NULL; @@ -103,6 +107,7 @@ void PGEntry:: operator = (const PGEntry ©) { PGItem::operator = (copy); _text = copy._text; + _obscured_text = copy._obscured_text; _cursor_position = copy._cursor_position; _max_chars = copy._max_chars; _max_width = copy._max_width; @@ -110,6 +115,9 @@ operator = (const PGEntry ©) { _blink_start = copy._blink_start; _blink_rate = copy._blink_rate; + _cursor_keys_active = copy._cursor_keys_active; + _obscure_mode = copy._obscure_mode; + _cursor_stale = true; _text_geom_stale = true; } @@ -180,6 +188,9 @@ 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_text.length() == _text.length()) { + _obscured_text.erase(_obscured_text.begin() + _obscured_text.length() - 1); + } _text.erase(_text.begin() + _cursor_position - 1); _cursor_position--; _cursor_stale = true; @@ -190,6 +201,9 @@ 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)_text.length()) { + if (_obscure_mode && _obscured_text.length() == _text.length()) { + _obscured_text.erase(_obscured_text.begin() + _obscured_text.length() - 1); + } _text.erase(_text.begin() + _cursor_position); _text_geom_stale = true; erase(param); @@ -235,6 +249,16 @@ press(const MouseWatcherParameter ¶m, bool background) { string new_text = _text.substr(0, _cursor_position) + key + _text.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; + if (_obscure_mode) { + measure_text = get_display_text() + '*'; + } else { + measure_text = new_text; + } // Check the length. bool too_long = false; @@ -243,13 +267,13 @@ press(const MouseWatcherParameter ¶m, bool background) { if (_num_lines <= 1) { // If we have only one line, we can check the length // by simply measuring the width of the text. - too_long = (text_node->calc_width(new_text) > _max_width); + too_long = (text_node->calc_width(measure_text) > _max_width); } else { // If we have multiple lines, we have to check the // length by wordwrapping it and counting up the // number of lines. - string ww_text = text_node->wordwrap_to(new_text, _max_width, true); + string 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; @@ -298,6 +322,9 @@ press(const MouseWatcherParameter ¶m, bool background) { } else { _text = new_text; + if (_obscure_mode) { + _obscured_text = measure_text; + } _cursor_position++; _cursor_stale = true; @@ -458,7 +485,6 @@ setup(float width, int num_lines) { // new RenderRelation(get_cursor_def(), text_node->generate()); } - //////////////////////////////////////////////////////////////////// // Function: PGEntry::set_text_def // Access: Published @@ -530,6 +556,34 @@ set_focus(bool focus) { update_state(); } +//////////////////////////////////////////////////////////////////// +// Function: PGEntry::get_display_text +// Access: Private +// Description: Returns the string that should be displayed within +// the entry. This is normally _text, but it may be +// _obscured_text. +//////////////////////////////////////////////////////////////////// +const string &PGEntry:: +get_display_text() { + 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 += '*'; + } + } + + return _obscured_text; + + } else { + // In normal, non-obscure mode, we display the actual text. + return _text; + } +} + //////////////////////////////////////////////////////////////////// // Function: PGEntry::slot_text_def // Access: Private @@ -555,12 +609,15 @@ update_text() { nassertv(node != (TextNode *)NULL); if (_text_geom_stale || node != _last_text_def) { + const string &display_text = get_display_text(); + // We need to regenerate. _last_text_def = node; if (_max_width > 0.0 && _num_lines > 1) { // Fold the text into multiple lines. - string ww_text = _last_text_def->wordwrap_to(_text, _max_width, true); + string ww_text = + _last_text_def->wordwrap_to(display_text, _max_width, true); // And chop the lines up into pieces. _ww_lines.clear(); @@ -599,9 +656,9 @@ update_text() { _ww_lines.clear(); _ww_lines.push_back(WWLine()); WWLine &line = _ww_lines.back(); - line._str = _text; + line._str = display_text; - _last_text_def->set_text(_text); + _last_text_def->set_text(display_text); line._left = _last_text_def->get_left(); } diff --git a/panda/src/pgui/pgEntry.h b/panda/src/pgui/pgEntry.h index 413f7a785e..bb22f9fb8f 100644 --- a/panda/src/pgui/pgEntry.h +++ b/panda/src/pgui/pgEntry.h @@ -86,6 +86,9 @@ PUBLISHED: INLINE void set_cursor_keys_active(bool flag); INLINE bool get_cursor_keys_active() const; + INLINE void set_obscure_mode(bool flag); + INLINE bool get_obscure_mode() const; + void set_text_def(int state, TextNode *node); TextNode *get_text_def(int state) const; @@ -103,6 +106,7 @@ PUBLISHED: INLINE string get_erase_event() const; private: + const string &get_display_text(); void slot_text_def(int state); void update_text(); void update_cursor(); @@ -110,6 +114,7 @@ private: void update_state(); string _text; + string _obscured_text; int _cursor_position; bool _cursor_stale; bool _cursor_visible; @@ -152,6 +157,7 @@ private: double _blink_rate; bool _cursor_keys_active; + bool _obscure_mode; public: static TypeHandle get_class_type() {