Sfoglia il codice sorgente

REVIEWED: GuiTextBoxMulti()

- REMOVED: framesCounter (static variable)
- REVIEWED: Cursors width
- Minor tweaks
Ray 4 anni fa
parent
commit
cf45f9bccf
1 ha cambiato i file con 127 aggiunte e 114 eliminazioni
  1. 127 114
      src/raygui.h

+ 127 - 114
src/raygui.h

@@ -220,8 +220,14 @@
         int format;             // Data format (PixelFormat type)
         int format;             // Data format (PixelFormat type)
     } Texture2D;
     } Texture2D;
 
 
-    // Font character info
-    typedef struct GlyphInfo GlyphInfo;
+    // GlyphInfo, font characters glyphs info
+    typedef struct GlyphInfo {
+        int value;              // Character value (Unicode)
+        int offsetX;            // Character offset X when drawing
+        int offsetY;            // Character offset Y when drawing
+        int advanceX;           // Character advance position X
+        Image image;            // Character image data
+    } GlyphInfo;
 
 
     // TODO: Font type is very coupled to raylib, mostly required by GuiLoadStyle()
     // TODO: Font type is very coupled to raylib, mostly required by GuiLoadStyle()
     // It should be redesigned to be provided by user
     // It should be redesigned to be provided by user
@@ -406,7 +412,7 @@ typedef enum {
 extern "C" {            // Prevents name mangling of functions
 extern "C" {            // Prevents name mangling of functions
 #endif
 #endif
 
 
-// State modification functions
+// Global gui state control functions
 RAYGUIDEF void GuiEnable(void);                                         // Enable gui controls (global state)
 RAYGUIDEF void GuiEnable(void);                                         // Enable gui controls (global state)
 RAYGUIDEF void GuiDisable(void);                                        // Disable gui controls (global state)
 RAYGUIDEF void GuiDisable(void);                                        // Disable gui controls (global state)
 RAYGUIDEF void GuiLock(void);                                           // Lock gui controls (global state)
 RAYGUIDEF void GuiLock(void);                                           // Lock gui controls (global state)
@@ -1067,7 +1073,7 @@ static unsigned int guiIcons[RICON_MAX_ICONS*RICON_DATA_ELEMENTS] = {
 #endif      // RAYGUI_SUPPORT_RICONS
 #endif      // RAYGUI_SUPPORT_RICONS
 
 
 #ifndef RICON_SIZE
 #ifndef RICON_SIZE
-    #define RICON_SIZE      0
+    #define RICON_SIZE                   0
 #endif
 #endif
 
 
 #define RAYGUI_MAX_CONTROLS             16      // Maximum number of standard controls
 #define RAYGUI_MAX_CONTROLS             16      // Maximum number of standard controls
@@ -1076,7 +1082,7 @@ static unsigned int guiIcons[RICON_MAX_ICONS*RICON_DATA_ELEMENTS] = {
 
 
 // TODO: Avoid animations and time-based states
 // TODO: Avoid animations and time-based states
 // Functions using it: GuiTextBox(), GuiValueBox(), GuiTextBoxMulti()
 // Functions using it: GuiTextBox(), GuiValueBox(), GuiTextBoxMulti()
-#define TEXTEDIT_CURSOR_BLINK_FRAMES    20      // Text edit controls cursor blink timming
+//#define TEXTEDIT_CURSOR_BLINK_FRAMES    20      // Text edit controls cursor blink timming
 
 
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 // Types and Structures Definition
@@ -1594,7 +1600,7 @@ bool GuiImageButtonEx(Rectangle bounds, const char *text, Texture2D texture, Rec
     //--------------------------------------------------------------------
     //--------------------------------------------------------------------
     GuiDrawRectangle(bounds, GuiGetStyle(BUTTON, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(BUTTON, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(BUTTON, BASE + (state*3))), guiAlpha));
     GuiDrawRectangle(bounds, GuiGetStyle(BUTTON, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(BUTTON, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(BUTTON, BASE + (state*3))), guiAlpha));
 
 
-    if (text != NULL) GuiDrawText(text, GetTextBounds(BUTTON, bounds), GuiGetStyle(BUTTON, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(BUTTON, TEXT + (state*3))), guiAlpha));
+    GuiDrawText(text, GetTextBounds(BUTTON, bounds), GuiGetStyle(BUTTON, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(BUTTON, TEXT + (state*3))), guiAlpha));
     if (texture.id > 0) DrawTextureRec(texture, texSource, RAYGUI_CLITERAL(Vector2){ bounds.x + bounds.width/2 - texSource.width/2, bounds.y + bounds.height/2 - texSource.height/2 }, Fade(GetColor(GuiGetStyle(BUTTON, TEXT + (state*3))), guiAlpha));
     if (texture.id > 0) DrawTextureRec(texture, texSource, RAYGUI_CLITERAL(Vector2){ bounds.x + bounds.width/2 - texSource.width/2, bounds.y + bounds.height/2 - texSource.height/2 }, Fade(GetColor(GuiGetStyle(BUTTON, TEXT + (state*3))), guiAlpha));
     //------------------------------------------------------------------
     //------------------------------------------------------------------
 
 
@@ -1730,7 +1736,7 @@ bool GuiCheckBox(Rectangle bounds, const char *text, bool checked)
         GuiDrawRectangle(check, 0, BLANK, Fade(GetColor(GuiGetStyle(CHECKBOX, TEXT + state*3)), guiAlpha));
         GuiDrawRectangle(check, 0, BLANK, Fade(GetColor(GuiGetStyle(CHECKBOX, TEXT + state*3)), guiAlpha));
     }
     }
 
 
-    if (text != NULL) GuiDrawText(text, textBounds, (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_RIGHT)? GUI_TEXT_ALIGN_LEFT : GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha));
+    GuiDrawText(text, textBounds, (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_RIGHT)? GUI_TEXT_ALIGN_LEFT : GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha));
     //--------------------------------------------------------------------
     //--------------------------------------------------------------------
 
 
     return checked;
     return checked;
