WARNING: REMOVED: DrawTextRec() and DrawTextRecEx()
- DrawTextRec() and DrawTextRecEx() have been moved to example, those functions could be very specific depending on user needs so it's better to give the user the full source in case of special requirements instead of allowing a function with +10 input parameters.
This commit is contained in:
parent
0ba49cce45
commit
5a259fa10f
4 changed files with 290 additions and 136 deletions
|
@ -13,6 +13,10 @@
|
|||
|
||||
#include "raylib.h"
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
// Main entry point
|
||||
int main(void)
|
||||
{
|
||||
// Initialization
|
||||
|
@ -119,4 +123,144 @@ tempor incididunt ut labore et dolore magna aliqua. Nec ullamcorper sit amet ris
|
|||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Module functions definition
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// 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.chars[index].advanceX == 0) ? font.recs[index].width*scaleFactor : font.chars[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;
|
||||
}
|
||||
}
|
|
@ -133,6 +133,9 @@ struct {
|
|||
//--------------------------------------------------------------------------------------
|
||||
static void RandomizeEmoji(void); // Fills the emoji array with random emojis
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Global variables
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
@ -145,6 +148,9 @@ struct {
|
|||
|
||||
static int hovered = -1, selected = -1;
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Main entry point
|
||||
//--------------------------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
// Initialization
|
||||
|
@ -317,3 +323,143 @@ static void RandomizeEmoji(void)
|
|||
emoji[i].message = GetRandomValue(0, SIZEOF(messages) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Module functions definition
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// 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.chars[index].advanceX == 0) ? font.recs[index].width*scaleFactor : font.chars[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;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue