mirror of
https://github.com/raysan5/raylib.git
synced 2025-09-14 15:28:14 +00:00
REXM: ADDED: example: text_inline_styling
This commit is contained in:
273
examples/text/text_inline_styling.c
Normal file
273
examples/text/text_inline_styling.c
Normal file
@@ -0,0 +1,273 @@
|
||||
/*******************************************************************************************
|
||||
*
|
||||
* raylib [text] example - inline styling
|
||||
*
|
||||
* Example complexity rating: [★★★☆] 3/4
|
||||
*
|
||||
* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
|
||||
*
|
||||
* Example contributed by Wagner Barongello (@SultansOfCode) and reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software
|
||||
*
|
||||
* Copyright (c) 2025 Wagner Barongello (@SultansOfCode) and Ramon Santamaria (@raysan5)
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
#include "raylib.h"
|
||||
|
||||
#include <stdlib.h> // Required for: strtoul(), NULL
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Declaration
|
||||
//----------------------------------------------------------------------------------
|
||||
static void DrawTextStyled(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color color);
|
||||
static Vector2 MeasureTextStyled(Font font, const char *text, float fontSize, float spacing);
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Program main entry point
|
||||
//------------------------------------------------------------------------------------
|
||||
int main(void)
|
||||
{
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
const int screenWidth = 800;
|
||||
const int screenHeight = 450;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raylib [text] example - inline styling");
|
||||
|
||||
Vector2 textSize = { 0 }; // Measure text box for provided font and text
|
||||
Color colRandom = RED; // Random color used on text
|
||||
int frameCounter = 0; // Used to generate a new random color every certain frames
|
||||
|
||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!WindowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
frameCounter++;
|
||||
|
||||
if ((frameCounter%20) == 0)
|
||||
{
|
||||
colRandom.r = (unsigned char)GetRandomValue(0, 255);
|
||||
colRandom.g = (unsigned char)GetRandomValue(0, 255);
|
||||
colRandom.b = (unsigned char)GetRandomValue(0, 255);
|
||||
colRandom.a = 255;
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
ClearBackground(RAYWHITE);
|
||||
|
||||
// Text inline styling strategy used: [ ] delimiters for format
|
||||
// - Define foreground color: [cRRGGBBAA]
|
||||
// - Define background color: [bRRGGBBAA]
|
||||
// - Reset formating: [r]
|
||||
// Example: [bAA00AAFF][cFF0000FF]red text on gray background[r] normal text
|
||||
|
||||
DrawTextStyled(GetFontDefault(), "This changes the [cFF0000FF]foreground color[r] of provided text!!!",
|
||||
(Vector2){ 100, 80 }, 20.0f, 2.0f, BLACK);
|
||||
|
||||
DrawTextStyled(GetFontDefault(), "This changes the [bFF00FFFF]background color[r] of provided text!!!",
|
||||
(Vector2){ 100, 120 }, 20.0f, 2.0f, BLACK);
|
||||
|
||||
DrawTextStyled(GetFontDefault(), "This changes the [c00ff00ff][bff0000ff]foreground and background colors[r]!!!",
|
||||
(Vector2){ 100, 160 }, 20.0f, 2.0f, BLACK);
|
||||
|
||||
// Get pointer to formated text
|
||||
const char *text = TextFormat("Let's be [c%02x%02x%02xFF]CREATIVE[r] !!!", colRandom.r, colRandom.g, colRandom.b);
|
||||
DrawTextStyled(GetFontDefault(), text, (Vector2){ 100, 220 }, 40.0f, 2.0f, BLACK);
|
||||
|
||||
textSize = MeasureTextStyled(GetFontDefault(), text, 40.0f, 2.0f);
|
||||
DrawRectangleLines(100, 220, textSize.x, textSize.y, GREEN);
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
// De-Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
// Draw text using inline styling
|
||||
// PARAM: color is the default text color, background color is BLANK by default
|
||||
static void DrawTextStyled(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color color)
|
||||
{
|
||||
// Text inline styling strategy used: [ ] delimiters for format
|
||||
// - Define foreground color: [cRRGGBBAA]
|
||||
// - Define background color: [bRRGGBBAA]
|
||||
// - Reset formating: [r]
|
||||
// Example: [bAA00AAFF][cFF0000FF]red text on gray background[r] normal text
|
||||
|
||||
if (font.texture.id == 0) font = GetFontDefault();
|
||||
|
||||
int textLen = TextLength(text);
|
||||
|
||||
Color colFront = color;
|
||||
Color colBack = BLANK;
|
||||
int backRecPadding = 4; // Background rectangle padding
|
||||
|
||||
float textOffsetY = 0.0f;
|
||||
float textOffsetX = 0.0f;
|
||||
float textLineSpacing = 0.0f;
|
||||
float scaleFactor = fontSize/font.baseSize;
|
||||
|
||||
for (int i = 0; i < textLen;)
|
||||
{
|
||||
int codepointByteCount = 0;
|
||||
int codepoint = GetCodepointNext(&text[i], &codepointByteCount);
|
||||
|
||||
if (codepoint == '\n')
|
||||
{
|
||||
textOffsetY += (fontSize + textLineSpacing);
|
||||
textOffsetX = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (codepoint == '[') // Process pipe styling
|
||||
{
|
||||
if (((i + 2) < textLen) && (text[i + 1] == 'r') && (text[i + 2] == ']')) // Reset styling
|
||||
{
|
||||
colFront = color;
|
||||
colBack = BLANK;
|
||||
|
||||
i += 3; // Skip "[r]"
|
||||
continue; // Do not draw characters
|
||||
}
|
||||
else if (((i + 1) < textLen) && ((text[i + 1] == 'c') || (text[i + 1] == 'b')))
|
||||
{
|
||||
i += 2; // Skip "[c" or "[b" to start parsing color
|
||||
|
||||
// Parse following color
|
||||
char colHexText[9] = { 0 };
|
||||
char *textPtr = &text[i]; // Color should start here, let's see...
|
||||
|
||||
int colHexCount = 0;
|
||||
while ((textPtr != NULL) && (textPtr[colHexCount] != '\0') && (textPtr[colHexCount] != ']'))
|
||||
{
|
||||
if (((textPtr[colHexCount] >= '0') && (textPtr[colHexCount] <= '9')) ||
|
||||
((textPtr[colHexCount] >= 'A') && (textPtr[colHexCount] <= 'F')) ||
|
||||
((textPtr[colHexCount] >= 'a') && (textPtr[colHexCount] <= 'f')))
|
||||
{
|
||||
colHexText[colHexCount] = textPtr[colHexCount];
|
||||
colHexCount++;
|
||||
}
|
||||
else break; // Only affects while loop
|
||||
}
|
||||
|
||||
// Convert hex color text into actual Color
|
||||
unsigned int colHexValue = strtoul(colHexText, NULL, 16);
|
||||
if (text[i - 1] == 'c') colFront = GetColor(colHexValue);
|
||||
else if (text[i - 1] == 'b') colBack = GetColor(colHexValue);
|
||||
|
||||
i += (colHexCount + 1); // Skip color value retrieved and ']'
|
||||
continue; // Do not draw characters
|
||||
}
|
||||
}
|
||||
|
||||
int index = GetGlyphIndex(font, codepoint);
|
||||
float increaseX = 0.0f;
|
||||
|
||||
if (font.glyphs[index].advanceX == 0) increaseX = ((float)font.recs[index].width*scaleFactor + spacing);
|
||||
else increaseX += ((float)font.glyphs[index].advanceX*scaleFactor + spacing);
|
||||
|
||||
// Draw background rectangle color (if required)
|
||||
if (colBack.a > 0) DrawRectangle(position.x + textOffsetX, position.y + textOffsetY - backRecPadding, increaseX, fontSize + 2*backRecPadding, colBack);
|
||||
|
||||
if ((codepoint != ' ') && (codepoint != '\t'))
|
||||
{
|
||||
DrawTextCodepoint(font, codepoint, (Vector2){ position.x + textOffsetX, position.y + textOffsetY }, fontSize, colFront);
|
||||
}
|
||||
|
||||
textOffsetX += increaseX;
|
||||
}
|
||||
|
||||
i += codepointByteCount;
|
||||
}
|
||||
}
|
||||
|
||||
// Measure inline styled text
|
||||
// NOTE: Measuring styled text requires skipping styling data
|
||||
// WARNING: Not considering line breaks
|
||||
static Vector2 MeasureTextStyled(Font font, const char *text, float fontSize, float spacing)
|
||||
{
|
||||
Vector2 textSize = { 0 };
|
||||
|
||||
if ((font.texture.id == 0) || (text == NULL) || (text[0] == '\0')) return textSize; // Security check
|
||||
|
||||
int textLen = TextLength(text); // Get size in bytes of text
|
||||
float textLineSpacing = fontSize*1.5f;
|
||||
|
||||
float textWidth = 0.0f;
|
||||
float textHeight = fontSize;
|
||||
float scaleFactor = fontSize/(float)font.baseSize;
|
||||
|
||||
int codepoint = 0; // Current character
|
||||
int index = 0; // Index position in sprite font
|
||||
int validCodepointCounter = 0;
|
||||
|
||||
for (int i = 0; i < textLen;)
|
||||
{
|
||||
int codepointByteCount = 0;
|
||||
codepoint = GetCodepointNext(&text[i], &codepointByteCount);
|
||||
|
||||
if (codepoint == '[') // Ignore pipe inline styling
|
||||
{
|
||||
if (((i + 2) < textLen) && (text[i + 1] == 'r') && (text[i + 2] == ']')) // Reset styling
|
||||
{
|
||||
i += 3; // Skip "[r]"
|
||||
continue; // Do not measure characters
|
||||
}
|
||||
else if (((i + 1) < textLen) && ((text[i + 1] == 'c') || (text[i + 1] == 'b')))
|
||||
{
|
||||
i += 2; // Skip "[c" or "[b" to start parsing color
|
||||
|
||||
char *textPtr = &text[i]; // Color should start here, let's see...
|
||||
|
||||
int colHexCount = 0;
|
||||
while ((textPtr != NULL) && (textPtr[colHexCount] != '\0') && (textPtr[colHexCount] != ']'))
|
||||
{
|
||||
if (((textPtr[colHexCount] >= '0') && (textPtr[colHexCount] <= '9')) ||
|
||||
((textPtr[colHexCount] >= 'A') && (textPtr[colHexCount] <= 'F')) ||
|
||||
((textPtr[colHexCount] >= 'a') && (textPtr[colHexCount] <= 'f')))
|
||||
{
|
||||
colHexCount++;
|
||||
}
|
||||
else break; // Only affects while loop
|
||||
}
|
||||
|
||||
i += (colHexCount + 1); // Skip color value retrieved and ']'
|
||||
continue; // Do not measure characters
|
||||
}
|
||||
}
|
||||
else if (codepoint != '\n')
|
||||
{
|
||||
index = GetGlyphIndex(font, codepoint);
|
||||
|
||||
if (font.glyphs[index].advanceX > 0) textWidth += font.glyphs[index].advanceX;
|
||||
else textWidth += (font.recs[index].width + font.glyphs[index].offsetX);
|
||||
|
||||
validCodepointCounter++;
|
||||
i += codepointByteCount;
|
||||
}
|
||||
}
|
||||
|
||||
textSize.x = textWidth*scaleFactor + (validCodepointCounter - 1)*spacing;
|
||||
textSize.y = textHeight;
|
||||
|
||||
return textSize;
|
||||
}
|
Reference in New Issue
Block a user