3 Commits

Author SHA1 Message Date
Ray
5cc802fd9e Update raygui.h 2026-07-03 11:34:08 +02:00
Ray
a05cdf74eb Update controls_test_suite.c 2026-06-28 01:00:16 +02:00
Ray
9832dbb0c4 ADDED: GuiTabBarEx() with additional parameters -WIP-
REVIEWED: `GuiTabBar()` added horizontal-scroll
2026-06-28 01:00:07 +02:00
2 changed files with 116 additions and 101 deletions

View File

@ -38,7 +38,7 @@
//#define RAYGUI_DEBUG_RECS_BOUNDS
//#define RAYGUI_DEBUG_TEXT_BOUNDS
//#define RAYGUI_FONT_ICONS_BAKING
#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
@ -74,8 +74,6 @@ int main()
// 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;
@ -218,7 +216,7 @@ int main()
if (showTextInputBox) GuiLock();
GuiSetStyle(TABBAR, TAB_ITEMS_WIDTH, 140);
GuiTabBar((Rectangle){ 0, 8, GetScreenWidth(), 26 }, tabNames, tabCount, &tabActive);
GuiTabBar((Rectangle){ 0, 8, GetScreenWidth(), 26 }, "#176#TAB_01;#177#TAB_02;#178#TAB_03;#179#TAB_04;#180#TAB_05;#181#TAB_06", NULL, &tabActive);
// First GUI column
//GuiSetStyle(CHECKBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
@ -244,6 +242,7 @@ int main()
GuiSetState(STATE_NORMAL);
//GuiUnlock();
GuiSetStyle(COMBOBOX, COMBO_BUTTON_WIDTH, 40);
GuiComboBox((Rectangle){ 25, 480 + 20, 125, 30 },
"default;Jungle;Lavanda;Dark;Bluish;Cyber;Terminal;Candy;Cherry;Ashes;Enefete;Sunny;Amber;Genesis", &visualStyleActive);
@ -257,7 +256,7 @@ int main()
GuiSetStyle(DROPDOWNBOX, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
GuiSetStyle(DROPDOWNBOX, TEXT_PADDING, 0);
if (GuiDropdownBox((Rectangle){ 25, 25 + 20, 125, 30 }, "ONE;TWO;THREE", &dropdownBox000Active, dropDown000EditMode)) dropDown000EditMode = !dropDown000EditMode;
if (GuiDropdownBox((Rectangle){ 25, 25 + 20, 125, 30 }, "#27#ONE;#28#TWO;#29#THREE", &dropdownBox000Active, dropDown000EditMode)) dropDown000EditMode = !dropDown000EditMode;
// Second GUI column
//GuiSetStyle(LISTVIEW, LIST_ITEMS_BORDER_NORMAL, 1);

View File

@ -133,7 +133,7 @@
* #define RAYGUI_CUSTOM_ICONS
* 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
@ -817,7 +817,6 @@ RAYGUIAPI int GuiWindowBox(Rectangle bounds, const char *title);
RAYGUIAPI int GuiGroupBox(Rectangle bounds, const char *text); // Group Box control with text name
RAYGUIAPI int GuiLine(Rectangle bounds, const char *text); // Line separator control, could contain text
RAYGUIAPI int GuiPanel(Rectangle bounds, const char *text); // Panel control, useful to group controls
RAYGUIAPI int GuiTabBar(Rectangle bounds, char **text, int count, int *active); // Tab Bar control, returns TAB to be closed or -1
RAYGUIAPI int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view); // Scroll Panel control
// Basic controls set
@ -845,15 +844,17 @@ RAYGUIAPI int GuiGrid(Rectangle bounds, const char *text, float spacing, int sub
// Advance controls set
RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active); // List View control
RAYGUIAPI int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus); // List View using text entries list and returning focus entry
RAYGUIAPI int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus); // List View control, using text entries list and returning focus entry
RAYGUIAPI int GuiTabBar(Rectangle bounds, const char *text, int *hscroll, int *active); // Tab Bar control
RAYGUIAPI int GuiTabBarEx(Rectangle bounds, char **text, int count, int *hscroll, int *active, int *focus); // Tab Bar control, using text entries list and returning focus entry
RAYGUIAPI int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons); // Message Box control, displays a message
RAYGUIAPI int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive); // Text Input Box control, ask for text, supports secret
RAYGUIAPI int GuiColorPicker(Rectangle bounds, const char *text, Color *color); // Color Picker control (multiple color controls)
RAYGUIAPI int GuiColorPicker(Rectangle bounds, const char *text, Color *color); // Color Picker control, includes Color bar controls
RAYGUIAPI int GuiColorPanel(Rectangle bounds, const char *text, Color *color); // Color Panel control
RAYGUIAPI int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha); // Color Bar Alpha control
RAYGUIAPI int GuiColorBarHue(Rectangle bounds, const char *text, float *value); // Color Bar Hue control
RAYGUIAPI int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Picker control that avoids conversion to RGB on each call (multiple color controls)
RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control that updates Hue-Saturation-Value color value, used by GuiColorPickerHSV()
RAYGUIAPI int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Picker control, using Hue-Saturation-Value color data, includes Color bar controls
RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control, using Hue-Saturation-Value color data
//----------------------------------------------------------------------------------------------------------
#if !defined(RAYGUI_NO_ICONS)
@ -1835,84 +1836,6 @@ int GuiPanel(Rectangle bounds, const char *text)
return result;
}
// Tab Bar control
// NOTE: Using GuiToggle() for the TABS
int GuiTabBar(Rectangle bounds, char **text, int count, int *active)
{
int result = -1;
//GuiState state = guiState;
int tabItemsWidth = GuiGetStyle(TABBAR, TAB_ITEMS_WIDTH);
Rectangle tabBounds = { bounds.x, bounds.y, (float)tabItemsWidth, bounds.height };
if (*active < 0) *active = 0;
else if (*active > count - 1) *active = count - 1;
int offsetX = 0; // Required in case tabs go out of screen
offsetX = (*active*tabItemsWidth) - GetScreenWidth();
if (offsetX < 0) offsetX = 0;
bool toggle = false; // Required for individual toggles
// Draw control
//--------------------------------------------------------------------
for (int i = 0; i < count; i++)
{
tabBounds.x = bounds.x + (tabItemsWidth + 4)*i + offsetX;
if (tabBounds.x < GetScreenWidth())
{
// Draw tabs as toggle controls
int textAlignment = GuiGetStyle(TOGGLE, TEXT_ALIGNMENT);
int textPadding = GuiGetStyle(TOGGLE, TEXT_PADDING);
GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
GuiSetStyle(TOGGLE, TEXT_PADDING, 8);
if (i == (*active))
{
toggle = true;
GuiToggle(tabBounds, text[i], &toggle);
}
else
{
toggle = false;
GuiToggle(tabBounds, text[i], &toggle);
if (toggle) *active = i;
}
// Close tab with middle mouse button pressed
if (CheckCollisionPointRec(GUI_POINTER_POSITION, tabBounds) && GUI_BUTTON_PRESSED_MID) result = i;
GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding);
GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment);
if (GuiGetStyle(TABBAR, TAB_CLOSE_BUTTON))
{
// Draw tab close button
// NOTE: Only draw close button for current tab: if (CheckCollisionPointRec(mousePosition, tabBounds))
int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
GuiSetStyle(BUTTON, BORDER_WIDTH, 1);
GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
#if defined(RAYGUI_NO_ICONS)
if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, "x")) result = i;
#else
if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 },
GuiIconText(ICON_CROSS_SMALL, NULL))) result = i;
#endif
GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment);
}
}
}
// Draw tab-bar bottom line
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
}
// Scroll Panel control
int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view)
{
@ -3859,6 +3782,98 @@ int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, in
return result;
}
// Tab Bar control
int GuiTabBar(Rectangle bounds, const char *text, int *hscroll, int *active)
{
int result = 0;
int itemCount = 0;
char **items = NULL;
if (text != NULL) items = GuiTextSplit(text, ';', &itemCount);
result = GuiTabBarEx(bounds, items, itemCount, hscroll, active, NULL);
return result;
}
// Tab Bar control, using text entries list and returning focus entry
// TODO: Remove using GuiToggle() for the TABS
int GuiTabBarEx(Rectangle bounds, char **text, int count, int *hscroll, int *active, int *focus)
{
int result = -1;
//GuiState state = guiState;
int tabItemsWidth = GuiGetStyle(TABBAR, TAB_ITEMS_WIDTH);
Rectangle tabBounds = { bounds.x, bounds.y, (float)tabItemsWidth, bounds.height };
if (*active < 0) *active = 0;
else if (*active > count - 1) *active = count - 1;
int offsetX = 0; // Required in case tabs go out of screen
offsetX = (*active*tabItemsWidth) - GetScreenWidth();
if (offsetX < 0) offsetX = 0;
bool toggle = false; // Required for individual toggles
// Draw control
//--------------------------------------------------------------------
for (int i = 0; i < count; i++)
{
tabBounds.x = bounds.x + (tabItemsWidth + 4)*i + offsetX;
if (tabBounds.x < GetScreenWidth())
{
// Draw tabs as toggle controls
int textAlignment = GuiGetStyle(TOGGLE, TEXT_ALIGNMENT);
int textPadding = GuiGetStyle(TOGGLE, TEXT_PADDING);
GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
GuiSetStyle(TOGGLE, TEXT_PADDING, 8);
if (i == (*active))
{
toggle = true;
GuiToggle(tabBounds, text[i], &toggle);
}
else
{
toggle = false;
GuiToggle(tabBounds, text[i], &toggle);
if (toggle) *active = i;
}
// Close tab with middle mouse button pressed
if (CheckCollisionPointRec(GUI_POINTER_POSITION, tabBounds) && GUI_BUTTON_PRESSED_MID) result = i;
GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding);
GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment);
if (GuiGetStyle(TABBAR, TAB_CLOSE_BUTTON))
{
// Draw tab close button
// NOTE: Only draw close button for current tab: if (CheckCollisionPointRec(mousePosition, tabBounds))
int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
GuiSetStyle(BUTTON, BORDER_WIDTH, 1);
GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
#if defined(RAYGUI_NO_ICONS)
if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, "x")) result = i;
#else
if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 },
GuiIconText(ICON_CROSS_SMALL, NULL))) result = i;
#endif
GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment);
}
}
}
// Draw tab-bar bottom line
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
}
// Color Panel control
int GuiColorPanel(Rectangle bounds, const char *text, Color *color)
{
@ -4498,7 +4513,8 @@ void GuiLoadStyle(const char *fileName)
sscanf(buffer, "f %d %s %[^\r\n]s", &fontSize, charmapFileName, fontFileName);
// GLOBAL: Copy font file name into guiFontName
strncpy(guiFontName, fontFileName, 31);
memcpy(guiFontName, fontFileName, 31);
guiFontName[31] = '\0';
Font font = { 0 };
int *codepoints = NULL;
@ -4987,7 +5003,7 @@ 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;
}
@ -5144,12 +5160,12 @@ void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color)
{
int maxIconsPerLine = guiFont.texture.width/(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING);
int x = iconId%maxIconsPerLine;
int y = 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,
Rectangle srcRec = { (float)x*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + RAYGUI_ICON_FONT_ATLAS_PADDING,
guiIconFontOffsetY + (float)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 };
Rectangle dstRec = { (float)posX, (float)posY, (float)pixelSize*RAYGUI_ICON_SIZE, (float)pixelSize*RAYGUI_ICON_SIZE };
DrawTexturePro(guiFont.texture, srcRec, dstRec, (Vector2){ 0, 0 }, 0.0f, color);
}
@ -5163,7 +5179,7 @@ void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color)
{
if (BIT_CHECK(guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i], k))
{
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);
}
@ -5641,7 +5657,7 @@ static void GuiTooltip(Rectangle controlRec)
{
if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiControlExclusiveMode)
{
Vector2 textSize = MeasureTextEx(guiFont, guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE),
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);
@ -5845,13 +5861,13 @@ static int GuiFontIconBaking(Image *imFont, Font font, Rectangle *whiteRec)
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;
if ((font.recs[i].y + font.recs[i].height) > maxGlyphRecY)
maxGlyphRecY = (int)font.recs[i].y + (int)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);
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)
@ -5876,7 +5892,7 @@ static int GuiFontIconBaking(Image *imFont, Font font, Rectangle *whiteRec)
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 };
*whiteRec = (Rectangle){ (float)imFont->width - 2, (float)imFont->height - 2, 1, 1 };
}
// Calculate image offset positions to start drawing