Compare commits

5 Commits

Author SHA1 Message Date
Ray
8d33708103 Create Directory.Build.props 2026-06-25 00:48:26 +02:00
Ray
1066fd663f Update raygui.rc 2026-06-25 00:48:18 +02:00
Ray
5d3a35d674 Update raygui.h 2026-06-25 00:38:07 +02:00
Ray
3ad9038e02 ADDED: GuiFontIconBaking() to support icons baking into font atlas image
REDESIGNED: `GuiLoadStyleFromMemory()` to support icons baking
2026-06-25 00:29:17 +02:00
Ray
ad18a0ab07 Code cleaning and some reorganization 2026-06-25 00:26:11 +02:00
4 changed files with 540 additions and 375 deletions

View File

@ -38,6 +38,7 @@
//#define RAYGUI_DEBUG_RECS_BOUNDS //#define RAYGUI_DEBUG_RECS_BOUNDS
//#define RAYGUI_DEBUG_TEXT_BOUNDS //#define RAYGUI_DEBUG_TEXT_BOUNDS
//#define RAYGUI_FONT_ICONS_BAKING
#define RAYGUI_IMPLEMENTATION #define RAYGUI_IMPLEMENTATION
//#define RAYGUI_CUSTOM_ICONS // It requires providing gui_icons.h in the same directory //#define RAYGUI_CUSTOM_ICONS // It requires providing gui_icons.h in the same directory
//#include "gui_icons.h" // External icons data provided, it can be generated with rGuiIcons tool //#include "gui_icons.h" // External icons data provided, it can be generated with rGuiIcons tool
@ -66,13 +67,17 @@ int main()
// Initialization // Initialization
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
const int screenWidth = 960; const int screenWidth = 960;
const int screenHeight = 560; const int screenHeight = 580;
InitWindow(screenWidth, screenHeight, "raygui - controls test suite"); InitWindow(screenWidth, screenHeight, "raygui - controls test suite");
SetExitKey(0); SetExitKey(0);
// GUI controls initialization // GUI controls initialization
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
char *tabNames[] = { "#124#TAB_01", "#98#TAB_02", "#217#TAB_03", "#56#TAB_04", "#24#TAB_05", "#12#TAB_06" };
int tabCount = 6;
int tabActive = 0;
int dropdownBox000Active = 0; int dropdownBox000Active = 0;
bool dropDown000EditMode = false; bool dropDown000EditMode = false;
@ -212,31 +217,34 @@ int main()
if (dropDown000EditMode || dropDown001EditMode) GuiLock(); if (dropDown000EditMode || dropDown001EditMode) GuiLock();
if (showTextInputBox) GuiLock(); if (showTextInputBox) GuiLock();
GuiSetStyle(TABBAR, TAB_ITEMS_WIDTH, 140);
GuiTabBar((Rectangle){ 0, 8, GetScreenWidth(), 26 }, tabNames, tabCount, &tabActive);
// First GUI column // First GUI column
//GuiSetStyle(CHECKBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); //GuiSetStyle(CHECKBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
GuiCheckBox((Rectangle){ 25, 108, 15, 15 }, "FORCE CHECK!", &forceSquaredChecked); GuiCheckBox((Rectangle){ 25, 108 + 20, 15, 15 }, "FORCE CHECK!", &forceSquaredChecked);
GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
//GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); //GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
if (GuiSpinner((Rectangle){ 25, 135, 125, 30 }, NULL, &spinner001Value, 0, 100, spinnerEditMode)) spinnerEditMode = !spinnerEditMode; if (GuiSpinner((Rectangle){ 25, 135 + 20, 125, 30 }, NULL, &spinner001Value, 0, 100, spinnerEditMode)) spinnerEditMode = !spinnerEditMode;
if (GuiValueBox((Rectangle){ 25, 175, 125, 30 }, NULL, &valueBox002Value, 0, 100, valueBoxEditMode)) valueBoxEditMode = !valueBoxEditMode; if (GuiValueBox((Rectangle){ 25, 175 + 20, 125, 30 }, NULL, &valueBox002Value, 0, 100, valueBoxEditMode)) valueBoxEditMode = !valueBoxEditMode;
GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
if (GuiTextBox((Rectangle){ 25, 215, 125, 30 }, textBoxText, 64, textBoxEditMode)) textBoxEditMode = !textBoxEditMode; if (GuiTextBox((Rectangle){ 25, 215 + 20, 125, 30 }, textBoxText, 64, textBoxEditMode)) textBoxEditMode = !textBoxEditMode;
GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
if (GuiButton((Rectangle){ 25, 255, 125, 30 }, GuiIconText(ICON_FILE_SAVE, "Save File"))) showTextInputBox = true; if (GuiButton((Rectangle){ 25, 255 + 20, 125, 30 }, GuiIconText(ICON_FILE_SAVE, "Save File"))) showTextInputBox = true;
GuiGroupBox((Rectangle){ 25, 310, 125, 150 }, "STATES"); GuiGroupBox((Rectangle){ 25, 310 + 20, 125, 150 }, "STATES");
//GuiLock(); //GuiLock();
GuiSetState(STATE_NORMAL); if (GuiButton((Rectangle){ 30, 320, 115, 30 }, "NORMAL")) { } GuiSetState(STATE_NORMAL); if (GuiButton((Rectangle){ 30, 320 + 20, 115, 30 }, "NORMAL")) { }
GuiSetState(STATE_FOCUSED); if (GuiButton((Rectangle){ 30, 355, 115, 30 }, "FOCUSED")) { } GuiSetState(STATE_FOCUSED); if (GuiButton((Rectangle){ 30, 355 + 20, 115, 30 }, "FOCUSED")) { }
GuiSetState(STATE_PRESSED); if (GuiButton((Rectangle){ 30, 390, 115, 30 }, "#15#PRESSED")) { } GuiSetState(STATE_PRESSED); if (GuiButton((Rectangle){ 30, 390 + 20, 115, 30 }, "#15#PRESSED")) { }
GuiSetState(STATE_DISABLED); if (GuiButton((Rectangle){ 30, 425, 115, 30 }, "DISABLED")) { } GuiSetState(STATE_DISABLED); if (GuiButton((Rectangle){ 30, 425 + 20, 115, 30 }, "DISABLED")) { }
GuiSetState(STATE_NORMAL); GuiSetState(STATE_NORMAL);
//GuiUnlock(); //GuiUnlock();
GuiComboBox((Rectangle){ 25, 480, 125, 30 }, GuiComboBox((Rectangle){ 25, 480 + 20, 125, 30 },
"default;Jungle;Lavanda;Dark;Bluish;Cyber;Terminal;Candy;Cherry;Ashes;Enefete;Sunny;Amber;Genesis", &visualStyleActive); "default;Jungle;Lavanda;Dark;Bluish;Cyber;Terminal;Candy;Cherry;Ashes;Enefete;Sunny;Amber;Genesis", &visualStyleActive);
// NOTE: GuiDropdownBox must draw after any other control that can be covered on unfolding // NOTE: GuiDropdownBox must draw after any other control that can be covered on unfolding
@ -245,48 +253,48 @@ int main()
GuiSetStyle(DROPDOWNBOX, TEXT_PADDING, 4); GuiSetStyle(DROPDOWNBOX, TEXT_PADDING, 4);
GuiSetStyle(DROPDOWNBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); GuiSetStyle(DROPDOWNBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
if (GuiDropdownBox((Rectangle){ 25, 65, 125, 30 }, "#01#ONE;#02#TWO;#03#THREE;#04#FOUR", &dropdownBox001Active, dropDown001EditMode)) dropDown001EditMode = !dropDown001EditMode; if (GuiDropdownBox((Rectangle){ 25, 65 + 20, 125, 30 }, "#01#ONE;#02#TWO;#03#THREE;#04#FOUR", &dropdownBox001Active, dropDown001EditMode)) dropDown001EditMode = !dropDown001EditMode;
GuiSetStyle(DROPDOWNBOX, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); GuiSetStyle(DROPDOWNBOX, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
GuiSetStyle(DROPDOWNBOX, TEXT_PADDING, 0); GuiSetStyle(DROPDOWNBOX, TEXT_PADDING, 0);
if (GuiDropdownBox((Rectangle){ 25, 25, 125, 30 }, "ONE;TWO;THREE", &dropdownBox000Active, dropDown000EditMode)) dropDown000EditMode = !dropDown000EditMode; if (GuiDropdownBox((Rectangle){ 25, 25 + 20, 125, 30 }, "ONE;TWO;THREE", &dropdownBox000Active, dropDown000EditMode)) dropDown000EditMode = !dropDown000EditMode;
// Second GUI column // Second GUI column
//GuiSetStyle(LISTVIEW, LIST_ITEMS_BORDER_NORMAL, 1); //GuiSetStyle(LISTVIEW, LIST_ITEMS_BORDER_NORMAL, 1);
GuiListView((Rectangle){ 165, 25, 140, 124 }, "Charmander;Bulbasaur;#18#Squirtle;Pikachu;Eevee;Pidgey", &listViewScrollIndex, &listViewActive); GuiListView((Rectangle){ 165, 25 + 20, 140, 124 }, "Charmander;Bulbasaur;#18#Squirtle;Pikachu;Eevee;Pidgey", &listViewScrollIndex, &listViewActive);
GuiListViewEx((Rectangle){ 165, 162, 140, 184 }, listViewExList, 8, &listViewExScrollIndex, &listViewExActive, &listViewExFocus); GuiListViewEx((Rectangle){ 165, 162 + 20, 140, 184 }, listViewExList, 8, &listViewExScrollIndex, &listViewExActive, &listViewExFocus);
GuiSetStyle(LISTVIEW, LIST_ITEMS_BORDER_NORMAL, 0); GuiSetStyle(LISTVIEW, LIST_ITEMS_BORDER_NORMAL, 0);
//GuiToggle((Rectangle){ 165, 400, 140, 25 }, "#1#ONE", &toggleGroupActive); //GuiToggle((Rectangle){ 165, 400, 140, 25 }, "#1#ONE", &toggleGroupActive);
GuiToggleGroup((Rectangle){ 165, 360, 140, 24 }, "#1#ONE\n#3#TWO\n#8#THREE\n#23#", &toggleGroupActive); GuiToggleGroup((Rectangle){ 165, 360 + 20, 140, 24 }, "#1#ONE\n#3#TWO\n#8#THREE\n#23#", &toggleGroupActive);
//GuiDisable(); //GuiDisable();
GuiSetStyle(SLIDER, SLIDER_PADDING, 2); GuiSetStyle(SLIDER, SLIDER_PADDING, 2);
GuiToggleSlider((Rectangle){ 165, 480, 140, 30 }, "ON;OFF", &toggleSliderActive); GuiToggleSlider((Rectangle){ 165, 480 + 20, 140, 30 }, "ON;OFF", &toggleSliderActive);
GuiSetStyle(SLIDER, SLIDER_PADDING, 0); GuiSetStyle(SLIDER, SLIDER_PADDING, 0);
// Third GUI column // Third GUI column
GuiPanel((Rectangle){ 320, 25, 225, 140 }, "Panel Info"); GuiPanel((Rectangle){ 320, 25 + 20, 225, 140 }, "Panel Info");
GuiColorPicker((Rectangle){ 320, 185, 196, 192 }, NULL, &colorPickerValue); GuiColorPicker((Rectangle){ 320, 185 + 20, 196, 192 }, NULL, &colorPickerValue);
//GuiDisable(); //GuiDisable();
GuiSlider((Rectangle){ 355, 400, 165, 20 }, "TEST", TextFormat("%2.2f", sliderValue), &sliderValue, -50, 100); GuiSlider((Rectangle){ 355, 400 + 20, 165, 20 }, "TEST", TextFormat("%2.2f", sliderValue), &sliderValue, -50, 100);
GuiSliderBar((Rectangle){ 320, 430, 200, 20 }, NULL, TextFormat("%i", (int)sliderBarValue), &sliderBarValue, 0, 100); GuiSliderBar((Rectangle){ 320, 430 + 20, 200, 20 }, NULL, TextFormat("%i", (int)sliderBarValue), &sliderBarValue, 0, 100);
GuiProgressBar((Rectangle){ 320, 460, 200, 20 }, NULL, TextFormat("%i%%", (int)(progressValue*100)), &progressValue, 0.0f, 1.0f); GuiProgressBar((Rectangle){ 320, 460 + 20, 200, 20 }, NULL, TextFormat("%i%%", (int)(progressValue*100)), &progressValue, 0.0f, 1.0f);
GuiEnable(); GuiEnable();
// NOTE: View rectangle could be used to perform some scissor test // NOTE: View rectangle could be used to perform some scissor test
Rectangle view = { 0 }; Rectangle view = { 0 };
GuiScrollPanel((Rectangle){ 560, 25, 102, 354 }, NULL, (Rectangle){ 560, 25, 300, 1200 }, &viewScroll, &view); GuiScrollPanel((Rectangle){ 560, 25 + 20, 102, 354 }, NULL, (Rectangle){ 560, 25, 300, 1200 }, &viewScroll, &view);
Vector2 mouseCell = { 0 }; Vector2 mouseCell = { 0 };
GuiGrid((Rectangle) { 560, 25 + 180 + 195, 100, 120 }, NULL, 20, 3, &mouseCell); GuiGrid((Rectangle) { 560, 25 + 180 + 195 + 20, 100, 120 }, NULL, 20, 3, &mouseCell);
GuiColorBarAlpha((Rectangle){ 320, 490, 200, 30 }, NULL, &alphaValue); GuiColorBarAlpha((Rectangle){ 320, 490 + 20, 200, 30 }, NULL, &alphaValue);
GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_TOP); // WARNING: Word-wrap does not work as expected in case of no-top alignment GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_TOP); // WARNING: Word-wrap does not work as expected in case of no-top alignment
GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_WORD); // WARNING: If wrap mode enabled, text editing is not supported GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_WORD); // WARNING: If wrap mode enabled, text editing is not supported
if (GuiTextBox((Rectangle){ 678, 25, 258, 492 }, textBoxMultiText, 1024, textBoxMultiEditMode)) textBoxMultiEditMode = !textBoxMultiEditMode; if (GuiTextBox((Rectangle){ 678, 25 + 20, 258, 492 }, textBoxMultiText, 1024, textBoxMultiEditMode)) textBoxMultiEditMode = !textBoxMultiEditMode;
GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_NONE); GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_NONE);
GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE);