@@ -1913,19 +1919,16 @@ bool GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMo
 }
 }
 
 
 // Text Box control, updates input text
 // Text Box control, updates input text
-// NOTE 1: Requires static variables: framesCounter
 // NOTE 2: Returns if KEY_ENTER pressed (useful for data validation)
 // NOTE 2: Returns if KEY_ENTER pressed (useful for data validation)
 bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
 bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
 {
 {
-    static int framesCounter = 0;       // Blinking cursor counter
-
     GuiControlState state = guiState;
     GuiControlState state = guiState;
     bool pressed = false;
     bool pressed = false;
 
 
     Rectangle cursor = {
     Rectangle cursor = {
         bounds.x + GuiGetStyle(TEXTBOX, TEXT_PADDING) + GetTextWidth(text) + 2,
         bounds.x + GuiGetStyle(TEXTBOX, TEXT_PADDING) + GetTextWidth(text) + 2,
         bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE),
         bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE),
-        1,
+        4,
         (float)GuiGetStyle(DEFAULT, TEXT_SIZE)*2
         (float)GuiGetStyle(DEFAULT, TEXT_SIZE)*2
     };
     };
 
 
@@ -1938,8 +1941,7 @@ bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
         if (editMode)
         if (editMode)
         {
         {
             state = GUI_STATE_PRESSED;
             state = GUI_STATE_PRESSED;
-            framesCounter++;
-
+            
             int key = GetCharPressed();      // Returns codepoint as Unicode
             int key = GetCharPressed();      // Returns codepoint as Unicode
             int keyCount = (int)strlen(text);
             int keyCount = (int)strlen(text);
 
 
@@ -1970,13 +1972,6 @@ bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
                 {
                 {
                     keyCount--;
                     keyCount--;
                     text[keyCount] = '\0';
                     text[keyCount] = '\0';
-                    framesCounter = 0;
-                    if (keyCount < 0) keyCount = 0;
-                }
-                else if (IsKeyDown(KEY_BACKSPACE))
-                {
-                    if ((framesCounter > TEXTEDIT_CURSOR_BLINK_FRAMES) && (framesCounter%2) == 0) keyCount--;
-                    text[keyCount] = '\0';
                     if (keyCount < 0) keyCount = 0;
                     if (keyCount < 0) keyCount = 0;
                 }
                 }
             }
             }
