Browse Source

*** empty log message ***

David Rose 25 years ago
parent
commit
7a110a31cd
4 changed files with 209 additions and 30 deletions
  1. 108 3
      panda/src/chat/chatInput.I
  2. 75 20
      panda/src/chat/chatInput.cxx
  3. 23 4
      panda/src/chat/chatInput.h
  4. 3 3
      panda/src/text/textNode.cxx

+ 108 - 3
panda/src/chat/chatInput.I

@@ -15,7 +15,7 @@
 INLINE void ChatInput::
 INLINE void ChatInput::
 set_max_chars(int max_chars) {
 set_max_chars(int max_chars) {
   _max_chars = max_chars;
   _max_chars = max_chars;
-  _has_max_chars = true;
+  _flags |= F_max_chars;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -26,7 +26,7 @@ set_max_chars(int max_chars) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void ChatInput::
 INLINE void ChatInput::
 clear_max_chars() {
 clear_max_chars() {
-  _has_max_chars = false;
+  _flags &= ~F_max_chars;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -37,7 +37,7 @@ clear_max_chars() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool ChatInput::
 INLINE bool ChatInput::
 has_max_chars() const {
 has_max_chars() const {
-  return _has_max_chars;
+  return (_flags & F_max_chars) != 0;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -52,6 +52,111 @@ get_max_chars() const {
   return _max_chars;
   return _max_chars;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: ChatInput::set_max_lines
+//       Access: Public
+//  Description: Sets a limit on the number of lines the user is
+//               allowed to type.  This makes sense only when wordwrap
+//               is enabled on the TextNode; otherwise, it will always
+//               be only one line.  When this limit is exceeded, no
+//               more characters will be accepted, and the event
+//               "chat_overflow" is thrown.
+////////////////////////////////////////////////////////////////////
+INLINE void ChatInput::
+set_max_lines(int max_lines) {
+  _max_lines = max_lines;
+  _flags |= F_max_lines;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ChatInput::clear_max_lines
+//       Access: Public
+//  Description: Removes the limit on the maximum number of
+//               characters.
+////////////////////////////////////////////////////////////////////
+INLINE void ChatInput::
+clear_max_lines() {
+  _flags &= ~F_max_lines;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ChatInput::has_max_lines
+//       Access: Public
+//  Description: Returns true if the maximum number of characters has
+//               been set by a call to set_max_lines().
+////////////////////////////////////////////////////////////////////
+INLINE bool ChatInput::
+has_max_lines() const {
+  return (_flags & F_max_lines) != 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ChatInput::get_max_lines
+//       Access: Public
+//  Description: If has_max_lines() returns true, this will return the
+//               maximum number of characters that was set.
+////////////////////////////////////////////////////////////////////
+INLINE int ChatInput::
+get_max_lines() const {
+  nassertr(has_max_lines(), 0);
+  return _max_lines;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ChatInput::set_max_width
+//       Access: Public
+//  Description: Sets a limit on the total width of the line the user
+//               is allowed to type.  When this limit is exceeded, no
+//               more characters will be accepted, and the event
+//               "chat_overflow" is thrown.
+//
+//               This is different than set_max_chars(), as some
+//               letters use more width than others; capital W, for
+//               instance, takes up more space than a lowercase i.  It
+//               only makes sense to set this option when wordwrap is
+//               *off* for the TextNode.  To limit the text length
+//               with wordwrap on, use set_max_lines().
+////////////////////////////////////////////////////////////////////
+INLINE void ChatInput::
+set_max_width(float max_width) {
+  _max_width = max_width;
+  _flags |= F_max_width;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ChatInput::clear_max_width
+//       Access: Public
+//  Description: Removes the limit on the maximum number of
+//               characters.
+////////////////////////////////////////////////////////////////////
+INLINE void ChatInput::
+clear_max_width() {
+  _flags &= ~F_max_width;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ChatInput::has_max_width
+//       Access: Public
+//  Description: Returns true if the maximum number of characters has
+//               been set by a call to set_max_width().
+////////////////////////////////////////////////////////////////////
+INLINE bool ChatInput::
+has_max_width() const {
+  return (_flags & F_max_width) != 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ChatInput::get_max_width
+//       Access: Public
+//  Description: If has_max_width() returns true, this will return the
+//               maximum number of characters that was set.
+////////////////////////////////////////////////////////////////////
+INLINE float ChatInput::
+get_max_width() const {
+  nassertr(has_max_width(), 0.0);
+  return _max_width;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: ChatInput::get_string
 //     Function: ChatInput::get_string
 //       Access: Public
 //       Access: Public

+ 75 - 20
panda/src/chat/chatInput.cxx

@@ -26,12 +26,14 @@ TypeHandle ChatInput::_button_events_type;
 //       Access: Public
 //       Access: Public
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-ChatInput::ChatInput(TextNode* text_node,
-		     const string& name) : DataNode(name) {
+ChatInput::
+ChatInput(TextNode* text_node, const string& name) : DataNode(name) {
   assert(text_node != NULL);
   assert(text_node != NULL);
   _text_node = text_node;
   _text_node = text_node;
   _max_chars = 0;
   _max_chars = 0;
-  _has_max_chars = false;
+  _max_lines = 0;
+  _max_width = 0.0;
+  _flags = 0;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -51,9 +53,8 @@ reset() {
 //       Access: Public
 //       Access: Public
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void ChatInput::transmit_data(NodeAttributes &data) {
-  bool changed = false;
-  
+void ChatInput::
+transmit_data(NodeAttributes &data) {
   // Look for keyboard events.
   // Look for keyboard events.
   const ButtonEventDataAttribute *b;
   const ButtonEventDataAttribute *b;
   if (get_attribute_into(b, data, _button_events_type)) {
   if (get_attribute_into(b, data, _button_events_type)) {
@@ -66,28 +67,23 @@ void ChatInput::transmit_data(NodeAttributes &data) {
 	  throw_event("chat_exit");
 	  throw_event("chat_exit");
 	  
 	  
 	} else if (be._button == KeyboardButton::backspace()) {
 	} else if (be._button == KeyboardButton::backspace()) {
-	  _str = _str.substr(0, _str.length()-1);
-	  changed = true;
+	  if (!_str.empty()) {
+	    _str = _str.substr(0, _str.length()-1);
+	    _text_node->set_text(_str);
+	  }
 	  
 	  
 	} else if (be._button.has_ascii_equivalent()) {
 	} else if (be._button.has_ascii_equivalent()) {
 	  char ch = be._button.get_ascii_equivalent();
 	  char ch = be._button.get_ascii_equivalent();
 	  
 	  
 	  if (isprint(ch)) {
 	  if (isprint(ch)) {
-	    if (has_max_chars() && (int)_str.size() >= get_max_chars()) {
+	    if (!append_character(ch)) {
 	      throw_event("chat_overflow");
 	      throw_event("chat_overflow");
-	    } else {
-	      _str += ch;
-	      changed = true;
 	    }
 	    }
 	  }
 	  }
 	}
 	}
       }
       }
     }
     }
   }
   }
-  
-  if (changed) {
-    _text_node->set_text(_str);
-  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -95,7 +91,8 @@ void ChatInput::transmit_data(NodeAttributes &data) {
 //       Access:
 //       Access:
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void ChatInput::init_type(void) {
+void ChatInput::
+init_type(void) {
   DataNode::init_type();
   DataNode::init_type();
   register_type(_type_handle, "ChatInput",
   register_type(_type_handle, "ChatInput",
 		DataNode::get_class_type());
 		DataNode::get_class_type());
@@ -107,10 +104,68 @@ void ChatInput::init_type(void) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: append 
 //     Function: append 
-//       Access:
-//  Description:
+//       Access: Public
+//  Description: Appends the indicated string to the end of the
+//               currently typed string, as if it were typed by the
+//               user.  No bounds checking is performed.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void ChatInput::append(const string &str) {
+void ChatInput::
+append(const string &str) {
   _str += str;
   _str += str;
   _text_node->set_text(_str);
   _text_node->set_text(_str);
 }
 }
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: append_character
+//       Access: Public
+//  Description: Adds the indicated character to the end of the
+//               string, as if it were typed.  Bounds checking is
+//               performed; the character must fit within the limits
+//               set by set_max_chars(), set_max_width(), and
+//               set_max_lines().  Returns true if the character fit
+//               (and was appended correctly), or false if it did not
+//               fit (in which case nothing is changed).
+////////////////////////////////////////////////////////////////////
+bool ChatInput::
+append_character(char ch) {
+  if (has_max_chars() && (int)_str.size() >= get_max_chars()) {
+    // This is an easy test.
+    return false;
+  }
+
+  string text = _str + ch;
+  if (_text_node->has_wordwrap()) {
+    text = 
+      _text_node->wordwrap_to(text, _text_node->get_wordwrap());
+  }
+
+  if (has_max_width()) {
+    nassertr(!_text_node->has_wordwrap(), false);
+
+    float width = _text_node->calc_width(text);
+    if (width > get_max_width()) {
+      return false;
+    }
+  }
+
+  if (has_max_lines()) {
+    // Count up the number of lines in the text.  This is one more
+    // than the number of newline characters.
+    int num_lines = 1;
+    string::const_iterator pi;
+    for (pi = text.begin(); pi != text.end(); ++pi) {
+      if (*pi == '\n') {
+	++num_lines;
+      }
+    }
+
+    if (num_lines > get_max_lines()) {
+      return false;
+    }
+  }
+
+  _str += ch;
+  _text_node->set_text(_str);
+  return true;
+}

+ 23 - 4
panda/src/chat/chatInput.h

@@ -34,6 +34,16 @@ PUBLISHED:
   INLINE bool has_max_chars() const;
   INLINE bool has_max_chars() const;
   INLINE int get_max_chars() const;
   INLINE int get_max_chars() const;
 
 
+  INLINE void set_max_lines(int max_lines);
+  INLINE void clear_max_lines();
+  INLINE bool has_max_lines() const;
+  INLINE int get_max_lines() const;
+
+  INLINE void set_max_width(float max_width);
+  INLINE void clear_max_width();
+  INLINE bool has_max_width() const;
+  INLINE float get_max_width() const;
+
   INLINE const string &get_string() const;
   INLINE const string &get_string() const;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -44,6 +54,7 @@ public:
   transmit_data(NodeAttributes &data);
   transmit_data(NodeAttributes &data);
 
 
   void append(const string &str);
   void append(const string &str);
+  bool append_character(char ch);
 
 
   NodeAttributes _attrib;
   NodeAttributes _attrib;
 
 
@@ -51,10 +62,18 @@ public:
   static TypeHandle _button_events_type;
   static TypeHandle _button_events_type;
 
 
 protected:
 protected:
-  PT(TextNode)			_text_node;
-  string			_str;
-  int                           _max_chars;
-  bool                          _has_max_chars;
+  PT(TextNode) _text_node;
+  string _str;
+  int _max_chars;
+  int _max_lines;
+  float _max_width;
+
+  enum Flags {
+    F_max_chars   = 0x001,
+    F_max_lines   = 0x002,
+    F_max_width   = 0x004,
+  };
+  int _flags;
 	
 	
 public:
 public:
   virtual TypeHandle get_type() const {
   virtual TypeHandle get_type() const {

+ 3 - 3
panda/src/text/textNode.cxx

@@ -172,7 +172,7 @@ wordwrap_to(const string &text, float wordwrap_width) const {
     float width = 0.0;
     float width = 0.0;
     while (q < text.length() && text[q] != '\n' && width <= wordwrap_width) {
     while (q < text.length() && text[q] != '\n' && width <= wordwrap_width) {
       if (isspace(text[q])) {
       if (isspace(text[q])) {
-  any_spaces = true;
+	any_spaces = true;
       }
       }
 
 
       width += calc_width(text[q]);
       width += calc_width(text[q]);
@@ -184,7 +184,7 @@ wordwrap_to(const string &text, float wordwrap_width) const {
       // back up to the end of the last complete word.
       // back up to the end of the last complete word.
 
 
       while (q > p && !isspace(text[q])) {
       while (q > p && !isspace(text[q])) {
-  q--;
+	q--;
       }
       }
     }
     }
 
 
@@ -205,7 +205,7 @@ wordwrap_to(const string &text, float wordwrap_width) const {
       q++;
       q++;
       next_start++;
       next_start++;
       while (next_start < text.length() && isblank(text[next_start])) {
       while (next_start < text.length() && isblank(text[next_start])) {
-  next_start++;
+	next_start++;
       }
       }
     }
     }