mirror of
https://github.com/raysan5/raygui.git
synced 2026-07-12 00:31:56 -04:00
Compare commits
5 Commits
a543dfd655
...
8d33708103
| Author | SHA1 | Date | |
|---|---|---|---|
| 8d33708103 | |||
| 1066fd663f | |||
| 5d3a35d674 | |||
| 3ad9038e02 | |||
| ad18a0ab07 |
@ -38,6 +38,7 @@
|
||||
//#define RAYGUI_DEBUG_RECS_BOUNDS
|
||||
//#define RAYGUI_DEBUG_TEXT_BOUNDS
|
||||
|
||||
//#define RAYGUI_FONT_ICONS_BAKING
|
||||
#define RAYGUI_IMPLEMENTATION
|
||||
//#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
|
||||
@ -66,13 +67,17 @@ int main()
|
||||
// Initialization
|
||||
//---------------------------------------------------------------------------------------
|
||||
const int screenWidth = 960;
|
||||
const int screenHeight = 560;
|
||||
const int screenHeight = 580;
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "raygui - controls test suite");
|
||||
SetExitKey(0);
|
||||
|
||||
// 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;
|
||||
bool dropDown000EditMode = false;
|
||||
|
||||
@ -212,31 +217,34 @@ int main()
|
||||
if (dropDown000EditMode || dropDown001EditMode) GuiLock();
|
||||
if (showTextInputBox) GuiLock();
|
||||
|
||||
GuiSetStyle(TABBAR, TAB_ITEMS_WIDTH, 140);
|
||||
GuiTabBar((Rectangle){ 0, 8, GetScreenWidth(), 26 }, tabNames, tabCount, &tabActive);
|
||||
|
||||
// First GUI column
|
||||
//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(VALUEBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
|
||||
if (GuiSpinner((Rectangle){ 25, 135, 125, 30 }, NULL, &spinner001Value, 0, 100, spinnerEditMode)) spinnerEditMode = !spinnerEditMode;
|
||||
if (GuiValueBox((Rectangle){ 25, 175, 125, 30 }, NULL, &valueBox002Value, 0, 100, valueBoxEditMode)) valueBoxEditMode = !valueBoxEditMode;
|
||||
if (GuiSpinner((Rectangle){ 25, 135 + 20, 125, 30 }, NULL, &spinner001Value, 0, 100, spinnerEditMode)) spinnerEditMode = !spinnerEditMode;
|
||||
if (GuiValueBox((Rectangle){ 25, 175 + 20, 125, 30 }, NULL, &valueBox002Value, 0, 100, valueBoxEditMode)) valueBoxEditMode = !valueBoxEditMode;
|
||||
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);
|
||||
|
||||
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();
|
||||
GuiSetState(STATE_NORMAL); if (GuiButton((Rectangle){ 30, 320, 115, 30 }, "NORMAL")) { }
|
||||
GuiSetState(STATE_FOCUSED); if (GuiButton((Rectangle){ 30, 355, 115, 30 }, "FOCUSED")) { }
|
||||
GuiSetState(STATE_PRESSED); if (GuiButton((Rectangle){ 30, 390, 115, 30 }, "#15#PRESSED")) { }
|
||||
GuiSetState(STATE_DISABLED); if (GuiButton((Rectangle){ 30, 425, 115, 30 }, "DISABLED")) { }
|
||||
GuiSetState(STATE_NORMAL); if (GuiButton((Rectangle){ 30, 320 + 20, 115, 30 }, "NORMAL")) { }
|
||||
GuiSetState(STATE_FOCUSED); if (GuiButton((Rectangle){ 30, 355 + 20, 115, 30 }, "FOCUSED")) { }
|
||||
GuiSetState(STATE_PRESSED); if (GuiButton((Rectangle){ 30, 390 + 20, 115, 30 }, "#15#PRESSED")) { }
|
||||
GuiSetState(STATE_DISABLED); if (GuiButton((Rectangle){ 30, 425 + 20, 115, 30 }, "DISABLED")) { }
|
||||
GuiSetState(STATE_NORMAL);
|
||||
//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);
|
||||
|
||||
// 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_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_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
|
||||
//GuiSetStyle(LISTVIEW, LIST_ITEMS_BORDER_NORMAL, 1);
|
||||
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);
|
||||
GuiListView((Rectangle){ 165, 25 + 20, 140, 124 }, "Charmander;Bulbasaur;#18#Squirtle;Pikachu;Eevee;Pidgey", &listViewScrollIndex, &listViewActive);
|
||||
GuiListViewEx((Rectangle){ 165, 162 + 20, 140, 184 }, listViewExList, 8, &listViewExScrollIndex, &listViewExActive, &listViewExFocus);
|
||||
GuiSetStyle(LISTVIEW, LIST_ITEMS_BORDER_NORMAL, 0);
|
||||
|
||||
//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();
|
||||
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);
|
||||
|
||||
// Third GUI column
|
||||
GuiPanel((Rectangle){ 320, 25, 225, 140 }, "Panel Info");
|
||||
GuiColorPicker((Rectangle){ 320, 185, 196, 192 }, NULL, &colorPickerValue);
|
||||
GuiPanel((Rectangle){ 320, 25 + 20, 225, 140 }, "Panel Info");
|
||||
GuiColorPicker((Rectangle){ 320, 185 + 20, 196, 192 }, NULL, &colorPickerValue);
|
||||
|
||||
//GuiDisable();
|
||||
GuiSlider((Rectangle){ 355, 400, 165, 20 }, "TEST", TextFormat("%2.2f", sliderValue), &sliderValue, -50, 100);
|
||||
GuiSliderBar((Rectangle){ 320, 430, 200, 20 }, NULL, TextFormat("%i", (int)sliderBarValue), &sliderBarValue, 0, 100);
|
||||
GuiSlider((Rectangle){ 355, 400 + 20, 165, 20 }, "TEST", TextFormat("%2.2f", sliderValue), &sliderValue, -50, 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();
|
||||
|
||||
// NOTE: View rectangle could be used to perform some scissor test
|
||||
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 };
|
||||
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_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_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE);
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
GLFW_ICON ICON "raygui.ico"
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 4,0,0,0
|
||||
PRODUCTVERSION 4,0,0,0
|
||||
FILEVERSION 5,0,0,0
|
||||
PRODUCTVERSION 5,0,0,0
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
@ -11,12 +11,12 @@ BEGIN
|
||||
BEGIN
|
||||
//VALUE "CompanyName", "raylib technologies"
|
||||
VALUE "FileDescription", "raygui application (www.raylib.com)"
|
||||
VALUE "FileVersion", "4.0.0"
|
||||
VALUE "FileVersion", "5.0.0"
|
||||
VALUE "InternalName", "raygui app"
|
||||
VALUE "LegalCopyright", "(c) 2023 Ramon Santamaria (@raysan5)"
|
||||
VALUE "LegalCopyright", "(c) 2026 Ramon Santamaria (@raysan5)"
|
||||
//VALUE "OriginalFilename", "raygui_app.exe"
|
||||
VALUE "ProductName", "raygui app"
|
||||
VALUE "ProductVersion", "4.0.0"
|
||||
VALUE "ProductVersion", "5.0.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
7
projects/VS2022/raylib/Directory.Build.props
Normal file
7
projects/VS2022/raylib/Directory.Build.props
Normal 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>
|
||||
618
src/raygui.h
618
src/raygui.h
@ -134,6 +134,10 @@
|
||||
* Includes custom ricons.h header defining a set of custom icons,
|
||||
* 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
|
||||
* Draw control bounds rectangles for debug
|
||||
*
|
||||
@ -143,6 +147,7 @@
|
||||
* VERSIONS HISTORY:
|
||||
* 5.0 (xx-Jun-2026) ADDED: TABBAR control: GuiTabBar()
|
||||
* ADDED: Support up to 512 icons (v500)
|
||||
* ADDED: Support icons baking into font atlas image
|
||||
* ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes
|
||||
* ADDED: Altrnative VALUEBOX: GuiValueBoxFloat()
|
||||
* ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP
|
||||
@ -167,6 +172,7 @@
|
||||
* REVIEWED: GuiProgressBar(), improved borders computing
|
||||
* REVIEWED: GuiTextBox(), multiple improvements: autocursor and more
|
||||
* 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: GuiColorPanel(), improved HSV <-> RGBA convertion
|
||||
* REDESIGNED: WARNING: TEXT_LINE_SPACING does not consider text height, only lines spacing
|
||||
@ -386,8 +392,8 @@
|
||||
#define RAYGUI_LOG(...)
|
||||
#endif
|
||||
|
||||
#if !defined(RAYGUI_STANDALONE)
|
||||
// Macros to define required UI inputs, including mapping to gamepad controls
|
||||
// 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
|
||||
@ -398,7 +404,9 @@
|
||||
#if !defined(GUI_BUTTON_PRESSED)
|
||||
#define GUI_BUTTON_PRESSED (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsGamepadButtonPressed(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN))
|
||||
#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)
|
||||
#define GUI_BUTTON_RELEASED (IsMouseButtonReleased(MOUSE_LEFT_BUTTON) || IsGamepadButtonReleased(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN))
|
||||
#endif
|
||||
@ -424,6 +432,18 @@
|
||||
#if !defined(GUI_INPUT_KEY)
|
||||
#define GUI_INPUT_KEY GetCharPressed()
|
||||
#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
|
||||
@ -458,6 +478,8 @@
|
||||
unsigned char a;
|
||||
} Color;
|
||||
|
||||
#define BLANK (Color){ 0, 0, 0, 0 } // Blank (Transparent)
|
||||
|
||||
// Rectangle type
|
||||
typedef struct Rectangle {
|
||||
float x;
|
||||
@ -466,7 +488,7 @@
|
||||
float height;
|
||||
} 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
|
||||
typedef struct Texture {
|
||||
unsigned int id; // OpenGL texture id
|
||||
@ -497,7 +519,7 @@
|
||||
Image image; // Character image data
|
||||
} 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
|
||||
typedef struct Font {
|
||||
int baseSize; // Base size (default chars height)
|
||||
@ -1152,7 +1174,9 @@ typedef enum {
|
||||
// Embedded icons, no external file provided
|
||||
#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_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_FONT_ATLAS_PADDING 1 // Padding between backed icons in font atlas
|
||||
|
||||
// Icons data is defined by bit array (every bit represents one pixel)
|
||||
// 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 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 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 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
|
||||
//-------------------------------------------------------------------------------
|
||||
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 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'
|
||||
@ -1567,6 +1595,7 @@ static void DrawRectangleGradientV(int posX, int posY, int width, int height, Co
|
||||
//----------------------------------------------------------------------------------
|
||||
// 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 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 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 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
|
||||
|
||||
@ -1851,7 +1881,7 @@ int GuiTabBar(Rectangle bounds, char **text, int count, int *active)
|
||||
}
|
||||
|
||||
// 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_ALIGNMENT, textAlignment);
|
||||
@ -1877,7 +1907,7 @@ int GuiTabBar(Rectangle bounds, char **text, int count, int *active)
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -2614,7 +2644,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
|
||||
int result = 0;
|
||||
GuiState state = guiState;
|
||||
|
||||
bool multiline = false; // TODO: Consider multiline text input
|
||||
bool multiline = false;
|
||||
int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE);
|
||||
|
||||
Rectangle textBounds = GetTextBounds(TEXTBOX, bounds);
|
||||
@ -4663,10 +4693,8 @@ void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
|
||||
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
|
||||
// NOTE: Font texture loading requires raylib
|
||||
int fontDataSize = 0;
|
||||
memcpy(&fontDataSize, fileDataPtr, sizeof(int));
|
||||
fileDataPtr += 4;
|
||||
@ -4732,16 +4760,7 @@ void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
|
||||
fileDataPtr += fontImageUncompSize;
|
||||
}
|
||||
|
||||
// Load texture from image
|
||||
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
|
||||
// Load font recs data (glyphs position and size in the image atlas)
|
||||
int recsDataSize = font.glyphCount*sizeof(Rectangle);
|
||||
int recsDataCompressedSize = 0;
|
||||
|
||||
@ -4835,11 +4854,22 @@ void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
|
||||
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
|
||||
// NOTE: It makes possible to draw shapes and text (full UI) in a single draw call
|
||||
if ((fontWhiteRec.x > 0) &&
|
||||
@ -4847,7 +4877,12 @@ void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
|
||||
(fontWhiteRec.width > 0) &&
|
||||
(fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec);
|
||||
}
|
||||
else font = GetFontDefault();
|
||||
|
||||
GuiSetFont(font);
|
||||
#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
|
||||
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
|
||||
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)))
|
||||
|
||||
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 !defined(RAYGUI_STANDALONE)
|
||||
GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize, (float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color);
|
||||
#endif
|
||||
GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize,
|
||||
(float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color);
|
||||
}
|
||||
|
||||
if ((k == 15) || (k == 31)) y++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set icon drawing size
|
||||
@ -5126,15 +5179,44 @@ void GuiSetIconScale(int scale)
|
||||
if (scale >= 1) guiIconScale = scale;
|
||||
}
|
||||
|
||||
// Get the width of a single line of gui text (stops at '\n' or '\0'),
|
||||
// considering the gui font/style and an optional icon marker '#NNN#' at
|
||||
// the start. Icon detection matches GetTextIcon(): 1..3 digits, skip past
|
||||
// the closing '#'.
|
||||
// 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 line width (stops at '\n' or '\0')
|
||||
// NOTE: Considers icon marker '#NNN#'
|
||||
static int GetLineWidth(const char *text)
|
||||
{
|
||||
#if !defined(RAYGUI_ICON_TEXT_PADDING)
|
||||
#if !defined(RAYGUI_ICON_TEXT_PADDING)
|
||||
#define RAYGUI_ICON_TEXT_PADDING 4
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Vector2 textSize = { 0 };
|
||||
int textIconOffset = 0;
|
||||
@ -5187,37 +5269,6 @@ static int GetLineWidth(const char *text)
|
||||
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
|
||||
static Rectangle GetTextBounds(int control, Rectangle bounds)
|
||||
{
|
||||
@ -5590,7 +5641,8 @@ static void GuiTooltip(Rectangle controlRec)
|
||||
{
|
||||
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);
|
||||
|
||||
@ -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())
|
||||
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;
|
||||
}
|
||||
|
||||
// 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
|
||||
// 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)
|
||||
{
|
||||
if (alpha < 0.0f) alpha = 0.0f;
|
||||
@ -5977,6 +6114,19 @@ static Color GetColor(int hexValue)
|
||||
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
|
||||
static int ColorToInt(Color color)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user