@@ -1996,8 +1991,6 @@ bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
                 if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
                 if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
             }
             }
         }
         }
-
-        if (pressed) framesCounter = 0;
     }
     }
     //--------------------------------------------------------------------
     //--------------------------------------------------------------------
 
 
@@ -2006,9 +1999,6 @@ bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
     if (state == GUI_STATE_PRESSED)
     if (state == GUI_STATE_PRESSED)
     {
     {
         GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED)), guiAlpha));
         GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED)), guiAlpha));
-
-        // Draw blinking cursor
-        if (editMode && ((framesCounter/20)%2 == 0)) GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)), guiAlpha));
     }
     }
     else if (state == GUI_STATE_DISABLED)
     else if (state == GUI_STATE_DISABLED)
     {
     {
@@ -2017,6 +2007,9 @@ bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
     else GuiDrawRectangle(bounds, 1, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), BLANK);
     else GuiDrawRectangle(bounds, 1, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), BLANK);
 
 
     GuiDrawText(text, GetTextBounds(TEXTBOX, bounds), GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha));
     GuiDrawText(text, GetTextBounds(TEXTBOX, bounds), GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha));
+    
+    // Draw cursor
+    if (editMode) GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)), guiAlpha));
     //--------------------------------------------------------------------
     //--------------------------------------------------------------------
 
 
     return pressed;
     return pressed;
@@ -2090,7 +2083,7 @@ bool GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, in
     GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
     GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
 
 
     // Draw text label if provided
     // Draw text label if provided
-    if (text != NULL) GuiDrawText(text, textBounds, (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_RIGHT)? GUI_TEXT_ALIGN_LEFT : GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha));
+    GuiDrawText(text, textBounds, (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_RIGHT)? GUI_TEXT_ALIGN_LEFT : GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha));
     //--------------------------------------------------------------------
     //--------------------------------------------------------------------
 
 
     *value = tempValue;
     *value = tempValue;
@@ -2105,8 +2098,6 @@ bool GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, i
         #define VALUEBOX_MAX_CHARS  32
         #define VALUEBOX_MAX_CHARS  32
     #endif
     #endif
 
 
-    static int framesCounter = 0;           // Blinking cursor counter
-
     GuiControlState state = guiState;
     GuiControlState state = guiState;
     bool pressed = false;
     bool pressed = false;
 
 
@@ -2135,8 +2126,6 @@ bool GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, i
         {
         {
             state = GUI_STATE_PRESSED;
             state = GUI_STATE_PRESSED;
 
 
-            framesCounter++;
-
             int keyCount = (int)strlen(textValue);
             int keyCount = (int)strlen(textValue);
 
 
             // Only allow keys in range [48..57]
             // Only allow keys in range [48..57]
@@ -2161,14 +2150,6 @@ bool GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, i
                 {
                 {
                     keyCount--;
                     keyCount--;
                     textValue[keyCount] = '\0';
                     textValue[keyCount] = '\0';
-                    framesCounter = 0;
-                    if (keyCount < 0) keyCount = 0;
-                    valueHasChanged = true;
-                }
-                else if (IsKeyDown(KEY_BACKSPACE))
-                {
-                    if ((framesCounter > TEXTEDIT_CURSOR_BLINK_FRAMES) && (framesCounter%2) == 0) keyCount--;
-                    textValue[keyCount] = '\0';
                     if (keyCount < 0) keyCount = 0;
                     if (keyCount < 0) keyCount = 0;
                     valueHasChanged = true;
                     valueHasChanged = true;
                 }
                 }
@@ -2189,8 +2170,6 @@ bool GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, i
                 if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
                 if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
             }
             }
         }
         }
