|
|
|
|
@ -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"
|
|
|
|
|
|
|
|
|
|
@ -384,7 +385,7 @@
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Macros to define required UI inputs, including mapping to gamepad controls
|
|
|
|
|
// TODO: Define additionally required macros for missing inputs
|
|
|
|
|
// TODO: Define additionally required macros for missing inputs
|
|
|
|
|
#if !defined(GUI_BUTTON_DOWN)
|
|
|
|
|
#define GUI_BUTTON_DOWN (IsMouseButtonDown(MOUSE_LEFT_BUTTON) || IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN))
|
|
|
|
|
#endif
|
|
|
|
|
@ -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
|
|
|
|
|
@ -652,7 +655,7 @@ typedef enum {
|
|
|
|
|
// ProgressBar
|
|
|
|
|
typedef enum {
|
|
|
|
|
PROGRESS_PADDING = 16, // ProgressBar internal padding
|
|
|
|
|
PROGRESS_SIDE, // ProgressBar increment side: 0-left->right, 1-right-left
|
|
|
|
|
PROGRESS_SIDE, // ProgressBar increment side: 0-left->right, 1-right-left
|
|
|
|
|
} GuiProgressBarProperty;
|
|
|
|
|
|
|
|
|
|
// ScrollBar
|
|
|
|
|
@ -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
|
|
|
|
|
|
|
|
|
|
@ -1606,7 +1608,7 @@ void GuiSetFont(Font font)
|
|
|
|
|
{
|
|
|
|
|
if (font.texture.id > 0)
|
|
|
|
|
{
|
|
|
|
|
// NOTE: If a font is tried to be set but default style has not been lazily loaded first,
|
|
|
|
|
// NOTE: If a font is tried to be set but default style has not been lazily loaded first,
|
|
|
|
|
// it will be overwritten, so default style loading needs to be forced first
|
|
|
|
|
if (!guiStyleLoaded) GuiLoadStyleDefault();
|
|
|
|
|
|
|
|
|
|
@ -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)
|
|
|
|
|
{
|
|
|
|
|
#define RAYGUI_TABBAR_ITEM_WIDTH 148
|
|
|
|
|
#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,11 +5129,15 @@ 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);
|
|
|
|
|
// Move text pointer after icon
|
|
|
|
|
// WARNING: If only icon provided, it could point to EOL character: '\0'
|
|
|
|
|
if (*iconId >= 0) text += (pos + 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
@ -5395,7 +5410,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (wrapMode == TEXT_WRAP_NONE) posOffsetY += (float)(GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING));
|
|
|
|
|
else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD))
|
|
|
|
|
else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD))
|
|
|
|
|
posOffsetY += (textOffsetY + GuiGetStyle(DEFAULT, TEXT_SIZE));
|
|
|
|
|
//---------------------------------------------------------------------------------
|
|
|
|
|
}
|
|
|
|
|
@ -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
|
|
|
|
|
|