Skip to main content
GameDev.net gamedev.net
🔒 Locked

Keyboard for GUI: Problem

Started by HellRiZZer Dec 19, 2004 at 4:52 AM 5 replies 850+ views
Original Post
HellRiZZer
HellRiZZer
Hello everybody, long time for me not posting, but here I'm back looking for your help :)) I've a problem with my TextBox in the OpenGL GUI (http://openglgui.sourceforge.net) with user typing whatever he wants in it. The Win32 API is a bit messy and it confuses "." with VK_DELETE (same codes) and there's also a few minor problems similar to the one above. Basically, I'm looking for some way to correct/go around that problem so that users can type whatever they want in the textbox, but I'm stuck with the thing mentioned above. Please help me so I can finish the GUI, and release it ASAP. Thank you.
Koshmaar
Koshmaar
OK... you asked for it! ;-)

// interface#include "tControl.h"#include "xmlFunctions.h"#include "..\..\Layer3\Timer\timerUtility.h"#include "..\..\Layer1\MathLib\types.h"#include <string>// -------------------------------------------------/* If editType == et_Numeric then:          minValue: minimum value user can type in     maxValue: maximum value user can type in      If user types number which is:          bigger then maxValue: it will be clamped to maxValue      smaller then maxValue: it will be clamped to maxValue      Additionaly:          if user types no number at all, defaultText will be assigned     typing more characters than possible maxValue has characters is not allowed  -------------------------------------------------   If editType == et_Mixed then:          minValue: minimum number of characters user can type in     maxValue: maximum number of characters user can type in      If user types count of characters which is:          bigger then maxValue: it's not possible, each letter which exceeds limit will be ignored     smaller then maxValue: it will be set to defaultText           *//* TODO (Koshmaar#1#): add negative values to et_Float and better handling                        of checking bounds */namespace SC {       enum eEditType   {    et_Integer,    et_Float, //!< currently negative values are not supported for this and generally it has little support    et_Mixed   }; // ------------------------------------------------- class TEdit : public TControl {    public:     TEdit() { }   ~TEdit();      const char * GetTypeName() const { return "Edit"; }      bool Create(const TiXmlElement * _xmlStream);      bool Keypressed(SDLKey _key);   void LeftMouseButtonPressed(const TScrPoint & _point);      eEditType GetType() const { return editType; }      //! If Edit's type is et_Integer then it converts its value to slint and puts it in @_integer and method   //! returns _ in normal string type   //! Else, if it's et_Mixed, then method return string and @_numeric == 0   const char * GetValue(slint & _integer, float & _float );   // -------------------------------------------------         //! edit can't have children   void LoadChildren(const TiXmlElement * _xmlStream) { }   TControl* FindChildAt(const TScrPoint & _position) { return 0; }   TControl* FindChild(const char * _childName) { return 0; }   void AddChild(TControl*) { }    // -------------------------------------------------   private:     void UpdateSelf() { }   void RenderSelf();   // -------------------------------------------------      void RebuildTextObj();   void ClampNumericText();   TextObjHandle renderedText;   TScrPoint textPosition;   TFontTag font;   TextureHandle left, middle, right;      std :: string typedText, oldTypedText, defaultText;   eEditType editType;   slint maxValue, minValue;      TimeMarker lastType;      bool acceptInput;         };   }