-
-        if (pressed) framesCounter = 0;
     }
     }
     //--------------------------------------------------------------------
     //--------------------------------------------------------------------
 
 
@@ -2204,16 +2183,16 @@ bool GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, i
     GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), guiAlpha), baseColor);
     GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), guiAlpha), baseColor);
     GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), GUI_TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3))), guiAlpha));
     GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), GUI_TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3))), guiAlpha));
 
 
-    // Draw blinking cursor
-    if ((state == GUI_STATE_PRESSED) && (editMode && ((framesCounter/20)%2 == 0)))
+    // Draw cursor
+    if (editMode)
     {
     {
         // NOTE: ValueBox internal text is always centered
         // NOTE: ValueBox internal text is always centered
-        Rectangle cursor = { bounds.x + GetTextWidth(textValue)/2 + bounds.width/2 + 2, bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 1, bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH) };
+        Rectangle cursor = { bounds.x + GetTextWidth(textValue)/2 + bounds.width/2 + 2, bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4, bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH) };
         GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED)), guiAlpha));
         GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED)), guiAlpha));
     }
     }
 
 
     // Draw text label if provided
     // Draw text label if provided
-    if (text != NULL) GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_RIGHT)? GUI_TEXT_ALIGN_LEFT : GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha));
+    GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_RIGHT)? GUI_TEXT_ALIGN_LEFT : GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha));
     //--------------------------------------------------------------------
     //--------------------------------------------------------------------
 
 
     return pressed;
     return pressed;
@@ -2222,8 +2201,6 @@ bool GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, i
 // Text Box control with multiple lines
 // Text Box control with multiple lines
 bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode)
 bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode)
 {
 {
-    static int framesCounter = 0;           // Blinking cursor counter
-
     GuiControlState state = guiState;
     GuiControlState state = guiState;
     bool pressed = false;
     bool pressed = false;
 
 
@@ -2235,10 +2212,9 @@ bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode)
     };
     };
 
 
     // Cursor position, [x, y] values should be updated
     // Cursor position, [x, y] values should be updated
-    Rectangle cursor = { 0, 0, 1, (float)GuiGetStyle(DEFAULT, TEXT_SIZE) + 2 };
-
-    int textWidth = 0;
-    int currentLine = 0;
+    Rectangle cursor = { 0, -1, 4, (float)GuiGetStyle(DEFAULT, TEXT_SIZE) + 2 };
+    
+    float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/(float)guiFont.baseSize;     // Character rectangle scaling factor
 
 
     // Update control
     // Update control
     //--------------------------------------------------------------------
     //--------------------------------------------------------------------