View File

@ -1,8 +1,8 @@
GLFW_ICON ICON "raygui.ico" GLFW_ICON ICON "raygui.ico"
1 VERSIONINFO 1 VERSIONINFO
FILEVERSION 4,0,0,0 FILEVERSION 5,0,0,0
PRODUCTVERSION 4,0,0,0 PRODUCTVERSION 5,0,0,0
BEGIN BEGIN
BLOCK "StringFileInfo" BLOCK "StringFileInfo"
BEGIN BEGIN
@ -11,12 +11,12 @@ BEGIN
BEGIN BEGIN
//VALUE "CompanyName", "raylib technologies" //VALUE "CompanyName", "raylib technologies"
VALUE "FileDescription", "raygui application (www.raylib.com)" VALUE "FileDescription", "raygui application (www.raylib.com)"
VALUE "FileVersion", "4.0.0" VALUE "FileVersion", "5.0.0"
VALUE "InternalName", "raygui app" VALUE "InternalName", "raygui app"
VALUE "LegalCopyright", "(c) 2023 Ramon Santamaria (@raysan5)" VALUE "LegalCopyright", "(c) 2026 Ramon Santamaria (@raysan5)"
//VALUE "OriginalFilename", "raygui_app.exe" //VALUE "OriginalFilename", "raygui_app.exe"
VALUE "ProductName", "raygui app" VALUE "ProductName", "raygui app"
VALUE "ProductVersion", "4.0.0" VALUE "ProductVersion", "5.0.0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -0,0 +1,7 @@
<Project>
<ItemDefinitionGroup>
<ClCompile>
<PreProcessorDefinitions>%(PreProcessorDefinitions);EXTERNAL_CONFIG_FLAGS;SUPPORT_MODULE_RSHAPES;SUPPORT_MODULE_RTEXTURES;SUPPORT_MODULE_RTEXT;SUPPORT_COMPRESSION_API;SUPPORT_SCREEN_CAPTURE;SUPPORT_QUADS_DRAW_MODE;SUPPORT_FILEFORMAT_TTF;SUPPORT_FILEFORMAT_PNG;SUPPORT_IMAGE_EXPORT;SUPPORT_TRACELOG</PreProcessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
</Project>

