mirror of
https://github.com/raysan5/raygui.git
synced 2025-12-25 10:22:33 -05:00
Modify custom_file_dialog, portable_window, propertly_list, and text_editor examples to be compatible with the newest raylib and raygui (#156)
Modify gui_textbox_extended.h to contain DrawTextRec and DrawTextRecEx since they were cut from raylib, also add DrawTextBoxedSelectable as an alias for DrawTextRecEx for compatibility/name consistency Modify gui_textbox_extended.h to be compatible with the latest raylib
This commit is contained in:
@ -31,7 +31,6 @@
|
||||
|
||||
#ifndef GUI_TEXTBOX_EXTENDED_H
|
||||
#define GUI_TEXTBOX_EXTENDED_H
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Defines and Macros
|
||||
//----------------------------------------------------------------------------------
|
||||
@ -78,6 +77,10 @@ RAYGUIDEF int GuiTextBoxGetByteIndex(const char *text, int start, int from, int
|
||||
|
||||
RAYGUIDEF bool GuiTextBoxEx(Rectangle bounds, char *text, int textSize, bool editMode);
|
||||
|
||||
RAYGUIDEF static void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint); // Draw text using font inside rectangle limits
|
||||
RAYGUIDEF static void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint); // Draw text using font inside rectangle limits with support for text selection
|
||||
RAYGUIDEF static void DrawTextBoxedSelectable(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint); // Alias for above
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -96,6 +99,146 @@ RAYGUIDEF bool GuiTextBoxEx(Rectangle bounds, char *text, int textSize, bool edi
|
||||
#include "raygui.h"
|
||||
#endif
|
||||
|
||||
// Draw text using font inside rectangle limits
|
||||
static void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint)
|
||||
{
|
||||
DrawTextRecEx(font, text, rec, fontSize, spacing, wordWrap, tint, 0, 0, WHITE, WHITE);
|
||||
}
|
||||
|
||||
// Draw text using font inside rectangle limits with support for text selection
|
||||
static void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint)
|
||||
{
|
||||
int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop
|
||||
|
||||
float textOffsetY = 0; // Offset between lines (on line break '\n')
|
||||
float textOffsetX = 0.0f; // Offset X to next character to draw
|
||||
|
||||
float scaleFactor = fontSize/(float)font.baseSize; // Character rectangle scaling factor
|
||||
|
||||
// Word/character wrapping mechanism variables
|
||||
enum { MEASURE_STATE = 0, DRAW_STATE = 1 };
|
||||
int state = wordWrap? MEASURE_STATE : DRAW_STATE;
|
||||
|
||||
int startLine = -1; // Index where to begin drawing (where a line begins)
|
||||
int endLine = -1; // Index where to stop drawing (where a line ends)
|
||||
int lastk = -1; // Holds last value of the character position
|
||||
|
||||
for (int i = 0, k = 0; i < length; i++, k++)
|
||||
{
|
||||
// Get next codepoint from byte string and glyph index in font
|
||||
int codepointByteCount = 0;
|
||||
int codepoint = GetCodepoint(&text[i], &codepointByteCount);
|
||||
int index = GetGlyphIndex(font, codepoint);
|
||||
|
||||
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
|
||||
// but we need to draw all of the bad bytes using the '?' symbol moving one byte
|
||||
if (codepoint == 0x3f) codepointByteCount = 1;
|
||||
i += (codepointByteCount - 1);
|
||||
|
||||
float glyphWidth = 0;
|
||||
if (codepoint != '\n')
|
||||
{
|
||||
glyphWidth = (font.glyphs[index].advanceX == 0) ? font.recs[index].width*scaleFactor : font.glyphs[index].advanceX*scaleFactor;
|
||||
|
||||
if (i + 1 < length) glyphWidth = glyphWidth + spacing;
|
||||
}
|
||||
|
||||
// NOTE: When wordWrap is ON we first measure how much of the text we can draw before going outside of the rec container
|
||||
// We store this info in startLine and endLine, then we change states, draw the text between those two variables
|
||||
// and change states again and again recursively until the end of the text (or until we get outside of the container).
|
||||
// When wordWrap is OFF we don't need the measure state so we go to the drawing state immediately
|
||||
// and begin drawing on the next line before we can get outside the container.
|
||||
if (state == MEASURE_STATE)
|
||||
{
|
||||
// TODO: There are multiple types of spaces in UNICODE, maybe it's a good idea to add support for more
|
||||
// Ref: http://jkorpela.fi/chars/spaces.html
|
||||
if ((codepoint == ' ') || (codepoint == '\t') || (codepoint == '\n')) endLine = i;
|
||||
|
||||
if ((textOffsetX + glyphWidth) > rec.width)
|
||||
{
|
||||
endLine = (endLine < 1)? i : endLine;
|
||||
if (i == endLine) endLine -= codepointByteCount;
|
||||
if ((startLine + codepointByteCount) == endLine) endLine = (i - codepointByteCount);
|
||||
|
||||
state = !state;
|
||||
}
|
||||
else if ((i + 1) == length)
|
||||
{
|
||||
endLine = i;
|
||||
state = !state;
|
||||
}
|
||||
else if (codepoint == '\n') state = !state;
|
||||
|
||||
if (state == DRAW_STATE)
|
||||
{
|
||||
textOffsetX = 0;
|
||||
i = startLine;
|
||||
glyphWidth = 0;
|
||||
|
||||
// Save character position when we switch states
|
||||
int tmp = lastk;
|
||||
lastk = k - 1;
|
||||
k = tmp;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (codepoint == '\n')
|
||||
{
|
||||
if (!wordWrap)
|
||||
{
|
||||
textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
|
||||
textOffsetX = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!wordWrap && ((textOffsetX + glyphWidth) > rec.width))
|
||||
{
|
||||
textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
|
||||
textOffsetX = 0;
|
||||
}
|
||||
|
||||
// When text overflows rectangle height limit, just stop drawing
|
||||
if ((textOffsetY + font.baseSize*scaleFactor) > rec.height) break;
|
||||
|
||||
// Draw selection background
|
||||
bool isGlyphSelected = false;
|
||||
if ((selectStart >= 0) && (k >= selectStart) && (k < (selectStart + selectLength)))
|
||||
{
|
||||
DrawRectangleRec((Rectangle){ rec.x + textOffsetX - 1, rec.y + textOffsetY, glyphWidth, (float)font.baseSize*scaleFactor }, selectBackTint);
|
||||
isGlyphSelected = true;
|
||||
}
|
||||
|
||||
// Draw current character glyph
|
||||
if ((codepoint != ' ') && (codepoint != '\t'))
|
||||
{
|
||||
DrawTextCodepoint(font, codepoint, (Vector2){ rec.x + textOffsetX, rec.y + textOffsetY }, fontSize, isGlyphSelected? selectTint : tint);
|
||||
}
|
||||
}
|
||||
|
||||
if (wordWrap && (i == endLine))
|
||||
{
|
||||
textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
|
||||
textOffsetX = 0;
|
||||
startLine = endLine;
|
||||
endLine = -1;
|
||||
glyphWidth = 0;
|
||||
selectStart += lastk - k;
|
||||
k = lastk;
|
||||
|
||||
state = !state;
|
||||
}
|
||||
}
|
||||
|
||||
textOffsetX += glyphWidth;
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawTextBoxedSelectable(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint) {
|
||||
DrawTextRecEx(font, text, rec, fontSize, spacing, wordWrap, tint, selectStart, selectLength, selectTint, selectBackTint);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Defines and Macros
|
||||
//----------------------------------------------------------------------------------
|
||||
@ -178,9 +321,9 @@ RAYGUIDEF void GuiTextBoxSetSelection(int start, int length)
|
||||
RAYGUIDEF Vector2 GuiTextBoxGetSelection(void)
|
||||
{
|
||||
if (guiTextBoxState.select == -1 || guiTextBoxState.select == guiTextBoxState.cursor) return RAYGUI_CLITERAL(Vector2){ 0 };
|
||||
else if (guiTextBoxState.cursor > guiTextBoxState.select) return RAYGUI_CLITERAL(Vector2){ guiTextBoxState.select, guiTextBoxState.cursor - guiTextBoxState.select };
|
||||
else if (guiTextBoxState.cursor > guiTextBoxState.select) return RAYGUI_CLITERAL(Vector2){ (float)guiTextBoxState.select, (float)guiTextBoxState.cursor - guiTextBoxState.select };
|
||||
|
||||
return RAYGUI_CLITERAL(Vector2){ guiTextBoxState.cursor, guiTextBoxState.select - guiTextBoxState.cursor };
|
||||
return RAYGUI_CLITERAL(Vector2){ (float)guiTextBoxState.cursor, (float)guiTextBoxState.select - guiTextBoxState.cursor };
|
||||
}
|
||||
|
||||
// Returns true if a textbox control with specified `bounds` is the active textbox
|
||||
@ -436,7 +579,7 @@ RAYGUIDEF bool GuiTextBoxEx(Rectangle bounds, char *text, int textSize, bool edi
|
||||
Rectangle textRec = { bounds.x + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING),
|
||||
bounds.y + verticalPadding + GuiGetStyle(TEXTBOX, BORDER_WIDTH),
|
||||
bounds.width - 2*(GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING) + GuiGetStyle(TEXTBOX, BORDER_WIDTH)),
|
||||
GuiGetStyle(DEFAULT, TEXT_SIZE) };
|
||||
(float)GuiGetStyle(DEFAULT, TEXT_SIZE) };
|
||||
|
||||
Vector2 cursorPos = { textRec.x, textRec.y }; // This holds the coordinates inside textRec of the cursor at current position and will be recalculated later
|
||||
bool active = GuiTextBoxIsActive(bounds); // Check if this textbox is the global active textbox
|
||||
@ -806,7 +949,7 @@ RAYGUIDEF bool GuiTextBoxEx(Rectangle bounds, char *text, int textSize, bool edi
|
||||
|
||||
if (pressed) framesCounter = 0;
|
||||
}
|
||||
|
||||
|
||||
// Draw control
|
||||
//--------------------------------------------------------------------
|
||||
DrawRectangleLinesEx(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha));
|
||||
@ -816,9 +959,9 @@ RAYGUIDEF bool GuiTextBoxEx(Rectangle bounds, char *text, int textSize, bool edi
|
||||
DrawRectangle(bounds.x + GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.height - 2*GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_FOCUSED)), guiAlpha));
|
||||
|
||||
// Draw blinking cursor
|
||||
if (editMode && active && ((framesCounter/TEXTEDIT_CURSOR_BLINK_FRAMES)%2 == 0) && selLength == 0)
|
||||
if (editMode && active && ((framesCounter/30)%2 == 0) && selLength == 0)
|
||||
{
|
||||
DrawRectangle(cursorPos.x, cursorPos.y, 1, GuiGetStyle(DEFAULT, TEXT_SIZE)*2, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)), guiAlpha));
|
||||
DrawRectangle(cursorPos.x, cursorPos.y-1, 1, GuiGetStyle(DEFAULT, TEXT_SIZE)+2, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)), guiAlpha));
|
||||
}
|
||||
}
|
||||
else if (state == GUI_STATE_DISABLED)
|
||||
@ -827,8 +970,8 @@ RAYGUIDEF bool GuiTextBoxEx(Rectangle bounds, char *text, int textSize, bool edi
|
||||
}
|
||||
|
||||
// Finally draw the text and selection
|
||||
DrawTextBoxedSelectable(guiFont, &text[textStartIndex], textRec, GuiGetStyle(DEFAULT, TEXT_SIZE), GuiGetStyle(DEFAULT, TEXT_SPACING), false, Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha), selStart, selLength, GetColor(GuiGetStyle(TEXTBOX, COLOR_SELECTED_FG)), GetColor(GuiGetStyle(TEXTBOX, COLOR_SELECTED_BG)));
|
||||
|
||||
DrawTextRecEx(guiFont, &text[textStartIndex], textRec, GuiGetStyle(DEFAULT, TEXT_SIZE), GuiGetStyle(DEFAULT, TEXT_SPACING), false, Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha), selStart, selLength, GetColor(GuiGetStyle(TEXTBOX, COLOR_SELECTED_FG)), GetColor(GuiGetStyle(TEXTBOX, COLOR_SELECTED_BG)));
|
||||
|
||||
return pressed;
|
||||
}
|
||||
|
||||
@ -904,9 +1047,9 @@ static int GuiMeasureTextBox(const char *text, int length, Rectangle rec, int *p
|
||||
|
||||
if (letter != '\n')
|
||||
{
|
||||
glyphWidth = (font.chars[index].advanceX == 0)?
|
||||
glyphWidth = (font.glyphs[index].advanceX == 0)?
|
||||
(int)(font.recs[index].width*scaleFactor + spacing):
|
||||
(int)(font.chars[index].advanceX*scaleFactor + spacing);
|
||||
(int)(font.glyphs[index].advanceX*scaleFactor + spacing);
|
||||
|
||||
if ((textOffsetX + glyphWidth + 1) >= rec.width) break;
|
||||
|
||||
@ -914,7 +1057,7 @@ static int GuiMeasureTextBox(const char *text, int length, Rectangle rec, int *p
|
||||
else if (mode == GUI_MEASURE_MODE_CURSOR_COORDS)
|
||||
{
|
||||
// Check if the mouse pointer is inside the glyph rect
|
||||
Rectangle grec = {rec.x + textOffsetX - 1, rec.y, glyphWidth, (font.baseSize + font.baseSize/2)*scaleFactor - 1 };
|
||||
Rectangle grec = {rec.x + textOffsetX - 1, rec.y, (float)glyphWidth, (font.baseSize + font.baseSize/2)*scaleFactor - 1 };
|
||||
Vector2 mouse = GetMousePosition();
|
||||
|
||||
if (CheckCollisionPointRec(mouse, grec))
|
||||
@ -970,9 +1113,9 @@ static int GuiMeasureTextBoxRev(const char *text, int length, Rectangle rec, int
|
||||
|
||||
if (letter != '\n')
|
||||
{
|
||||
glyphWidth = (font.chars[index].advanceX == 0)?
|
||||
glyphWidth = (font.glyphs[index].advanceX == 0)?
|
||||
(int)(font.recs[index].width*scaleFactor + spacing):
|
||||
(int)(font.chars[index].advanceX*scaleFactor + spacing);
|
||||
(int)(font.glyphs[index].advanceX*scaleFactor + spacing);
|
||||
|
||||
if ((textOffsetX + glyphWidth + 1) >= rec.width) break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user