|
@@ -132,6 +132,9 @@
|
|
* Includes custom ricons.h header defining a set of custom icons,
|
|
* Includes custom ricons.h header defining a set of custom icons,
|
|
* this file can be generated using rGuiIcons tool
|
|
* this file can be generated using rGuiIcons tool
|
|
*
|
|
*
|
|
|
|
+* #define RAYGUI_DEBUG_RECS_BOUNDS
|
|
|
|
+* Draw control bounds rectangles for debug
|
|
|
|
+*
|
|
* #define RAYGUI_DEBUG_TEXT_BOUNDS
|
|
* #define RAYGUI_DEBUG_TEXT_BOUNDS
|
|
* Draw text bounds rectangles for debug
|
|
* Draw text bounds rectangles for debug
|
|
*
|
|
*
|
|
@@ -1380,7 +1383,7 @@ static Vector3 ConvertRGBtoHSV(Vector3 rgb); // Convert color
|
|
static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel()
|
|
static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel()
|
|
static void GuiTooltip(Rectangle controlRec); // Draw tooltip using control rec position
|
|
static void GuiTooltip(Rectangle controlRec); // Draw tooltip using control rec position
|
|
|
|
|
|
-static Color GuiFade(Color color, float alpha);
|
|
|
|
|
|
+static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor
|
|
|
|
|
|
//----------------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------------
|
|
// Gui Setup Functions Definition
|
|
// Gui Setup Functions Definition
|
|
@@ -2330,6 +2333,7 @@ int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode)
|
|
|
|
|
|
int alignmentVertical = GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT_VERTICAL);
|
|
int alignmentVertical = GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT_VERTICAL);
|
|
int multiline = GuiGetStyle(TEXTBOX, TEXT_MULTILINE);
|
|
int multiline = GuiGetStyle(TEXTBOX, TEXT_MULTILINE);
|
|
|
|
+ int wrapMode = GuiGetStyle(TEXTBOX, TEXT_WRAP_MODE);
|
|
|
|
|
|
// Cursor rectangle
|
|
// Cursor rectangle
|
|
// NOTE: Position X value should be updated
|
|
// NOTE: Position X value should be updated
|
|
@@ -2366,7 +2370,8 @@ int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode)
|
|
|
|
|
|
// Update control
|
|
// Update control
|
|
//--------------------------------------------------------------------
|
|
//--------------------------------------------------------------------
|
|
- if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging && (GuiGetStyle(TEXTBOX, TEXT_READONLY) == 0))
|
|
|
|
|
|
+ // WARNING: If wrapMode is enabled, text editing is not supported
|
|
|
|
+ if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging && (GuiGetStyle(TEXTBOX, TEXT_READONLY) == 0) && (wrapMode == 0))
|
|
{
|
|
{
|
|
Vector2 mousePoint = GetMousePosition();
|
|
Vector2 mousePoint = GetMousePosition();
|
|
|
|
|
|
@@ -3725,8 +3730,9 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect
|
|
Vector2 mousePoint = GetMousePosition();
|
|
Vector2 mousePoint = GetMousePosition();
|
|
Vector2 currentMouseCell = { 0 };
|
|
Vector2 currentMouseCell = { 0 };
|
|
|
|
|
|
- int linesV = ((int)(bounds.width/spacing))*subdivs + subdivs;
|
|
|
|
- int linesH = ((int)(bounds.height/spacing))*subdivs + subdivs;
|
|
|
|
|
|
+ float spaceWidth = spacing/(float)subdivs;
|
|
|
|
+ int linesV = (int)(bounds.width/spaceWidth) + 1;
|
|
|
|
+ int linesH = (int)(bounds.height/spaceWidth) + 1;
|
|
|
|
|
|
// Update control
|
|
// Update control
|
|
//--------------------------------------------------------------------
|
|
//--------------------------------------------------------------------
|
|
@@ -3930,6 +3936,7 @@ void GuiLoadStyleDefault(void)
|
|
GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
|
|
GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
|
|
GuiSetStyle(BUTTON, BORDER_WIDTH, 2);
|
|
GuiSetStyle(BUTTON, BORDER_WIDTH, 2);
|
|
GuiSetStyle(SLIDER, TEXT_PADDING, 4);
|
|
GuiSetStyle(SLIDER, TEXT_PADDING, 4);
|
|
|
|
+ GuiSetStyle(PROGRESSBAR, TEXT_PADDING, 4);
|
|
GuiSetStyle(CHECKBOX, TEXT_PADDING, 4);
|
|
GuiSetStyle(CHECKBOX, TEXT_PADDING, 4);
|
|
GuiSetStyle(CHECKBOX, TEXT_ALIGNMENT, TEXT_ALIGN_RIGHT);
|
|
GuiSetStyle(CHECKBOX, TEXT_ALIGNMENT, TEXT_ALIGN_RIGHT);
|
|
GuiSetStyle(TEXTBOX, TEXT_PADDING, 4);
|
|
GuiSetStyle(TEXTBOX, TEXT_PADDING, 4);
|
|
@@ -4513,6 +4520,35 @@ const char **GetTextLines(const char *text, int *count)
|
|
return lines;
|
|
return lines;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// Get text width to next space for provided string
|
|
|
|
+static int GetNextSpaceWidth(const char *text, int nextSpaceIndex)
|
|
|
|
+{
|
|
|
|
+ int width = 0;
|
|
|
|
+ int codepointByteCount = 0;
|
|
|
|
+ int codepoint = 0;
|
|
|
|
+ int index = 0;
|
|
|
|
+ float glyphWidth = 0;
|
|
|
|
+ float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize;
|
|
|
|
+
|
|
|
|
+ for (int i = 0; text[i] != '\0'; i++)
|
|
|
|
+ {
|
|
|
|
+ if (text[i] != ' ')
|
|
|
|
+ {
|
|
|
|
+ codepoint = GetCodepoint(&text[i], &codepointByteCount);
|
|
|
|
+ index = GetGlyphIndex(guiFont, codepoint);
|
|
|
|
+ glyphWidth = (guiFont.glyphs[index].advanceX == 0)? guiFont.recs[index].width*scaleFactor : guiFont.glyphs[index].advanceX*scaleFactor;
|
|
|
|
+ width += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ nextSpaceIndex = i;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return width;
|
|
|
|
+}
|
|
|
|
+
|
|
// Gui draw text using default font
|
|
// Gui draw text using default font
|
|
static void GuiDrawText(const char *text, Rectangle bounds, int alignment, Color tint)
|
|
static void GuiDrawText(const char *text, Rectangle bounds, int alignment, Color tint)
|
|
{
|
|
{
|
|
@@ -4522,267 +4558,171 @@ static void GuiDrawText(const char *text, Rectangle bounds, int alignment, Color
|
|
#define ICON_TEXT_PADDING 4
|
|
#define ICON_TEXT_PADDING 4
|
|
#endif
|
|
#endif
|
|
|
|
|
|
- int wrapMode = GuiGetStyle(TEXTBOX, TEXT_WRAP_MODE);
|
|
|
|
- int alignmentVertical = GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT_VERTICAL);
|
|
|
|
|
|
+ if ((text == NULL) || (text[0] == '\0')) return; // Security check
|
|
|
|
|
|
- // We process the text lines one by one
|
|
|
|
- if ((text != NULL) && (text[0] != '\0'))
|
|
|
|
- {
|
|
|
|
- // Get text lines ('\n' delimiter) to process lines individually
|
|
|
|
- // NOTE: We can't use GuiTextSplit() because it can be already used before calling
|
|
|
|
- // GuiDrawText() and static buffer would be overriden :(
|
|
|
|
- int lineCount = 0;
|
|
|
|
- const char **lines = GetTextLines(text, &lineCount);
|
|
|
|
|
|
+ // PROCEDURE:
|
|
|
|
+ // - Text is processed line per line
|
|
|
|
+ // - For every line, horizontal alignment is defined
|
|
|
|
+ // - For all text, vertical alignment is defined (multiline text only)
|
|
|
|
+ // - For every line, wordwrap mode is checked (useful for GuitextBox(), read-only)
|
|
|
|
|
|
- //Rectangle textBounds = GetTextBounds(LABEL, bounds);
|
|
|
|
- float totalHeight = (float)(lineCount*GuiGetStyle(DEFAULT, TEXT_SIZE) + (lineCount - 1)*GuiGetStyle(DEFAULT, TEXT_SIZE)/2);
|
|
|
|
- float posOffsetY = 0;
|
|
|
|
|
|
+ // Get text lines (using '\n' as delimiter) to be processed individually
|
|
|
|
+ // WARNING: We can't use GuiTextSplit() function because it can be already used
|
|
|
|
+ // before the GuiDrawText() call and its buffer is static, it would be overriden :(
|
|
|
|
+ int lineCount = 0;
|
|
|
|
+ const char **lines = GetTextLines(text, &lineCount);
|
|
|
|
|
|
- for (int i = 0; i < lineCount; i++)
|
|
|
|
- {
|
|
|
|
- int iconId = 0;
|
|
|
|
- lines[i] = GetTextIcon(lines[i], &iconId); // Check text for icon and move cursor
|
|
|
|
|
|
+ // TextBox specific variables
|
|
|
|
+ int wrapMode = GuiGetStyle(TEXTBOX, TEXT_WRAP_MODE); // Wrap-mode only available in read-only mode, no for text editing
|
|
|
|
+ int alignmentVertical = GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT_VERTICAL);
|
|
|
|
+
|
|
|
|
+ // TODO: WARNING: This totalHeight is not valid for vertical alignment in case of word-wrap
|
|
|
|
+ float totalHeight = (float)(lineCount*GuiGetStyle(DEFAULT, TEXT_SIZE) + (lineCount - 1)*GuiGetStyle(DEFAULT, TEXT_SIZE)/2);
|
|
|
|
+ float posOffsetY = 0.0f;
|
|
|
|
|
|
- // Get text position depending on alignment and iconId
|
|
|
|
- //---------------------------------------------------------------------------------
|
|
|
|
- Vector2 boundsPos = { bounds.x, bounds.y };
|
|
|
|
|
|
+ for (int i = 0; i < lineCount; i++)
|
|
|
|
+ {
|
|
|
|
+ int iconId = 0;
|
|
|
|
+ lines[i] = GetTextIcon(lines[i], &iconId); // Check text for icon and move cursor
|
|
|
|
|
|
- // NOTE: We get text size after icon has been processed
|
|
|
|
- // WARNING: GetTextWidth() also processes text icon to get width! -> Really needed?
|
|
|
|
- int textSizeX = GetTextWidth(lines[i]);
|
|
|
|
|
|
+ // Get text position depending on alignment and iconId
|
|
|
|
+ //---------------------------------------------------------------------------------
|
|
|
|
+ Vector2 boundsPos = { bounds.x, bounds.y };
|
|
|
|
|
|
- // If text requires an icon, add size to measure
|
|
|
|
- if (iconId >= 0)
|
|
|
|
- {
|
|
|
|
- textSizeX += RAYGUI_ICON_SIZE*guiIconScale;
|
|
|
|
|
|
+ // NOTE: We get text size after icon has been processed
|
|
|
|
+ // WARNING: GetTextWidth() also processes text icon to get width! -> Really needed?
|
|
|
|
+ int textSizeX = GetTextWidth(lines[i]);
|
|
|
|
+
|
|
|
|
+ // If text requires an icon, add size to measure
|
|
|
|
+ if (iconId >= 0)
|
|
|
|
+ {
|
|
|
|
+ textSizeX += RAYGUI_ICON_SIZE*guiIconScale;
|
|
|
|
|
|
- // WARNING: If only icon provided, text could be pointing to EOF character: '\0'
|
|
|
|
|
|
+ // WARNING: If only icon provided, text could be pointing to EOF character: '\0'
|
|
#if !defined(RAYGUI_NO_ICONS)
|
|
#if !defined(RAYGUI_NO_ICONS)
|
|
- if ((lines[i] != NULL) && (lines[i][0] != '\0')) textSizeX += ICON_TEXT_PADDING;
|
|
|
|
|
|
+ if ((lines[i] != NULL) && (lines[i][0] != '\0')) textSizeX += ICON_TEXT_PADDING;
|
|
#endif
|
|
#endif
|
|
- }
|
|
|
|
|
|
+ }
|
|
|
|
|
|
- // Check guiTextAlign global variables
|
|
|
|
- switch (alignment)
|
|
|
|
- {
|
|
|
|
- case TEXT_ALIGN_LEFT: boundsPos.x = bounds.x; break;
|
|
|
|
- case TEXT_ALIGN_CENTER: boundsPos.x = bounds.x + bounds.width/2 - textSizeX/2; break;
|
|
|
|
- case TEXT_ALIGN_RIGHT: boundsPos.x = bounds.x + bounds.width - textSizeX; break;
|
|
|
|
- default: break;
|
|
|
|
- }
|
|
|
|
|
|
+ // Check guiTextAlign global variables
|
|
|
|
+ switch (alignment)
|
|
|
|
+ {
|
|
|
|
+ case TEXT_ALIGN_LEFT: boundsPos.x = bounds.x; break;
|
|
|
|
+ case TEXT_ALIGN_CENTER: boundsPos.x = bounds.x + bounds.width/2 - textSizeX/2; break;
|
|
|
|
+ case TEXT_ALIGN_RIGHT: boundsPos.x = bounds.x + bounds.width - textSizeX; break;
|
|
|
|
+ default: break;
|
|
|
|
+ }
|
|
|
|
|
|
- switch (alignmentVertical)
|
|
|
|
- {
|
|
|
|
- case 0: boundsPos.y = bounds.y + posOffsetY + bounds.height/2 - totalHeight/2 + TEXT_VALIGN_PIXEL_OFFSET(bounds.height); break; // CENTERED
|
|
|
|
- case 1: boundsPos.y = bounds.y + posOffsetY; break; // UP
|
|
|
|
- case 2: boundsPos.y = bounds.y + posOffsetY + bounds.height - totalHeight + TEXT_VALIGN_PIXEL_OFFSET(bounds.height); break; // DOWN
|
|
|
|
- default: break;
|
|
|
|
- }
|
|
|
|
|
|
+ switch (alignmentVertical)
|
|
|
|
+ {
|
|
|
|
+ // Only valid in case of wordWrap = 0;
|
|
|
|
+ case 0: boundsPos.y = bounds.y + posOffsetY + bounds.height/2 - totalHeight/2 + TEXT_VALIGN_PIXEL_OFFSET(bounds.height); break; // CENTERED
|
|
|
|
+ case 1: boundsPos.y = bounds.y + posOffsetY; break; // UP
|
|
|
|
+ case 2: boundsPos.y = bounds.y + posOffsetY + bounds.height - totalHeight + TEXT_VALIGN_PIXEL_OFFSET(bounds.height); break; // DOWN
|
|
|
|
+ default: break;
|
|
|
|
+ }
|
|
|
|
|
|
- // NOTE: Make sure we get pixel-perfect coordinates,
|
|
|
|
- // In case of decimals we got weird text positioning
|
|
|
|
- boundsPos.x = (float)((int)boundsPos.x);
|
|
|
|
- boundsPos.y = (float)((int)boundsPos.y);
|
|
|
|
- //---------------------------------------------------------------------------------
|
|
|
|
|
|
+ // NOTE: Make sure we get pixel-perfect coordinates,
|
|
|
|
+ // In case of decimals we got weird text positioning
|
|
|
|
+ boundsPos.x = (float)((int)boundsPos.x);
|
|
|
|
+ boundsPos.y = (float)((int)boundsPos.y);
|
|
|
|
+ //---------------------------------------------------------------------------------
|
|
|
|
|
|
- // Draw text (with icon if available)
|
|
|
|
- //---------------------------------------------------------------------------------
|
|
|
|
|
|
+ // Draw text (with icon if available)
|
|
|
|
+ //---------------------------------------------------------------------------------
|
|
#if !defined(RAYGUI_NO_ICONS)
|
|
#if !defined(RAYGUI_NO_ICONS)
|
|
- if (iconId >= 0)
|
|
|
|
- {
|
|
|
|
- // NOTE: We consider icon height, probably different than text size
|
|
|
|
- GuiDrawIcon(iconId, (int)boundsPos.x, (int)(bounds.y + bounds.height/2 - RAYGUI_ICON_SIZE*guiIconScale/2 + TEXT_VALIGN_PIXEL_OFFSET(bounds.height)), guiIconScale, tint);
|
|
|
|
- boundsPos.x += (RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING);
|
|
|
|
- }
|
|
|
|
|
|
+ if (iconId >= 0)
|
|
|
|
+ {
|
|
|
|
+ // NOTE: We consider icon height, probably different than text size
|
|
|
|
+ GuiDrawIcon(iconId, (int)boundsPos.x, (int)(bounds.y + bounds.height/2 - RAYGUI_ICON_SIZE*guiIconScale/2 + TEXT_VALIGN_PIXEL_OFFSET(bounds.height)), guiIconScale, tint);
|
|
|
|
+ boundsPos.x += (RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING);
|
|
|
|
+ }
|
|
#endif
|
|
#endif
|
|
- // Get size in bytes of text,
|
|
|
|
- // considering end of line and line break
|
|
|
|
- int lineSize = 0;
|
|
|
|
- for (int c = 0; (lines[i][c] != '\0') && (lines[i][c] != '\n'); c++, lineSize++){ }
|
|
|
|
- float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- // TODO: WARNING: For wordwrap, text must be measured from space to space before being drawn!
|
|
|
|
- int wrapModeState = 0; // 0-TEXT_MEASURING, 1-TEXT_DRAWING
|
|
|
|
-
|
|
|
|
- float textOffsetY = 0.0f; // Offset between wordwrap lines
|
|
|
|
- float textOffsetX = 0.0f; // Offset X to next character to draw
|
|
|
|
|
|
+ // Get size in bytes of text,
|
|
|
|
+ // considering end of line and line break
|
|
|
|
+ int lineSize = 0;
|
|
|
|
+ for (int c = 0; (lines[i][c] != '\0') && (lines[i][c] != '\n') && (lines[i][c] != '\r'); c++, lineSize++){ }
|
|
|
|
+ float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize;
|
|
|
|
+
|
|
|
|
+ int textOffsetY = 0;
|
|
|
|
+ float textOffsetX = 0.0f;
|
|
|
|
+ for (int c = 0, codepointSize = 0; c < lineSize; c += codepointSize)
|
|
|
|
+ {
|
|
|
|
+ int codepoint = GetCodepointNext(&lines[i][c], &codepointSize);
|
|
|
|
+ int index = GetGlyphIndex(guiFont, codepoint);
|
|
|
|
|
|
- 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
|
|
|
|
|
|
+ // 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) codepointSize = 1; // TODO: Review not recognized codepoints size
|
|
|
|
|
|
- for (int i = 0, k = 0; i < lineSize; i++, k++)
|
|
|
|
|
|
+ // Wrap mode text measuring to space to validate if it can be drawn or
|
|
|
|
+ // a new line is required
|
|
|
|
+ if (wrapMode == 1)
|
|
{
|
|
{
|
|
- // Get next codepoint from byte string and glyph index in font
|
|
|
|
- int codepointByteCount = 0;
|
|
|
|
- int codepoint = GetCodepoint(&text[i], &codepointByteCount);
|
|
|
|
- int index = GetGlyphIndex(guiFont, 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);
|
|
|
|
-
|
|
|
|
|
|
+ // Get glyph width to check if it goes out of bounds
|
|
float glyphWidth = 0;
|
|
float glyphWidth = 0;
|
|
- if (codepoint != '\n')
|
|
|
|
- {
|
|
|
|
- glyphWidth = (guiFont.glyphs[index].advanceX == 0)? guiFont.recs[index].width*scaleFactor : guiFont.glyphs[index].advanceX*scaleFactor;
|
|
|
|
-
|
|
|
|
- if (i + 1 < lineSize) glyphWidth = glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING);
|
|
|
|
- }
|
|
|
|
|
|
+ if (guiFont.glyphs[index].advanceX == 0) glyphWidth = ((float)guiFont.recs[index].width*scaleFactor);
|
|
|
|
+ else glyphWidth = (float)guiFont.glyphs[index].advanceX*scaleFactor;
|
|
|
|
|
|
- // 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 (wrapModeState == 0) // TEXT_MEASURING
|
|
|
|
|
|
+ // Jump to next line if current character reach end of the box limits
|
|
|
|
+ if ((textOffsetX + glyphWidth) > bounds.width)
|
|
{
|
|
{
|
|
- // 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) > bounds.width)
|
|
|
|
- {
|
|
|
|
- endLine = (endLine < 1)? i : endLine;
|
|
|
|
- if (i == endLine) endLine -= codepointByteCount;
|
|
|
|
- if ((startLine + codepointByteCount) == endLine) endLine = (i - codepointByteCount);
|
|
|
|
-
|
|
|
|
- wrapModeState = !wrapModeState;
|
|
|
|
- }
|
|
|
|
- else if ((i + 1) == lineSize)
|
|
|
|
- {
|
|
|
|
- endLine = i;
|
|
|
|
- wrapModeState = !wrapModeState;
|
|
|
|
- }
|
|
|
|
- //else if (codepoint == '\n') state = !state;
|
|
|
|
-
|
|
|
|
- if (wrapModeState == 1) // TEXT_DRAWING
|
|
|
|
- {
|
|
|
|
- textOffsetX = 0;
|
|
|
|
- i = startLine;
|
|
|
|
- glyphWidth = 0;
|
|
|
|
-
|
|
|
|
- // Save character position when we switch states
|
|
|
|
- int tmp = lastk;
|
|
|
|
- lastk = k - 1;
|
|
|
|
- k = tmp;
|
|
|
|
- }
|
|
|
|
|
|
+ textOffsetX = 0.0f;
|
|
|
|
+ textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING);
|
|
}
|
|
}
|
|
- else
|
|
|
|
- {
|
|
|
|
- if (codepoint == '\n')
|
|
|
|
- {
|
|
|
|
- if (wrapMode != 2) // WORD_WRAP
|
|
|
|
- {
|
|
|
|
- textOffsetY += (guiFont.baseSize + guiFont.baseSize/2)*scaleFactor;
|
|
|
|
- textOffsetX = 0;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- if ((wrapMode == 1) && ((textOffsetX + glyphWidth) > bounds.width)) // CHAR_WRAP
|
|
|
|
- {
|
|
|
|
- textOffsetY += (guiFont.baseSize + guiFont.baseSize/2)*scaleFactor;
|
|
|
|
- textOffsetX = 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // When text overflows rectangle height limit, just stop drawing
|
|
|
|
- if ((textOffsetY + guiFont.baseSize*scaleFactor) > bounds.height) break;
|
|
|
|
-
|
|
|
|
- // Draw text selected 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(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ boundsPos.x + textOffsetX, boundsPos.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), tint); // isGlyphSelected? selectTint : tint);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ }
|
|
|
|
+ else if (wrapMode == 2) // 2-WORD_WRAP
|
|
|
|
+ {
|
|
|
|
+ // Get width to next space in line
|
|
|
|
+ int nextSpaceIndex = 0;
|
|
|
|
+ int nextSpaceWidth = GetNextSpaceWidth(lines[i] + c, &nextSpaceIndex);
|
|
|
|
|
|
- if ((wrapMode == 2) && (i == endLine)) // WORD_WRAP
|
|
|
|
- {
|
|
|
|
- textOffsetY += (guiFont.baseSize + guiFont.baseSize/2)*scaleFactor;
|
|
|
|
- textOffsetX = 0;
|
|
|
|
- startLine = endLine;
|
|
|
|
- endLine = -1;
|
|
|
|
- glyphWidth = 0;
|
|
|
|
- //selectStart += lastk - k;
|
|
|
|
- k = lastk;
|
|
|
|
-
|
|
|
|
- wrapModeState = !wrapModeState;
|
|
|
|
- }
|
|
|
|
|
|
+ if ((textOffsetX + nextSpaceWidth) > bounds.width)
|
|
|
|
+ {
|
|
|
|
+ textOffsetX = 0.0f;
|
|
|
|
+ textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING);
|
|
}
|
|
}
|
|
|
|
|
|
- if ((textOffsetX != 0) || (codepoint != ' ')) textOffsetX += glyphWidth; // Avoid leading spaces
|
|
|
|
|
|
+ // TODO: Consider case: (nextSpaceWidth >= bounds.width)
|
|
}
|
|
}
|
|
- */
|
|
|
|
|
|
|
|
- int lastSpacePos = 0;
|
|
|
|
- int textOffsetY = 0;
|
|
|
|
- float textOffsetX = 0.0f;
|
|
|
|
- for (int c = 0, codepointSize = 0; c < lineSize; c += codepointSize)
|
|
|
|
|
|
+ if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint
|
|
|
|
+ else
|
|
{
|
|
{
|
|
- int codepoint = GetCodepointNext(&lines[i][c], &codepointSize);
|
|
|
|
- int index = GetGlyphIndex(guiFont, 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) codepointSize = 1;
|
|
|
|
-
|
|
|
|
- if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint
|
|
|
|
- else
|
|
|
|
|
|
+ // TODO: There are multiple types of spaces in Unicode,
|
|
|
|
+ // maybe it's a good idea to add support for more: http://jkorpela.fi/chars/spaces.html
|
|
|
|
+ if ((codepoint != ' ') && (codepoint != '\t')) // Do not draw codepoints with no glyph
|
|
{
|
|
{
|
|
- if ((codepoint != ' ') && (codepoint != '\t'))
|
|
|
|
|
|
+ if (wrapMode == 0) // 0-NO_WRAP
|
|
{
|
|
{
|
|
- if (wrapMode == 0) // 0-NO_WRAP
|
|
|
|
- {
|
|
|
|
- // Draw only required text glyphs fitting the bounds.width
|
|
|
|
- if (textOffsetX < (bounds.width - guiFont.recs[index].width))
|
|
|
|
- {
|
|
|
|
- DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ boundsPos.x + textOffsetX, boundsPos.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha));
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- else if (wrapMode == 1) // 1-CHAR_WRAP
|
|
|
|
|
|
+ // Draw only required text glyphs fitting the bounds.width
|
|
|
|
+ if (textOffsetX < (bounds.width - guiFont.recs[index].width))
|
|
{
|
|
{
|
|
- // Get glyph width to check if it goes out of bounds
|
|
|
|
- float glyphWidth = 0;
|
|
|
|
- if (guiFont.glyphs[index].advanceX == 0) glyphWidth = ((float)guiFont.recs[index].width*scaleFactor);
|
|
|
|
- else glyphWidth = (float)guiFont.glyphs[index].advanceX*scaleFactor;
|
|
|
|
-
|
|
|
|
- // Jump to next line if current character reach end of the box limits
|
|
|
|
- if ((boundsPos.x + textOffsetX + glyphWidth) > (bounds.x + bounds.width))
|
|
|
|
- {
|
|
|
|
- textOffsetX = 0.0f;
|
|
|
|
- textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING);
|
|
|
|
-
|
|
|
|
- DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ boundsPos.x + textOffsetX, boundsPos.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha));
|
|
|
|
- }
|
|
|
|
|
|
+ DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ boundsPos.x + textOffsetX, boundsPos.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha));
|
|
}
|
|
}
|
|
- else if (wrapMode == 2) // 2-WORD_WRAP
|
|
|
|
|
|
+ }
|
|
|
|
+ else if (wrapMode >= 1) // 2-WORD_WRAP
|
|
|
|
+ {
|
|
|
|
+ // Draw only glyphs inside the bounds
|
|
|
|
+ if ((boundsPos.y + textOffsetY) <= (bounds.y + bounds.height - GuiGetStyle(DEFAULT, TEXT_SIZE)))
|
|
{
|
|
{
|
|
- // TODO: Word wrap mode requires previously measured text to last space!
|
|
|
|
|
|
+ DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ boundsPos.x + textOffsetX, boundsPos.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- else lastSpacePos = c;
|
|
|
|
-
|
|
|
|
- if (guiFont.glyphs[index].advanceX == 0) textOffsetX += ((float)guiFont.recs[index].width*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
|
|
|
|
- else textOffsetX += ((float)guiFont.glyphs[index].advanceX*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
|
|
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
|
|
- posOffsetY += (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING);
|
|
|
|
- //---------------------------------------------------------------------------------
|
|
|
|
|
|
+ if (guiFont.glyphs[index].advanceX == 0) textOffsetX += ((float)guiFont.recs[index].width*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
|
|
|
|
+ else textOffsetX += ((float)guiFont.glyphs[index].advanceX*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ if (wrapMode == 0) posOffsetY += (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING);
|
|
|
|
+ else if (wrapMode >= 1) posOffsetY += (textOffsetY + (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING));
|
|
|
|
+ //---------------------------------------------------------------------------------
|
|
}
|
|
}
|
|
|
|
+
|
|
#if defined(RAYGUI_DEBUG_TEXT_BOUNDS)
|
|
#if defined(RAYGUI_DEBUG_TEXT_BOUNDS)
|
|
- GuiDrawRectangle(bounds, 0, WHITE, Fade(RED, 0.4f));
|
|
|
|
|
|
+ GuiDrawRectangle(bounds, 0, WHITE, Fade(BLUE, 0.4f));
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
@@ -4803,6 +4743,10 @@ static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor,
|
|
DrawRectangle((int)rec.x + (int)rec.width - borderWidth, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, GuiFade(borderColor, guiAlpha));
|
|
DrawRectangle((int)rec.x + (int)rec.width - borderWidth, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, GuiFade(borderColor, guiAlpha));
|
|
DrawRectangle((int)rec.x, (int)rec.y + (int)rec.height - borderWidth, (int)rec.width, borderWidth, GuiFade(borderColor, guiAlpha));
|
|
DrawRectangle((int)rec.x, (int)rec.y + (int)rec.height - borderWidth, (int)rec.width, borderWidth, GuiFade(borderColor, guiAlpha));
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+#if defined(RAYGUI_DEBUG_RECS_BOUNDS)
|
|
|
|
+ DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, Fade(RED, 0.4f));
|
|
|
|
+#endif
|
|
}
|
|
}
|
|
|
|
|
|
// Draw tooltip using control bounds
|
|
// Draw tooltip using control bounds
|