Ver Fonte

Merge pull request #1042 from Pixelized/password-text-box

Password text box
Sean Paul Taylor há 12 anos atrás
pai
commit
e0719e4c4a

+ 1 - 1
gameplay/src/Label.h

@@ -117,7 +117,7 @@ protected:
      *
      * @param clip The clipping rectangle of this label's parent container.
      */
-    void drawText(const Rectangle& clip);
+    virtual void drawText(const Rectangle& clip);
 
     /**
      * The text displayed by this label.

+ 102 - 20
gameplay/src/TextBox.cpp

@@ -4,7 +4,7 @@
 namespace gameplay
 {
 
-TextBox::TextBox() : _lastKeypress(0), _fontSize(0), _caretImage(NULL)
+TextBox::TextBox() : _lastKeypress(0), _fontSize(0), _caretImage(NULL), _passwordChar('*'), _inputMode(TEXT)
 {
 }
 
@@ -32,6 +32,33 @@ TextBox* TextBox::create(Theme::Style* style, Properties* properties)
     return textBox;
 }
 
+void TextBox::initialize(Theme::Style* style, Properties* properties)
+{
+    GP_ASSERT(properties);
+
+    Label::initialize(style, properties);
+    const char* inputMode = properties->getString("inputMode");
+    if (inputMode)
+    {
+		if (strcasecmp(inputMode, "text") == 0)
+		{
+			_inputMode = TEXT;
+		}
+		else if (strcasecmp(inputMode, "password") == 0)
+		{
+			_inputMode = PASSWORD;
+		}
+		else
+		{
+			_inputMode = TEXT;
+		}
+    }
+	else
+	{
+		_inputMode = TEXT;
+	}
+}
+
 int TextBox::getLastKeypress()
 {
     return _lastKeypress;
@@ -133,11 +160,11 @@ bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                     Font::Justify textAlignment = getTextAlignment(_state);
                     bool rightToLeft = getTextRightToLeft(_state);
 
-                    int textIndex = font->getIndexAtLocation(_text.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
+                    int textIndex = font->getIndexAtLocation(getDisplayedText().c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
                         textAlignment, true, rightToLeft);
                         
                     _text.erase(textIndex, 1);
-                    font->getLocationAtIndex(_text.c_str(), _textBounds, fontSize, &_caretLocation, textIndex,
+                    font->getLocationAtIndex(getDisplayedText().c_str(), _textBounds, fontSize, &_caretLocation, textIndex,
                         textAlignment, true, rightToLeft);
                     _dirty = true;
                     notifyListeners(Control::Listener::TEXT_CHANGED);
@@ -151,30 +178,32 @@ bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                 }
                 case Keyboard::KEY_LEFT_ARROW:
                 {
+					const std::string displayedText = getDisplayedText();
                     Font* font = getFont(_state);
                     GP_ASSERT(font);
                     unsigned int fontSize = getFontSize(_state);
                     Font::Justify textAlignment = getTextAlignment(_state);
                     bool rightToLeft = getTextRightToLeft(_state);
 
-                    int textIndex = font->getIndexAtLocation(_text.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
+                    int textIndex = font->getIndexAtLocation(displayedText.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
                         textAlignment, true, rightToLeft);
-                    font->getLocationAtIndex(_text.c_str(), _textBounds, fontSize, &_caretLocation, textIndex - 1,
+                    font->getLocationAtIndex(displayedText.c_str(), _textBounds, fontSize, &_caretLocation, textIndex - 1,
                         textAlignment, true, rightToLeft);
                     _dirty = true;
                     break;
                 }
                 case Keyboard::KEY_RIGHT_ARROW:
                 {
+					const std::string displayedText = getDisplayedText();
                     Font* font = getFont(_state);
                     GP_ASSERT(font);
                     unsigned int fontSize = getFontSize(_state);
                     Font::Justify textAlignment = getTextAlignment(_state);
                     bool rightToLeft = getTextRightToLeft(_state);
 
-                    int textIndex = font->getIndexAtLocation(_text.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
+                    int textIndex = font->getIndexAtLocation(displayedText.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
                         textAlignment, true, rightToLeft);
-                    font->getLocationAtIndex(_text.c_str(), _textBounds, fontSize, &_caretLocation, textIndex + 1,
+                    font->getLocationAtIndex(displayedText.c_str(), _textBounds, fontSize, &_caretLocation, textIndex + 1,
                         textAlignment, true, rightToLeft);
                     _dirty = true;
                     break;
@@ -188,7 +217,7 @@ bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                     bool rightToLeft = getTextRightToLeft(_state);
                     _prevCaretLocation.set(_caretLocation);
                     _caretLocation.y -= fontSize;
-                    int textIndex = font->getIndexAtLocation(_text.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
+                    int textIndex = font->getIndexAtLocation(getDisplayedText().c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
                         textAlignment, true, rightToLeft);
                     if (textIndex == -1)
                     {
@@ -207,7 +236,7 @@ bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                     bool rightToLeft = getTextRightToLeft(_state);
                     _prevCaretLocation.set(_caretLocation);
                     _caretLocation.y += fontSize;
-                    int textIndex = font->getIndexAtLocation(_text.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
+                    int textIndex = font->getIndexAtLocation(getDisplayedText().c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
                         textAlignment, true, rightToLeft);
                     if (textIndex == -1)
                     {
@@ -229,12 +258,12 @@ bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
             Font::Justify textAlignment = getTextAlignment(_state);
             bool rightToLeft = getTextRightToLeft(_state);
 
-            int textIndex = font->getIndexAtLocation(_text.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
+            int textIndex = font->getIndexAtLocation(getDisplayedText().c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
                 textAlignment, true, rightToLeft);
             if (textIndex == -1)
             {
                 textIndex = 0;
-                font->getLocationAtIndex(_text.c_str(), _textBounds, fontSize, &_caretLocation, 0,
+                font->getLocationAtIndex(getDisplayedText().c_str(), _textBounds, fontSize, &_caretLocation, 0,
                     textAlignment, true, rightToLeft);
             }
 
@@ -246,7 +275,7 @@ bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                     {
                         --textIndex;
                         _text.erase(textIndex, 1);
-                        font->getLocationAtIndex(_text.c_str(), _textBounds, fontSize, &_caretLocation, textIndex,
+                        font->getLocationAtIndex(getDisplayedText().c_str(), _textBounds, fontSize, &_caretLocation, textIndex,
                             textAlignment, true, rightToLeft);
 
                         _dirty = true;
@@ -268,7 +297,7 @@ bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                     _text.insert(textIndex, 1, (char)key);
 
                     // Get new location of caret.
-                    font->getLocationAtIndex(_text.c_str(), _textBounds, fontSize, &_caretLocation, textIndex + 1,
+                    font->getLocationAtIndex(getDisplayedText().c_str(), _textBounds, fontSize, &_caretLocation, textIndex + 1,
                         textAlignment, true, rightToLeft);
 
                     if (key == ' ')
@@ -279,7 +308,7 @@ bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                         {
                             // If not, undo the character insertion.
                             _text.erase(textIndex, 1);
-                            font->getLocationAtIndex(_text.c_str(), _textBounds, fontSize, &_caretLocation, textIndex,
+                            font->getLocationAtIndex(getDisplayedText().c_str(), _textBounds, fontSize, &_caretLocation, textIndex,
                                 textAlignment, true, rightToLeft);
 
                             // No need to check again.
@@ -289,13 +318,13 @@ bool TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
 
                     // Always check that the text still fits within the clip region.
                     Rectangle textBounds;
-                    font->measureText(_text.c_str(), _textBounds, fontSize, &textBounds, textAlignment, true, true);
+                    font->measureText(getDisplayedText().c_str(), _textBounds, fontSize, &textBounds, textAlignment, true, true);
                     if (textBounds.x < _textBounds.x || textBounds.y < _textBounds.y ||
                         textBounds.width >= _textBounds.width || textBounds.height >= _textBounds.height)
                     {
                         // If not, undo the character insertion.
                         _text.erase(textIndex, 1);
-                        font->getLocationAtIndex(_text.c_str(), _textBounds, fontSize, &_caretLocation, textIndex,
+                        font->getLocationAtIndex(getDisplayedText().c_str(), _textBounds, fontSize, &_caretLocation, textIndex,
                             textAlignment, true, rightToLeft);
 
                         // TextBox is not dirty.
@@ -360,20 +389,21 @@ void TextBox::setCaretLocation(int x, int y)
     unsigned int fontSize = getFontSize(_state);
     Font::Justify textAlignment = getTextAlignment(_state);
     bool rightToLeft = getTextRightToLeft(_state);
+	const std::string displayedText = getDisplayedText();
 
-    int index = font->getIndexAtLocation(_text.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
+    int index = font->getIndexAtLocation(displayedText.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
             textAlignment, true, rightToLeft);
 
     if (index == -1)
     {
         // Attempt to find the nearest valid caret location.
         Rectangle textBounds;
-        font->measureText(_text.c_str(), _textBounds, fontSize, &textBounds, textAlignment, true, true);
+        font->measureText(displayedText.c_str(), _textBounds, fontSize, &textBounds, textAlignment, true, true);
 
         if (_caretLocation.x > textBounds.x + textBounds.width &&
             _caretLocation.y > textBounds.y + textBounds.height)
         {
-            font->getLocationAtIndex(_text.c_str(), _textBounds, fontSize, &_caretLocation, (unsigned int)_text.length(),
+            font->getLocationAtIndex(displayedText.c_str(), _textBounds, fontSize, &_caretLocation, (unsigned int)_text.length(),
                 textAlignment, true, rightToLeft);
             return;
         }
@@ -399,7 +429,7 @@ void TextBox::setCaretLocation(int x, int y)
             _caretLocation.y = textBounds.y + textBounds.height - fontSize;
         }
 
-        index = font->getIndexAtLocation(_text.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
+        index = font->getIndexAtLocation(displayedText.c_str(), _textBounds, fontSize, _caretLocation, &_caretLocation,
             textAlignment, true, rightToLeft);
 
         if (index == -1)
@@ -415,4 +445,56 @@ const char* TextBox::getType() const
     return "textBox";
 }
 
+void TextBox::setPasswordChar(char character)
+{
+	_passwordChar = character;
+}
+
+char TextBox::getPasswordChar() const
+{
+	return _passwordChar;
+}
+
+void TextBox::setInputMode(InputMode inputMode)
+{
+	_inputMode = inputMode;
+}
+
+TextBox::InputMode TextBox::getInputMode() const
+{
+	return _inputMode;
+}
+
+void TextBox::drawText(const Rectangle& clip)
+{
+    if (_text.size() <= 0)
+        return;
+
+    // Draw the text.
+    if (_font)
+    {
+		const std::string displayedText = getDisplayedText();
+        _font->start();
+        _font->drawText(displayedText.c_str(), _textBounds, _textColor, getFontSize(_state), getTextAlignment(_state), true, getTextRightToLeft(_state), &_viewportClipBounds);
+        _font->finish();
+    }
+}
+
+std::string TextBox::getDisplayedText() const
+{
+	std::string displayedText;
+	switch (_inputMode) {
+		case PASSWORD:
+			displayedText.insert(0, _text.length(), _passwordChar);
+			break;
+
+		case TEXT:
+		default:
+			displayedText = _text;
+			break;
+	}
+
+	return displayedText;
+}
+
 }

+ 77 - 2
gameplay/src/TextBox.h

@@ -30,6 +30,7 @@ namespace gameplay
          width       = <width>   // Can be used in place of 'size', e.g. with 'autoHeight = true'
          height      = <height>  // Can be used in place of 'size', e.g. with 'autoWidth = true'
          text        = <string>
+         inputMode   = <TextBox::InputMode constant>
     }
  @endverbatim
  */
