5 Commits

Author SHA1 Message Date
b256d4552b Standardize the internal icon logic (#553)
Replaced all #{icon_id}# strings with GuiIconText() using the hard coded enum values

I also noticed that the eye on/off icons in GuiTextInputBox() were not guarded by RAYGUI_NO_ICONS, so I updated them to be properly guarded as well. For now, I just used 'O' and '*' for the eye on/off as placeholders.
2026-05-17 22:12:23 +02:00
36b79b7e14 Avoid overrunning the 256 icon memory buffer (#491)
* Avoid overrunning the 256 icon memory buffer

* Set maximum icons rendered to the fixed value of RAYGUI_ICON_MAX_ICONS

* Correct GuiGetTextWidth() for icons with id >255

---------

Co-authored-by: segcore <segcore@github.com>
2026-05-17 21:11:38 +02:00
4fbd4253cc feat: expose GuiLoadStyleFromMemory() (#549) 2026-05-17 21:00:27 +02:00
Ray
669c88fe71 REVIEWED: Examples, noted that latest raylib and raygui mist be used #536 2026-05-17 20:55:24 +02:00
Ray
f4a124239a Update raygui.h 2026-05-17 20:54:54 +02:00
12 changed files with 292 additions and 277 deletions

View File

@ -3,15 +3,15 @@
* Animation curves - An example demo for animation curves
*
* DEPENDENCIES:
* raylib 4.0 - Windowing/input management and drawing.
* raygui 3.0 - Immediate-mode GUI controls.
* raylib 6.1-dev - Windowing/input management and drawing
* raygui 5.0-dev - Immediate-mode GUI controls with custom styling and icons
*
* COMPILATION (Windows - MinGW):
* gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2023 Pierre Jaffuer (@smallcluster)
* Copyright (c) 2023-2026 Pierre Jaffuer (@smallcluster) and Ramon Santamaria (@raysan5)
*
**********************************************************************************************/

View File

@ -21,15 +21,15 @@
*
*
* DEPENDENCIES:
* raylib 4.5 - Windowing/input management and drawing
* raygui 3.5 - Immediate-mode GUI controls with custom styling and icons
* raylib 6.1-dev - Windowing/input management and drawing
* raygui 5.0-dev - Immediate-mode GUI controls with custom styling and icons
*
* COMPILATION (Windows - MinGW):
* gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2016-2024 Ramon Santamaria (@raysan5)
* Copyright (c) 2016-2026 Ramon Santamaria (@raysan5)
*
**********************************************************************************************/
@ -253,7 +253,7 @@ int main()
// Second GUI column
//GuiSetStyle(LISTVIEW, LIST_ITEMS_BORDER_NORMAL, 1);
GuiListView((Rectangle){ 165, 25, 140, 124 }, "Charmander;Bulbasaur;#18#Squirtel;Pikachu;Eevee;Pidgey", &listViewScrollIndex, &listViewActive);
GuiListView((Rectangle){ 165, 25, 140, 124 }, "Charmander;Bulbasaur;#18#Squirtle;Pikachu;Eevee;Pidgey", &listViewScrollIndex, &listViewActive);
GuiListViewEx((Rectangle){ 165, 162, 140, 184 }, listViewExList, 8, &listViewExScrollIndex, &listViewExActive, &listViewExFocus);
GuiSetStyle(LISTVIEW, LIST_ITEMS_BORDER_NORMAL, 0);

View File

@ -3,15 +3,15 @@
* raygui - custom file dialog to load image
*
* DEPENDENCIES:
* raylib 4.0 - Windowing/input management and drawing.
* raygui 3.0 - Immediate-mode GUI controls.
* raylib 6.1-dev - Windowing/input management and drawing
* raygui 5.0-dev - Immediate-mode GUI controls with custom styling and icons
*
* COMPILATION (Windows - MinGW):
* gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2016-2024 Ramon Santamaria (@raysan5)
* Copyright (c) 2016-2026 Ramon Santamaria (@raysan5)
*
**********************************************************************************************/

View File

@ -18,7 +18,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2019-2024 Ramon Santamaria (@raysan5)
* Copyright (c) 2019-2026 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@ -427,7 +427,7 @@ static void ReloadDirectoryFiles(GuiWindowFileDialogState *state)
{
UnloadDirectoryFiles(state->dirFiles);
state->dirFiles = LoadDirectoryFilesEx(state->dirPathText, (state->filterExt[0] == '\0')? NULL : state->filterExt, false);
state->dirFiles = LoadDirectoryFilesEx(state->dirPathText, (state->filterExt[0] == '\0')? "*.*" : TextFormat("DIRS*;%s", state->filterExt), false);
state->itemFocused = 0;
// Reset dirFilesIcon memory

View File

@ -3,15 +3,15 @@
* raygui - image exporter
*
* DEPENDENCIES:
* raylib 4.0 - Windowing/input management and drawing.
* raygui 3.0 - Immediate-mode GUI controls.
* raylib 6.1-dev - Windowing/input management and drawing
* raygui 5.0-dev - Immediate-mode GUI controls with custom styling and icons
*
* COMPILATION (Windows - MinGW):
* gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2015-2024 Ramon Santamaria (@raysan5)
* Copyright (c) 2015-2026 Ramon Santamaria (@raysan5)
*
********************************************************************************************/

View File

@ -3,15 +3,15 @@
* raygui - image raw importer
*
* DEPENDENCIES:
* raylib 4.0 - Windowing/input management and drawing.
* raygui 3.0 - Immediate-mode GUI controls.
* raylib 6.1-dev - Windowing/input management and drawing
* raygui 5.0-dev - Immediate-mode GUI controls with custom styling and icons
*
* COMPILATION (Windows - MinGW):
* gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2015-2024 Ramon Santamaria (@raysan5)
* Copyright (c) 2015-2026 Ramon Santamaria (@raysan5)
*
**********************************************************************************************/

View File

@ -3,15 +3,15 @@
* raygui - portable window
*
* DEPENDENCIES:
* raylib 4.0 - Windowing/input management and drawing.
* raygui 3.0 - Immediate-mode GUI controls.
* raylib 6.1-dev - Windowing/input management and drawing
* raygui 5.0-dev - Immediate-mode GUI controls with custom styling and icons
*
* COMPILATION (Windows - MinGW):
* gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2016-2024 Ramon Santamaria (@raysan5)
* Copyright (c) 2016-2026 Ramon Santamaria (@raysan5)
*
**********************************************************************************************/

View File

@ -3,15 +3,15 @@
* raygui - custom property list control
*
* DEPENDENCIES:
* raylib 4.0 - Windowing/input management and drawing.
* raygui 3.0 - Immediate-mode GUI controls.
* raylib 6.1-dev - Windowing/input management and drawing
* raygui 5.0-dev - Immediate-mode GUI controls with custom styling and icons
*
* COMPILATION (Windows - MinGW):
* gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2020-2024 Vlad Adrian (@Demizdor) and Ramon Santamaria (@raysan5)
* Copyright (c) 2020-2026 Vlad Adrian (@Demizdor) and Ramon Santamaria (@raysan5)
*
**********************************************************************************************/

View File

@ -6,8 +6,8 @@
* - GuiScrollPanel()
*
* DEPENDENCIES:
* raylib 4.0 - Windowing/input management and drawing.
* raygui 3.0 - Immediate-mode GUI controls.
* raylib 6.1-dev - Windowing/input management and drawing
* raygui 5.0-dev - Immediate-mode GUI controls with custom styling and icons
*
* COMPILATION (Windows - MinGW):
* gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99
@ -17,7 +17,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2019-2024 Vlad Adrian (@Demizdor) and Ramon Santamaria (@raysan5)
* Copyright (c) 2019-2026 Vlad Adrian (@Demizdor) and Ramon Santamaria (@raysan5)
*
**********************************************************************************************/

View File

@ -3,15 +3,15 @@
* raygui - style selector
*
* DEPENDENCIES:
* raylib 4.5 - Windowing/input management and drawing
* raygui 3.5 - Immediate-mode GUI controls with custom styling and icons
* raylib 6.1-dev - Windowing/input management and drawing
* raygui 5.0-dev - Immediate-mode GUI controls with custom styling and icons
*
* COMPILATION (Windows - MinGW):
* gcc -o $(NAME_PART).exe $(FILE_NAME) -I../../src -lraylib -lopengl32 -lgdi32 -std=c99
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2016-2024 Ramon Santamaria (@raysan5)
* Copyright (c) 2016-2026 Ramon Santamaria (@raysan5)
*
**********************************************************************************************/

View File

@ -23,5 +23,5 @@ i Int Range 0 32 0 100 1
r Rect 0 0 0 100 200
v2 Vec2 0 20.000000 20.000000
v3 Vec3 0 12.000000 13.000000 14.000000
v4 Vec4 0 14.000000 13.000000 14.000000 15.000000
v4 Vec4 0 12.000000 13.000000 14.000000 15.000000
c Color 0 0 255 0 255

View File

@ -1,6 +1,6 @@
/*******************************************************************************************
*
* raygui v5.0 - A simple and easy-to-use immediate-mode gui library
* raygui v5.0-dev - A simple and easy-to-use immediate-mode gui library
*
* DESCRIPTION:
* raygui is a tools-dev-focused immediate-mode-gui library based on raylib but also
@ -141,7 +141,8 @@
* Draw text bounds rectangles for debug
*
* VERSIONS HISTORY:
* 5.0 (xx-Mar-2026) ADDED: Support up to 32 controls (v500)
* 5.0 (xx-May-2026) ADDED: Support up to 32 controls (v500)
* ADDED: Support up to 512 icons (v500)
* ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes
* ADDED: GuiValueBoxFloat()
* ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP
@ -340,8 +341,8 @@
#ifndef RAYGUI_H
#define RAYGUI_H
#define RAYGUI_VERSION_MAJOR 4
#define RAYGUI_VERSION_MINOR 5
#define RAYGUI_VERSION_MAJOR 5
#define RAYGUI_VERSION_MINOR 0
#define RAYGUI_VERSION_PATCH 0
#define RAYGUI_VERSION "5.0-dev"
@ -559,6 +560,7 @@ typedef enum {
} GuiTextWrapMode;
// Gui controls
// NOTE: Up to 16 controls supported or 32 controls (v500)
typedef enum {
// Default -> populates to all controls when set
DEFAULT = 0,
@ -579,6 +581,7 @@ typedef enum {
COLORPICKER,
SCROLLBAR,
STATUSBAR
// NOTE: More controls can be added if required
} GuiControl;
// Gui base properties for every control
@ -753,6 +756,7 @@ RAYGUIAPI int GuiGetStyle(int control, int property); // Get one style
// Styles loading functions
RAYGUIAPI void GuiLoadStyle(const char *fileName); // Load style file over global style variable (.rgs)
RAYGUIAPI void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only)
RAYGUIAPI void GuiLoadStyleDefault(void); // Load style default over global style
// Tooltips management functions
@ -1548,8 +1552,6 @@ static void DrawRectangleGradientV(int posX, int posY, int width, int height, Co
//----------------------------------------------------------------------------------
// Module Internal Functions Declaration
//----------------------------------------------------------------------------------
static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only)
static Rectangle GetTextBounds(int control, Rectangle bounds); // Get text bounds considering control bounds
static const char *GetTextIcon(const char *text, int *iconId); // Get text icon if provided and move text cursor
@ -1792,7 +1794,9 @@ int GuiPanel(Rectangle bounds, const char *text)
// NOTE: Using GuiToggle() for the TABS
int GuiTabBar(Rectangle bounds, char **text, int count, int *active)
{
#if !defined(RAYGUI_TABBAR_ITEM_WIDTH)
#define RAYGUI_TABBAR_ITEM_WIDTH 148
#endif
int result = -1;
//GuiState state = guiState;
@ -1803,7 +1807,7 @@ int GuiTabBar(Rectangle bounds, char **text, int count, int *active)
else if (*active > count - 1) *active = count - 1;
int offsetX = 0; // Required in case tabs go out of screen
offsetX = (*active + 2)*RAYGUI_TABBAR_ITEM_WIDTH - GetScreenWidth();
offsetX = (*active*RAYGUI_TABBAR_ITEM_WIDTH) - GetScreenWidth();
if (offsetX < 0) offsetX = 0;
bool toggle = false; // Required for individual toggles
@ -1812,7 +1816,7 @@ int GuiTabBar(Rectangle bounds, char **text, int count, int *active)
//--------------------------------------------------------------------
for (int i = 0; i < count; i++)
{
tabBounds.x = bounds.x + (RAYGUI_TABBAR_ITEM_WIDTH + 4)*i - offsetX;
tabBounds.x = bounds.x + (RAYGUI_TABBAR_ITEM_WIDTH + 4)*i + offsetX;
if (tabBounds.x < GetScreenWidth())
{
@ -2529,7 +2533,8 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod
GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 },
TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))));
#else
GuiDrawText(direction? "#121#" : "#120#", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 },
GuiDrawText(direction? GuiIconText(ICON_ARROW_UP_FILL, NULL) : GuiIconText(ICON_ARROW_DOWN_FILL, NULL),
RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 },
TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); // ICON_ARROW_DOWN_FILL
#endif
}
@ -4262,7 +4267,13 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co
if (GuiTextBox(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x, textBoxBounds.y, textBoxBounds.width - 4 - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.height },
((*secretViewActive == 1) || textEditMode)? text : stars, textMaxSize, textEditMode)) textEditMode = !textEditMode;
GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, (*secretViewActive == 1)? "#44#" : "#45#", secretViewActive);
#if defined(RAYGUI_NO_ICONS)
GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT },
(*secretViewActive == 1)? "O" : "*", secretViewActive);
#else
GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT },
(*secretViewActive == 1)? GuiIconText(ICON_EYE_ON, NULL) : GuiIconText(ICON_EYE_OFF, NULL), secretViewActive);
#endif
}
else
{
@ -4485,6 +4496,228 @@ void GuiLoadStyle(const char *fileName)
}
}
// Load style from memory
// WARNING: Binary files only
void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
{
unsigned char *fileDataPtr = (unsigned char *)fileData;
char signature[5] = { 0 };
short version = 0;
short reserved = 0;
int propertyCount = 0;
memcpy(signature, fileDataPtr, 4);
memcpy(&version, fileDataPtr + 4, sizeof(short));
memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short));
memcpy(&propertyCount, fileDataPtr + 4 + 2 + 2, sizeof(int));
fileDataPtr += 12;
if ((signature[0] == 'r') &&
(signature[1] == 'G') &&
(signature[2] == 'S') &&
(signature[3] == ' '))
{
short controlId = 0;
short propertyId = 0;
unsigned int propertyValue = 0;
for (int i = 0; i < propertyCount; i++)
{
memcpy(&controlId, fileDataPtr, sizeof(short));
memcpy(&propertyId, fileDataPtr + 2, sizeof(short));
memcpy(&propertyValue, fileDataPtr + 2 + 2, sizeof(unsigned int));
fileDataPtr += 8;
if (controlId == 0) // DEFAULT control
{
// If a DEFAULT property is loaded, it is propagated to all controls
// NOTE: All DEFAULT properties should be defined first in the file
GuiSetStyle(0, (int)propertyId, propertyValue);
if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int j = 1; j < RAYGUI_MAX_CONTROLS; j++) GuiSetStyle(j, (int)propertyId, propertyValue);
}
else GuiSetStyle((int)controlId, (int)propertyId, propertyValue);
}
// Font loading is highly dependant on raylib API to load font data and image
#if !defined(RAYGUI_STANDALONE)
// Load custom font if available
int fontDataSize = 0;
memcpy(&fontDataSize, fileDataPtr, sizeof(int));
fileDataPtr += 4;
if (fontDataSize > 0)
{
Font font = { 0 };
int fontType = 0; // 0-Normal, 1-SDF
memcpy(&font.baseSize, fileDataPtr, sizeof(int));
memcpy(&font.glyphCount, fileDataPtr + 4, sizeof(int));
memcpy(&fontType, fileDataPtr + 4 + 4, sizeof(int));
fileDataPtr += 12;
// Load font white rectangle
Rectangle fontWhiteRec = { 0 };
memcpy(&fontWhiteRec, fileDataPtr, sizeof(Rectangle));
fileDataPtr += 16;
// Load font image parameters
int fontImageUncompSize = 0;
int fontImageCompSize = 0;
memcpy(&fontImageUncompSize, fileDataPtr, sizeof(int));
memcpy(&fontImageCompSize, fileDataPtr + 4, sizeof(int));
fileDataPtr += 8;
Image imFont = { 0 };
imFont.mipmaps = 1;
memcpy(&imFont.width, fileDataPtr, sizeof(int));
memcpy(&imFont.height, fileDataPtr + 4, sizeof(int));
memcpy(&imFont.format, fileDataPtr + 4 + 4, sizeof(int));
fileDataPtr += 12;
if ((fontImageCompSize > 0) && (fontImageCompSize != fontImageUncompSize))
{
// Compressed font atlas image data (DEFLATE), it requires DecompressData()
int dataUncompSize = 0;
unsigned char *compData = (unsigned char *)RAYGUI_CALLOC(fontImageCompSize, sizeof(unsigned char));
memcpy(compData, fileDataPtr, fontImageCompSize);
fileDataPtr += fontImageCompSize;
imFont.data = DecompressData(compData, fontImageCompSize, &dataUncompSize);
// Security check, dataUncompSize must match the provided fontImageUncompSize
if (dataUncompSize != fontImageUncompSize) RAYGUI_LOG("WARNING: Uncompressed font atlas image data could be corrupted");
RAYGUI_FREE(compData);
}
else
{
// Font atlas image data is not compressed
imFont.data = (unsigned char *)RAYGUI_CALLOC(fontImageUncompSize, sizeof(unsigned char));
memcpy(imFont.data, fileDataPtr, fontImageUncompSize);
fileDataPtr += fontImageUncompSize;
}
if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture);
font.texture = LoadTextureFromImage(imFont);
RAYGUI_FREE(imFont.data);
// Validate font atlas texture was loaded correctly
if (font.texture.id != 0)
{
// Load font recs data
int recsDataSize = font.glyphCount*sizeof(Rectangle);
int recsDataCompressedSize = 0;
// WARNING: Version 400 adds the compression size parameter
if (version >= 400)
{
// RGS files version 400 support compressed recs data
memcpy(&recsDataCompressedSize, fileDataPtr, sizeof(int));
fileDataPtr += sizeof(int);
}
if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize))
{
// Recs data is compressed, uncompress it
unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_CALLOC(recsDataCompressedSize, sizeof(unsigned char));
memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize);
fileDataPtr += recsDataCompressedSize;
int recsDataUncompSize = 0;
font.recs = (Rectangle *)DecompressData(recsDataCompressed, recsDataCompressedSize, &recsDataUncompSize);
// Security check, data uncompressed size must match the expected original data size
if (recsDataUncompSize != recsDataSize) RAYGUI_LOG("WARNING: Uncompressed font recs data could be corrupted");
RAYGUI_FREE(recsDataCompressed);
}
else
{
// Recs data is uncompressed
font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
for (int i = 0; i < font.glyphCount; i++)
{
memcpy(&font.recs[i], fileDataPtr, sizeof(Rectangle));
fileDataPtr += sizeof(Rectangle);
}
}
// Load font glyphs info data
int glyphsDataSize = font.glyphCount*16; // 16 bytes data per glyph
int glyphsDataCompressedSize = 0;
// WARNING: Version 400 adds the compression size parameter
if (version >= 400)
{
// RGS files version 400 support compressed glyphs data
memcpy(&glyphsDataCompressedSize, fileDataPtr, sizeof(int));
fileDataPtr += sizeof(int);
}
// Allocate required glyphs space to fill with data
font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize))
{
// Glyphs data is compressed, uncompress it
unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_CALLOC(glyphsDataCompressedSize, sizeof(unsigned char));
memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize);
fileDataPtr += glyphsDataCompressedSize;
int glyphsDataUncompSize = 0;
unsigned char *glyphsDataUncomp = DecompressData(glypsDataCompressed, glyphsDataCompressedSize, &glyphsDataUncompSize);
// Security check, data uncompressed size must match the expected original data size
if (glyphsDataUncompSize != glyphsDataSize) RAYGUI_LOG("WARNING: Uncompressed font glyphs data could be corrupted");
unsigned char *glyphsDataUncompPtr = glyphsDataUncomp;
for (int i = 0; i < font.glyphCount; i++)
{
memcpy(&font.glyphs[i].value, glyphsDataUncompPtr, sizeof(int));
memcpy(&font.glyphs[i].offsetX, glyphsDataUncompPtr + 4, sizeof(int));
memcpy(&font.glyphs[i].offsetY, glyphsDataUncompPtr + 8, sizeof(int));
memcpy(&font.glyphs[i].advanceX, glyphsDataUncompPtr + 12, sizeof(int));
glyphsDataUncompPtr += 16;
}
RAYGUI_FREE(glypsDataCompressed);
RAYGUI_FREE(glyphsDataUncomp);
}
else
{
// Glyphs data is uncompressed
for (int i = 0; i < font.glyphCount; i++)
{
memcpy(&font.glyphs[i].value, fileDataPtr, sizeof(int));
memcpy(&font.glyphs[i].offsetX, fileDataPtr + 4, sizeof(int));
memcpy(&font.glyphs[i].offsetY, fileDataPtr + 8, sizeof(int));
memcpy(&font.glyphs[i].advanceX, fileDataPtr + 12, sizeof(int));
fileDataPtr += 16;
}
}
}
else font = GetFontDefault(); // Fallback in case of errors loading font atlas texture
GuiSetFont(font);
// Set font texture source rectangle to be used as white texture to draw shapes
// NOTE: It makes possible to draw shapes and text (full UI) in a single draw call
if ((fontWhiteRec.x > 0) &&
(fontWhiteRec.y > 0) &&
(fontWhiteRec.width > 0) &&
(fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec);
}
#endif
}
}
// Load style default over global style
void GuiLoadStyleDefault(void)
{
@ -4794,7 +5027,7 @@ int GuiGetTextWidth(const char *text)
{
if (text[i] == '#')
{
textIconOffset = i;
if(TextToInteger(&text[1]) < RAYGUI_ICON_MAX_ICONS) textIconOffset = i;
break;
}
}
@ -4843,228 +5076,6 @@ int GuiGetTextWidth(const char *text)
//----------------------------------------------------------------------------------
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
// Load style from memory
// WARNING: Binary files only
static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
{
unsigned char *fileDataPtr = (unsigned char *)fileData;
char signature[5] = { 0 };
short version = 0;
short reserved = 0;
int propertyCount = 0;
memcpy(signature, fileDataPtr, 4);
memcpy(&version, fileDataPtr + 4, sizeof(short));
memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short));
memcpy(&propertyCount, fileDataPtr + 4 + 2 + 2, sizeof(int));
fileDataPtr += 12;
if ((signature[0] == 'r') &&
(signature[1] == 'G') &&
(signature[2] == 'S') &&
(signature[3] == ' '))
{
short controlId = 0;
short propertyId = 0;
unsigned int propertyValue = 0;
for (int i = 0; i < propertyCount; i++)
{
memcpy(&controlId, fileDataPtr, sizeof(short));
memcpy(&propertyId, fileDataPtr + 2, sizeof(short));
memcpy(&propertyValue, fileDataPtr + 2 + 2, sizeof(unsigned int));
fileDataPtr += 8;
if (controlId == 0) // DEFAULT control
{
// If a DEFAULT property is loaded, it is propagated to all controls
// NOTE: All DEFAULT properties should be defined first in the file
GuiSetStyle(0, (int)propertyId, propertyValue);
if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int j = 1; j < RAYGUI_MAX_CONTROLS; j++) GuiSetStyle(j, (int)propertyId, propertyValue);
}
else GuiSetStyle((int)controlId, (int)propertyId, propertyValue);
}
// Font loading is highly dependant on raylib API to load font data and image
#if !defined(RAYGUI_STANDALONE)
// Load custom font if available
int fontDataSize = 0;
memcpy(&fontDataSize, fileDataPtr, sizeof(int));
fileDataPtr += 4;
if (fontDataSize > 0)
{
Font font = { 0 };
int fontType = 0; // 0-Normal, 1-SDF
memcpy(&font.baseSize, fileDataPtr, sizeof(int));
memcpy(&font.glyphCount, fileDataPtr + 4, sizeof(int));
memcpy(&fontType, fileDataPtr + 4 + 4, sizeof(int));
fileDataPtr += 12;
// Load font white rectangle
Rectangle fontWhiteRec = { 0 };
memcpy(&fontWhiteRec, fileDataPtr, sizeof(Rectangle));
fileDataPtr += 16;
// Load font image parameters
int fontImageUncompSize = 0;
int fontImageCompSize = 0;
memcpy(&fontImageUncompSize, fileDataPtr, sizeof(int));
memcpy(&fontImageCompSize, fileDataPtr + 4, sizeof(int));
fileDataPtr += 8;
Image imFont = { 0 };
imFont.mipmaps = 1;
memcpy(&imFont.width, fileDataPtr, sizeof(int));
memcpy(&imFont.height, fileDataPtr + 4, sizeof(int));
memcpy(&imFont.format, fileDataPtr + 4 + 4, sizeof(int));
fileDataPtr += 12;
if ((fontImageCompSize > 0) && (fontImageCompSize != fontImageUncompSize))
{
// Compressed font atlas image data (DEFLATE), it requires DecompressData()
int dataUncompSize = 0;
unsigned char *compData = (unsigned char *)RAYGUI_CALLOC(fontImageCompSize, sizeof(unsigned char));
memcpy(compData, fileDataPtr, fontImageCompSize);
fileDataPtr += fontImageCompSize;
imFont.data = DecompressData(compData, fontImageCompSize, &dataUncompSize);
// Security check, dataUncompSize must match the provided fontImageUncompSize
if (dataUncompSize != fontImageUncompSize) RAYGUI_LOG("WARNING: Uncompressed font atlas image data could be corrupted");
RAYGUI_FREE(compData);
}
else
{
// Font atlas image data is not compressed
imFont.data = (unsigned char *)RAYGUI_CALLOC(fontImageUncompSize, sizeof(unsigned char));
memcpy(imFont.data, fileDataPtr, fontImageUncompSize);
fileDataPtr += fontImageUncompSize;
}
if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture);
font.texture = LoadTextureFromImage(imFont);
RAYGUI_FREE(imFont.data);
// Validate font atlas texture was loaded correctly
if (font.texture.id != 0)
{
// Load font recs data
int recsDataSize = font.glyphCount*sizeof(Rectangle);
int recsDataCompressedSize = 0;
// WARNING: Version 400 adds the compression size parameter
if (version >= 400)
{
// RGS files version 400 support compressed recs data
memcpy(&recsDataCompressedSize, fileDataPtr, sizeof(int));
fileDataPtr += sizeof(int);
}
if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize))
{
// Recs data is compressed, uncompress it
unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_CALLOC(recsDataCompressedSize, sizeof(unsigned char));
memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize);
fileDataPtr += recsDataCompressedSize;
int recsDataUncompSize = 0;
font.recs = (Rectangle *)DecompressData(recsDataCompressed, recsDataCompressedSize, &recsDataUncompSize);
// Security check, data uncompressed size must match the expected original data size
if (recsDataUncompSize != recsDataSize) RAYGUI_LOG("WARNING: Uncompressed font recs data could be corrupted");
RAYGUI_FREE(recsDataCompressed);
}
else
{
// Recs data is uncompressed
font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
for (int i = 0; i < font.glyphCount; i++)
{
memcpy(&font.recs[i], fileDataPtr, sizeof(Rectangle));
fileDataPtr += sizeof(Rectangle);
}
}
// Load font glyphs info data
int glyphsDataSize = font.glyphCount*16; // 16 bytes data per glyph
int glyphsDataCompressedSize = 0;
// WARNING: Version 400 adds the compression size parameter
if (version >= 400)
{
// RGS files version 400 support compressed glyphs data
memcpy(&glyphsDataCompressedSize, fileDataPtr, sizeof(int));
fileDataPtr += sizeof(int);
}
// Allocate required glyphs space to fill with data
font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize))
{
// Glyphs data is compressed, uncompress it
unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_CALLOC(glyphsDataCompressedSize, sizeof(unsigned char));
memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize);
fileDataPtr += glyphsDataCompressedSize;
int glyphsDataUncompSize = 0;
unsigned char *glyphsDataUncomp = DecompressData(glypsDataCompressed, glyphsDataCompressedSize, &glyphsDataUncompSize);
// Security check, data uncompressed size must match the expected original data size
if (glyphsDataUncompSize != glyphsDataSize) RAYGUI_LOG("WARNING: Uncompressed font glyphs data could be corrupted");
unsigned char *glyphsDataUncompPtr = glyphsDataUncomp;
for (int i = 0; i < font.glyphCount; i++)
{
memcpy(&font.glyphs[i].value, glyphsDataUncompPtr, sizeof(int));
memcpy(&font.glyphs[i].offsetX, glyphsDataUncompPtr + 4, sizeof(int));
memcpy(&font.glyphs[i].offsetY, glyphsDataUncompPtr + 8, sizeof(int));
memcpy(&font.glyphs[i].advanceX, glyphsDataUncompPtr + 12, sizeof(int));
glyphsDataUncompPtr += 16;
}
RAYGUI_FREE(glypsDataCompressed);
RAYGUI_FREE(glyphsDataUncomp);
}
else
{
// Glyphs data is uncompressed
for (int i = 0; i < font.glyphCount; i++)
{
memcpy(&font.glyphs[i].value, fileDataPtr, sizeof(int));
memcpy(&font.glyphs[i].offsetX, fileDataPtr + 4, sizeof(int));
memcpy(&font.glyphs[i].offsetY, fileDataPtr + 8, sizeof(int));
memcpy(&font.glyphs[i].advanceX, fileDataPtr + 12, sizeof(int));
fileDataPtr += 16;
}
}
}
else font = GetFontDefault(); // Fallback in case of errors loading font atlas texture
GuiSetFont(font);
// Set font texture source rectangle to be used as white texture to draw shapes
// NOTE: It makes possible to draw shapes and text (full UI) in a single draw call
if ((fontWhiteRec.x > 0) &&
(fontWhiteRec.y > 0) &&
(fontWhiteRec.width > 0) &&
(fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec);
}
#endif
}
}
// Get text bounds considering control bounds
static Rectangle GetTextBounds(int control, Rectangle bounds)
{
@ -5100,12 +5111,12 @@ static Rectangle GetTextBounds(int control, Rectangle bounds)
}
// Get text icon if provided and move text cursor
// NOTE: Up to #999# values supported for iconId
// NOTE: Up to RAYGUI_ICON_MAX_ICONS supported for iconId
static const char *GetTextIcon(const char *text, int *iconId)
{
#if !defined(RAYGUI_NO_ICONS)
*iconId = -1;
if (text[0] == '#') // Maybe it is stars with an icon, ending # must be found
if (text[0] == '#') // Maybe an icon, if it starts with # but an ending # must be found
{
char iconValue[4] = { 0 }; // Maximum length for icon value: 3 digits + '\0'
@ -5118,13 +5129,17 @@ static const char *GetTextIcon(const char *text, int *iconId)
if (text[pos] == '#')
{
*iconId = TextToInteger(iconValue);
int rawIconId = TextToInteger(iconValue);
if (rawIconId < RAYGUI_ICON_MAX_ICONS)
{
*iconId = rawIconId;
// Move text pointer after icon
// WARNING: If only icon provided, it could point to EOL character: '\0'
if (*iconId >= 0) text += (pos + 1);
}
}
}
#endif
return text;
@ -5794,10 +5809,10 @@ static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue)
RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height },
TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))));
#else
GuiDrawText(isVertical? "#121#" : "#118#",
GuiDrawText(isVertical? GuiIconText(ICON_ARROW_UP_FILL, NULL) : GuiIconText(ICON_ARROW_LEFT_FILL, NULL),
RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height },
TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_UP_FILL / ICON_ARROW_LEFT_FILL
GuiDrawText(isVertical? "#120#" : "#119#",
GuiDrawText(isVertical? GuiIconText(ICON_ARROW_DOWN_FILL, NULL) : GuiIconText(ICON_ARROW_RIGHT_FILL, NULL),
RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height },
TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_DOWN_FILL / ICON_ARROW_RIGHT_FILL
#endif