View File

@ -134,6 +134,10 @@
* Includes custom ricons.h header defining a set of custom icons, * Includes custom ricons.h header defining a set of custom icons,
* this file can be generated using rGuiIcons tool * this file can be generated using rGuiIcons tool
* *
* #define RAYGUI_FONT_ICONS_BAKING
* On gui font loading from style file, append the icons to font atlas image, so,
* icons can be drawn along the text as a texture, instead of using shapes to draw them
*
* #define RAYGUI_DEBUG_RECS_BOUNDS * #define RAYGUI_DEBUG_RECS_BOUNDS
* Draw control bounds rectangles for debug * Draw control bounds rectangles for debug
* *
@ -143,6 +147,7 @@
* VERSIONS HISTORY: * VERSIONS HISTORY:
* 5.0 (xx-Jun-2026) ADDED: TABBAR control: GuiTabBar() * 5.0 (xx-Jun-2026) ADDED: TABBAR control: GuiTabBar()
* ADDED: Support up to 512 icons (v500) * ADDED: Support up to 512 icons (v500)
* ADDED: Support icons baking into font atlas image
* ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes * ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes
* ADDED: Altrnative VALUEBOX: GuiValueBoxFloat() * ADDED: Altrnative VALUEBOX: GuiValueBoxFloat()
* ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP * ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP
@ -167,6 +172,7 @@
* REVIEWED: GuiProgressBar(), improved borders computing * REVIEWED: GuiProgressBar(), improved borders computing
* REVIEWED: GuiTextBox(), multiple improvements: autocursor and more * REVIEWED: GuiTextBox(), multiple improvements: autocursor and more
* REVIEWED: Functions descriptions, removed wrong return value reference * REVIEWED: Functions descriptions, removed wrong return value reference
* REDESIGNED: GuiLoadStyleFromMemory() to support icons baking into font atlas
* REDESIGNED: GuiToggleGroup() to process rows/cols with no need for GuiTextSplit() * REDESIGNED: GuiToggleGroup() to process rows/cols with no need for GuiTextSplit()
* REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion * REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion
* REDESIGNED: WARNING: TEXT_LINE_SPACING does not consider text height, only lines spacing * REDESIGNED: WARNING: TEXT_LINE_SPACING does not consider text height, only lines spacing
@ -386,8 +392,8 @@
#define RAYGUI_LOG(...) #define RAYGUI_LOG(...)
#endif #endif
#if !defined(RAYGUI_STANDALONE)
// Macros to define required UI inputs, including mapping to gamepad controls // Macros to define required UI inputs, including mapping to gamepad controls
// TODO: Define additionally required macros for missing inputs
#if !defined(GUI_BUTTON_DOWN) #if !defined(GUI_BUTTON_DOWN)
#define GUI_BUTTON_DOWN (IsMouseButtonDown(MOUSE_LEFT_BUTTON) || IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) #define GUI_BUTTON_DOWN (IsMouseButtonDown(MOUSE_LEFT_BUTTON) || IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN))
#endif #endif
@ -398,7 +404,9 @@
#if !defined(GUI_BUTTON_PRESSED) #if !defined(GUI_BUTTON_PRESSED)
#define GUI_BUTTON_PRESSED (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsGamepadButtonPressed(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) #define GUI_BUTTON_PRESSED (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsGamepadButtonPressed(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN))
#endif #endif
// TODO: WARNING: GuiTabBar() still requires IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON) #if !defined(GUI_BUTTON_PRESSED_MID)
#define GUI_BUTTON_PRESSED_MID (IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON) || IsGamepadButtonPressed(0, GAMEPAD_BUTTON_RIGHT_FACE_UP))
#endif
#if !defined(GUI_BUTTON_RELEASED) #if !defined(GUI_BUTTON_RELEASED)
#define GUI_BUTTON_RELEASED (IsMouseButtonReleased(MOUSE_LEFT_BUTTON) || IsGamepadButtonReleased(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) #define GUI_BUTTON_RELEASED (IsMouseButtonReleased(MOUSE_LEFT_BUTTON) || IsGamepadButtonReleased(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN))
#endif #endif
@ -424,6 +432,18 @@
#if !defined(GUI_INPUT_KEY) #if !defined(GUI_INPUT_KEY)
#define GUI_INPUT_KEY GetCharPressed() #define GUI_INPUT_KEY GetCharPressed()
#endif #endif
#else
#define GUI_BUTTON_DOWN 0
#define GUI_BUTTON_DOWN_ALT 0
#define GUI_BUTTON_PRESSED 0
#define GUI_BUTTON_PRESSED_MID 0
#define GUI_BUTTON_RELEASED 0
#define GUI_SCROLL_DELTA 0
#define GUI_POINTER_POSITION (Vector2){ 0 }
#define GUI_KEY_DOWN(key) 0
#define GUI_KEY_PRESSED(key) 0
#define GUI_INPUT_KEY 0
#endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Types and Structures Definition // Types and Structures Definition
@ -458,6 +478,8 @@
unsigned char a; unsigned char a;
} Color; } Color;
#define BLANK (Color){ 0, 0, 0, 0 } // Blank (Transparent)
// Rectangle type // Rectangle type
typedef struct Rectangle { typedef struct Rectangle {
float x; float x;
@ -466,7 +488,7 @@
float height; float height;
} Rectangle; } Rectangle;
// TODO: Texture2D type is very coupled to raylib, required by Font type // NOTE: Texture2D type is very coupled to raylib, required by Font type
// It should be redesigned to be provided by user // It should be redesigned to be provided by user
typedef struct Texture { typedef struct Texture {
unsigned int id; // OpenGL texture id unsigned int id; // OpenGL texture id
@ -497,7 +519,7 @@
Image image; // Character image data Image image; // Character image data
} GlyphInfo; } GlyphInfo;
// TODO: Font type is very coupled to raylib, mostly required by GuiLoadStyle() // NOTE: Font type is very coupled to raylib, mostly required by GuiLoadStyle()
// It should be redesigned to be provided by user // It should be redesigned to be provided by user
typedef struct Font { typedef struct Font {
int baseSize; // Base size (default chars height) int baseSize; // Base size (default chars height)
@ -1152,7 +1174,9 @@ typedef enum {
// Embedded icons, no external file provided // Embedded icons, no external file provided
#define RAYGUI_ICON_SIZE 16 // Size of icons in pixels (squared) #define RAYGUI_ICON_SIZE 16 // Size of icons in pixels (squared)
#define RAYGUI_ICON_MAX_ICONS 512 // Maximum number of icons #define RAYGUI_ICON_MAX_ICONS 512 // Maximum number of icons
#define RAYGUI_ICON_MAX_FONT_BACKED 257 // Maximum number of icons to back in font atlas
#define RAYGUI_ICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id #define RAYGUI_ICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id
#define RAYGUI_ICON_FONT_ATLAS_PADDING 1 // Padding between backed icons in font atlas
// Icons data is defined by bit array (every bit represents one pixel) // Icons data is defined by bit array (every bit represents one pixel)
// Those arrays are stored as unsigned int data arrays, so, // Those arrays are stored as unsigned int data arrays, so,
@ -1465,6 +1489,7 @@ static bool guiLocked = false; // Gui lock state (no inputs pro
static float guiAlpha = 1.0f; // Gui controls transparency static float guiAlpha = 1.0f; // Gui controls transparency
static unsigned int guiIconScale = 1; // Gui icon default scale (if icons enabled) static unsigned int guiIconScale = 1; // Gui icon default scale (if icons enabled)
static unsigned int guiIconFontOffsetY = 0; // Gui icon font atlas offset (if icons backed)
static bool guiTooltip = false; // Tooltip enabled/disabled static bool guiTooltip = false; // Tooltip enabled/disabled
static const char *guiTooltipPtr = NULL; // Tooltip string pointer (string provided by user) static const char *guiTooltipPtr = NULL; // Tooltip string pointer (string provided by user)
@ -1545,11 +1570,14 @@ static int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle(
static void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list static void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list
static unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle() static unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle()
static Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
// raylib functions already implemented in raygui // raylib functions already implemented in raygui
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
static Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value static Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value
static Color Fade(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f
static int ColorToInt(Color color); // Returns hexadecimal value for a Color static int ColorToInt(Color color); // Returns hexadecimal value for a Color
static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle
static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed' static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed'
@ -1567,6 +1595,7 @@ static void DrawRectangleGradientV(int posX, int posY, int width, int height, Co
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Internal Functions Declaration // Module Internal Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
static int GetLineWidth(const char *text); // Get text line width (stops at '\n' or '\0')
static Rectangle GetTextBounds(int control, Rectangle bounds); // Get text bounds considering control bounds 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 static const char *GetTextIcon(const char *text, int *iconId); // Get text icon if provided and move text cursor
@ -1577,8 +1606,9 @@ static char **GuiTextSplit(const char *text, char delimiter, int *count); // Spl
static Vector3 ConvertHSVtoRGB(Vector3 hsv); // Convert color data from HSV to RGB static Vector3 ConvertHSVtoRGB(Vector3 hsv); // Convert color data from HSV to RGB
static Vector3 ConvertRGBtoHSV(Vector3 rgb); // Convert color data from RGB to HSV static Vector3 ConvertRGBtoHSV(Vector3 rgb); // Convert color data from RGB to HSV
static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel()
static void GuiTooltip(Rectangle controlRec); // Draw tooltip using control rec position static void GuiTooltip(Rectangle controlRec); // Draw tooltip using control rec position
static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel()
static int GuiFontIconBaking(Image *imFont, Font font, Rectangle *whiteRec); // Update font image atlas to append raygui icons
static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor
@ -1851,7 +1881,7 @@ int GuiTabBar(Rectangle bounds, char **text, int count, int *active)
} }
// Close tab with middle mouse button pressed // Close tab with middle mouse button pressed
if (CheckCollisionPointRec(GUI_POINTER_POSITION, tabBounds) && IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON)) result = i; if (CheckCollisionPointRec(GUI_POINTER_POSITION, tabBounds) && GUI_BUTTON_PRESSED_MID) result = i;
GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding); GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding);
GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment); GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment);
@ -1877,7 +1907,7 @@ int GuiTabBar(Rectangle bounds, char **text, int count, int *active)
} }
// Draw tab-bar bottom line // Draw tab-bar bottom line
GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, 1 }, 0, BLANK, GetColor(GuiGetStyle(TOGGLE, BORDER_COLOR_NORMAL))); GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, 1 }, 0, BLANK, GetColor(GuiGetStyle(TABBAR, BORDER_COLOR_NORMAL)));
//-------------------------------------------------------------------- //--------------------------------------------------------------------
return result; // Return as result the current TAB closing requested return result; // Return as result the current TAB closing requested
@ -2614,7 +2644,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
int result = 0; int result = 0;
GuiState state = guiState; GuiState state = guiState;
bool multiline = false; // TODO: Consider multiline text input bool multiline = false;
int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE);
Rectangle textBounds = GetTextBounds(TEXTBOX, bounds); Rectangle textBounds = GetTextBounds(TEXTBOX, bounds);
@ -4663,10 +4693,8 @@ void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
else GuiSetStyle((int)controlId, (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 // Load custom font if available
// NOTE: Font texture loading requires raylib
int fontDataSize = 0; int fontDataSize = 0;
memcpy(&fontDataSize, fileDataPtr, sizeof(int)); memcpy(&fontDataSize, fileDataPtr, sizeof(int));
fileDataPtr += 4; fileDataPtr += 4;
@ -4732,16 +4760,7 @@ void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
fileDataPtr += fontImageUncompSize; fileDataPtr += fontImageUncompSize;
} }
// Load texture from image // Load font recs data (glyphs position and size in the image atlas)
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 recsDataSize = font.glyphCount*sizeof(Rectangle);
int recsDataCompressedSize = 0; int recsDataCompressedSize = 0;
@ -4835,11 +4854,22 @@ void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
fileDataPtr += 16; fileDataPtr += 16;
} }
} }
}
else font = GetFontDefault(); // Fallback in case of errors loading font atlas texture
GuiSetFont(font); #if defined(RAYGUI_FONT_ICONS_BAKING)
// Font atlas image icons baking
Rectangle updatedWhiteRec = { 0 };
guiIconFontOffsetY = GuiFontIconBaking(&imFont, font, &updatedWhiteRec);
if (guiIconFontOffsetY > 0) fontWhiteRec = updatedWhiteRec;
#endif
#if !defined(RAYGUI_STANDALONE)
// Load texture from image
if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture);
font.texture = LoadTextureFromImage(imFont);
// Fallback to default raylib texture if font texture loading fails
if (font.texture.id != 0)
{
// Set font texture source rectangle to be used as white texture to draw shapes // 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 // NOTE: It makes possible to draw shapes and text (full UI) in a single draw call
if ((fontWhiteRec.x > 0) && if ((fontWhiteRec.x > 0) &&
@ -4847,7 +4877,12 @@ void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
(fontWhiteRec.width > 0) && (fontWhiteRec.width > 0) &&
(fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec); (fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec);
} }
else font = GetFontDefault();
GuiSetFont(font);
#endif #endif
RAYGUI_FREE(imFont.data);
}
} }
} }
@ -4952,6 +4987,9 @@ void GuiLoadStyleDefault(void)
// NOTE: Setting up a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering // NOTE: Setting up a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering
SetShapesTexture(guiFont.texture, RAYGUI_CLITERAL(Rectangle){ whiteChar.x + 1, whiteChar.y + 1, whiteChar.width - 2, whiteChar.height - 2 }); SetShapesTexture(guiFont.texture, RAYGUI_CLITERAL(Rectangle){ whiteChar.x + 1, whiteChar.y + 1, whiteChar.width - 2, whiteChar.height - 2 });
// Reset baked icons offset in font
guiIconFontOffsetY = 0;
} }
} }
@ -5102,6 +5140,21 @@ char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool
// Draw selected icon using rectangles pixel-by-pixel // Draw selected icon using rectangles pixel-by-pixel
void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color) void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color)
{ {
if ((guiIconFontOffsetY > 0) && (iconId < RAYGUI_ICON_MAX_FONT_BACKED))
{
int maxIconsPerLine = guiFont.texture.width/(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING);
int x = iconId%maxIconsPerLine;
int y = iconId/maxIconsPerLine;
Rectangle srcRec = { x*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + RAYGUI_ICON_FONT_ATLAS_PADDING,
guiIconFontOffsetY + y*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + RAYGUI_ICON_FONT_ATLAS_PADDING,
RAYGUI_ICON_SIZE, RAYGUI_ICON_SIZE };
Rectangle dstRec = { posX, posY, RAYGUI_ICON_SIZE*pixelSize, RAYGUI_ICON_SIZE*pixelSize };
DrawTexturePro(guiFont.texture, srcRec, dstRec, (Vector2){ 0, 0 }, 0.0f, color);
}
else
{
#define BIT_CHECK(a,b) ((a) & (1u<<(b))) #define BIT_CHECK(a,b) ((a) & (1u<<(b)))
for (int i = 0, y = 0; i < RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32; i++) for (int i = 0, y = 0; i < RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32; i++)
@ -5110,14 +5163,14 @@ void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color)
{ {
if (BIT_CHECK(guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i], k)) if (BIT_CHECK(guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i], k))
{ {
#if !defined(RAYGUI_STANDALONE) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize,
GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize, (float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color); (float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color);
#endif
} }
if ((k == 15) || (k == 31)) y++; if ((k == 15) || (k == 31)) y++;
} }
} }
}
} }
// Set icon drawing size // Set icon drawing size
@ -5126,15 +5179,44 @@ void GuiSetIconScale(int scale)
if (scale >= 1) guiIconScale = scale; if (scale >= 1) guiIconScale = scale;
} }
// Get the width of a single line of gui text (stops at '\n' or '\0'), // Get text width considering gui style and icon size (if required).
// considering the gui font/style and an optional icon marker '#NNN#' at // For multi-line text (containing '\n'), returns the width of the widest line.
// the start. Icon detection matches GetTextIcon(): 1..3 digits, skip past int GuiGetTextWidth(const char *text)
// the closing '#'. {
if (text == NULL) return 0;
int maxWidth = 0;
const char *linePtr = text;
while ((linePtr[0] != '\0') && ((linePtr - text) < MAX_LINE_BUFFER_SIZE))
{
int lineWidth = GetLineWidth(linePtr);
if (lineWidth > maxWidth) maxWidth = lineWidth;
// Skip to the next '\n' (or end of string/buffer)
while ((linePtr[0] != '\0') && (linePtr[0] != '\n') && ((linePtr - text) < MAX_LINE_BUFFER_SIZE))
{
linePtr++;
}
// Advance past the '\n' delimiter to the start of the next line
if (linePtr[0] == '\n') linePtr++;
}
return maxWidth;
}
#endif // !RAYGUI_NO_ICONS
//----------------------------------------------------------------------------------
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
// Get text line width (stops at '\n' or '\0')
// NOTE: Considers icon marker '#NNN#'
static int GetLineWidth(const char *text) static int GetLineWidth(const char *text)
{ {
#if !defined(RAYGUI_ICON_TEXT_PADDING) #if !defined(RAYGUI_ICON_TEXT_PADDING)
#define RAYGUI_ICON_TEXT_PADDING 4 #define RAYGUI_ICON_TEXT_PADDING 4
#endif #endif
Vector2 textSize = { 0 }; Vector2 textSize = { 0 };
int textIconOffset = 0; int textIconOffset = 0;
@ -5187,37 +5269,6 @@ static int GetLineWidth(const char *text)
return (int)textSize.x; return (int)textSize.x;
} }
// Get text width considering gui style and icon size (if required).
// For multi-line text (containing '\n'), returns the width of the widest line.
int GuiGetTextWidth(const char *text)
{
if (text == NULL) return 0;
int maxWidth = 0;
const char *linePtr = text;
while ((linePtr[0] != '\0') && ((linePtr - text) < MAX_LINE_BUFFER_SIZE))
{
int lineWidth = GetLineWidth(linePtr);
if (lineWidth > maxWidth) maxWidth = lineWidth;
// Skip to the next '\n' (or end of string/buffer)
while ((linePtr[0] != '\0') && (linePtr[0] != '\n') && ((linePtr - text) < MAX_LINE_BUFFER_SIZE))
{
linePtr++;
}
// Advance past the '\n' delimiter to the start of the next line
if (linePtr[0] == '\n') linePtr++;
}
return maxWidth;
}
#endif // !RAYGUI_NO_ICONS
//----------------------------------------------------------------------------------
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
// Get text bounds considering control bounds // Get text bounds considering control bounds
static Rectangle GetTextBounds(int control, Rectangle bounds) static Rectangle GetTextBounds(int control, Rectangle bounds)
{ {
@ -5590,7 +5641,8 @@ static void GuiTooltip(Rectangle controlRec)
{ {
if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiControlExclusiveMode) if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiControlExclusiveMode)
{ {
Vector2 textSize = MeasureTextEx(GuiGetFont(), guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); Vector2 textSize = MeasureTextEx(guiFont, guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE),
(float)GuiGetStyle(DEFAULT, TEXT_SPACING));
if ((controlRec.x + textSize.x + 16) > GetScreenWidth()) controlRec.x -= (textSize.x + 16 - controlRec.width); if ((controlRec.x + textSize.x + 16) > GetScreenWidth()) controlRec.x -= (textSize.x + 16 - controlRec.width);
@ -5612,174 +5664,6 @@ static void GuiTooltip(Rectangle controlRec)
} }
} }
// Split controls text into multiple strings
// NOTE: Re-used by GuiToggleSlider(), GuiComboBox(), GuiDropdownBox(), GuiListView(), GuiMessageBox(), GuiInputBox()
static char **GuiTextSplit(const char *text, char delimiter, int *count)
{
// NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
// inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
// all used memory is static... it has some limitations:
// 1. Maximum number of possible split strings is set by RAYGUI_TEXTSPLIT_MAX_ITEMS
// 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE
// NOTE: Those definitions could be externally provided if required
#if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS)
#define RAYGUI_TEXTSPLIT_MAX_ITEMS 128
#endif
#if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE)
#define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 // WARNING: Max expected size for all concat items
#endif
static char *itemPtrs[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { 0 }; // String pointers array (points to buffer data)
static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; // Buffer data (text input copy with '\0' added)
memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE);
itemPtrs[0] = buffer;
int itemCounter = 1;
// Count how many substrings text contains and point to every one of them
for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++)
{
buffer[i] = text[i];
if (buffer[i] == '\0') break;
else if ((buffer[i] == delimiter) || (buffer[i] == '\n'))
{
itemPtrs[itemCounter] = buffer + i + 1;
buffer[i] = '\0'; // Set terminator for current item
itemCounter++;
if (itemCounter >= RAYGUI_TEXTSPLIT_MAX_ITEMS) break;
}
}
*count = itemCounter;
return itemPtrs;
}
// Convert color data from RGB to HSV
// NOTE: Color data should be passed normalized
static Vector3 ConvertRGBtoHSV(Vector3 rgb)
{
Vector3 hsv = { 0 };
float min = 0.0f;
float max = 0.0f;
float delta = 0.0f;
min = (rgb.x < rgb.y)? rgb.x : rgb.y;
min = (min < rgb.z)? min : rgb.z;
max = (rgb.x > rgb.y)? rgb.x : rgb.y;
max = (max > rgb.z)? max : rgb.z;
hsv.z = max; // Value
delta = max - min;
if (delta < 0.00001f)
{
hsv.y = 0.0f;
hsv.x = 0.0f; // Undefined, maybe NAN?
return hsv;
}
if (max > 0.0f)
{
// NOTE: If max is 0, this divide would cause a crash
hsv.y = (delta/max); // Saturation
}
else
{
// NOTE: If max is 0, then r = g = b = 0, s = 0, h is undefined
hsv.y = 0.0f;
hsv.x = 0.0f; // Undefined, maybe NAN?
return hsv;
}
// NOTE: Comparing float values could not work properly
if (rgb.x >= max) hsv.x = (rgb.y - rgb.z)/delta; // Between yellow & magenta
else
{
if (rgb.y >= max) hsv.x = 2.0f + (rgb.z - rgb.x)/delta; // Between cyan & yellow
else hsv.x = 4.0f + (rgb.x - rgb.y)/delta; // Between magenta & cyan
}
hsv.x *= 60.0f; // Convert to degrees
if (hsv.x < 0.0f) hsv.x += 360.0f;
return hsv;
}
// Convert color data from HSV to RGB
// NOTE: Color data should be passed normalized
static Vector3 ConvertHSVtoRGB(Vector3 hsv)
{
Vector3 rgb = { 0 };
float hh = 0.0f, p = 0.0f, q = 0.0f, t = 0.0f, ff = 0.0f;
long i = 0;
// NOTE: Comparing float values could not work properly
if (hsv.y <= 0.0f)
{
rgb.x = hsv.z;
rgb.y = hsv.z;
rgb.z = hsv.z;
return rgb;
}
hh = hsv.x;
if (hh >= 360.0f) hh = 0.0f;
hh /= 60.0f;
i = (long)hh;
ff = hh - i;
p = hsv.z*(1.0f - hsv.y);
q = hsv.z*(1.0f - (hsv.y*ff));
t = hsv.z*(1.0f - (hsv.y*(1.0f - ff)));
switch (i)
{
case 0:
{
rgb.x = hsv.z;
rgb.y = t;
rgb.z = p;
} break;
case 1:
{
rgb.x = q;
rgb.y = hsv.z;
rgb.z = p;
} break;
case 2:
{
rgb.x = p;
rgb.y = hsv.z;
rgb.z = t;
} break;
case 3:
{
rgb.x = p;
rgb.y = q;
rgb.z = hsv.z;
} break;
case 4:
{
rgb.x = t;
rgb.y = p;
rgb.z = hsv.z;
} break;
case 5:
default:
{
rgb.x = hsv.z;
rgb.y = p;
rgb.z = q;
} break;
}
return rgb;
}
// Scroll bar control (used by GuiScrollPanel()) // Scroll bar control (used by GuiScrollPanel())
static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue)
{ {
@ -5951,8 +5835,261 @@ static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue)
return value; return value;
} }
// Update font image atlas to append raygui icons
static int GuiFontIconBaking(Image *imFont, Font font, Rectangle *whiteRec)
{
int iconOffsetY = 0;
// Check max glyph rec y bottom position in the atlas image,
// to start drawing icons below that line
int maxGlyphRecY = 0;
for (int i = 0; i < font.glyphCount; i++)
{
if ((font.recs[i].y + font.recs[i].height) > maxGlyphRecY)
maxGlyphRecY = font.recs[i].y + font.recs[i].height;
}
int maxIconsPerLine = imFont->width/(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING);
int reqIconLines = RAYGUI_ICON_MAX_FONT_BACKED/maxIconsPerLine + RAYGUI_ICON_MAX_FONT_BACKED%maxIconsPerLine + 1; // One extra line
int reqHeight = reqIconLines*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING);
// Check if image requires scaling and how much
if ((maxGlyphRecY + reqHeight) > imFont->height)
{
int newImHeight = 1;
while (newImHeight < (maxGlyphRecY + reqHeight)) newImHeight <<= 1; // Round to next POT
char *newImData = (char *)RL_CALLOC(imFont->width*newImHeight*2, sizeof(char));
memcpy(newImData, imFont->data, imFont->width*imFont->height*2);
RL_FREE(imFont->data);
// Clear imFont bottom-right corner rec
for (int y = 0; y < 4; y++)
for (int x = 0; x < 4; x++)
((unsigned short *)newImData)[(imFont->height - y - 1)*imFont->width + imFont->width - x - 1] = 0x0000;
imFont->data = newImData;
imFont->height = newImHeight;
// Set new image white corner and new white rec
for (int y = 0; y < 3; y++)
for (int x = 0; x < 3; x++)
((unsigned short *)newImData)[(imFont->height - y - 1)*imFont->width + imFont->width - x - 1] = 0xffff;
*whiteRec = (Rectangle){ imFont->width - 2, imFont->height - 2, 1, 1 };
}
// Calculate image offset positions to start drawing
// NOTE: For Y, look for a multiple of icon size + 2*padding, for better alignment
int offsetX = RAYGUI_ICON_FONT_ATLAS_PADDING;
int offsetY = ((maxGlyphRecY + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING - 1))/
(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING))*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) +
RAYGUI_ICON_FONT_ATLAS_PADDING;
iconOffsetY = offsetY - RAYGUI_ICON_FONT_ATLAS_PADDING;
unsigned short *pixels = (unsigned short *)imFont->data;
#define BIT_CHECK(a,b) ((a) & (1u<<(b)))
for (int iconId = 0; iconId < RAYGUI_ICON_MAX_FONT_BACKED; iconId++)
{
// Wrap to next line if next icon won't fit
if ((offsetX + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING)) > imFont->width)
{
offsetX = RAYGUI_ICON_FONT_ATLAS_PADDING;
offsetY += RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING;
}
for (int i = 0, y = 0; i < RAYGUI_ICON_DATA_ELEMENTS; i++)
{
unsigned int data = guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i];
for (int k = 0; k < 32; k++)
{
pixels[(offsetY + y)*imFont->width + offsetX + k%16] = (BIT_CHECK(data, k))? 0xffff : 0x00ff;
if ((k == 15) || (k == 31)) y++;
}
}
// Update current icon X position
offsetX += (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING);
}
return iconOffsetY;
}
// Split controls text into multiple strings
// NOTE: Re-used by GuiToggleSlider(), GuiComboBox(), GuiDropdownBox(), GuiListView(), GuiMessageBox(), GuiInputBox()
static char **GuiTextSplit(const char *text, char delimiter, int *count)
{
// NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
// inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
// all used memory is static... it has some limitations:
// 1. Maximum number of possible split strings is set by RAYGUI_TEXTSPLIT_MAX_ITEMS
// 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE
// NOTE: Those definitions could be externally provided if required
#if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS)
#define RAYGUI_TEXTSPLIT_MAX_ITEMS 128
#endif
#if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE)
#define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 // WARNING: Max expected size for all concat items
#endif
static char *itemPtrs[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { 0 }; // String pointers array (points to buffer data)
static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; // Buffer data (text input copy with '\0' added)
memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE);
itemPtrs[0] = buffer;
int itemCounter = 1;
// Count how many substrings text contains and point to every one of them
for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++)
{
buffer[i] = text[i];
if (buffer[i] == '\0') break;
else if ((buffer[i] == delimiter) || (buffer[i] == '\n'))
{
itemPtrs[itemCounter] = buffer + i + 1;
buffer[i] = '\0'; // Set terminator for current item
itemCounter++;
if (itemCounter >= RAYGUI_TEXTSPLIT_MAX_ITEMS) break;
}
}
*count = itemCounter;
return itemPtrs;
}
// Convert color data from RGB to HSV
// NOTE: Color data should be passed normalized
static Vector3 ConvertRGBtoHSV(Vector3 rgb)
{
Vector3 hsv = { 0 };
float min = 0.0f;
float max = 0.0f;
float delta = 0.0f;
min = (rgb.x < rgb.y)? rgb.x : rgb.y;
min = (min < rgb.z)? min : rgb.z;
max = (rgb.x > rgb.y)? rgb.x : rgb.y;
max = (max > rgb.z)? max : rgb.z;
hsv.z = max; // Value
delta = max - min;
if (delta < 0.00001f)
{
hsv.y = 0.0f;
hsv.x = 0.0f; // Undefined, maybe NAN?
return hsv;
}
if (max > 0.0f)
{
// NOTE: If max is 0, this divide would cause a crash
hsv.y = (delta/max); // Saturation
}
else
{
// NOTE: If max is 0, then r = g = b = 0, s = 0, h is undefined
hsv.y = 0.0f;
hsv.x = 0.0f; // Undefined, maybe NAN?
return hsv;
}
// NOTE: Comparing float values could not work properly
if (rgb.x >= max) hsv.x = (rgb.y - rgb.z)/delta; // Between yellow & magenta
else
{
if (rgb.y >= max) hsv.x = 2.0f + (rgb.z - rgb.x)/delta; // Between cyan & yellow
else hsv.x = 4.0f + (rgb.x - rgb.y)/delta; // Between magenta & cyan
}
hsv.x *= 60.0f; // Convert to degrees
if (hsv.x < 0.0f) hsv.x += 360.0f;
return hsv;
}
// Convert color data from HSV to RGB
// NOTE: Color data should be passed normalized
static Vector3 ConvertHSVtoRGB(Vector3 hsv)
{
Vector3 rgb = { 0 };
float hh = 0.0f, p = 0.0f, q = 0.0f, t = 0.0f, ff = 0.0f;
long i = 0;
// NOTE: Comparing float values could not work properly
if (hsv.y <= 0.0f)
{
rgb.x = hsv.z;
rgb.y = hsv.z;
rgb.z = hsv.z;
return rgb;
}
hh = hsv.x;
if (hh >= 360.0f) hh = 0.0f;
hh /= 60.0f;
i = (long)hh;
ff = hh - i;
p = hsv.z*(1.0f - hsv.y);
q = hsv.z*(1.0f - (hsv.y*ff));
t = hsv.z*(1.0f - (hsv.y*(1.0f - ff)));
switch (i)
{
case 0:
{
rgb.x = hsv.z;
rgb.y = t;
rgb.z = p;
} break;
case 1:
{
rgb.x = q;
rgb.y = hsv.z;
rgb.z = p;
} break;
case 2:
{
rgb.x = p;
rgb.y = hsv.z;
rgb.z = t;
} break;
case 3:
{
rgb.x = p;
rgb.y = q;
rgb.z = hsv.z;
} break;
case 4:
{
rgb.x = t;
rgb.y = p;
rgb.z = hsv.z;
} break;
case 5:
default:
{
rgb.x = hsv.z;
rgb.y = p;
rgb.z = q;
} break;
}
return rgb;
}
// Color fade-in or fade-out, alpha goes from 0.0f to 1.0f // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
// WARNING: It multiplies current alpha by alpha scale factor // WARNING: It multiplies current alpha by alpha scale factor,
// raylib Fade() multiplies alpha by 255.0f
static Color GuiFade(Color color, float alpha) static Color GuiFade(Color color, float alpha)
{ {
if (alpha < 0.0f) alpha = 0.0f; if (alpha < 0.0f) alpha = 0.0f;
@ -5977,6 +6114,19 @@ static Color GetColor(int hexValue)
return color; return color;
} }
// Get color with alpha applied, alpha goes from 0.0f to 1.0f
static Color Fade(Color color, float alpha)
{
Color result = color;
if (alpha < 0.0f) alpha = 0.0f;
else if (alpha > 1.0f) alpha = 1.0f;
result.a = (unsigned char)(255.0f*alpha);
return result;
}
// Returns hexadecimal value for a Color // Returns hexadecimal value for a Color
static int ColorToInt(Color color) static int ColorToInt(Color color)
{ {