REVIEWED: GuiTextBox(), support cursor positioning with mouse

This commit is contained in:
Ray 2023-09-03 22:17:50 +02:00
parent abf35d8895
commit 8d9a4b537f
2 changed files with 73 additions and 33 deletions

View File

@ -129,6 +129,10 @@ int main()
float alpha = 1.0f; float alpha = 1.0f;
// DEBUG: Testing how those two properties affect all controls!
//GuiSetStyle(DEFAULT, TEXT_PADDING, 0);
//GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
SetTargetFPS(60); SetTargetFPS(60);
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
@ -259,8 +263,6 @@ int main()
Vector2 mouseCell = { 0 }; Vector2 mouseCell = { 0 };
GuiGrid((Rectangle) { 560, 25 + 180 + 195, 100, 120 }, NULL, 20, 3, &mouseCell); GuiGrid((Rectangle) { 560, 25 + 180 + 195, 100, 120 }, NULL, 20, 3, &mouseCell);
//GuiStatusBar((Rectangle){ 0, (float)GetScreenHeight() - 20, (float)GetScreenWidth(), 20 }, "This is a status bar");
GuiColorBarAlpha((Rectangle){ 320, 490, 200, 30 }, NULL, &alphaValue); GuiColorBarAlpha((Rectangle){ 320, 490, 200, 30 }, NULL, &alphaValue);
GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_TOP); // WARNING: Word-wrap does not work as expected in case of no-top alignment GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_TOP); // WARNING: Word-wrap does not work as expected in case of no-top alignment
@ -269,6 +271,11 @@ int main()
GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_NONE); GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_NONE);
GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE);
GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
GuiStatusBar((Rectangle){ 0, (float)GetScreenHeight() - 20, (float)GetScreenWidth(), 20 }, "This is a status bar");
GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
//GuiSetStyle(STATUSBAR, TEXT_INDENTATION, 20);
if (showMessageBox) if (showMessageBox)
{ {
DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Fade(RAYWHITE, 0.8f)); DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Fade(RAYWHITE, 0.8f));

View File

