Modify custom_file_dialog, portable_window, propertly_list, and text_editor examples to be compatible with the newest raylib and raygui (#156)

Modify gui_textbox_extended.h to contain DrawTextRec and DrawTextRecEx since they were cut from raylib, also add DrawTextBoxedSelectable as an alias for DrawTextRecEx for compatibility/name consistency
Modify gui_textbox_extended.h to be compatible with the latest raylib
This commit is contained in:
Winter
2021-09-19 11:15:24 -07:00
committed by GitHub
parent c1af7c3edd
commit e81fd89b6d
7 changed files with 173 additions and 30 deletions

View File

@ -47,7 +47,7 @@ Styles can be loaded at runtime using raygui `GuiLoadStyle()` function. Simple a
## raygui icons
`raygui` supports custom icons provided as an external array of data. To support icons just define `RAYGUI_SUPPORT_ICONS` before including `raygui`.
`raygui` supports custom icons provided as an external array of data. To support icons just define `RAYGUI_SUPPORT_RICONS` before including `raygui`.
A set of custom handcrafted icons is provided in [`ricons`](src/ricons.h). This set of icons can be created and customized using [rGuiIcons](https://raylibtech.itch.io/rguiicons) tool.
@ -55,7 +55,7 @@ A set of custom handcrafted icons is provided in [`ricons`](src/ricons.h). This
```c
#define RAYGUI_IMPLEMENTATION
#define RAYGUI_SUPPORT_ICONS
#define RAYGUI_SUPPORT_RICONS
#include "raygui.h"
```
To use any of those icons in your gui, just preprend *iconId* to any text written within `raygui` controls:
@ -71,7 +71,7 @@ if (GuiButton(rec, GuiIconText(RICON_FILE_OPEN, "Open Image"))) { /* ACTION */ }
`raygui` is intended to be used as a portable library to be integrated in code form into the target project but some users could require a shared/dynamic version of the library, for example, to create bindings. In that case, `raygui` can be built as a shared library using:
```
mv src/raygui.h src/raygui.c && gcc -shared -fpic -DRAYGUI_SUPPORT_ICONS -DRAYGUI_IMPLEMENTATION -lraylib -lGL -lm -lpthread -ldl -lrt -lX11 src/raygui.c -o raygui.so
mv src/raygui.h src/raygui.c && gcc -shared -fpic -DRAYGUI_SUPPORT_RICONS -DRAYGUI_IMPLEMENTATION -lraylib -lGL -lm -lpthread -ldl -lrt -lX11 src/raygui.c -o raygui.so
```
license

View File

@ -18,7 +18,7 @@
#include "raylib.h"
#define RAYGUI_IMPLEMENTATION
#define RAYGUI_SUPPORT_ICONS
#define RAYGUI_SUPPORT_RICONS
#include "../../src/raygui.h"
#undef RAYGUI_IMPLEMENTATION // Avoid including raygui implementation again

View File

@ -18,7 +18,7 @@
#include "raylib.h"
#define RAYGUI_IMPLEMENTATION
#define RAYGUI_SUPPORT_ICONS
#define RAYGUI_SUPPORT_RICONS
#include "../../src/raygui.h"
//------------------------------------------------------------------------------------

View File

@ -398,7 +398,7 @@ double GuiDMSpinner(Rectangle bounds, double value, double minValue, double maxV
GuiSetStyle(BUTTON, BORDER_WIDTH, GuiGetStyle(SPINNER, BORDER_WIDTH));
GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
#if defined(RAYGUI_SUPPORT_ICONS)
#if defined(RAYGUI_SUPPORT_RICONS)
if (GuiButton(leftButtonBound, GuiIconText(RICON_ARROW_LEFT_FILL, NULL))) value -= step;
if (GuiButton(rightButtonBound, GuiIconText(RICON_ARROW_RIGHT_FILL, NULL))) value += step;
#else
@ -417,7 +417,7 @@ double GuiDMSpinner(Rectangle bounds, double value, double minValue, double maxV
void GuiDMPropertyList(Rectangle bounds, GuiDMProperty* props, int count, int* focus, int* scrollIndex) {
#ifdef RAYGUI_SUPPORT_ICONS
#ifdef RAYGUI_SUPPORT_RICONS
#define PROPERTY_COLLAPSED_ICON "#120#"
#define PROPERTY_EXPANDED_ICON "#121#"
#else

View File

@ -18,7 +18,7 @@
#include "raylib.h"
#define RAYGUI_IMPLEMENTATION
#define RAYGUI_SUPPORT_ICONS
#define RAYGUI_SUPPORT_RICONS
#include "../../src/raygui.h"
#undef RAYGUI_IMPLEMENTATION // Avoid including raygui implementation again

View File

@ -21,7 +21,7 @@
#include "raylib.h"
#define RAYGUI_IMPLEMENTATION
#define RAYGUI_SUPPORT_ICONS
#define RAYGUI_SUPPORT_RICONS
#include "../../src/raygui.h"
@ -131,7 +131,7 @@ bool GuiTextEditor(Rectangle bounds, char *text, int textSize, bool editMode)
bool textWrap = true; // TODO: Word-Wrap vs Char-Wrap -> textWrapMode { NO_WRAP_LOCK, NO_WRAP_OVERFLOW, CHAR_WRAP, WORD_WRAP }
// WARNING: First string full traversal
int codepointCount = GetCodepointsCount(text);
int codepointCount = GetCodepointCount(text);
int textLen = strlen(text); // Text length in bytes
@ -214,8 +214,8 @@ bool GuiTextEditor(Rectangle bounds, char *text, int textSize, bool editMode)
int codepoint = GetCodepoint(&text[i], &codepointByteCount);
int index = GetGlyphIndex(font, codepoint);
Rectangle rec = { bounds.x + textOffsetX + font.chars[index].offsetX*scaleFactor,
bounds.y + textOffsetY + font.chars[index].offsetY*scaleFactor,
Rectangle rec = { bounds.x + textOffsetX + font.glyphs[index].offsetX*scaleFactor,
bounds.y + textOffsetY + font.glyphs[index].offsetY*scaleFactor,
font.recs[index].width*scaleFactor, font.recs[index].height*scaleFactor };
// Automatic line break to wrap text inside box
@ -225,8 +225,8 @@ bool GuiTextEditor(Rectangle bounds, char *text, int textSize, bool editMode)
textOffsetX = 0.0f;
// Recalculate drawing rectangle position
rec = (Rectangle){ bounds.x + textOffsetX + font.chars[index].offsetX*scaleFactor,
bounds.y + textOffsetY + font.chars[index].offsetY*scaleFactor,
rec = (Rectangle){ bounds.x + textOffsetX + font.glyphs[index].offsetX*scaleFactor,
bounds.y + textOffsetY + font.glyphs[index].offsetY*scaleFactor,
font.recs[index].width*scaleFactor, font.recs[index].height*scaleFactor };
}
@ -280,8 +280,8 @@ bool GuiTextEditor(Rectangle bounds, char *text, int textSize, bool editMode)
// TODO: Consider spacing when drawing selected characters background
if (editMode && (selectStartCp != -1) && ((cp >= selectStartCp) && (cp <= (selectStartCp + selectLengthCp)))) DrawRectangleRec(rec, MAROON);
if (font.chars[index].advanceX == 0) textOffsetX += ((float)font.recs[index].width*scaleFactor + GuiGetStyle(DEFAULT, TEXT_SPACING));
else textOffsetX += ((float)font.chars[index].advanceX*scaleFactor + GuiGetStyle(DEFAULT, TEXT_SPACING));
if (font.glyphs[index].advanceX == 0) textOffsetX += ((float)font.recs[index].width*scaleFactor + GuiGetStyle(DEFAULT, TEXT_SPACING));
else textOffsetX += ((float)font.glyphs[index].advanceX*scaleFactor + GuiGetStyle(DEFAULT, TEXT_SPACING));
i += (codepointByteCount - 1); // Move text bytes counter to next codepoint
cp++;

View File

@ -31,7 +31,6 @@
#ifndef GUI_TEXTBOX_EXTENDED_H
#define GUI_TEXTBOX_EXTENDED_H
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
@ -78,6 +77,10 @@ RAYGUIDEF int GuiTextBoxGetByteIndex(const char *text, int start, int from, int
RAYGUIDEF bool GuiTextBoxEx(Rectangle bounds, char *text, int textSize, bool editMode);
RAYGUIDEF static void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint); // Draw text using font inside rectangle limits
RAYGUIDEF static void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint); // Draw text using font inside rectangle limits with support for text selection
RAYGUIDEF static void DrawTextBoxedSelectable(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint); // Alias for above
#ifdef __cplusplus
}
#endif
@ -96,6 +99,146 @@ RAYGUIDEF bool GuiTextBoxEx(Rectangle bounds, char *text, int textSize, bool edi
#include "raygui.h"
#endif
// Draw text using font inside rectangle limits
static void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint)
{
DrawTextRecEx(font, text, rec, fontSize, spacing, wordWrap, tint, 0, 0, WHITE, WHITE);
}
// Draw text using font inside rectangle limits with support for text selection
static void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint)
{
int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop
float textOffsetY = 0; // Offset between lines (on line break '\n')
float textOffsetX = 0.0f; // Offset X to next character to draw
float scaleFactor = fontSize/(float)font.baseSize; // Character rectangle scaling factor
// Word/character wrapping mechanism variables
enum { MEASURE_STATE = 0, DRAW_STATE = 1 };
int state = wordWrap? MEASURE_STATE : DRAW_STATE;
int startLine = -1; // Index where to begin drawing (where a line begins)
int endLine = -1; // Index where to stop drawing (where a line ends)
int lastk = -1; // Holds last value of the character position
for (int i = 0, k = 0; i < length; i++, k++)
{
// Get next codepoint from byte string and glyph index in font
int codepointByteCount = 0;
int codepoint = GetCodepoint(&text[i], &codepointByteCount);
int index = GetGlyphIndex(font, codepoint);
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
// but we need to draw all of the bad bytes using the '?' symbol moving one byte
if (codepoint == 0x3f) codepointByteCount = 1;
i += (codepointByteCount - 1);
float glyphWidth = 0;
if (codepoint != '\n')
{
glyphWidth = (font.glyphs[index].advanceX == 0) ? font.recs[index].width*scaleFactor : font.glyphs[index].advanceX*scaleFactor;
if (i + 1 < length) glyphWidth = glyphWidth + spacing;
}
// NOTE: When wordWrap is ON we first measure how much of the text we can draw before going outside of the rec container
// We store this info in startLine and endLine, then we change states, draw the text between those two variables
// and change states again and again recursively until the end of the text (or until we get outside of the container).
// When wordWrap is OFF we don't need the measure state so we go to the drawing state immediately
// and begin drawing on the next line before we can get outside the container.
if (state == MEASURE_STATE)
{
// TODO: There are multiple types of spaces in UNICODE, maybe it's a good idea to add support for more
// Ref: http://jkorpela.fi/chars/spaces.html
if ((codepoint == ' ') || (codepoint == '\t') || (codepoint == '\n')) endLine = i;
if ((textOffsetX + glyphWidth) > rec.width)
{
endLine = (endLine < 1)? i : endLine;
if (i == endLine) endLine -= codepointByteCount;
if ((startLine + codepointByteCount) == endLine) endLine = (i - codepointByteCount);
state = !state;
}
else if ((i + 1) == length)
{
endLine = i;
state = !state;
}
else if (codepoint == '\n') state = !state;
if (state == DRAW_STATE)
{
textOffsetX = 0;
i = startLine;
glyphWidth = 0;
// Save character position when we switch states
int tmp = lastk;
lastk = k - 1;
k = tmp;
}
}
else
{
if (codepoint == '\n')
{
if (!wordWrap)
{
textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
textOffsetX = 0;
}
}
else
{
if (!wordWrap && ((textOffsetX + glyphWidth) > rec.width))
{
textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
textOffsetX = 0;
}
// When text overflows rectangle height limit, just stop drawing
if ((textOffsetY + font.baseSize*scaleFactor) > rec.height) break;
// Draw selection background
bool isGlyphSelected = false;
if ((selectStart >= 0) && (k >= selectStart) && (k < (selectStart + selectLength)))
{
DrawRectangleRec((Rectangle){ rec.x + textOffsetX - 1, rec.y + textOffsetY, glyphWidth, (float)font.baseSize*scaleFactor }, selectBackTint);
isGlyphSelected = true;
}
// Draw current character glyph
if ((codepoint != ' ') && (codepoint != '\t'))
{
DrawTextCodepoint(font, codepoint, (Vector2){ rec.x + textOffsetX, rec.y + textOffsetY }, fontSize, isGlyphSelected? selectTint : tint);
}
}
if (wordWrap && (i == endLine))
{
textOffsetY += (font.baseSize + font.baseSize/2)*scaleFactor;
textOffsetX = 0;
startLine = endLine;
endLine = -1;
glyphWidth = 0;
selectStart += lastk - k;
k = lastk;
state = !state;
}
}
textOffsetX += glyphWidth;
}
}
static void DrawTextBoxedSelectable(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint) {
DrawTextRecEx(font, text, rec, fontSize, spacing, wordWrap, tint, selectStart, selectLength, selectTint, selectBackTint);
}
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
@ -178,9 +321,9 @@ RAYGUIDEF void GuiTextBoxSetSelection(int start, int length)
RAYGUIDEF Vector2 GuiTextBoxGetSelection(void)
{
if (guiTextBoxState.select == -1 || guiTextBoxState.select == guiTextBoxState.cursor) return RAYGUI_CLITERAL(Vector2){ 0 };
else if (guiTextBoxState.cursor > guiTextBoxState.select) return RAYGUI_CLITERAL(Vector2){ guiTextBoxState.select, guiTextBoxState.cursor - guiTextBoxState.select };
else if (guiTextBoxState.cursor > guiTextBoxState.select) return RAYGUI_CLITERAL(Vector2){ (float)guiTextBoxState.select, (float)guiTextBoxState.cursor - guiTextBoxState.select };
return RAYGUI_CLITERAL(Vector2){ guiTextBoxState.cursor, guiTextBoxState.select - guiTextBoxState.cursor };
return RAYGUI_CLITERAL(Vector2){ (float)guiTextBoxState.cursor, (float)guiTextBoxState.select - guiTextBoxState.cursor };
}
// Returns true if a textbox control with specified `bounds` is the active textbox
@ -436,7 +579,7 @@ RAYGUIDEF bool GuiTextBoxEx(Rectangle bounds, char *text, int textSize, bool edi
Rectangle textRec = { bounds.x + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING),
bounds.y + verticalPadding + GuiGetStyle(TEXTBOX, BORDER_WIDTH),
bounds.width - 2*(GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING) + GuiGetStyle(TEXTBOX, BORDER_WIDTH)),
GuiGetStyle(DEFAULT, TEXT_SIZE) };
(float)GuiGetStyle(DEFAULT, TEXT_SIZE) };
Vector2 cursorPos = { textRec.x, textRec.y }; // This holds the coordinates inside textRec of the cursor at current position and will be recalculated later
bool active = GuiTextBoxIsActive(bounds); // Check if this textbox is the global active textbox
@ -816,9 +959,9 @@ RAYGUIDEF bool GuiTextBoxEx(Rectangle bounds, char *text, int textSize, bool edi
DrawRectangle(bounds.x + GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.height - 2*GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_FOCUSED)), guiAlpha));
// Draw blinking cursor
if (editMode && active && ((framesCounter/TEXTEDIT_CURSOR_BLINK_FRAMES)%2 == 0) && selLength == 0)
if (editMode && active && ((framesCounter/30)%2 == 0) && selLength == 0)
{
DrawRectangle(cursorPos.x, cursorPos.y, 1, GuiGetStyle(DEFAULT, TEXT_SIZE)*2, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)), guiAlpha));
DrawRectangle(cursorPos.x, cursorPos.y-1, 1, GuiGetStyle(DEFAULT, TEXT_SIZE)+2, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)), guiAlpha));
}
}
else if (state == GUI_STATE_DISABLED)
@ -827,7 +970,7 @@ RAYGUIDEF bool GuiTextBoxEx(Rectangle bounds, char *text, int textSize, bool edi
}
// Finally draw the text and selection
DrawTextBoxedSelectable(guiFont, &text[textStartIndex], textRec, GuiGetStyle(DEFAULT, TEXT_SIZE), GuiGetStyle(DEFAULT, TEXT_SPACING), false, Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha), selStart, selLength, GetColor(GuiGetStyle(TEXTBOX, COLOR_SELECTED_FG)), GetColor(GuiGetStyle(TEXTBOX, COLOR_SELECTED_BG)));
DrawTextRecEx(guiFont, &text[textStartIndex], textRec, GuiGetStyle(DEFAULT, TEXT_SIZE), GuiGetStyle(DEFAULT, TEXT_SPACING), false, Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha), selStart, selLength, GetColor(GuiGetStyle(TEXTBOX, COLOR_SELECTED_FG)), GetColor(GuiGetStyle(TEXTBOX, COLOR_SELECTED_BG)));
return pressed;
}
@ -904,9 +1047,9 @@ static int GuiMeasureTextBox(const char *text, int length, Rectangle rec, int *p
if (letter != '\n')
{
glyphWidth = (font.chars[index].advanceX == 0)?
glyphWidth = (font.glyphs[index].advanceX == 0)?
(int)(font.recs[index].width*scaleFactor + spacing):
(int)(font.chars[index].advanceX*scaleFactor + spacing);
(int)(font.glyphs[index].advanceX*scaleFactor + spacing);
if ((textOffsetX + glyphWidth + 1) >= rec.width) break;
@ -914,7 +1057,7 @@ static int GuiMeasureTextBox(const char *text, int length, Rectangle rec, int *p
else if (mode == GUI_MEASURE_MODE_CURSOR_COORDS)
{
// Check if the mouse pointer is inside the glyph rect
Rectangle grec = {rec.x + textOffsetX - 1, rec.y, glyphWidth, (font.baseSize + font.baseSize/2)*scaleFactor - 1 };
Rectangle grec = {rec.x + textOffsetX - 1, rec.y, (float)glyphWidth, (font.baseSize + font.baseSize/2)*scaleFactor - 1 };
Vector2 mouse = GetMousePosition();
if (CheckCollisionPointRec(mouse, grec))
@ -970,9 +1113,9 @@ static int GuiMeasureTextBoxRev(const char *text, int length, Rectangle rec, int
if (letter != '\n')
{
glyphWidth = (font.chars[index].advanceX == 0)?
glyphWidth = (font.glyphs[index].advanceX == 0)?
(int)(font.recs[index].width*scaleFactor + spacing):
(int)(font.chars[index].advanceX*scaleFactor + spacing);
(int)(font.glyphs[index].advanceX*scaleFactor + spacing);
if ((textOffsetX + glyphWidth + 1) >= rec.width) break;
}