// implementation#include <string>#include <cctype>#include "tEdit.h"#include "xmlFunctions.h"#include "..\Logger\logger.h"#include "..\Misc\misc.h"#include "..\..\Layer1\Renderer\renderer.h"#include "..\..\Layer2\FontMgr\fontMgr.h"#include "..\..\Layer3\Input\inputUtility.h"#include "..\..\Layer1\MathLib\miscFunctions.h"#include "..\..\Layer1\MemoryMgr\mmgr.h"using namespace std;// ------------------------------------------------- SC :: TEdit :: ~TEdit() {  if (renderedText.id != 0) getRenderer.FreeTextObj(renderedText);   } // ------------------------------------------------- // ------------------------------------------------- start Createbool SC :: TEdit :: Create(const TiXmlElement * _xmlStream) {  if (!TControl::Create(_xmlStream)) return false;     size.x = GetTagValueSlint(_xmlStream, "Width");  if (size.x == 0) return false;        if (!ParseFontTag(_xmlStream, font)) return false;  // -------------------------------------------------      const char * typeTag = GetTagValueTxt(_xmlStream, "Type");    if (!typeTag) return false;    if (!strcmp(typeTag, "Integer")) editType = et_Integer;   else if (!strcmp(typeTag, "Float")) editType = et_Float;      else editType = et_Mixed;     const char * defaultTag = GetTagValueTxt(_xmlStream, "Default");    if (defaultTag) typedText = oldTypedText = defaultText = defaultTag;    maxValue = GetTagValueSlint(_xmlStream, "MaxValue");    minValue = GetTagValueSlint(_xmlStream, "MinValue");    if (maxValue <= minValue)   {    logError2("GUI", "MaxValue <= MinValue for one of the edit's")    maxValue = minValue + 1;          }    ClampNumericText();  // ------------------------------------------------- graphics  TiXmlElement * xmlAppearanceTag = _xmlStream->FirstChildElement("Appearance");  if (xmlAppearanceTag)   {    const char * textureName[3];    string textureList;        textureName[0] = GetTagValueTxt(xmlAppearanceTag, "Left");    textureName[1] = GetTagValueTxt(xmlAppearanceTag, "Middle");    textureName[2] = GetTagValueTxt(xmlAppearanceTag, "Right");        for (usint i = 0; i < 3; ++i)     if (textureName)      {       textureList += textureName;       textureList += " ";      }                   if (textureList.empty())     {      string tmp("Couldn't find any textures in edit definition for: ");      tmp += name;      logError2("GUI", tmp.c_str())         return false;     }              //printTxt(textureList.c_str())        ssint failures = getTextureMgr.LoadTextures("Edits", textureList.c_str());    //printVal(failures)        if (textureName[0]) getTextureMgr.GetTextureID(left, "Edits", textureName[0]);    if (textureName[1]) getTextureMgr.GetTextureID(middle, "Edits", textureName[1]);    if (textureName[2]) getTextureMgr.GetTextureID(right, "Edits", textureName[2]);                    if (failures)     {      string tmp("Couldn't load textures in edit definition for: ");      tmp += name;      tmp += ", not-loaded texture count: ";      const char * number = ssintToString(failures);      tmp += number;      logError2("GUI", tmp.c_str())      delete [] number;      return false;     }             size.y = left.height;        }    else   {    string tmp("Couldn't find 'Appearance' tag inside edit definition of: ");    tmp += name;    logError2("GUI", tmp.c_str())    return false;   }// ------------------------------------------------- font          FontSizeList fontSizes;      fontSizes.push_back(font.size);      getFontMgr.LoadFont(font.name.c_str(), fontSizes);  renderedText.id = 0;  acceptInput = false;    RebuildTextObj();      return true;     }    // ------------------------------------------------- end Create// ------------------------------------------------- start RenderSelfvoid SC :: TEdit :: RenderSelf() {  if (visible)   {    TScrPoint tmp;    GetAbsPosition(tmp);        // left        getRenderer.UseTexture(left);    getRenderer.RenderTexture(tmp, left.width, left.height, zPosition, TScrPnt(0,0), left.width, left.height);        getRenderer.UseTexture(middle);    // here textPosition is used as tmp    TScrPntSet(textPosition, tmp.x + left.width, tmp.y);        // middle    getRenderer.RenderTexture(textPosition, size.x - right.width - left.width, left.height, zPosition, TScrPnt(0,0), size.x - right.width - left.width, left.height);        // right    getRenderer.UseTexture(right);        TScrPntSet(textPosition, tmp.x + size.x - right.width, tmp.y);    getRenderer.RenderTexture(textPosition, right.width, left.height, zPosition, TScrPnt(0,0), right.width, left.height);        if (typedText.size())     {      usint verticalCenter = (tmp.y) + (size.y)/2 - (renderedText.height)/2;               if (renderedText.width < (size.x - left.width - right.width ))       {        TScrPntSet(textPosition, tmp.x + left.width, verticalCenter);        getRenderer.RenderText(renderedText, textPosition, font.justify);       }          else       {                        TScrPntSet(textPosition, tmp.x + left.width, tmp.y);        TScrPoint endOfEdit;        TScrPntAdd(endOfEdit, textPosition, size );        getRenderer.SetWindowClipRegion(textPosition, endOfEdit);        /*  getRenderer.UseBlankTexture();  getRenderer.SetColor(255, 0, 0, 100);  getRenderer.RenderRectangleFilled(textPosition,size);  getRenderer.SetColor(255, 255, 255, 255);*/                TScrPntSet(textPosition, size.x - left.width - renderedText.width, verticalCenter);        TScrPntAddX(textPosition, tmp, textPosition);                getRenderer.RenderText(renderedText, textPosition, font.justify);                       getRenderer.UnsetWindowClipRegion();       }         }   }   } // ------------------------------------------------- end RenderSelf// ------------------------------------------------- start GetValueconst char * SC :: TEdit :: GetValue(slint & _integer, float & _float) {  if (editType == et_Integer)   {    _integer = stringToSlint(typedText.c_str());    _float = 0;   }    else if (editType == et_Float)   {    _integer = 0;       _float = stringToFloat(typedText.c_str());   }           else if (editType == et_Mixed)   {    _integer = 0;    _float = 0;       }     return typedText.c_str();           } // ------------------------------------------------- end GetValueSC :: usint SlintWide(SC :: slint _value) {  SC :: usint wide;  SC :: slint value = SC :: Abs(_value);    if (value < 10) wide = 1;   else if (value >= 10 && value < 100) wide = 2;    else if (value >= 100 && value < 1000) wide = 3;     else if (value >= 1000 && value < 10000) wide = 4;      else if (value >= 10000 && value < 100000) wide = 5;       else if (value >= 100000 && value < 1000000) wide = 6;        else if (value >= 1000000 && value < 10000000) wide = 7;         else { SC_ASSERT(!"So high numbers can't be used") }                            return wide;} // ------------------------------------------------- start ClampNumericTextvoid SC :: TEdit :: ClampNumericText() {  if (editType == et_Integer)   {    const char * tmp;        // minus alone desribes no number and -0 isn't vaild number, set to default to prevent weird errors    if (!strcmp(typedText.c_str(), "-") || (!strcmp(typedText.c_str(), "-0")))     {      typedText = defaultText;      return;     }                       slint value(stringToSlint(typedText.c_str()));           if ( value < minValue)      {      tmp = slintToString(minValue);      if (tmp) typedText = tmp;      delete [] tmp;     }         if (value > maxValue)     {      tmp = slintToString(maxValue);      if (tmp) typedText = tmp;      delete [] tmp;     }   }     if (editType == et_Float)   {               if (( typedText.size() < minValue) || (typedText.size() > maxValue))     {      typedText = defaultText;     }        if (typedText.size() && (typedText[typedText.size()-1] == '.'))    {     typedText = defaultText;    }        }     } // ------------------------------------------------- end ClampNumericText// ------------------------------------------------- start RebuildTextObjvoid SC :: TEdit :: RebuildTextObj() {  if (renderedText.id != 0)   getRenderer.FreeTextObj(renderedText);  if (typedText.size() > 0)    getRenderer.CreateTextObject(renderedText, typedText.c_str(), font.name.c_str(), font.size, font.colorR, font.colorG,                                font.colorB, font.style, font.renderMode); } // ------------------------------------------------- end RebuildTextObj// ------------------------------------------------- start LeftMouseButtonPressedvoid SC :: TEdit :: LeftMouseButtonPressed(const TScrPoint & _point) {  if (acceptInput)   {    // when end typing     acceptInput = false;        getInput.UnfreezeMouseCursor();    getInput.SetMouseCursorState(true);    oldTypedText = typedText;        if ((editType == et_Mixed) && (typedText.size() < minValue))     {      typedText = defaultText;     }        if ((editType != et_Mixed) && (!typedText.size()))     {      typedText = defaultText;     }         ClampNumericText();         RebuildTextObj();        if (userHandlers)     userHandlers->LeftMouseButtonPressed(_point);   }    else   {    // on start typing    acceptInput = true;    getInput.FreezeMouseCursor();        getInput.SetMouseCursorState(false);   }     }    // ------------------------------------------------- end LeftMouseButtonPressed// ------------------------------------------------- start Keypressedbool SC :: TEdit :: Keypressed(SDLKey _key) {         // first you must click on edit to type anything  if (!acceptInput) return true;    if (userHandlers)   {     if (!userHandlers->Keypressed(_key))     return true;   }      lastType.Mark();        switch (_key)   {           case SDLK_ESCAPE:     typedText = oldTypedText;     LeftMouseButtonPressed(TScrPnt(0,0));     return true;                         break;              case SDLK_RETURN:     LeftMouseButtonPressed(TScrPnt(0,0));     return true;                              break;        case SDLK_BACKSPACE:             if (!typedText.size()) return true;     typedText.erase(typedText.size()-1, 1);                    RebuildTextObj();     return true;         break;        case SDLK_MINUS:         if ((editType != et_Mixed) && (typedText.size() == 0) && ( minValue < 0 ))      {       typedText += '-';       RebuildTextObj();       return true; // must give chance for shift matching      }              break;        // used by et_Integer    case SDLK_UP:    {         slint convertedText = stringToSlint(typedText.c_str());          if ((editType == et_Integer) && (typedText.size() > 0) && (convertedText < maxValue))      {              ++convertedText;       const char * tmpText = slintToString(convertedText);       if (tmpText) { typedText = tmpText; RebuildTextObj(); }       delete [] tmpText;      }     }          return true;                 break;        // used by et_Integer    case SDLK_DOWN:    {         slint convertedText = stringToSlint(typedText.c_str());          if ((editType == et_Integer) && (typedText.size() > 0) && (convertedText > minValue))      {              --convertedText;       const char * tmpText = slintToString(convertedText);       if (tmpText) { typedText = tmpText; RebuildTextObj(); }       delete [] tmpText;      }     }          return true;                 break;          case SDLK_PERIOD: // used for et_Float             if ((editType == et_Float) && (typedText.size() != 0) && (typedText.find(".") == string :: npos) )      {       typedText += '.';       RebuildTextObj();       return true; // must give chance for shift matching      }              break;          };               if (editType == et_Integer)    {          slint convertedText;     usint textWide;     usint maxValueWide;                      // this prevents from excesing maximum available characters count, also for negative numbers     if (typedText.size() && typedText[0] != '-')      {       convertedText = stringToSlint(typedText.c_str());       textWide = SlintWide(convertedText);       maxValueWide = SlintWide( ( (convertedText >= 0) ? maxValue : minValue ));      }       else      {       textWide = 1;       maxValueWide = 2;      }                         // prevents from writing 07     if ((typedText.size() == 1) && (typedText[0] == '0')) return true;          // prevents from writing 00001 etc.     if (((typedText[0] == '0') || (typedText[0] == '-')) && (_key == SDLK_0) && (typedText.size() == 1)) return true;                 if ((_key >= SDLK_0) && (_key <= SDLK_9) && (textWide < maxValueWide))      {              typedText += _key;       RebuildTextObj();      }    }        else if (editType == et_Float)    {     // prevents from writing 00001 etc.     if ( ((typedText[0] == '0') || (typedText[0] == '-')) && (_key == SDLK_0) && (typedText.size() == 1) ) return true;               if ((_key >= SDLK_0) && (_key <= SDLK_9) && (typedText.size() < maxValue))      {       typedText += _key;       RebuildTextObj();      }    }        else     {                if ((_key > 31) && (_key < 128) && (typedText.size() < maxValue ))      {              typedText += _key;       RebuildTextObj();      }     }            return true; }    // ------------------------------------------------- end Keypressed