@ -1699,7 +1699,7 @@ int GuiTabBar(Rectangle bounds, const char **text, int count, int *active)
GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment); GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment);
// Draw tab close button // Draw tab close button
// NOTE: Only draw close button for curren tab: if (CheckCollisionPointRec(mousePoint, tabBounds)) // NOTE: Only draw close button for current tab: if (CheckCollisionPointRec(mousePosition, tabBounds))
int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
GuiSetStyle(BUTTON, BORDER_WIDTH, 1); GuiSetStyle(BUTTON, BORDER_WIDTH, 1);
@ -2388,14 +2388,13 @@ int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode)
int result = 0; int result = 0;
GuiState state = guiState; GuiState state = guiState;
bool multiline = false; // TODO: Consider multiline text input
int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE);
Rectangle textBounds = GetTextBounds(TEXTBOX, bounds); Rectangle textBounds = GetTextBounds(TEXTBOX, bounds);
int textWidth = GetTextWidth(text) - GetTextWidth(text + textBoxCursorIndex); int textWidth = GetTextWidth(text) - GetTextWidth(text + textBoxCursorIndex);
int textIndexOffset = 0; // Text index offset to start drawing in the box int textIndexOffset = 0; // Text index offset to start drawing in the box
int alignmentVertical = GuiGetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL);
int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE);
bool multiline = false; // TODO: Multiline text editing, not supported at the momnet
// Cursor rectangle // Cursor rectangle
// NOTE: Position X value should be updated // NOTE: Position X value should be updated
Rectangle cursor = { Rectangle cursor = {
@ -2405,17 +2404,15 @@ int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode)
(float)GuiGetStyle(DEFAULT, TEXT_SIZE)*2 (float)GuiGetStyle(DEFAULT, TEXT_SIZE)*2
}; };
switch (alignmentVertical)
{
case 0: cursor.y = textBounds.y + textBounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE); break; // CENTERED
case 1: cursor.y = textBounds.y - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; break; // UP
case 2: cursor.y = textBounds.y + textBounds.height; break; // DOWN
default: break;
}
if (cursor.height >= bounds.height) cursor.height = bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2; if (cursor.height >= bounds.height) cursor.height = bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2;
if (cursor.y < (bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH))) cursor.y = bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH); if (cursor.y < (bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH))) cursor.y = bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH);
// Mouse cursor rectangle
// NOTE: Initialized outside of screen
Rectangle mouseCursor = cursor;
mouseCursor.x = -1;
mouseCursor.width = 1;
// Auto-cursor movement logic // Auto-cursor movement logic
// NOTE: Cursor moves automatically when key down after some time // 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++; if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_UP) || IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_BACKSPACE) || IsKeyDown(KEY_DELETE)) autoCursorCooldownCounter++;
@ -2438,7 +2435,7 @@ int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode)
!guiSliderDragging && // No gui slider on dragging !guiSliderDragging && // No gui slider on dragging
(wrapMode == TEXT_WRAP_NONE)) // No wrap mode (wrapMode == TEXT_WRAP_NONE)) // No wrap mode
{ {
Vector2 mousePoint = GetMousePosition(); Vector2 mousePosition = GetMousePosition();
if (editMode) if (editMode)
{ {
@ -2484,16 +2481,10 @@ int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode)
} }
// Move cursor to start // Move cursor to start
if ((textLength > 0) && IsKeyPressed(KEY_HOME)) if ((textLength > 0) && IsKeyPressed(KEY_HOME)) textBoxCursorIndex = 0;
{
textBoxCursorIndex = 0;
}
// Move cursor to end // Move cursor to end
if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_END)) if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_END)) textBoxCursorIndex = textLength;
{
textBoxCursorIndex = textLength;
}
// Delete codepoint from text, after current cursor position // Delete codepoint from text, after current cursor position
if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(KEY_DELETE) && (autoCursorCooldownCounter >= RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)))) if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(KEY_DELETE) && (autoCursorCooldownCounter >= RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN))))
@ -2541,7 +2532,6 @@ int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode)
} }
// Move cursor position with keys // Move cursor position with keys
//if (IsKeyDown(KEY_LEFT) && autoCursorMode)
if (IsKeyPressed(KEY_LEFT) || (IsKeyDown(KEY_LEFT) && (autoCursorCooldownCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN))) if (IsKeyPressed(KEY_LEFT) || (IsKeyDown(KEY_LEFT) && (autoCursorCooldownCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)))
{ {
autoCursorDelayCounter++; autoCursorDelayCounter++;
@ -2567,11 +2557,51 @@ int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode)
} }
} }
// TODO: Get cursor rectangle from mouse position // Move cursor position with mouse
//cursor = GetCursorFromMousePosition(bounds, text, mouse); // Gui style considered internally, including wrapMode if (CheckCollisionPointRec(mousePosition, textBounds)) // Mouse hover text
{
float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/(float)guiFont.baseSize;
int codepoint = 0;
int codepointSize = 0;
int codepointIndex = 0;
float glyphWidth = 0.0f;
int widthToMouseX = 0;
int mouseCursorIndex = 0;
// TODO: Get cursor rectangle from buffer index for (int i = textIndexOffset; i < textLength; i++)
//cursor = GetCursorFromIndex(bounds, text, index); // Gui style considered internally, including wrapMode {
codepoint = GetCodepointNext(&text[i], &codepointSize);
codepointIndex = GetGlyphIndex(guiFont, codepoint);
if (guiFont.glyphs[codepointIndex].advanceX == 0) glyphWidth = ((float)guiFont.recs[codepointIndex].width*scaleFactor);
else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor);
if (mousePosition.x <= (textBounds.x + (widthToMouseX + glyphWidth/2)))
{
mouseCursor.x = textBounds.x + widthToMouseX;
mouseCursorIndex = i;
break;
}
widthToMouseX += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
}
// Check if mouse cursor is at the last position
int textEndWidth = GetTextWidth(text + textIndexOffset);
if (GetMousePosition().x >= (textBounds.x + textEndWidth - glyphWidth/2))
{
mouseCursor.x = textBounds.x + textEndWidth;
mouseCursorIndex = strlen(text);
}
// Place cursor at required index on mouse click
if ((mouseCursor.x >= 0) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
{
cursor.x = mouseCursor.x;
textBoxCursorIndex = mouseCursorIndex;
}
}
else mouseCursor.x = -1;
// Recalculate cursor position.y depending on textBoxCursorIndex // Recalculate cursor position.y depending on textBoxCursorIndex
cursor.x = bounds.x + GuiGetStyle(TEXTBOX, TEXT_PADDING) + GetTextWidth(text + textIndexOffset) - GetTextWidth(text + textBoxCursorIndex) + GuiGetStyle(DEFAULT, TEXT_SPACING); cursor.x = bounds.x + GuiGetStyle(TEXTBOX, TEXT_PADDING) + GetTextWidth(text + textIndexOffset) - GetTextWidth(text + textBoxCursorIndex) + GuiGetStyle(DEFAULT, TEXT_SPACING);
@ -2579,7 +2609,7 @@ int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode)
// Finish text editing on ENTER or mouse click outside bounds // Finish text editing on ENTER or mouse click outside bounds
if ((!multiline && IsKeyPressed(KEY_ENTER)) || if ((!multiline && IsKeyPressed(KEY_ENTER)) ||
(!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) (!CheckCollisionPointRec(mousePosition, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)))
{ {
textBoxCursorIndex = 0; // GLOBAL: Reset the shared cursor index textBoxCursorIndex = 0; // GLOBAL: Reset the shared cursor index
result = 1; result = 1;
@ -2587,7 +2617,7 @@ int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode)
} }
else else
{ {
if (CheckCollisionPointRec(mousePoint, bounds)) if (CheckCollisionPointRec(mousePosition, bounds))
{ {
state = STATE_FOCUSED; state = STATE_FOCUSED;
@ -2622,6 +2652,9 @@ int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode)
{ {
//if (autoCursorMode || ((blinkCursorFrameCounter/40)%2 == 0)) //if (autoCursorMode || ((blinkCursorFrameCounter/40)%2 == 0))
GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED))); GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)));
// Draw mouse position cursor (if required)
if (mouseCursor.x >= 0) GuiDrawRectangle(mouseCursor, 0, BLANK, GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)));
} }
else if (state == STATE_FOCUSED) GuiTooltip(bounds); else if (state == STATE_FOCUSED) GuiTooltip(bounds);
//-------------------------------------------------------------------- //--------------------------------------------------------------------
@ -2875,7 +2908,7 @@ int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight,
{ {
state = STATE_PRESSED; state = STATE_PRESSED;
// Get equivalent value and slider position from mousePoint.x // Get equivalent value and slider position from mousePosition.x
*value = ((maxValue - minValue)*(mousePoint.x - (float)(bounds.x + sliderWidth/2)))/(float)(bounds.width - sliderWidth) + minValue; *value = ((maxValue - minValue)*(mousePoint.x - (float)(bounds.x + sliderWidth/2)))/(float)(bounds.width - sliderWidth) + minValue;
} }
} }
@ -2895,7 +2928,7 @@ int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight,
if (!CheckCollisionPointRec(mousePoint, slider)) if (!CheckCollisionPointRec(mousePoint, slider))
{ {
// Get equivalent value and slider position from mousePoint.x // Get equivalent value and slider position from mousePosition.x
*value = ((maxValue - minValue)*(mousePoint.x - (float)(bounds.x + sliderWidth/2)))/(float)(bounds.width - sliderWidth) + minValue; *value = ((maxValue - minValue)*(mousePoint.x - (float)(bounds.x + sliderWidth/2)))/(float)(bounds.width - sliderWidth) + minValue;
if (sliderWidth > 0) slider.x = mousePoint.x - slider.width/2; // Slider if (sliderWidth > 0) slider.x = mousePoint.x - slider.width/2; // Slider