@@ -39,6 +40,21 @@ class TextBox : public Label
 
 public:
 
+	/**
+	 * Input modes. Default is Text.
+	 */
+	enum InputMode {
+		/**
+		 * Text: Text is displayed directly.
+		 */
+		TEXT = 0x01,
+
+		/**
+		 * Password: Text is replaced by _passwordChar, which is '*' by default.
+		 */
+		PASSWORD = 0x02
+	};
+
     /**
      * Create a new text box control.
      *
@@ -50,6 +66,11 @@ public:
      */
     static TextBox* create(const char* id, Theme::Style* style);
 
+    /**
+     * Initialize this textbox.
+     */
+	virtual void initialize(Theme::Style* style, Properties* properties);
+
     /**
      * Add a listener to be notified of specific events affecting
      * this control.  Event types can be OR'ed together.
@@ -74,6 +95,34 @@ public:
      */
     const char* getType() const;
 
+	/**
+	 * Set the character displayed in password mode.
+	 *
+	 * @param character Character to display in password mode.
+	 */
+	void setPasswordChar(char character);
+
+	/**
+	 * Get the character displayed in password mode.
+	 *
+	 * @return The character displayed in password mode.
+	 */
+	char getPasswordChar() const;
+
+	/**
+	 * Set the input mode.
+	 *
+	 * @param inputMode Input mode to set.
+	 */
+	void setInputMode(InputMode inputMode);
+
+	/**
+	 * Get the input mode.
+	 *
+	 * @return The input mode.
+	 */
+	InputMode getInputMode() const;
+
 protected:
 
     /**
@@ -136,8 +185,24 @@ protected:
      *
      * @param spriteBatch The sprite batch containing this control's icons.
      * @param clip The clipping rectangle of this control's parent container.
-     */
-    void drawImages(SpriteBatch* spriteBatch, const Rectangle& clip);
+	 */
+	void drawImages(SpriteBatch* spriteBatch, const Rectangle& clip);
+
+	/**
+	 * Draw this textbox's text.
+	 *
+	 * @param clip The clipping rectangle of this textbox's
+	 * parent container.
+	 **/
+	virtual void drawText(const Rectangle& clip);
+
+	/**
+	 * Get the text which should be displayed, depending on
+	 * _inputMode.
+	 *
+	 * @return The text to be displayed.
+	 */
+	std::string getDisplayedText() const;
 
     /**
      * The current position of the TextBox's caret.
@@ -164,6 +229,16 @@ protected:
      */
     Theme::ThemeImage* _caretImage;
 
+	/**
+	 * The character displayed in password mode.
+	 */
+	char _passwordChar;
+
+	/**
+	 * The mode used to display the typed text.
+	 */
+	InputMode _inputMode;
+
 private:
 
     /**

+ 11 - 1
samples/browser/res/common/forms/formBasicControls.form

@@ -62,6 +62,16 @@ form basicControls
 		consumeInputEvents = true
     }
 
+    textBox testPasswordTextBox
+    {
+        style = topLeftAlignedEntry
+        position = 20, 540
+        size = 250, 40
+        text = password
+        consumeInputEvents = true
+        inputMode = PASSWORD
+    }
+
 	container radioButtonContainer
 	{
 		layout = LAYOUT_VERTICAL
@@ -116,4 +126,4 @@ form basicControls
         size = 200, 100
         text = Alignment: bottom-right. Right margin: 50. Bottom margin: 100.
     }
-}
+}