This started being much better designed, sadly as time passed on, deadlines approached and new things were added, it turned into this... mess :-/ Integer and Mixed modes are working well, but Float is not finished and I don't have time for it now. If you have any questions why foo was done like it was done, just ask. Also, I would be gratefull if anyone points out any ways to improve this code (ie. that SlintWide thing annoys me to no end).
foofightr
foofightr
Re: SlintWide

char buf[32];sprintf(buf, "%d", _value);return strlen(buf);


And there's probably a much better way than this. It's just off the top of my head. Logarithms sound like a better way actually.
Zahlman
Zahlman
Quote:
Original post by foofightr
Re: SlintWide

char buf[32];sprintf(buf, "%d", _value);return strlen(buf);


And there's probably a much better way than this. It's just off the top of my head. Logarithms sound like a better way actually.


If you need to know how long a number is when written in text, chances are good that you're going to need that text representation anyway. Given the text representation, it's easy to re-find the length.

That said, why not actually use a real textual type?

// Also need to include <sstream>stringstream ss;ss << _value;return ss.str(); // And call .length() on the result if needed


(Edit: While checking on stringstream usage via Google, I encountered the following awful code fragment:

string Tiff_rgb_pixel::to_string( ) {  string pixel_str;  pixel_str.append( "(" );  // stringstream already able to do conversions easily  std::stringstream ss1;  ss1 << (int) red;  pixel_str.append( ss1.str( ) );  pixel_str.append( "," );  // need new ss since str() makes its array unusable  std::stringstream ss2;  ss2 << (int) green;  pixel_str.append( ss2.str( ) );  pixel_str.append( "," );  std::stringstream ss3;  ss3 << (int) blue;  pixel_str.append( ss3.str( ) );  pixel_str.append( ")" );  return( pixel_str );}


Which of course could be rewritten much more simply:

string Tiff_rgb_pixel::to_string() {  std::stringstream ss;  ss << "(" << (int) red << "," << (int) green << "," << (int) blue << ")";  return ss.str();}


Which goes to show that using proper tools does not insure you against missing the blindingly obvious. :s

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.