@@ -2249,77 +2225,52 @@ bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode)
         if (editMode)
         if (editMode)
         {
         {
             state = GUI_STATE_PRESSED;
             state = GUI_STATE_PRESSED;
-            framesCounter++;
 
 
-            int character = GetCharPressed();
-            int keyCount = (int)strlen(text);
+            // We get an Unicode codepoint
+            int codepoint = GetCharPressed();      
+            int textLength = (int)strlen(text);     // Length in bytes (UTF-8 string)
 
 
             // Introduce characters
             // Introduce characters
-            if (keyCount < (textSize - 1))
+            if (textLength < (textSize - 1))
             {
             {
-                Vector2 textSize = MeasureTextEx(guiFont, text, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
-
-                if (textSize.y < (textAreaBounds.height - GuiGetStyle(DEFAULT, TEXT_SIZE)))
+                if (IsKeyPressed(KEY_ENTER))
                 {
                 {
-                    if (IsKeyPressed(KEY_ENTER))
-                    {
-                        text[keyCount] = '\n';
-                        keyCount++;
-                    }
-                    else if (((character >= 32) && (character < 255)))  // TODO: Support Unicode inputs
-                    {
-                        text[keyCount] = (char)character;
-                        keyCount++;
-                    }
+                    text[textLength] = '\n';
+                    textLength++;
                 }
                 }
-            }
-
-            // Delete characters
-            if (keyCount > 0)
-            {
-                if (IsKeyPressed(KEY_BACKSPACE))
+                else if (codepoint >= 32)
                 {
                 {
-                    keyCount--;
-                    text[keyCount] = '\0';
-                    framesCounter = 0;
-
-                    if (keyCount < 0) keyCount = 0;
-                }
-                else if (IsKeyDown(KEY_BACKSPACE))
-                {
-                    if ((framesCounter > TEXTEDIT_CURSOR_BLINK_FRAMES) && (framesCounter%2) == 0) keyCount--;
-                    text[keyCount] = '\0';
-
-                    if (keyCount < 0) keyCount = 0;
+                    // Supports Unicode inputs -> Encoded to UTF-8
+                    int charUTF8Length = 0;
+                    const char *charEncoded = CodepointToUTF8(codepoint, &charUTF8Length);
+                    memcpy(text + textLength, charEncoded, charUTF8Length);
+                    textLength += charUTF8Length;
                 }
                 }
             }
             }
 
 
-            // Calculate cursor position considering text
-            char oneCharText[2] = { 0 };
-            int lastBreakingPos = -1;
-
-            for (int i = 0; i < keyCount && currentLine < keyCount; i++)
+            // Delete characters
+            if (textLength > 0)
             {
             {
-                oneCharText[0] = text[i];
-                textWidth += (GetTextWidth(oneCharText) + GuiGetStyle(DEFAULT, TEXT_SPACING));
-
-                if (text[i] == ' ' || text[i] == '\n') lastBreakingPos = i;
-
-                if ( text[i] == '\n' || textWidth >= textAreaBounds.width)
+                if (IsKeyPressed(KEY_BACKSPACE))
                 {
                 {
-                    currentLine++;
-                    textWidth = 0;
-
-                    if (lastBreakingPos > 0) i = lastBreakingPos;
-                    else textWidth += (GetTextWidth(oneCharText) + GuiGetStyle(DEFAULT, TEXT_SPACING));
-
-                    lastBreakingPos = -1;
+                    if ((unsigned char)text[textLength - 1] < 127)
+                    {
+                        // Remove ASCII equivalent character (1 byte)
+                        textLength--;
+                        text[textLength] = '\0';
+                    }
+                    else
+                    {
+                        // Remove latest UTF-8 unicode character introduced (n bytes)
+                        int charUTF8Length = 0;
+                        while (((unsigned char)text[textLength - 1 - charUTF8Length] & 0b01000000) == 0) charUTF8Length++;
+                    
+                        textLength -= (charUTF8Length + 1);
+                        text[textLength] = '\0';
+                    }
                 }
                 }
             }
             }
 
 
-            cursor.x = bounds.x + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING) + textWidth - GuiGetStyle(DEFAULT, TEXT_SPACING);
-            cursor.y = bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING)/2 + ((GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING))*currentLine);
-
             // Exit edit mode
             // Exit edit mode
             if (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
             if (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
         }
         }
@@ -2331,8 +2282,6 @@ bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode)
                 if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
                 if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
             }
             }
         }
         }
-
-        if (pressed) framesCounter = 0;     // Reset blinking cursor
     }
     }
     //--------------------------------------------------------------------
     //--------------------------------------------------------------------
 
 
@@ -2341,9 +2290,6 @@ bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode)
     if (state == GUI_STATE_PRESSED)
     if (state == GUI_STATE_PRESSED)
     {
     {
         GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED)), guiAlpha));
         GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED)), guiAlpha));
-
-        // Draw blinking cursor
-        if (editMode && ((framesCounter/20)%2 == 0)) GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)), guiAlpha));
     }
     }
     else if (state == GUI_STATE_DISABLED)
     else if (state == GUI_STATE_DISABLED)
     {
     {
@@ -2351,9 +2297,76 @@ bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode)
     }
     }
     else GuiDrawRectangle(bounds, 1, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), BLANK);
     else GuiDrawRectangle(bounds, 1, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), BLANK);
 
 
-    // TODO: Review to support boxed text with word-wrap
-    //DrawTextBoxed(guiFont, text, textAreaBounds, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING), true, Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha));
-    DrawTextEx(guiFont, text, (Vector2){ textAreaBounds.x, textAreaBounds.y }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING), Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha));
+    int wrapMode = 1;      // 0-No wrap, 1-Char wrap, 2-Word wrap
+    Vector2 cursorPos = { textAreaBounds.x, textAreaBounds.y };
+
+    //int lastSpacePos = 0;
+    //int lastSpaceWidth = 0;
+    //int lastSpaceCursorPos = 0;
+    
+    for (int i = 0, codepointLength = 0; text[i] != '\0'; i += codepointLength)
+    {
+        int codepoint = GetCodepoint(text + i, &codepointLength);
+        int index = GetGlyphIndex(guiFont, codepoint);      // If requested codepoint is not found, we get '?' (0x3f) -> TODO: review that case!
+        Rectangle atlasRec = guiFont.recs[index];
+        GlyphInfo glyphInfo = guiFont.chars[index];         // Glyph measures
+        
+        if ((codepointLength == 1) && (codepoint == '\n')) 
+        {
+            cursorPos.y += (guiFont.baseSize*scaleFactor + GuiGetStyle(TEXTBOX, TEXT_LINES_PADDING));           // Line feed
+            cursorPos.x = textAreaBounds.x;             // Carriage return
+        }
+        else
+        {
+            if (wrapMode == 1)
+            {
+                int glyphWidth = 0;
+                if (glyphInfo.advanceX != 0) glyphWidth += glyphInfo.advanceX;
+                else glyphWidth += (atlasRec.width + glyphInfo.offsetX);
+            
+                // Jump line if the end of the text box area has been reached
+                if ((cursorPos.x + (glyphWidth*scaleFactor)) > (textAreaBounds.x + textAreaBounds.width))
+                {
+                    cursorPos.y += (guiFont.baseSize*scaleFactor + GuiGetStyle(TEXTBOX, TEXT_LINES_PADDING));   // Line feed
+                    cursorPos.x = textAreaBounds.x;     // Carriage return
+                }
+            }
+            else if (wrapMode == 2)
+            {
+                /*
+                if ((codepointLength == 1) && (codepoint == ' ')) 
+                {
+                    lastSpacePos = i;
+                    lastSpaceWidth = 0;
+                    lastSpaceCursorPos = cursorPos.x;
+                }
+
+                // Jump line if last word reaches end of text box area
+                if ((lastSpaceCursorPos + lastSpaceWidth) > (textAreaBounds.x + textAreaBounds.width))
+                {
+                    cursorPos.y += 12;               // Line feed
+                    cursorPos.x = textAreaBounds.x;  // Carriage return
+                }
+                */
+            }
+            
+            // Draw current character glyph
+            DrawTextCodepoint(guiFont, codepoint, cursorPos, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha));
+            
+            int glyphWidth = 0;
+            if (glyphInfo.advanceX != 0) glyphWidth += glyphInfo.advanceX;
+            else glyphWidth += (atlasRec.width + glyphInfo.offsetX);
+            
+            cursorPos.x += (glyphWidth*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
+            //if (i > lastSpacePos) lastSpaceWidth += (atlasRec.width + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
+        }
+    }
+
+    cursor.x = cursorPos.x;
+    cursor.y = cursorPos.y;
+    
+    // Draw cursor position considering text glyphs
+    if (editMode) GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)), guiAlpha));
     //--------------------------------------------------------------------
     //--------------------------------------------------------------------
 
 
     return pressed;
     return pressed;