Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added DrawTextRecEx() #734

Merged
merged 1 commit into from
Feb 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/raylib.h
Original file line number Diff line number Diff line change
Expand Up @@ -1134,6 +1134,8 @@ RLAPI void DrawFPS(int posX, int posY);
RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font)
RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters
RLAPI void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint); // Draw text using font inside rectangle limits
RLAPI void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint,
int selectStart, int selectLength, Color selectText, Color selectBG); // Draw text using font inside rectangle limits with support for text selection

// Text misc. functions
RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font
Expand Down
134 changes: 76 additions & 58 deletions src/text.c
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,13 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f

// Draw text using font inside rectangle limits
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
void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint,
int selectStart, int selectLength, Color selectText, Color selectBG)
{
int length = strlen(text);
int textOffsetX = 0; // Offset between characters
Expand All @@ -792,12 +799,10 @@ void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, flo

scaleFactor = fontSize/font.baseSize;

enum { MEASURE_WORD = 0, DRAW_WORD = 1 };
int state = wordWrap ? MEASURE_WORD : DRAW_WORD;
int lastTextOffsetX = 0;
int wordStart = 0;

bool firstWord = true;
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)

for (int i = 0; i < length; i++)
{
Expand Down Expand Up @@ -827,77 +832,90 @@ void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, flo
(int)(font.chars[index].advanceX*scaleFactor + spacing);
}

// NOTE: When word wrap is active first we measure a `word`(measure until a ' ','\n','\t' is found)
// then set all the variables back to what they were before the measurement, change the state to
// draw that word then change the state again and repeat until the end of the string...when the word
// doesn't fit inside the rect we simple increase `textOffsetY` to draw it on the next line
if (state == MEASURE_WORD)
// 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 inside
// `startLine` and `endLine` then we change states, draw the text between those two
// variables then 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)
{
// Measuring state
if ((letter == ' ') || (letter == '\n') || (letter == '\t') || ((i + 1) == length))
if((letter == ' ') || (letter == '\t') || (letter == '\n')) endLine = i;

if(textOffsetX + glyphWidth + 1 >= rec.width)
{
int t = textOffsetX + glyphWidth;

if (textOffsetX+1>=rec.width)
{
textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
lastTextOffsetX = t - lastTextOffsetX;
textOffsetX = 0;
}
else
{
textOffsetX = lastTextOffsetX;
lastTextOffsetX = t;
}

endLine = (endLine < 1) ? i : endLine;
if(i == endLine) endLine -= 1;
if(startLine + 1 == endLine ) endLine = i - 1;
state = !state;
}
else if(i + 1 == length)
{
endLine = i;
state = !state;
}
else if(letter == '\n')
{
state = !state;
}

if(state == DRAW_STATE) {
textOffsetX = 0;
i = startLine;
glyphWidth = 0;
state = !state; // Change state
t = i;
i = firstWord?-1:wordStart;
wordStart = t;
}

}
else
{
// Drawing state
int t = textOffsetX + glyphWidth;

if (letter == '\n')
if (letter == '\n')
{
textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
lastTextOffsetX = t - lastTextOffsetX;
if (lastTextOffsetX < 0) lastTextOffsetX = 0;
textOffsetX = 0;
if(!wordWrap){
textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
textOffsetX = 0;
}
}
else if ((letter != ' ') && (letter != '\t'))
else
{
if ((t + 1) >= rec.width)
{
if(!wordWrap && textOffsetX + glyphWidth + 1 >= rec.width) {
textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
textOffsetX = 0;
}

if ((textOffsetY + (int)((font.baseSize + font.baseSize/2)*scaleFactor)) > rec.height) break;

DrawTexturePro(font.texture, font.chars[index].rec,
(Rectangle){ rec.x + textOffsetX + font.chars[index].offsetX*scaleFactor,
rec.y + textOffsetY + font.chars[index].offsetY*scaleFactor,
font.chars[index].rec.width*scaleFactor,
font.chars[index].rec.height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint);
}

if (wordWrap)
{
if ((letter == ' ') || (letter == '\n') || (letter == '\t'))
//draw selected
bool isGlyphSelected = false;
if(selectStart >= 0 && i >= selectStart && i < selectStart + selectLength) {
Rectangle strec = {rec.x + textOffsetX-1, rec.y + textOffsetY,
glyphWidth,(font.baseSize + font.baseSize/4)*scaleFactor};
DrawRectangleRec(strec, selectBG);
isGlyphSelected = true;
}

//draw glyph
if ((letter != ' ') && (letter != '\t'))
{
// After drawing a word change the state
firstWord = false;
i = wordStart;
textOffsetX = lastTextOffsetX;
glyphWidth = 0;
state = !state;
DrawTexturePro(font.texture, font.chars[index].rec,
(Rectangle){ rec.x + textOffsetX + font.chars[index].offsetX*scaleFactor,
rec.y + textOffsetY + font.chars[index].offsetY*scaleFactor,
font.chars[index].rec.width*scaleFactor,
font.chars[index].rec.height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f,
(!isGlyphSelected) ? tint : selectText);
}
}

if (wordWrap && i == endLine)
{
textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
textOffsetX = 0;
startLine = endLine;
endLine = -1;
glyphWidth = 0;
state = !state;
}
}

textOffsetX += glyphWidth;
Expand Down