|
@@ -1395,8 +1395,7 @@ static Rectangle guiControlExclusiveRec = { 0 }; // Gui control exclusive bounds
|
|
|
|
|
|
static int textBoxCursorIndex = 0; // Cursor index, shared by all GuiTextBox*()
|
|
|
//static int blinkCursorFrameCounter = 0; // Frame counter for cursor blinking
|
|
|
-static int autoCursorCooldownCounter = 0; // Cooldown frame counter for automatic cursor movement on key-down
|
|
|
-static int autoCursorDelayCounter = 0; // Delay frame counter for automatic cursor movement
|
|
|
+static int autoCursorCounter = 0; // Frame counter for automatic repeated cursor movement on key-down (cooldown and delay)
|
|
|
|
|
|
//----------------------------------------------------------------------------------
|
|
|
// Style data array for all gui style properties (allocated on data segment by default)
|
|
@@ -2489,10 +2488,10 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod
|
|
|
int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
|
|
|
{
|
|
|
#if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)
|
|
|
- #define RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN 40 // Frames to wait for autocursor movement
|
|
|
+ #define RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN 30 // Frames to wait for autocursor movement
|
|
|
#endif
|
|
|
#if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY)
|
|
|
- #define RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY 1 // Frames delay for autocursor movement
|
|
|
+ #define RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY 2 // Frames delay for autocursor movement
|
|
|
#endif
|
|
|
|
|
|
int result = 0;
|
|
@@ -2526,15 +2525,6 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
|
|
|
mouseCursor.x = -1;
|
|
|
mouseCursor.width = 1;
|
|
|
|
|
|
- // Auto-cursor movement logic
|
|
|
- // NOTE: Cursor moves automatically when key down after some time
|
|
|
- if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_UP) || IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_BACKSPACE) || IsKeyDown(KEY_DELETE)) autoCursorCooldownCounter++;
|
|
|
- else
|
|
|
- {
|
|
|
- autoCursorCooldownCounter = 0; // GLOBAL: Cursor cooldown counter
|
|
|
- autoCursorDelayCounter = 0; // GLOBAL: Cursor delay counter
|
|
|
- }
|
|
|
-
|
|
|
// Blink-cursor frame counter
|
|
|
//if (!autoCursorMode) blinkCursorFrameCounter++;
|
|
|
//else blinkCursorFrameCounter = 0;
|
|
@@ -2552,6 +2542,15 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
|
|
|
|
|
|
if (editMode)
|
|
|
{
|
|
|
+ // GLOBAL: Auto-cursor movement logic
|
|
|
+ // NOTE: Keystrokes are handled repeatedly when button is held down for some time
|
|
|
+ if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_UP) || IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_BACKSPACE) || IsKeyDown(KEY_DELETE)) autoCursorCounter++;
|
|
|
+ else
|
|
|
+ {
|
|
|
+ autoCursorCounter = 0;
|
|
|
+ }
|
|
|
+ bool autoCursorShouldTrigger = (autoCursorCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN) && ((autoCursorCounter % RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0);
|
|
|
+
|
|
|
state = STATE_PRESSED;
|
|
|
|
|
|
if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength;
|
|
@@ -2629,113 +2628,175 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
|
|
|
// Move cursor to end
|
|
|
if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_END)) textBoxCursorIndex = textLength;
|
|
|
|
|
|
- // Delete codepoint from text, after current cursor position
|
|
|
- if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(KEY_DELETE) && (autoCursorCooldownCounter >= RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN))))
|
|
|
+ // Delete related codepoints from text, after current cursor position
|
|
|
+ if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_DELETE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
|
|
|
{
|
|
|
- autoCursorDelayCounter++;
|
|
|
-
|
|
|
- if (IsKeyPressed(KEY_DELETE) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames
|
|
|
+ int offset = textBoxCursorIndex;
|
|
|
+ int accCodepointSize = 0;
|
|
|
+ int nextCodepointSize;
|
|
|
+ int nextCodepoint;
|
|
|
+ // Check characters of the same type to delete (either ASCII punctuation or anything non-whitespace)
|
|
|
+ // Not using isalnum() since it only works on ASCII characters
|
|
|
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
|
|
|
+ bool puctuation = ispunct(nextCodepoint & 0xFF);
|
|
|
+ while (offset < textLength)
|
|
|
{
|
|
|
- int nextCodepointSize = 0;
|
|
|
- GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
|
|
|
+ if ((puctuation && !ispunct(nextCodepoint & 0xFF)) || (!puctuation && (isspace(nextCodepoint & 0xFF) || ispunct(nextCodepoint & 0xFF))))
|
|
|
+ break;
|
|
|
+ offset += nextCodepointSize;
|
|
|
+ accCodepointSize += nextCodepointSize;
|
|
|
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
|
|
|
+ }
|
|
|
+ // Check whitespace to delete (ASCII only)
|
|
|
+ while (offset < textLength)
|
|
|
+ {
|
|
|
+ if (!isspace(nextCodepoint & 0xFF))
|
|
|
+ break;
|
|
|
+ offset += nextCodepointSize;
|
|
|
+ accCodepointSize += nextCodepointSize;
|
|
|
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
|
|
|
+ }
|
|
|
|
|
|
- // Move backward text from cursor position
|
|
|
- for (int i = textBoxCursorIndex; i < textLength; i++) text[i] = text[i + nextCodepointSize];
|
|
|
+ // Move text after cursor forward (including final null terminator)
|
|
|
+ for (int i = offset; i <= textLength; i++) text[i - accCodepointSize] = text[i];
|
|
|
|
|
|
- textLength -= nextCodepointSize;
|
|
|
- if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength;
|
|
|
+ textLength -= accCodepointSize;
|
|
|
+ }
|
|
|
+ // Delete single codepoint from text, after current cursor position
|
|
|
+ else if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(KEY_DELETE) && autoCursorShouldTrigger)))
|
|
|
+ {
|
|
|
+ int nextCodepointSize = 0;
|
|
|
+ GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
|
|
|
|
|
|
- // Make sure text last character is EOL
|
|
|
- text[textLength] = '\0';
|
|
|
- }
|
|
|
+ // Move text after cursor forward (including final null terminator)
|
|
|
+ for (int i = textBoxCursorIndex + nextCodepointSize; i <= textLength; i++) text[i - nextCodepointSize] = text[i];
|
|
|
+
|
|
|
+ textLength -= nextCodepointSize;
|
|
|
}
|
|
|
|
|
|
// Delete related codepoints from text, before current cursor position
|
|
|
- if ((textLength > 0) && IsKeyPressed(KEY_BACKSPACE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
|
|
|
+ if ((textBoxCursorIndex > 0) && IsKeyPressed(KEY_BACKSPACE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
|
|
|
{
|
|
|
- int i = textBoxCursorIndex - 1;
|
|
|
+ int offset = textBoxCursorIndex;
|
|
|
int accCodepointSize = 0;
|
|
|
+ int prevCodepointSize;
|
|
|
+ int prevCodepoint;
|
|
|
|
|
|
- // Move cursor to the end of word if on space already
|
|
|
- while ((i > 0) && isspace(text[i]))
|
|
|
+ // Check whitespace to delete (ASCII only)
|
|
|
+ while (offset > 0)
|
|
|
{
|
|
|
- int prevCodepointSize = 0;
|
|
|
- GetCodepointPrevious(text + i, &prevCodepointSize);
|
|
|
- i -= prevCodepointSize;
|
|
|
+ prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize);
|
|
|
+ if (!isspace(prevCodepoint & 0xFF))
|
|
|
+ break;
|
|
|
+ offset -= prevCodepointSize;
|
|
|
accCodepointSize += prevCodepointSize;
|
|
|
}
|
|
|
-
|
|
|
- // Move cursor to the start of the word
|
|
|
- while ((i > 0) && !isspace(text[i]))
|
|
|
+ // Check characters of the same type to delete (either ASCII punctuation or anything non-whitespace)
|
|
|
+ // Not using isalnum() since it only works on ASCII characters
|
|
|
+ bool puctuation = ispunct(prevCodepoint & 0xFF);
|
|
|
+ while (offset > 0)
|
|
|
{
|
|
|
- int prevCodepointSize = 0;
|
|
|
- GetCodepointPrevious(text + i, &prevCodepointSize);
|
|
|
- i -= prevCodepointSize;
|
|
|
+ prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize);
|
|
|
+ if ((puctuation && !ispunct(prevCodepoint & 0xFF)) || (!puctuation && (isspace(prevCodepoint & 0xFF) || ispunct(prevCodepoint & 0xFF))))
|
|
|
+ break;
|
|
|
+ offset -= prevCodepointSize;
|
|
|
accCodepointSize += prevCodepointSize;
|
|
|
}
|
|
|
|
|
|
- // Move forward text from cursor position
|
|
|
- for (int j = (textBoxCursorIndex - accCodepointSize); j < textLength; j++) text[j] = text[j + accCodepointSize];
|
|
|
+ // Move text after cursor forward (including final null terminator)
|
|
|
+ for (int i = textBoxCursorIndex; i <= textLength; i++) text[i - accCodepointSize] = text[i];
|
|
|
|
|
|
- // Prevent cursor index from decrementing past 0
|
|
|
- if (textBoxCursorIndex > 0)
|
|
|
- {
|
|
|
- textBoxCursorIndex -= accCodepointSize;
|
|
|
- textLength -= accCodepointSize;
|
|
|
- }
|
|
|
-
|
|
|
- // Make sure text last character is EOL
|
|
|
- text[textLength] = '\0';
|
|
|
+ textLength -= accCodepointSize;
|
|
|
+ textBoxCursorIndex -= accCodepointSize;
|
|
|
}
|
|
|
- else if ((textLength > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(KEY_BACKSPACE) && (autoCursorCooldownCounter >= RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN))))
|
|
|
+ // Delete single codepoint from text, before current cursor position
|
|
|
+ else if ((textBoxCursorIndex > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(KEY_BACKSPACE) && autoCursorShouldTrigger)))
|
|
|
{
|
|
|
- autoCursorDelayCounter++;
|
|
|
+ int prevCodepointSize = 0;
|
|
|
|
|
|
- if (IsKeyPressed(KEY_BACKSPACE) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames
|
|
|
- {
|
|
|
- int prevCodepointSize = 0;
|
|
|
-
|
|
|
- // Prevent cursor index from decrementing past 0
|
|
|
- if (textBoxCursorIndex > 0)
|
|
|
- {
|
|
|
- GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
|
|
|
+ GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
|
|
|
|
|
|
- // Move backward text from cursor position
|
|
|
- for (int i = (textBoxCursorIndex - prevCodepointSize); i < textLength; i++) text[i] = text[i + prevCodepointSize];
|
|
|
+ // Move text after cursor forward (including final null terminator)
|
|
|
+ for (int i = textBoxCursorIndex; i <= textLength; i++) text[i - prevCodepointSize] = text[i];
|
|
|
|
|
|
- textBoxCursorIndex -= prevCodepointSize;
|
|
|
- textLength -= prevCodepointSize;
|
|
|
- }
|
|
|
-
|
|
|
- // Make sure text last character is EOL
|
|
|
- text[textLength] = '\0';
|
|
|
- }
|
|
|
+ textLength -= prevCodepointSize;
|
|
|
+ textBoxCursorIndex -= prevCodepointSize;
|
|
|
}
|
|
|
|
|
|
// Move cursor position with keys
|
|
|
- if (IsKeyPressed(KEY_LEFT) || (IsKeyDown(KEY_LEFT) && (autoCursorCooldownCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)))
|
|
|
+ if ((textBoxCursorIndex > 0) && IsKeyPressed(KEY_LEFT) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
|
|
|
{
|
|
|
- autoCursorDelayCounter++;
|
|
|
+ int offset = textBoxCursorIndex;
|
|
|
+ int accCodepointSize = 0;
|
|
|
+ int prevCodepointSize;
|
|
|
+ int prevCodepoint;
|
|
|
|
|
|
- if (IsKeyPressed(KEY_LEFT) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames
|
|
|
+ // Check whitespace to skip (ASCII only)
|
|
|
+ while (offset > 0)
|
|
|
{
|
|
|
- int prevCodepointSize = 0;
|
|
|
- if (textBoxCursorIndex > 0) GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
|
|
|
-
|
|
|
- if (textBoxCursorIndex >= prevCodepointSize) textBoxCursorIndex -= prevCodepointSize;
|
|
|
+ prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize);
|
|
|
+ if (!isspace(prevCodepoint & 0xFF))
|
|
|
+ break;
|
|
|
+ offset -= prevCodepointSize;
|
|
|
+ accCodepointSize += prevCodepointSize;
|
|
|
+ }
|
|
|
+ // Check characters of the same type to skip (either ASCII punctuation or anything non-whitespace)
|
|
|
+ // Not using isalnum() since it only works on ASCII characters
|
|
|
+ bool puctuation = ispunct(prevCodepoint & 0xFF);
|
|
|
+ while (offset > 0)
|
|
|
+ {
|
|
|
+ prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize);
|
|
|
+ if ((puctuation && !ispunct(prevCodepoint & 0xFF)) || (!puctuation && (isspace(prevCodepoint & 0xFF) || ispunct(prevCodepoint & 0xFF))))
|
|
|
+ break;
|
|
|
+ offset -= prevCodepointSize;
|
|
|
+ accCodepointSize += prevCodepointSize;
|
|
|
}
|
|
|
+
|
|
|
+ textBoxCursorIndex = offset;
|
|
|
}
|
|
|
- else if (IsKeyPressed(KEY_RIGHT) || (IsKeyDown(KEY_RIGHT) && (autoCursorCooldownCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)))
|
|
|
+ else if ((textBoxCursorIndex > 0) && (IsKeyPressed(KEY_LEFT) || (IsKeyDown(KEY_LEFT) && autoCursorShouldTrigger)))
|
|
|
{
|
|
|
- autoCursorDelayCounter++;
|
|
|
+ int prevCodepointSize = 0;
|
|
|
+ GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
|
|
|
|
|
|
- if (IsKeyPressed(KEY_RIGHT) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames
|
|
|
+ textBoxCursorIndex -= prevCodepointSize;
|
|
|
+ }
|
|
|
+ else if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_RIGHT) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
|
|
|
+ {
|
|
|
+ int offset = textBoxCursorIndex;
|
|
|
+ int accCodepointSize = 0;
|
|
|
+ int nextCodepointSize;
|
|
|
+ int nextCodepoint;
|
|
|
+ // Check characters of the same type to skip (either ASCII punctuation or anything non-whitespace)
|
|
|
+ // Not using isalnum() since it only works on ASCII characters
|
|
|
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
|
|
|
+ bool puctuation = ispunct(nextCodepoint & 0xFF);
|
|
|
+ while (offset < textLength)
|
|
|
{
|
|
|
- int nextCodepointSize = 0;
|
|
|
- GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
|
|
|
-
|
|
|
- if ((textBoxCursorIndex + nextCodepointSize) <= textLength) textBoxCursorIndex += nextCodepointSize;
|
|
|
+ if ((puctuation && !ispunct(nextCodepoint & 0xFF)) || (!puctuation && (isspace(nextCodepoint & 0xFF) || ispunct(nextCodepoint & 0xFF))))
|
|
|
+ break;
|
|
|
+ offset += nextCodepointSize;
|
|
|
+ accCodepointSize += nextCodepointSize;
|
|
|
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
|
|
|
+ }
|
|
|
+ // Check whitespace to skip (ASCII only)
|
|
|
+ while (offset < textLength)
|
|
|
+ {
|
|
|
+ if (!isspace(nextCodepoint & 0xFF))
|
|
|
+ break;
|
|
|
+ offset += nextCodepointSize;
|
|
|
+ accCodepointSize += nextCodepointSize;
|
|
|
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
|
|
|
}
|
|
|
+
|
|
|
+ textBoxCursorIndex = offset;
|
|
|
+ }
|
|
|
+ else if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_RIGHT) || (IsKeyDown(KEY_RIGHT) && autoCursorShouldTrigger)))
|
|
|
+ {
|
|
|
+ int nextCodepointSize = 0;
|
|
|
+ GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
|
|
|
+
|
|
|
+ textBoxCursorIndex += nextCodepointSize;
|
|
|
}
|
|
|
|
|
|
// Move cursor position with mouse
|
|
@@ -2791,6 +2852,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
|
|
|
(!CheckCollisionPointRec(mousePosition, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)))
|
|
|
{
|
|
|
textBoxCursorIndex = 0; // GLOBAL: Reset the shared cursor index
|
|
|
+ autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes
|
|
|
result = 1;
|
|
|
}
|
|
|
}
|
|
@@ -2803,6 +2865,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
|
|
|
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
|
|
|
{
|
|
|
textBoxCursorIndex = textLength; // GLOBAL: Place cursor index to the end of current text
|
|
|
+ autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes
|
|
|
result = 1;
|
|
|
}
|
|
|
}
|