From 08f91480134959df6ac3b66a9530fd83e78ae386 Mon Sep 17 00:00:00 2001 From: v0idh4nd Date: Sat, 15 Mar 2025 08:06:47 +0300 Subject: [PATCH] change version --- sw1nek23per/backend/raylib/lib/raygui.h | 1211 ++++++++--------------- 1 file changed, 404 insertions(+), 807 deletions(-) diff --git a/sw1nek23per/backend/raylib/lib/raygui.h b/sw1nek23per/backend/raylib/lib/raygui.h index a93f290..c1ea5df 100644 --- a/sw1nek23per/backend/raylib/lib/raygui.h +++ b/sw1nek23per/backend/raylib/lib/raygui.h @@ -1,6 +1,6 @@ /******************************************************************************************* * -* raygui v4.5-dev - A simple and easy-to-use immediate-mode gui library +* raygui v4.0 - A simple and easy-to-use immediate-mode gui library * * DESCRIPTION: * raygui is a tools-dev-focused immediate-mode-gui library based on raylib but also @@ -26,7 +26,7 @@ * NOTES: * - WARNING: GuiLoadStyle() and GuiLoadStyle{Custom}() functions, allocate memory for * font atlas recs and glyphs, freeing that memory is (usually) up to the user, -* no unload function is explicitly provided... but note that GuiLoadStyleDefault() unloads +* no unload function is explicitly provided... but note that GuiLoadStyleDefaulf() unloads * by default any previously loaded font (texture, recs, glyphs). * - Global UI alpha (guiAlpha) is applied inside GuiDrawRectangle() and GuiDrawText() functions * @@ -136,33 +136,11 @@ * * #define RAYGUI_DEBUG_RECS_BOUNDS * Draw control bounds rectangles for debug -* +* * #define RAYGUI_DEBUG_TEXT_BOUNDS * Draw text bounds rectangles for debug * * VERSIONS HISTORY: -* 5.0-dev (2025) Current dev version... -* ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes -* ADDED: GuiValueBoxFloat() -* ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP -* ADDED: GuiListView() property: LIST_ITEMS_BORDER_WIDTH -* ADDED: GuiLoadIconsFromMemory() -* ADDED: Multiple new icons -* REMOVED: GuiSpinner() from controls list, using BUTTON + VALUEBOX properties -* REVIEWED: Controls using text labels to use LABEL properties -* REVIEWED: Replaced sprintf() by snprintf() for more safety -* REVIEWED: GuiTabBar(), close tab with mouse middle button -* REVIEWED: GuiScrollPanel(), scroll speed proportional to content -* REVIEWED: GuiDropdownBox(), support roll up and hidden arrow -* REVIEWED: GuiTextBox(), cursor position initialization -* REVIEWED: GuiSliderPro(), control value change check -* REVIEWED: GuiGrid(), simplified implementation -* REVIEWED: GuiIconText(), increase buffer size and reviewed padding -* REVIEWED: GuiDrawText(), improved wrap mode drawing -* REVIEWED: GuiScrollBar(), minor tweaks -* REVIEWED: Functions descriptions, removed wrong return value reference -* REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion -* * 4.0 (12-Sep-2023) ADDED: GuiToggleSlider() * ADDED: GuiColorPickerHSV() and GuiColorPanelHSV() * ADDED: Multiple new icons, mostly compiler related @@ -268,7 +246,7 @@ * 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria. * * DEPENDENCIES: -* raylib 5.0 - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing +* raylib 4.6-dev Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing * * STANDALONE MODE: * By default raygui depends on raylib mostly for the inputs and the drawing functionality but that dependency can be disabled @@ -313,7 +291,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -336,9 +314,9 @@ #define RAYGUI_H #define RAYGUI_VERSION_MAJOR 4 -#define RAYGUI_VERSION_MINOR 5 +#define RAYGUI_VERSION_MINOR 0 #define RAYGUI_VERSION_PATCH 0 -#define RAYGUI_VERSION "5.0-dev" +#define RAYGUI_VERSION "4.0" #if !defined(RAYGUI_STANDALONE) #include "raylib.h" @@ -463,6 +441,7 @@ } Font; #endif + // Style property // NOTE: Used when exporting style as code for convenience typedef struct GuiStyleProp { @@ -519,7 +498,7 @@ typedef enum { typedef enum { // Default -> populates to all controls when set DEFAULT = 0, - + // Basic controls LABEL, // Used also for: LABELBUTTON BUTTON, @@ -531,7 +510,7 @@ typedef enum { DROPDOWNBOX, TEXTBOX, // Used also for: TEXTBOXMULTI VALUEBOX, - CONTROL11, + SPINNER, // Uses: BUTTON, VALUEBOX LISTVIEW, COLORPICKER, SCROLLBAR, @@ -553,12 +532,12 @@ typedef enum { BORDER_COLOR_DISABLED, // Control border color in STATE_DISABLED BASE_COLOR_DISABLED, // Control base color in STATE_DISABLED TEXT_COLOR_DISABLED, // Control text color in STATE_DISABLED - BORDER_WIDTH = 12, // Control border size, 0 for no border + BORDER_WIDTH, // Control border size, 0 for no border //TEXT_SIZE, // Control text size (glyphs max height) -> GLOBAL for all controls //TEXT_SPACING, // Control text spacing between glyphs -> GLOBAL for all controls - //TEXT_LINE_SPACING, // Control text spacing between lines -> GLOBAL for all controls - TEXT_PADDING = 13, // Control text padding, not considering border - TEXT_ALIGNMENT = 14, // Control text horizontal alignment inside control text bound (after border and padding) + //TEXT_LINE_SPACING // Control text spacing between lines -> GLOBAL for all controls + TEXT_PADDING, // Control text padding, not considering border + TEXT_ALIGNMENT, // Control text horizontal alignment inside control text bound (after border and padding) //TEXT_WRAP_MODE // Control text wrap-mode inside text bounds -> GLOBAL for all controls } GuiControlProperty; @@ -567,6 +546,7 @@ typedef enum { // TEXT_SIZE, TEXT_SPACING, TEXT_LINE_SPACING, TEXT_ALIGNMENT_VERTICAL, TEXT_WRAP_MODE are global and // should be configured by user as needed while defining the UI layout + // Gui extended properties depend on control // NOTE: RAYGUI_MAX_PROPS_EXTENDED properties (by default, max 8 properties) //---------------------------------------------------------------------------------- @@ -582,12 +562,12 @@ typedef enum { TEXT_ALIGNMENT_VERTICAL, // Text vertical alignment inside text bounds (after border and padding) TEXT_WRAP_MODE // Text wrap-mode inside text bounds //TEXT_DECORATION // Text decoration: 0-None, 1-Underline, 2-Line-through, 3-Overline - //TEXT_DECORATION_THICK // Text decoration line thickness + //TEXT_DECORATION_THICK // Text decoration line thikness } GuiDefaultProperty; // Other possible text properties: // TEXT_WEIGHT // Normal, Italic, Bold -> Requires specific font change -// TEXT_INDENT // Text indentation -> Now using TEXT_PADDING... +// TEXT_INDENT // Text indentation -> Now using TEXT_PADDING... // Label //typedef enum { } GuiLabelProperty; @@ -635,9 +615,7 @@ typedef enum { // DropdownBox typedef enum { ARROW_PADDING = 16, // DropdownBox arrow separation from border and items - DROPDOWN_ITEMS_SPACING, // DropdownBox items separation - DROPDOWN_ARROW_HIDDEN, // DropdownBox arrow hidden - DROPDOWN_ROLL_UP // DropdownBox roll up flag (default rolls down) + DROPDOWN_ITEMS_SPACING // DropdownBox items separation } GuiDropdownBoxProperty; // TextBox/TextBoxMulti/ValueBox/Spinner @@ -645,14 +623,11 @@ typedef enum { TEXT_READONLY = 16, // TextBox in read-only mode: 0-text editable, 1-text no-editable } GuiTextBoxProperty; -// ValueBox/Spinner +// Spinner typedef enum { - SPINNER_BUTTON_WIDTH = 16, // Spinner left/right buttons width - SPINNER_BUTTON_SPACING, // Spinner buttons separation -} GuiValueBoxProperty; - -// Control11 -//typedef enum { } GuiControl11Property; + SPIN_BUTTON_WIDTH = 16, // Spinner left/right buttons width + SPIN_BUTTON_SPACING, // Spinner buttons separation +} GuiSpinnerProperty; // ListView typedef enum { @@ -660,8 +635,6 @@ typedef enum { LIST_ITEMS_SPACING, // ListView items separation SCROLLBAR_WIDTH, // ListView scrollbar size (usually width) SCROLLBAR_SIDE, // ListView scrollbar side (0-SCROLLBAR_LEFT_SIDE, 1-SCROLLBAR_RIGHT_SIDE) - LIST_ITEMS_BORDER_NORMAL, // ListView items border enabled in normal state - LIST_ITEMS_BORDER_WIDTH // ListView items border width } GuiListViewProperty; // ColorPicker @@ -725,6 +698,7 @@ RAYGUIAPI char **GuiLoadIcons(const char *fileName, bool loadIconsName); // Load RAYGUIAPI void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color); // Draw icon using pixel size at specified position #endif + // Controls //---------------------------------------------------------------------------------------------------------- // Container/separator controls, useful for controls organization @@ -736,30 +710,29 @@ RAYGUIAPI int GuiTabBar(Rectangle bounds, const char **text, int count, int *act RAYGUIAPI int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view); // Scroll Panel control // Basic controls set -RAYGUIAPI int GuiLabel(Rectangle bounds, const char *text); // Label control +RAYGUIAPI int GuiLabel(Rectangle bounds, const char *text); // Label control, shows text RAYGUIAPI int GuiButton(Rectangle bounds, const char *text); // Button control, returns true when clicked -RAYGUIAPI int GuiLabelButton(Rectangle bounds, const char *text); // Label button control, returns true when clicked -RAYGUIAPI int GuiToggle(Rectangle bounds, const char *text, bool *active); // Toggle Button control -RAYGUIAPI int GuiToggleGroup(Rectangle bounds, const char *text, int *active); // Toggle Group control -RAYGUIAPI int GuiToggleSlider(Rectangle bounds, const char *text, int *active); // Toggle Slider control +RAYGUIAPI int GuiLabelButton(Rectangle bounds, const char *text); // Label button control, show true when clicked +RAYGUIAPI int GuiToggle(Rectangle bounds, const char *text, bool *active); // Toggle Button control, returns true when active +RAYGUIAPI int GuiToggleGroup(Rectangle bounds, const char *text, int *active); // Toggle Group control, returns active toggle index +RAYGUIAPI int GuiToggleSlider(Rectangle bounds, const char *text, int *active); // Toggle Slider control, returns true when clicked RAYGUIAPI int GuiCheckBox(Rectangle bounds, const char *text, bool *checked); // Check Box control, returns true when active -RAYGUIAPI int GuiComboBox(Rectangle bounds, const char *text, int *active); // Combo Box control +RAYGUIAPI int GuiComboBox(Rectangle bounds, const char *text, int *active); // Combo Box control, returns selected item index -RAYGUIAPI int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode); // Dropdown Box control -RAYGUIAPI int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Spinner control +RAYGUIAPI int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode); // Dropdown Box control, returns selected item +RAYGUIAPI int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Spinner control, returns selected value RAYGUIAPI int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Value Box control, updates input text with numbers -RAYGUIAPI int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode); // Value box control for float values RAYGUIAPI int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode); // Text Box control, updates input text -RAYGUIAPI int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider control -RAYGUIAPI int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider Bar control -RAYGUIAPI int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Progress Bar control +RAYGUIAPI int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider control, returns selected value +RAYGUIAPI int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider Bar control, returns selected value +RAYGUIAPI int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Progress Bar control, shows current progress value RAYGUIAPI int GuiStatusBar(Rectangle bounds, const char *text); // Status Bar control, shows info text RAYGUIAPI int GuiDummyRec(Rectangle bounds, const char *text); // Dummy control for placeholders -RAYGUIAPI int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vector2 *mouseCell); // Grid control +RAYGUIAPI int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vector2 *mouseCell); // Grid control, returns mouse cell position // Advance controls set -RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active); // List View control +RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active); // List View control, returns selected list item index RAYGUIAPI int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollIndex, int *active, int *focus); // List View with extended parameters 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 @@ -768,9 +741,10 @@ RAYGUIAPI int GuiColorPanel(Rectangle bounds, const char *text, Color *color); 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 GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control that returns HSV color value, used by GuiColorPickerHSV() //---------------------------------------------------------------------------------------------------------- + #if !defined(RAYGUI_NO_ICONS) #if !defined(RAYGUI_CUSTOM_ICONS) @@ -998,15 +972,15 @@ typedef enum { ICON_FOLDER = 217, ICON_FILE = 218, ICON_SAND_TIMER = 219, - ICON_WARNING = 220, - ICON_HELP_BOX = 221, - ICON_INFO_BOX = 222, - ICON_PRIORITY = 223, - ICON_LAYERS_ISO = 224, - ICON_LAYERS2 = 225, - ICON_MLAYERS = 226, - ICON_MAPS = 227, - ICON_HOT = 228, + ICON_220 = 220, + ICON_221 = 221, + ICON_222 = 222, + ICON_223 = 223, + ICON_224 = 224, + ICON_225 = 225, + ICON_226 = 226, + ICON_227 = 227, + ICON_228 = 228, ICON_229 = 229, ICON_230 = 230, ICON_231 = 231, @@ -1053,8 +1027,7 @@ typedef enum { #if defined(RAYGUI_IMPLEMENTATION) -#include // required for: isspace() [GuiTextBox()] -#include // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()] +#include // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()] #include // Required for: malloc(), calloc(), free() [GuiLoadStyle(), GuiLoadIcons()] #include // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy() #include // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()] @@ -1317,15 +1290,15 @@ static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x40024002, 0x40024002, 0x7ffe4002, 0x00000000, // ICON_FOLDER 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x00003ffc, // ICON_FILE 0x1ff00000, 0x20082008, 0x17d02fe8, 0x05400ba0, 0x09200540, 0x23881010, 0x2fe827c8, 0x00001ff0, // ICON_SAND_TIMER - 0x01800000, 0x02400240, 0x05a00420, 0x09900990, 0x11881188, 0x21842004, 0x40024182, 0x00003ffc, // ICON_WARNING - 0x7ffe0000, 0x4ff24002, 0x4c324ff2, 0x4f824c02, 0x41824f82, 0x41824002, 0x40024182, 0x00007ffe, // ICON_HELP_BOX - 0x7ffe0000, 0x41824002, 0x40024182, 0x41824182, 0x41824182, 0x41824182, 0x40024182, 0x00007ffe, // ICON_INFO_BOX - 0x01800000, 0x04200240, 0x10080810, 0x7bde2004, 0x0a500a50, 0x08500bd0, 0x08100850, 0x00000ff0, // ICON_PRIORITY - 0x01800000, 0x18180660, 0x80016006, 0x98196006, 0x99996666, 0x19986666, 0x01800660, 0x00000000, // ICON_LAYERS_ISO - 0x07fe0000, 0x1c020402, 0x74021402, 0x54025402, 0x54025402, 0x500857fe, 0x40205ff8, 0x00007fe0, // ICON_LAYERS2 - 0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x422a422a, 0x422e422a, 0x40384e28, 0x00007fe0, // ICON_MLAYERS - 0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x5b2a512a, 0x512e552a, 0x40385128, 0x00007fe0, // ICON_MAPS - 0x04200000, 0x1cf00c60, 0x11f019f0, 0x0f3807b8, 0x1e3c0f3c, 0x1c1c1e1c, 0x1e3c1c1c, 0x00000f70, // ICON_HOT + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_220 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_221 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_222 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_223 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_224 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_225 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_226 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_227 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_228 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_229 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_230 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_231 @@ -1355,7 +1328,7 @@ static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_255 }; -// NOTE: A pointer to current icons array should be defined +// NOTE: We keep a pointer to the icons array, useful to point to other sets if required static unsigned int *guiIconsPtr = guiIcons; #endif // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS @@ -1390,12 +1363,13 @@ static unsigned int guiIconScale = 1; // Gui icon default scale (if ic static bool guiTooltip = false; // Tooltip enabled/disabled static const char *guiTooltipPtr = NULL; // Tooltip string pointer (string provided by user) -static bool guiControlExclusiveMode = false; // Gui control exclusive mode (no inputs processed except current control) -static Rectangle guiControlExclusiveRec = { 0 }; // Gui control exclusive bounds rectangle, used as an unique identifier +static bool guiSliderDragging = false; // Gui slider drag state (no inputs processed except dragged slider) +static Rectangle guiSliderActive = { 0 }; // Gui slider active bounds rectangle, used as an unique identifier static int textBoxCursorIndex = 0; // Cursor index, shared by all GuiTextBox*() //static int blinkCursorFrameCounter = 0; // Frame counter for cursor blinking -static int autoCursorCounter = 0; // Frame counter for automatic repeated cursor movement on key-down (cooldown and delay) +static int autoCursorCooldownCounter = 0; // Cooldown frame counter for automatic cursor movement on key-down +static int autoCursorDelayCounter = 0; // Delay frame counter for automatic cursor movement //---------------------------------------------------------------------------------- // Style data array for all gui style properties (allocated on data segment by default) @@ -1476,7 +1450,6 @@ static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed' static const char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings static int TextToInteger(const char *text); // Get integer value from text -static float TextToFloat(const char *text); // Get float value from text static int GetCodepointNext(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded text static const char *CodepointToUTF8(int codepoint, int *byteSize); // Encode codepoint into UTF-8 text (char array size returned as parameter) @@ -1596,10 +1569,6 @@ int GuiWindowBox(Rectangle bounds, const char *title) #define RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT 24 #endif - #if !defined(RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT) - #define RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT 18 - #endif - int result = 0; //GuiState state = guiState; @@ -1608,10 +1577,9 @@ int GuiWindowBox(Rectangle bounds, const char *title) Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)statusBarHeight }; if (bounds.height < statusBarHeight*2.0f) bounds.height = statusBarHeight*2.0f; - const float vPadding = statusBarHeight/2.0f - RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT/2.0f; Rectangle windowPanel = { bounds.x, bounds.y + (float)statusBarHeight - 1, bounds.width, bounds.height - (float)statusBarHeight + 1 }; - Rectangle closeButtonRec = { statusBar.x + statusBar.width - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT - vPadding, - statusBar.y + vPadding, RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT, RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT }; + Rectangle closeButtonRec = { statusBar.x + statusBar.width - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - 20, + statusBar.y + statusBarHeight/2.0f - 18.0f/2.0f, 18, 18 }; // Update control //-------------------------------------------------------------------- @@ -1652,9 +1620,9 @@ int GuiGroupBox(Rectangle bounds, const char *text) // Draw control //-------------------------------------------------------------------- - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR))); - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, RAYGUI_GROUPBOX_LINE_THICK }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR))); - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, RAYGUI_GROUPBOX_LINE_THICK }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR))); GuiLine(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y - GuiGetStyle(DEFAULT, TEXT_SIZE)/2, bounds.width, (float)GuiGetStyle(DEFAULT, TEXT_SIZE) }, text); //-------------------------------------------------------------------- @@ -1665,7 +1633,7 @@ int GuiGroupBox(Rectangle bounds, const char *text) // Line control int GuiLine(Rectangle bounds, const char *text) { - #if !defined(RAYGUI_LINE_MARGIN_TEXT) + #if !defined(RAYGUI_LINE_ORIGIN_SIZE) #define RAYGUI_LINE_MARGIN_TEXT 12 #endif #if !defined(RAYGUI_LINE_TEXT_PADDING) @@ -1675,7 +1643,7 @@ int GuiLine(Rectangle bounds, const char *text) int result = 0; GuiState state = guiState; - Color color = GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)); + Color color = GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)); // Draw control //-------------------------------------------------------------------- @@ -1723,7 +1691,7 @@ int GuiPanel(Rectangle bounds, const char *text) //-------------------------------------------------------------------- if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar - GuiDrawRectangle(bounds, RAYGUI_PANEL_BORDER_WIDTH, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED: (int)LINE_COLOR)), + GuiDrawRectangle(bounds, RAYGUI_PANEL_BORDER_WIDTH, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED: LINE_COLOR)), GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BASE_COLOR_DISABLED : BACKGROUND_COLOR))); //-------------------------------------------------------------------- @@ -1776,9 +1744,6 @@ int GuiTabBar(Rectangle bounds, const char **text, int count, int *active) if (toggle) *active = i; } - // Close tab with middle mouse button pressed - if (CheckCollisionPointRec(GetMousePosition(), tabBounds) && IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON)) result = i; - GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding); GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment); @@ -1810,10 +1775,10 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector { #define RAYGUI_MIN_SCROLLBAR_WIDTH 40 #define RAYGUI_MIN_SCROLLBAR_HEIGHT 40 - #define RAYGUI_MIN_MOUSE_WHEEL_SPEED 20 - + int result = 0; GuiState state = guiState; + float mouseWheelSpeed = 20.0f; // Default movement speed with mouse wheel Rectangle temp = { 0 }; if (view == NULL) view = &temp; @@ -1841,22 +1806,31 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector int horizontalScrollBarWidth = hasHorizontalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0; int verticalScrollBarWidth = hasVerticalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0; - Rectangle horizontalScrollBar = { - (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + verticalScrollBarWidth : (float)bounds.x) + GuiGetStyle(DEFAULT, BORDER_WIDTH), - (float)bounds.y + bounds.height - horizontalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH), - (float)bounds.width - verticalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH), - (float)horizontalScrollBarWidth + Rectangle horizontalScrollBar = { + (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + verticalScrollBarWidth : (float)bounds.x) + GuiGetStyle(DEFAULT, BORDER_WIDTH), + (float)bounds.y + bounds.height - horizontalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH), + (float)bounds.width - verticalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH), + (float)horizontalScrollBarWidth }; - Rectangle verticalScrollBar = { - (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)bounds.x + bounds.width - verticalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH)), - (float)bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), - (float)verticalScrollBarWidth, - (float)bounds.height - horizontalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) + Rectangle verticalScrollBar = { + (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)bounds.x + bounds.width - verticalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH)), + (float)bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), + (float)verticalScrollBarWidth, + (float)bounds.height - horizontalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) }; // Make sure scroll bars have a minimum width/height - if (horizontalScrollBar.width < RAYGUI_MIN_SCROLLBAR_WIDTH) horizontalScrollBar.width = RAYGUI_MIN_SCROLLBAR_WIDTH; - if (verticalScrollBar.height < RAYGUI_MIN_SCROLLBAR_HEIGHT) verticalScrollBar.height = RAYGUI_MIN_SCROLLBAR_HEIGHT; + // NOTE: If content >>> bounds, size could be very small or even 0 + if (horizontalScrollBar.width < RAYGUI_MIN_SCROLLBAR_WIDTH) + { + horizontalScrollBar.width = RAYGUI_MIN_SCROLLBAR_WIDTH; + mouseWheelSpeed = 30.0f; // TODO: Calculate speed increment based on content.height vs bounds.height + } + if (verticalScrollBar.height < RAYGUI_MIN_SCROLLBAR_HEIGHT) + { + verticalScrollBar.height = RAYGUI_MIN_SCROLLBAR_HEIGHT; + mouseWheelSpeed = 30.0f; // TODO: Calculate speed increment based on content.width vs bounds.width + } // Calculate view area (area without the scrollbars) *view = (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? @@ -1899,14 +1873,9 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector #endif float wheelMove = GetMouseWheelMove(); - // Set scrolling speed with mouse wheel based on ratio between bounds and content - Vector2 mouseWheelSpeed = { content.width/bounds.width, content.height/bounds.height }; - if (mouseWheelSpeed.x < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.x = RAYGUI_MIN_MOUSE_WHEEL_SPEED; - if (mouseWheelSpeed.y < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.y = RAYGUI_MIN_MOUSE_WHEEL_SPEED; - // Horizontal and vertical scrolling with mouse wheel - if (hasHorizontalScrollBar && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_LEFT_SHIFT))) scrollPos.x += wheelMove*mouseWheelSpeed.x; - else scrollPos.y += wheelMove*mouseWheelSpeed.y; // Vertical scroll + if (hasHorizontalScrollBar && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_LEFT_SHIFT))) scrollPos.x += wheelMove*mouseWheelSpeed; + else scrollPos.y += wheelMove*mouseWheelSpeed; // Vertical scroll } } @@ -1952,7 +1921,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector } // Draw scrollbar lines depending on current state - GuiDrawRectangle(bounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + (state*3))), BLANK); + GuiDrawRectangle(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + (state*3))), BLANK); // Set scrollbar slider size back to the way it was before GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, slider); @@ -1990,7 +1959,7 @@ int GuiButton(Rectangle bounds, const char *text) // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) { Vector2 mousePoint = GetMousePosition(); @@ -2028,7 +1997,7 @@ int GuiLabelButton(Rectangle bounds, const char *text) // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) { Vector2 mousePoint = GetMousePosition(); @@ -2051,7 +2020,7 @@ int GuiLabelButton(Rectangle bounds, const char *text) return pressed; } -// Toggle Button control +// Toggle Button control, returns true when active int GuiToggle(Rectangle bounds, const char *text, bool *active) { int result = 0; @@ -2062,7 +2031,7 @@ int GuiToggle(Rectangle bounds, const char *text, bool *active) // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) { Vector2 mousePoint = GetMousePosition(); @@ -2099,7 +2068,7 @@ int GuiToggle(Rectangle bounds, const char *text, bool *active) return result; } -// Toggle Group control +// Toggle Group control, returns toggled button codepointIndex int GuiToggleGroup(Rectangle bounds, const char *text, int *active) { #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEMS) @@ -2148,7 +2117,7 @@ int GuiToggleGroup(Rectangle bounds, const char *text, int *active) return result; } -// Toggle Slider control extended +// Toggle Slider control extended, returns true when clicked int GuiToggleSlider(Rectangle bounds, const char *text, int *active) { int result = 0; @@ -2161,9 +2130,7 @@ int GuiToggleSlider(Rectangle bounds, const char *text, int *active) // Get substrings items from text (items pointers) int itemCount = 0; - const char **items = NULL; - - if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL); + const char **items = GuiTextSplit(text, ';', &itemCount, NULL); Rectangle slider = { 0, // Calculated later depending on the active toggle @@ -2188,7 +2155,7 @@ int GuiToggleSlider(Rectangle bounds, const char *text, int *active) } else state = STATE_FOCUSED; } - + if ((*active) && (state != STATE_FOCUSED)) state = STATE_PRESSED; } @@ -2222,7 +2189,7 @@ int GuiToggleSlider(Rectangle bounds, const char *text, int *active) return result; } -// Check Box control, returns 1 when state changed +// Check Box control, returns true when active int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) { int result = 0; @@ -2244,7 +2211,7 @@ int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) { Vector2 mousePoint = GetMousePosition(); @@ -2261,11 +2228,7 @@ int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; else state = STATE_FOCUSED; - if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) - { - *checked = !(*checked); - result = 1; - } + if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) *checked = !(*checked); } } //-------------------------------------------------------------------- @@ -2289,7 +2252,7 @@ int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) return result; } -// Combo Box control +// Combo Box control, returns selected item codepointIndex int GuiComboBox(Rectangle bounds, const char *text, int *active) { int result = 0; @@ -2312,7 +2275,7 @@ int GuiComboBox(Rectangle bounds, const char *text, int *active) // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && (itemCount > 1) && !guiControlExclusiveMode) + if ((state != STATE_DISABLED) && !guiLocked && (itemCount > 1) && !guiSliderDragging) { Vector2 mousePoint = GetMousePosition(); @@ -2360,28 +2323,21 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod int result = 0; GuiState state = guiState; - int temp = 0; - if (active == NULL) active = &temp; - int itemSelected = *active; int itemFocused = -1; - int direction = 0; // Dropdown box open direction: down (default) - if (GuiGetStyle(DROPDOWNBOX, DROPDOWN_ROLL_UP) == 1) direction = 1; // Up - // Get substrings items from text (items pointers, lengths and count) int itemCount = 0; const char **items = GuiTextSplit(text, ';', &itemCount, NULL); Rectangle boundsOpen = bounds; boundsOpen.height = (itemCount + 1)*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); - if (direction == 1) boundsOpen.y -= itemCount*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)) + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING); Rectangle itemBounds = bounds; // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && (editMode || !guiLocked) && (itemCount > 1) && !guiControlExclusiveMode) + if ((state != STATE_DISABLED) && (editMode || !guiLocked) && (itemCount > 1) && !guiSliderDragging) { Vector2 mousePoint = GetMousePosition(); @@ -2402,8 +2358,7 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod for (int i = 0; i < itemCount; i++) { // Update item rectangle y position for next item - if (direction == 0) itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); - else itemBounds.y -= (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); if (CheckCollisionPointRec(mousePoint, itemBounds)) { @@ -2447,8 +2402,7 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod for (int i = 0; i < itemCount; i++) { // Update item rectangle y position for next item - if (direction == 0) itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); - else itemBounds.y -= (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); if (i == itemSelected) { @@ -2464,17 +2418,14 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod } } - if (!GuiGetStyle(DROPDOWNBOX, DROPDOWN_ARROW_HIDDEN)) - { - // Draw arrows (using icon if available) + // Draw arrows (using icon if available) #if defined(RAYGUI_NO_ICONS) - GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); + GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); #else - GuiDrawText(direction? "#121#" : "#120#", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); // ICON_ARROW_DOWN_FILL + GuiDrawText("#120#", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); // ICON_ARROW_DOWN_FILL #endif - } //-------------------------------------------------------------------- *active = itemSelected; @@ -2485,13 +2436,13 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod // Text Box control // NOTE: Returns true on ENTER pressed (useful for data validation) -int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) +int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode) { #if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN) - #define RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN 30 // Frames to wait for autocursor movement + #define RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN 40 // Frames to wait for autocursor movement #endif #if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) - #define RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY 2 // Frames delay for autocursor movement + #define RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY 1 // Frames delay for autocursor movement #endif int result = 0; @@ -2501,10 +2452,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); Rectangle textBounds = GetTextBounds(TEXTBOX, bounds); - int textLength = (int)strlen(text); // Get current text length - int thisCursorIndex = textBoxCursorIndex; - if (thisCursorIndex > textLength) thisCursorIndex = textLength; - int textWidth = GetTextWidth(text) - GetTextWidth(text + thisCursorIndex); + int textWidth = GetTextWidth(text) - GetTextWidth(text + textBoxCursorIndex); int textIndexOffset = 0; // Text index offset to start drawing in the box // Cursor rectangle @@ -2525,6 +2473,15 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) mouseCursor.x = -1; mouseCursor.width = 1; + // Auto-cursor movement logic + // NOTE: Cursor moves automatically when key down after some time + if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_UP) || IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_BACKSPACE) || IsKeyDown(KEY_DELETE)) autoCursorCooldownCounter++; + else + { + autoCursorCooldownCounter = 0; // GLOBAL: Cursor cooldown counter + autoCursorDelayCounter = 0; // GLOBAL: Cursor delay counter + } + // Blink-cursor frame counter //if (!autoCursorMode) blinkCursorFrameCounter++; //else blinkCursorFrameCounter = 0; @@ -2535,26 +2492,15 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) if ((state != STATE_DISABLED) && // Control not disabled !GuiGetStyle(TEXTBOX, TEXT_READONLY) && // TextBox not on read-only mode !guiLocked && // Gui not locked - !guiControlExclusiveMode && // No gui slider on dragging + !guiSliderDragging && // No gui slider on dragging (wrapMode == TEXT_WRAP_NONE)) // No wrap mode { Vector2 mousePosition = GetMousePosition(); if (editMode) { - // GLOBAL: Auto-cursor movement logic - // NOTE: Keystrokes are handled repeatedly when button is held down for some time - if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_UP) || IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_BACKSPACE) || IsKeyDown(KEY_DELETE)) autoCursorCounter++; - else - { - autoCursorCounter = 0; - } - bool autoCursorShouldTrigger = (autoCursorCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN) && ((autoCursorCounter % RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0); - state = STATE_PRESSED; - if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength; - // If text does not fit in the textbox and current cursor position is out of bounds, // we add an index offset to text for drawing only what requires depending on cursor while (textWidth >= textBounds.width) @@ -2567,47 +2513,19 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) textWidth = GetTextWidth(text + textIndexOffset) - GetTextWidth(text + textBoxCursorIndex); } + int textLength = (int)strlen(text); // Get current text length int codepoint = GetCharPressed(); // Get Unicode codepoint if (multiline && IsKeyPressed(KEY_ENTER)) codepoint = (int)'\n'; + if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength; + // Encode codepoint as UTF-8 int codepointSize = 0; const char *charEncoded = CodepointToUTF8(codepoint, &codepointSize); - // Handle Paste action - if (IsKeyPressed(KEY_V) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL))) - { - const char *pasteText = GetClipboardText(); - if (pasteText != NULL) - { - int pasteLength = 0; - int pasteCodepoint; - int pasteCodepointSize; - // count how many codepoints to copy, stopping at the first unwanted control character - while (true) - { - pasteCodepoint = GetCodepointNext(pasteText + pasteLength, &pasteCodepointSize); - if (textLength + pasteLength + pasteCodepointSize >= textSize) break; - if (!(multiline && (pasteCodepoint == (int)'\n')) && !(pasteCodepoint >= 32)) break; - pasteLength += pasteCodepointSize; - } - if (pasteLength > 0) - { - // Move forward data from cursor position - for (int i = textLength + pasteLength; i > textBoxCursorIndex; i--) text[i] = text[i - pasteLength]; - - // Paste data in at cursor - for (int i = 0; i < pasteLength; i++) text[textBoxCursorIndex + i] = pasteText[i]; - - textBoxCursorIndex += pasteLength; - textLength += pasteLength; - text[textLength] = '\0'; - } - } - } // Add codepoint to text, at current cursor position // NOTE: Make sure we do not overflow buffer size - else if (((multiline && (codepoint == (int)'\n')) || (codepoint >= 32)) && ((textLength + codepointSize) < textSize)) + if (((multiline && (codepoint == (int)'\n')) || (codepoint >= 32)) && ((textLength + codepointSize) < bufferSize)) { // Move forward data from cursor position for (int i = (textLength + codepointSize); i > textBoxCursorIndex; i--) text[i] = text[i - codepointSize]; @@ -2628,187 +2546,89 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) // Move cursor to end if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_END)) textBoxCursorIndex = textLength; - // Delete related codepoints from text, after current cursor position - if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_DELETE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL))) + // Delete codepoint from text, after current cursor position + if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(KEY_DELETE) && (autoCursorCooldownCounter >= RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)))) { - int offset = textBoxCursorIndex; - int accCodepointSize = 0; - int nextCodepointSize; - int nextCodepoint; - // Check characters of the same type to delete (either ASCII punctuation or anything non-whitespace) - // Not using isalnum() since it only works on ASCII characters - nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); - bool puctuation = ispunct(nextCodepoint & 0xFF); - while (offset < textLength) + autoCursorDelayCounter++; + + if (IsKeyPressed(KEY_DELETE) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames { - if ((puctuation && !ispunct(nextCodepoint & 0xFF)) || (!puctuation && (isspace(nextCodepoint & 0xFF) || ispunct(nextCodepoint & 0xFF)))) - break; - offset += nextCodepointSize; - accCodepointSize += nextCodepointSize; - nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); + int nextCodepointSize = 0; + GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize); + + // Move backward text from cursor position + for (int i = textBoxCursorIndex; i < textLength; i++) text[i] = text[i + nextCodepointSize]; + + textLength -= codepointSize; + + // Make sure text last character is EOL + text[textLength] = '\0'; } - // Check whitespace to delete (ASCII only) - while (offset < textLength) - { - if (!isspace(nextCodepoint & 0xFF)) - break; - offset += nextCodepointSize; - accCodepointSize += nextCodepointSize; - nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); - } - - // Move text after cursor forward (including final null terminator) - for (int i = offset; i <= textLength; i++) text[i - accCodepointSize] = text[i]; - - textLength -= accCodepointSize; - } - // Delete single codepoint from text, after current cursor position - else if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(KEY_DELETE) && autoCursorShouldTrigger))) - { - int nextCodepointSize = 0; - GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize); - - // Move text after cursor forward (including final null terminator) - for (int i = textBoxCursorIndex + nextCodepointSize; i <= textLength; i++) text[i - nextCodepointSize] = text[i]; - - textLength -= nextCodepointSize; } - // Delete related codepoints from text, before current cursor position - if ((textBoxCursorIndex > 0) && IsKeyPressed(KEY_BACKSPACE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL))) + // Delete codepoint from text, before current cursor position + if ((textLength > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(KEY_BACKSPACE) && (autoCursorCooldownCounter >= RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)))) { - int offset = textBoxCursorIndex; - int accCodepointSize = 0; - int prevCodepointSize; - int prevCodepoint; + autoCursorDelayCounter++; - // Check whitespace to delete (ASCII only) - while (offset > 0) + if (IsKeyPressed(KEY_BACKSPACE) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames { - prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize); - if (!isspace(prevCodepoint & 0xFF)) - break; - offset -= prevCodepointSize; - accCodepointSize += prevCodepointSize; + int prevCodepointSize = 0; + GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize); + + // Move backward text from cursor position + for (int i = (textBoxCursorIndex - prevCodepointSize); i < textLength; i++) text[i] = text[i + prevCodepointSize]; + + // Prevent cursor index from decrementing past 0 + if (textBoxCursorIndex > 0) + { + textBoxCursorIndex -= codepointSize; + textLength -= codepointSize; + } + + // Make sure text last character is EOL + text[textLength] = '\0'; } - // Check characters of the same type to delete (either ASCII punctuation or anything non-whitespace) - // Not using isalnum() since it only works on ASCII characters - bool puctuation = ispunct(prevCodepoint & 0xFF); - while (offset > 0) - { - prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize); - if ((puctuation && !ispunct(prevCodepoint & 0xFF)) || (!puctuation && (isspace(prevCodepoint & 0xFF) || ispunct(prevCodepoint & 0xFF)))) - break; - offset -= prevCodepointSize; - accCodepointSize += prevCodepointSize; - } - - // Move text after cursor forward (including final null terminator) - for (int i = textBoxCursorIndex; i <= textLength; i++) text[i - accCodepointSize] = text[i]; - - textLength -= accCodepointSize; - textBoxCursorIndex -= accCodepointSize; - } - // Delete single codepoint from text, before current cursor position - else if ((textBoxCursorIndex > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(KEY_BACKSPACE) && autoCursorShouldTrigger))) - { - int prevCodepointSize = 0; - - GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize); - - // Move text after cursor forward (including final null terminator) - for (int i = textBoxCursorIndex; i <= textLength; i++) text[i - prevCodepointSize] = text[i]; - - textLength -= prevCodepointSize; - textBoxCursorIndex -= prevCodepointSize; } // Move cursor position with keys - if ((textBoxCursorIndex > 0) && IsKeyPressed(KEY_LEFT) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL))) + if (IsKeyPressed(KEY_LEFT) || (IsKeyDown(KEY_LEFT) && (autoCursorCooldownCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN))) { - int offset = textBoxCursorIndex; - int accCodepointSize = 0; - int prevCodepointSize; - int prevCodepoint; + autoCursorDelayCounter++; - // Check whitespace to skip (ASCII only) - while (offset > 0) + if (IsKeyPressed(KEY_LEFT) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames { - prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize); - if (!isspace(prevCodepoint & 0xFF)) - break; - offset -= prevCodepointSize; - accCodepointSize += prevCodepointSize; - } - // Check characters of the same type to skip (either ASCII punctuation or anything non-whitespace) - // Not using isalnum() since it only works on ASCII characters - bool puctuation = ispunct(prevCodepoint & 0xFF); - while (offset > 0) - { - prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize); - if ((puctuation && !ispunct(prevCodepoint & 0xFF)) || (!puctuation && (isspace(prevCodepoint & 0xFF) || ispunct(prevCodepoint & 0xFF)))) - break; - offset -= prevCodepointSize; - accCodepointSize += prevCodepointSize; - } + int prevCodepointSize = 0; + GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize); - textBoxCursorIndex = offset; + if (textBoxCursorIndex >= prevCodepointSize) textBoxCursorIndex -= prevCodepointSize; + } } - else if ((textBoxCursorIndex > 0) && (IsKeyPressed(KEY_LEFT) || (IsKeyDown(KEY_LEFT) && autoCursorShouldTrigger))) + else if (IsKeyPressed(KEY_RIGHT) || (IsKeyDown(KEY_RIGHT) && (autoCursorCooldownCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN))) { - int prevCodepointSize = 0; - GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize); + autoCursorDelayCounter++; - textBoxCursorIndex -= prevCodepointSize; - } - else if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_RIGHT) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL))) - { - int offset = textBoxCursorIndex; - int accCodepointSize = 0; - int nextCodepointSize; - int nextCodepoint; - // Check characters of the same type to skip (either ASCII punctuation or anything non-whitespace) - // Not using isalnum() since it only works on ASCII characters - nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); - bool puctuation = ispunct(nextCodepoint & 0xFF); - while (offset < textLength) + if (IsKeyPressed(KEY_RIGHT) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames { - if ((puctuation && !ispunct(nextCodepoint & 0xFF)) || (!puctuation && (isspace(nextCodepoint & 0xFF) || ispunct(nextCodepoint & 0xFF)))) - break; - offset += nextCodepointSize; - accCodepointSize += nextCodepointSize; - nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); - } - // Check whitespace to skip (ASCII only) - while (offset < textLength) - { - if (!isspace(nextCodepoint & 0xFF)) - break; - offset += nextCodepointSize; - accCodepointSize += nextCodepointSize; - nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); - } + int nextCodepointSize = 0; + GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize); - textBoxCursorIndex = offset; - } - else if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_RIGHT) || (IsKeyDown(KEY_RIGHT) && autoCursorShouldTrigger))) - { - int nextCodepointSize = 0; - GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize); - - textBoxCursorIndex += nextCodepointSize; + if ((textBoxCursorIndex + nextCodepointSize) <= textLength) textBoxCursorIndex += nextCodepointSize; + } } // Move cursor position with mouse if (CheckCollisionPointRec(mousePosition, textBounds)) // Mouse hover text { float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/(float)guiFont.baseSize; + int codepoint = 0; + int codepointSize = 0; int codepointIndex = 0; float glyphWidth = 0.0f; float widthToMouseX = 0; int mouseCursorIndex = 0; - for (int i = textIndexOffset; i < textLength; i += codepointSize) + for (int i = textIndexOffset; i < textLength; i++) { codepoint = GetCodepointNext(&text[i], &codepointSize); codepointIndex = GetGlyphIndex(guiFont, codepoint); @@ -2822,7 +2642,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) mouseCursorIndex = i; break; } - + widthToMouseX += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); } @@ -2831,7 +2651,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) if (GetMousePosition().x >= (textBounds.x + textEndWidth - glyphWidth/2)) { mouseCursor.x = textBounds.x + textEndWidth; - mouseCursorIndex = textLength; + mouseCursorIndex = strlen(text); } // Place cursor at required index on mouse click @@ -2852,7 +2672,6 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) (!CheckCollisionPointRec(mousePosition, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) { textBoxCursorIndex = 0; // GLOBAL: Reset the shared cursor index - autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes result = 1; } } @@ -2864,8 +2683,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { - textBoxCursorIndex = textLength; // GLOBAL: Place cursor index to the end of current text - autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes + textBoxCursorIndex = (int)strlen(text); // GLOBAL: Place cursor index to the end of current text result = 1; } } @@ -2907,7 +2725,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) /* // Text Box control with multiple lines and word-wrap // NOTE: This text-box is readonly, no editing supported by default -bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode) +bool GuiTextBoxMulti(Rectangle bounds, char *text, int bufferSize, bool editMode) { bool pressed = false; @@ -2916,12 +2734,12 @@ bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode) GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_TOP); // TODO: Implement methods to calculate cursor position properly - pressed = GuiTextBox(bounds, text, textSize, editMode); + pressed = GuiTextBox(bounds, text, bufferSize, editMode); GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_NONE); GuiSetStyle(TEXTBOX, TEXT_READONLY, 0); - + return pressed; } */ @@ -2934,27 +2752,24 @@ int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int int tempValue = *value; - Rectangle valueBoxBounds = { - bounds.x + GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH) + GuiGetStyle(VALUEBOX, SPINNER_BUTTON_SPACING), - bounds.y, - bounds.width - 2*(GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH) + GuiGetStyle(VALUEBOX, SPINNER_BUTTON_SPACING)), bounds.height }; - Rectangle leftButtonBound = { (float)bounds.x, (float)bounds.y, (float)GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH), (float)bounds.height }; - Rectangle rightButtonBound = { (float)bounds.x + bounds.width - GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH), (float)bounds.y, - (float)GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH), (float)bounds.height }; + Rectangle spinner = { bounds.x + GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_SPACING), bounds.y, + bounds.width - 2*(GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_SPACING)), bounds.height }; + Rectangle leftButtonBound = { (float)bounds.x, (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height }; + Rectangle rightButtonBound = { (float)bounds.x + bounds.width - GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height }; Rectangle textBounds = { 0 }; if (text != NULL) { textBounds.width = (float)GetTextWidth(text) + 2; textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(SPINNER, TEXT_PADDING); textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING); + if (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SPINNER, TEXT_PADDING); } // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) { Vector2 mousePoint = GetMousePosition(); @@ -2983,20 +2798,20 @@ int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int // Draw control //-------------------------------------------------------------------- - result = GuiValueBox(valueBoxBounds, NULL, &tempValue, minValue, maxValue, editMode); + result = GuiValueBox(spinner, NULL, &tempValue, minValue, maxValue, editMode); // Draw value selector custom buttons // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); - GuiSetStyle(BUTTON, BORDER_WIDTH, GuiGetStyle(VALUEBOX, BORDER_WIDTH)); + GuiSetStyle(BUTTON, BORDER_WIDTH, GuiGetStyle(SPINNER, BORDER_WIDTH)); GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign); GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); // Draw text label if provided - GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + GuiDrawText(text, textBounds, (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); //-------------------------------------------------------------------- *value = tempValue; @@ -3015,7 +2830,7 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in GuiState state = guiState; char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0"; - snprintf(textValue, RAYGUI_VALUEBOX_MAX_CHARS + 1, "%i", *value); + sprintf(textValue, "%i", *value); Rectangle textBounds = { 0 }; if (text != NULL) @@ -3029,7 +2844,7 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) { Vector2 mousePoint = GetMousePosition(); @@ -3073,13 +2888,7 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in //if (*value > maxValue) *value = maxValue; //else if (*value < minValue) *value = minValue; - if ((IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) - { - if (*value > maxValue) *value = maxValue; - else if (*value < minValue) *value = minValue; - - result = 1; - } + if (IsKeyPressed(KEY_ENTER) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) result = 1; } else { @@ -3104,14 +2913,11 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), baseColor); GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3)))); - // Draw cursor rectangle + // Draw cursor if (editMode) { // NOTE: ValueBox internal text is always centered - Rectangle cursor = { bounds.x + GetTextWidth(textValue)/2 + bounds.width/2 + 1, - bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + 2, - 2, bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2 - 4 }; - if (cursor.height > bounds.height) cursor.height = bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2; + Rectangle cursor = { bounds.x + GetTextWidth(textValue)/2 + bounds.width/2 + 1, bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4, bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH) }; GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED))); } @@ -3122,117 +2928,6 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in return result; } -// Floating point Value Box control, updates input val_str with numbers -// NOTE: Requires static variables: frameCounter -int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode) -{ - #if !defined(RAYGUI_VALUEBOX_MAX_CHARS) - #define RAYGUI_VALUEBOX_MAX_CHARS 32 - #endif - - int result = 0; - GuiState state = guiState; - - //char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0"; - //snprintf(textValue, sizeof(textValue), "%2.2f", *value); - - Rectangle textBounds = {0}; - if (text != NULL) - { - textBounds.width = (float)GetTextWidth(text) + 2; - textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING); - textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING); - } - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) - { - Vector2 mousePoint = GetMousePosition(); - - bool valueHasChanged = false; - - if (editMode) - { - state = STATE_PRESSED; - - int keyCount = (int)strlen(textValue); - - // Only allow keys in range [48..57] - if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) - { - if (GetTextWidth(textValue) < bounds.width) - { - int key = GetCharPressed(); - if (((key >= 48) && (key <= 57)) || - (key == '.') || - ((keyCount == 0) && (key == '+')) || // NOTE: Sign can only be in first position - ((keyCount == 0) && (key == '-'))) - { - textValue[keyCount] = (char)key; - keyCount++; - - valueHasChanged = true; - } - } - } - - // Pressed backspace - if (IsKeyPressed(KEY_BACKSPACE)) - { - if (keyCount > 0) - { - keyCount--; - textValue[keyCount] = '\0'; - valueHasChanged = true; - } - } - - if (valueHasChanged) *value = TextToFloat(textValue); - - if ((IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) result = 1; - } - else - { - if (CheckCollisionPointRec(mousePoint, bounds)) - { - state = STATE_FOCUSED; - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1; - } - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - Color baseColor = BLANK; - if (state == STATE_PRESSED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_PRESSED)); - else if (state == STATE_DISABLED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_DISABLED)); - - GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), baseColor); - GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3)))); - - // Draw cursor - if (editMode) - { - // NOTE: ValueBox internal text is always centered - Rectangle cursor = {bounds.x + GetTextWidth(textValue)/2 + bounds.width/2 + 1, - bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4, - bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH)}; - GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED))); - } - - // Draw text label if provided - GuiDrawText(text, textBounds, - (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, - GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); - //-------------------------------------------------------------------- - - return result; -} - // Slider control with pro parameters // NOTE: Other GuiSlider*() controls use this one int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue, int sliderWidth) @@ -3242,32 +2937,45 @@ int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight, float temp = (maxValue - minValue)/2.0f; if (value == NULL) value = &temp; - float oldValue = *value; + + int sliderValue = (int)(((*value - minValue)/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))); Rectangle slider = { bounds.x, bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING), 0, bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) }; + if (sliderWidth > 0) // Slider + { + slider.x += (sliderValue - sliderWidth/2); + slider.width = (float)sliderWidth; + } + else if (sliderWidth == 0) // SliderBar + { + slider.x += GuiGetStyle(SLIDER, BORDER_WIDTH); + slider.width = (float)sliderValue; + } + // Update control //-------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked) { Vector2 mousePoint = GetMousePosition(); - if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + if (guiSliderDragging) // Keep dragging outside of bounds { if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) { - if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + if (CHECK_BOUNDS_ID(bounds, guiSliderActive)) { state = STATE_PRESSED; + // Get equivalent value and slider position from mousePosition.x - *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width-sliderWidth)) + minValue; + *value = ((maxValue - minValue)*(mousePoint.x - (float)(bounds.x + sliderWidth/2)))/(float)(bounds.width - sliderWidth) + minValue; } } else { - guiControlExclusiveMode = false; - guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + guiSliderDragging = false; + guiSliderActive = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; } } else if (CheckCollisionPointRec(mousePoint, bounds)) @@ -3275,13 +2983,16 @@ int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight, if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) { state = STATE_PRESSED; - guiControlExclusiveMode = true; - guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + guiSliderDragging = true; + guiSliderActive = bounds; // Store bounds as an identifier when dragging starts if (!CheckCollisionPointRec(mousePoint, slider)) { // Get equivalent value and slider position from mousePosition.x - *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width-sliderWidth)) + minValue; + *value = ((maxValue - minValue)*(mousePoint.x - (float)(bounds.x + sliderWidth/2)))/(float)(bounds.width - sliderWidth) + minValue; + + if (sliderWidth > 0) slider.x = mousePoint.x - slider.width/2; // Slider + else if (sliderWidth == 0) slider.width = (float)sliderValue; // SliderBar } } else state = STATE_FOCUSED; @@ -3291,23 +3002,14 @@ int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight, else if (*value < minValue) *value = minValue; } - // Control value change check - if (oldValue == *value) result = 0; - else result = 1; - - // Slider bar limits check - float sliderValue = (((*value - minValue)/(maxValue - minValue))*(bounds.width - sliderWidth - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))); + // Bar limits check if (sliderWidth > 0) // Slider { - slider.x += sliderValue; - slider.width = (float)sliderWidth; if (slider.x <= (bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH))) slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH); else if ((slider.x + slider.width) >= (bounds.x + bounds.width)) slider.x = bounds.x + bounds.width - slider.width - GuiGetStyle(SLIDER, BORDER_WIDTH); } else if (sliderWidth == 0) // SliderBar { - slider.x += GuiGetStyle(SLIDER, BORDER_WIDTH); - slider.width = sliderValue; if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH); } //-------------------------------------------------------------------- @@ -3320,7 +3022,6 @@ int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight, if (state == STATE_NORMAL) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED))); else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_FOCUSED))); else if (state == STATE_PRESSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_PRESSED))); - else if (state == STATE_DISABLED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_DISABLED))); // Draw left/right text if provided if (textLeft != NULL) @@ -3331,7 +3032,7 @@ int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight, textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SLIDER, TEXT_PADDING); textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(SLIDER, TEXT + (state*3)))); } if (textRight != NULL) @@ -3342,7 +3043,7 @@ int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight, textBounds.x = bounds.x + bounds.width + GuiGetStyle(SLIDER, TEXT_PADDING); textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(SLIDER, TEXT + (state*3)))); } //-------------------------------------------------------------------- @@ -3371,16 +3072,16 @@ int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight if (value == NULL) value = &temp; // Progress bar - Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) + GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING), + Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) + GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING), 0, - bounds.height - GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - 2*GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING) -1 }; + bounds.height - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - 2*GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING) }; // Update control //-------------------------------------------------------------------- if (*value > maxValue) *value = maxValue; // WARNING: Working with floats could lead to rounding issues - if ((state != STATE_DISABLED)) progress.width = ((float)*value / (maxValue - minValue)) * (bounds.width - 2 * GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)); + if ((state != STATE_DISABLED)) progress.width = (float)(*value/(maxValue - minValue))*bounds.width - ((*value >= maxValue) ? (float)(2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)) : 0.0f); //-------------------------------------------------------------------- // Draw control @@ -3398,18 +3099,18 @@ int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height - 2 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); } - else GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height+GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)-1 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); + else GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); - if (*value >= maxValue) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height+GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)-1}, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); + if (*value >= maxValue) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + progress.width + 1, bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); else { // Draw borders not yet reached by value - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y, bounds.width - (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y + bounds.height - 1, bounds.width - (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height+GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)-1 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + 1, bounds.y, bounds.width - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + 1, bounds.y + bounds.height - 1, bounds.width - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y + 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height - 2 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); } + // Draw slider internal progress bar (depends on state) - progress.width -= 2*GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING); GuiDrawRectangle(progress, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BASE_COLOR_PRESSED))); } @@ -3422,7 +3123,7 @@ int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight textBounds.x = bounds.x - textBounds.width - GuiGetStyle(PROGRESSBAR, TEXT_PADDING); textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(PROGRESSBAR, TEXT + (state*3)))); } if (textRight != NULL) @@ -3433,7 +3134,7 @@ int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight textBounds.x = bounds.x + bounds.width + GuiGetStyle(PROGRESSBAR, TEXT_PADDING); textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(PROGRESSBAR, TEXT + (state*3)))); } //-------------------------------------------------------------------- @@ -3463,7 +3164,7 @@ int GuiDummyRec(Rectangle bounds, const char *text) // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) { Vector2 mousePoint = GetMousePosition(); @@ -3530,7 +3231,7 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) { Vector2 mousePoint = GetMousePosition(); @@ -3578,16 +3279,14 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd // Draw control //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background + GuiDrawRectangle(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background // Draw visible items for (int i = 0; ((i < visibleItems) && (text != NULL)); i++) { - if (GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_NORMAL)) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_NORMAL)), BLANK); - if (state == STATE_DISABLED) { - if ((startIndex + i) == itemSelected) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED))); + if ((startIndex + i) == itemSelected) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED))); GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED))); } @@ -3596,18 +3295,18 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd if (((startIndex + i) == itemSelected) && (active != NULL)) { // Draw item selected - GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED))); + GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED))); GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED))); } else if (((startIndex + i) == itemFocused)) // && (focus != NULL)) // NOTE: We want items focused, despite not returned! { // Draw item focused - GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED))); + GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED))); GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED))); } else { - // Draw item normal (no rectangle) + // Draw item normal GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL))); } } @@ -3647,32 +3346,84 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd return result; } -// Color Panel control - Color (RGBA) variant. +// Color Panel control int GuiColorPanel(Rectangle bounds, const char *text, Color *color) { int result = 0; + GuiState state = guiState; + Vector2 pickerSelector = { 0 }; + + const Color colWhite = { 255, 255, 255, 255 }; + const Color colBlack = { 0, 0, 0, 255 }; Vector3 vcolor = { (float)color->r/255.0f, (float)color->g/255.0f, (float)color->b/255.0f }; Vector3 hsv = ConvertRGBtoHSV(vcolor); - Vector3 prevHsv = hsv; // workaround to see if GuiColorPanelHSV modifies the hsv. - GuiColorPanelHSV(bounds, text, &hsv); + pickerSelector.x = bounds.x + (float)hsv.y*bounds.width; // HSV: Saturation + pickerSelector.y = bounds.y + (1.0f - (float)hsv.z)*bounds.height; // HSV: Value - // Check if the hsv was changed, only then change the color. - // This is required, because the Color->HSV->Color conversion has precision errors. - // Thus the assignment from HSV to Color should only be made, if the HSV has a new user-entered value. - // Otherwise GuiColorPanel would often modify it's color without user input. - // TODO: GuiColorPanelHSV could return 1 if the slider was dragged, to simplify this check. - if (hsv.x != prevHsv.x || hsv.y != prevHsv.y || hsv.z != prevHsv.z) + float hue = -1.0f; + Vector3 maxHue = { hue >= 0.0f ? hue : hsv.x, 1.0f, 1.0f }; + Vector3 rgbHue = ConvertHSVtoRGB(maxHue); + Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x), + (unsigned char)(255.0f*rgbHue.y), + (unsigned char)(255.0f*rgbHue.z), 255 }; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) { - Vector3 rgb = ConvertHSVtoRGB(hsv); + Vector2 mousePoint = GetMousePosition(); - // NOTE: Vector3ToColor() only available on raylib 1.8.1 - *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x), - (unsigned char)(255.0f*rgb.y), - (unsigned char)(255.0f*rgb.z), - color->a }; + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + { + state = STATE_PRESSED; + pickerSelector = mousePoint; + + // Calculate color from picker + Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y }; + + colorPick.x /= (float)bounds.width; // Get normalized value on x + colorPick.y /= (float)bounds.height; // Get normalized value on y + + hsv.y = colorPick.x; + hsv.z = 1.0f - colorPick.y; + + Vector3 rgb = ConvertHSVtoRGB(hsv); + + // NOTE: Vector3ToColor() only available on raylib 1.8.1 + *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x), + (unsigned char)(255.0f*rgb.y), + (unsigned char)(255.0f*rgb.z), + (unsigned char)(255.0f*(float)color->a/255.0f) }; + + } + else state = STATE_FOCUSED; + } } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state != STATE_DISABLED) + { + DrawRectangleGradientEx(bounds, Fade(colWhite, guiAlpha), Fade(colWhite, guiAlpha), Fade(maxHueCol, guiAlpha), Fade(maxHueCol, guiAlpha)); + DrawRectangleGradientEx(bounds, Fade(colBlack, 0), Fade(colBlack, guiAlpha), Fade(colBlack, guiAlpha), Fade(colBlack, 0)); + + // Draw color picker: selector + Rectangle selector = { pickerSelector.x - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, pickerSelector.y - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE), (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE) }; + GuiDrawRectangle(selector, 0, BLANK, colWhite); + } + else + { + DrawRectangleGradientEx(bounds, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.6f), guiAlpha)); + } + + GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); + //-------------------------------------------------------------------- + return result; } @@ -3686,10 +3437,7 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) int result = 0; GuiState state = guiState; - Rectangle selector = { (float)bounds.x + (*alpha)*bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, - (float)bounds.y - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), - (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT), - (float)bounds.height + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2 }; + Rectangle selector = { (float)bounds.x + (*alpha)*bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.y - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT), (float)bounds.height + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2 }; // Update control //-------------------------------------------------------------------- @@ -3697,11 +3445,11 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) { Vector2 mousePoint = GetMousePosition(); - if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + if (guiSliderDragging) // Keep dragging outside of bounds { if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) { - if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + if (CHECK_BOUNDS_ID(bounds, guiSliderActive)) { state = STATE_PRESSED; @@ -3712,8 +3460,8 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) } else { - guiControlExclusiveMode = false; - guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + guiSliderDragging = false; + guiSliderActive = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; } } else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) @@ -3721,8 +3469,8 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) { state = STATE_PRESSED; - guiControlExclusiveMode = true; - guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + guiSliderDragging = true; + guiSliderActive = bounds; // Store bounds as an identifier when dragging starts *alpha = (mousePoint.x - bounds.x)/bounds.width; if (*alpha <= 0.0f) *alpha = 0.0f; @@ -3736,6 +3484,7 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) // Draw control //-------------------------------------------------------------------- + // Draw alpha bar: checked background if (state != STATE_DISABLED) { @@ -3782,11 +3531,11 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) { Vector2 mousePoint = GetMousePosition(); - if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + if (guiSliderDragging) // Keep dragging outside of bounds { if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) { - if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + if (CHECK_BOUNDS_ID(bounds, guiSliderActive)) { state = STATE_PRESSED; @@ -3797,8 +3546,8 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) } else { - guiControlExclusiveMode = false; - guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + guiSliderDragging = false; + guiSliderActive = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; } } else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) @@ -3806,8 +3555,8 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) { state = STATE_PRESSED; - guiControlExclusiveMode = true; - guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + guiSliderDragging = true; + guiSliderActive = bounds; // Store bounds as an identifier when dragging starts *hue = (mousePoint.y - bounds.y)*360/bounds.height; if (*hue <= 0.0f) *hue = 0.0f; @@ -3860,7 +3609,6 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) // float GuiColorBarAlpha(Rectangle bounds, float alpha) // float GuiColorBarHue(Rectangle bounds, float value) // NOTE: bounds define GuiColorPanel() size -// NOTE: this picker converts RGB to HSV, which can cause the Hue control to jump. If you have this problem, consider using the HSV variant instead int GuiColorPicker(Rectangle bounds, const char *text, Color *color) { int result = 0; @@ -3873,7 +3621,6 @@ int GuiColorPicker(Rectangle bounds, const char *text, Color *color) Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; //Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) }; - // NOTE: this conversion can cause low hue-resolution, if the r, g and b value are very similar, which causes the hue bar to shift around when only the GuiColorPanel is used. Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ (*color).r/255.0f, (*color).g/255.0f, (*color).b/255.0f }); GuiColorBarHue(boundsHue, NULL, &hsv.x); @@ -3915,7 +3662,8 @@ int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) return result; } -// Color Panel control - HSV variant +// Color Panel control, returns HSV color value in *colorHsv. +// Used by GuiColorPickerHSV() int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) { int result = 0; @@ -3928,7 +3676,8 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) pickerSelector.x = bounds.x + (float)colorHsv->y*bounds.width; // HSV: Saturation pickerSelector.y = bounds.y + (1.0f - (float)colorHsv->z)*bounds.height; // HSV: Value - Vector3 maxHue = { colorHsv->x, 1.0f, 1.0f }; + float hue = -1.0f; + Vector3 maxHue = { hue >= 0.0f ? hue : colorHsv->x, 1.0f, 1.0f }; Vector3 rgbHue = ConvertHSVtoRGB(maxHue); Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x), (unsigned char)(255.0f*rgbHue.y), @@ -3936,47 +3685,15 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked) + if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) { Vector2 mousePoint = GetMousePosition(); - if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) - { - if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) - { - pickerSelector = mousePoint; - - if (pickerSelector.x < bounds.x) pickerSelector.x = bounds.x; - if (pickerSelector.x > bounds.x + bounds.width) pickerSelector.x = bounds.x + bounds.width; - if (pickerSelector.y < bounds.y) pickerSelector.y = bounds.y; - if (pickerSelector.y > bounds.y + bounds.height) pickerSelector.y = bounds.y + bounds.height; - - // Calculate color from picker - Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y }; - - colorPick.x /= (float)bounds.width; // Get normalized value on x - colorPick.y /= (float)bounds.height; // Get normalized value on y - - colorHsv->y = colorPick.x; - colorHsv->z = 1.0f - colorPick.y; - - } - } - else - { - guiControlExclusiveMode = false; - guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; - } - } - else if (CheckCollisionPointRec(mousePoint, bounds)) + if (CheckCollisionPointRec(mousePoint, bounds)) { if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) { state = STATE_PRESSED; - guiControlExclusiveMode = true; - guiControlExclusiveRec = bounds; pickerSelector = mousePoint; // Calculate color from picker @@ -4035,12 +3752,12 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons buttonBounds.width = (bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount; buttonBounds.height = RAYGUI_MESSAGEBOX_BUTTON_HEIGHT; - //int textWidth = GetTextWidth(message) + 2; + int textWidth = GetTextWidth(message) + 2; Rectangle textBounds = { 0 }; - textBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING; + textBounds.x = bounds.x + bounds.width/2 - textWidth/2; textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + RAYGUI_MESSAGEBOX_BUTTON_PADDING; - textBounds.width = bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*2; + textBounds.width = (float)textWidth; textBounds.height = bounds.height - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 3*RAYGUI_MESSAGEBOX_BUTTON_PADDING - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT; // Draw control @@ -4173,17 +3890,15 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect GuiState state = guiState; Vector2 mousePoint = GetMousePosition(); - Vector2 currentMouseCell = { -1, -1 }; + Vector2 currentMouseCell = { 0 }; float spaceWidth = spacing/(float)subdivs; int linesV = (int)(bounds.width/spaceWidth) + 1; int linesH = (int)(bounds.height/spaceWidth) + 1; - int color = GuiGetStyle(DEFAULT, LINE_COLOR); - // Update control //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging) { if (CheckCollisionPointRec(mousePoint, bounds)) { @@ -4196,23 +3911,28 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect // Draw control //-------------------------------------------------------------------- - if (state == STATE_DISABLED) color = GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED); - - if (subdivs > 0) + switch (state) { - // Draw vertical grid lines - for (int i = 0; i < linesV; i++) + case STATE_NORMAL: { - Rectangle lineV = { bounds.x + spacing*i/subdivs, bounds.y, 1, bounds.height + 1 }; - GuiDrawRectangle(lineV, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(color), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(color), RAYGUI_GRID_ALPHA)); - } + if (subdivs > 0) + { + // Draw vertical grid lines + for (int i = 0; i < linesV; i++) + { + Rectangle lineV = { bounds.x + spacing*i/subdivs, bounds.y, 1, bounds.height }; + GuiDrawRectangle(lineV, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)), RAYGUI_GRID_ALPHA)); + } - // Draw horizontal grid lines - for (int i = 0; i < linesH; i++) - { - Rectangle lineH = { bounds.x, bounds.y + spacing*i/subdivs, bounds.width + 1, 1 }; - GuiDrawRectangle(lineH, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(color), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(color), RAYGUI_GRID_ALPHA)); - } + // Draw horizontal grid lines + for (int i = 0; i < linesH; i++) + { + Rectangle lineH = { bounds.x, bounds.y + spacing*i/subdivs, bounds.width, 1 }; + GuiDrawRectangle(lineH, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)), RAYGUI_GRID_ALPHA)); + } + } + } break; + default: break; } if (mouseCell != NULL) *mouseCell = currentMouseCell; @@ -4232,6 +3952,7 @@ void GuiDisableTooltip(void) { guiTooltip = false; } // Set tooltip string void GuiSetTooltip(const char *tooltip) { guiTooltipPtr = tooltip; } + //---------------------------------------------------------------------------------- // Styles loading functions //---------------------------------------------------------------------------------- @@ -4244,7 +3965,6 @@ void GuiLoadStyle(const char *fileName) #define MAX_LINE_BUFFER_SIZE 256 bool tryBinary = false; - if (!guiStyleLoaded) GuiLoadStyleDefault(); // Try reading the files as text file first FILE *rgsFile = fopen(fileName, "rt"); @@ -4377,7 +4097,7 @@ void GuiLoadStyleDefault(void) GuiSetStyle(DEFAULT, BORDER_WIDTH, 1); GuiSetStyle(DEFAULT, TEXT_PADDING, 0); GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); - + // Initialize default extended property values // NOTE: By default, extended property values are initialized to 0 GuiSetStyle(DEFAULT, TEXT_SIZE, 10); // DEFAULT, shared by all controls @@ -4401,6 +4121,8 @@ void GuiLoadStyleDefault(void) GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); GuiSetStyle(VALUEBOX, TEXT_PADDING, 0); GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(SPINNER, TEXT_PADDING, 0); + GuiSetStyle(SPINNER, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); GuiSetStyle(STATUSBAR, TEXT_PADDING, 8); GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); @@ -4415,8 +4137,8 @@ void GuiLoadStyleDefault(void) GuiSetStyle(COMBOBOX, COMBO_BUTTON_SPACING, 2); GuiSetStyle(DROPDOWNBOX, ARROW_PADDING, 16); GuiSetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING, 2); - GuiSetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH, 24); - GuiSetStyle(VALUEBOX, SPINNER_BUTTON_SPACING, 2); + GuiSetStyle(SPINNER, SPIN_BUTTON_WIDTH, 24); + GuiSetStyle(SPINNER, SPIN_BUTTON_SPACING, 2); GuiSetStyle(SCROLLBAR, BORDER_WIDTH, 0); GuiSetStyle(SCROLLBAR, ARROWS_VISIBLE, 0); GuiSetStyle(SCROLLBAR, ARROWS_SIZE, 6); @@ -4426,7 +4148,6 @@ void GuiLoadStyleDefault(void) GuiSetStyle(SCROLLBAR, SCROLL_SPEED, 12); GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, 28); GuiSetStyle(LISTVIEW, LIST_ITEMS_SPACING, 2); - GuiSetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH, 1); GuiSetStyle(LISTVIEW, SCROLLBAR_WIDTH, 12); GuiSetStyle(LISTVIEW, SCROLLBAR_SIDE, SCROLLBAR_RIGHT_SIDE); GuiSetStyle(COLORPICKER, COLOR_SELECTOR_SIZE, 8); @@ -4464,12 +4185,12 @@ const char *GuiIconText(int iconId, const char *text) return NULL; #else static char buffer[1024] = { 0 }; - static char iconBuffer[16] = { 0 }; + static char iconBuffer[6] = { 0 }; if (text != NULL) { memset(buffer, 0, 1024); - snprintf(buffer, 1024, "#%03i#", iconId); + sprintf(buffer, "#%03i#", iconId); for (int i = 5; i < 1024; i++) { @@ -4481,7 +4202,7 @@ const char *GuiIconText(int iconId, const char *text) } else { - snprintf(iconBuffer, 16, "#%03i#", iconId); + sprintf(iconBuffer, "#%03i#", iconId & 0x1ff); return iconBuffer; } @@ -4566,56 +4287,6 @@ char **GuiLoadIcons(const char *fileName, bool loadIconsName) return guiIconsName; } -// Load icons from memory -// WARNING: Binary files only -char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName) -{ - unsigned char *fileDataPtr = (unsigned char *)fileData; - char **guiIconsName = NULL; - - char signature[5] = { 0 }; - short version = 0; - short reserved = 0; - short iconCount = 0; - short iconSize = 0; - - memcpy(signature, fileDataPtr, 4); - memcpy(&version, fileDataPtr + 4, sizeof(short)); - memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short)); - memcpy(&iconCount, fileDataPtr + 4 + 2 + 2, sizeof(short)); - memcpy(&iconSize, fileDataPtr + 4 + 2 + 2 + 2, sizeof(short)); - fileDataPtr += 12; - - if ((signature[0] == 'r') && - (signature[1] == 'G') && - (signature[2] == 'I') && - (signature[3] == ' ')) - { - if (loadIconsName) - { - guiIconsName = (char **)RAYGUI_MALLOC(iconCount*sizeof(char *)); - for (int i = 0; i < iconCount; i++) - { - guiIconsName[i] = (char *)RAYGUI_MALLOC(RAYGUI_ICON_MAX_NAME_LENGTH); - memcpy(guiIconsName[i], fileDataPtr, RAYGUI_ICON_MAX_NAME_LENGTH); - fileDataPtr += RAYGUI_ICON_MAX_NAME_LENGTH; - } - } - else - { - // Skip icon name data if not required - fileDataPtr += iconCount*RAYGUI_ICON_MAX_NAME_LENGTH; - } - - int iconDataSize = iconCount*(iconSize*iconSize/32)*sizeof(unsigned int); - guiIconsPtr = (unsigned int *)RAYGUI_MALLOC(iconDataSize); - - memcpy(guiIconsPtr, fileDataPtr, iconDataSize); - } - - return guiIconsName; -} - // Draw selected icon using rectangles pixel-by-pixel void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color) { @@ -4688,7 +4359,7 @@ static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize) // NOTE: All DEFAULT properties should be defined first in the file GuiSetStyle(0, (int)propertyId, propertyValue); - if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int j = 1; j < RAYGUI_MAX_CONTROLS; j++) GuiSetStyle(j, (int)propertyId, propertyValue); + if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int i = 1; i < RAYGUI_MAX_CONTROLS; i++) GuiSetStyle(i, (int)propertyId, propertyValue); } else GuiSetStyle((int)controlId, (int)propertyId, propertyValue); } @@ -4927,7 +4598,7 @@ static int GetTextWidth(const char *text) } } - if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + ICON_TEXT_PADDING); + if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE - ICON_TEXT_PADDING); } return (int)textSize.x; @@ -4953,7 +4624,7 @@ static Rectangle GetTextBounds(int control, Rectangle bounds) case SLIDER: case CHECKBOX: case VALUEBOX: - case CONTROL11: + case SPINNER: // TODO: More special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER default: { @@ -5100,7 +4771,6 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C // Get text position depending on alignment and iconId //--------------------------------------------------------------------------------- Vector2 textBoundsPosition = { textBounds.x, textBounds.y }; - float textBoundsWidthOffset = 0.0f; // NOTE: We get text size after icon has been processed // WARNING: GetTextWidth() also processes text icon to get width! -> Really needed? @@ -5126,8 +4796,6 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C default: break; } - if (textSizeX > textBounds.width && (lines[i] != NULL) && (lines[i][0] != '\0')) textBoundsPosition.x = textBounds.x; - switch (alignmentVertical) { // Only valid in case of wordWrap = 0; @@ -5150,8 +4818,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C { // NOTE: We consider icon height, probably different than text size GuiDrawIcon(iconId, (int)textBoundsPosition.x, (int)(textBounds.y + textBounds.height/2 - RAYGUI_ICON_SIZE*guiIconScale/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height)), guiIconScale, tint); - textBoundsPosition.x += (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); - textBoundsWidthOffset = (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); + textBoundsPosition.x += (RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); } #endif // Get size in bytes of text, @@ -5160,15 +4827,9 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C for (int c = 0; (lines[i][c] != '\0') && (lines[i][c] != '\n') && (lines[i][c] != '\r'); c++, lineSize++){ } float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize; - int lastSpaceIndex = 0; - bool tempWrapCharMode = false; - int textOffsetY = 0; float textOffsetX = 0.0f; float glyphWidth = 0; - - int ellipsisWidth = GetTextWidth("..."); - bool textOverflow = false; for (int c = 0, codepointSize = 0; c < lineSize; c += codepointSize) { int codepoint = GetCodepointNext(&lines[i][c], &codepointSize); @@ -5176,85 +4837,54 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C // 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) codepointSize = 1; // TODO: Review not recognized codepoints size + if (codepoint == 0x3f) codepointSize = 1; // TODO: Review not recognized codepoints size - // Get glyph width to check if it goes out of bounds - if (guiFont.glyphs[index].advanceX == 0) glyphWidth = ((float)guiFont.recs[index].width*scaleFactor); - else glyphWidth = (float)guiFont.glyphs[index].advanceX*scaleFactor; - - // Wrap mode text measuring, to validate if - // it can be drawn or a new line is required + // Wrap mode text measuring to space to validate if it can be drawn or + // a new line is required if (wrapMode == TEXT_WRAP_CHAR) { + // Get glyph width to check if it goes out of bounds + if (guiFont.glyphs[index].advanceX == 0) glyphWidth = ((float)guiFont.recs[index].width*scaleFactor); + else glyphWidth = (float)guiFont.glyphs[index].advanceX*scaleFactor; + // Jump to next line if current character reach end of the box limits - if ((textOffsetX + glyphWidth) > textBounds.width - textBoundsWidthOffset) + if ((textOffsetX + glyphWidth) > textBounds.width) { textOffsetX = 0.0f; textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING); - - if (tempWrapCharMode) // Wrap at char level when too long words - { - wrapMode = TEXT_WRAP_WORD; - tempWrapCharMode = false; - } } } else if (wrapMode == TEXT_WRAP_WORD) { - if (codepoint == 32) lastSpaceIndex = c; - // Get width to next space in line int nextSpaceIndex = 0; float nextSpaceWidth = GetNextSpaceWidth(lines[i] + c, &nextSpaceIndex); - int nextSpaceIndex2 = 0; - float nextWordSize = GetNextSpaceWidth(lines[i] + lastSpaceIndex + 1, &nextSpaceIndex2); - - if (nextWordSize > textBounds.width - textBoundsWidthOffset) - { - // Considering the case the next word is longer than bounds - tempWrapCharMode = true; - wrapMode = TEXT_WRAP_CHAR; - } - else if ((textOffsetX + nextSpaceWidth) > textBounds.width - textBoundsWidthOffset) + if ((textOffsetX + nextSpaceWidth) > textBounds.width) { textOffsetX = 0.0f; textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING); } + + // TODO: Consider case: (nextSpaceWidth >= textBounds.width) } if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint else { - // TODO: There are multiple types of spaces in Unicode, + // TODO: There are multiple types of spaces in Unicode, // maybe it's a good idea to add support for more: http://jkorpela.fi/chars/spaces.html if ((codepoint != ' ') && (codepoint != '\t')) // Do not draw codepoints with no glyph { if (wrapMode == TEXT_WRAP_NONE) { // Draw only required text glyphs fitting the textBounds.width - if (textSizeX > textBounds.width) - { - if (textOffsetX <= (textBounds.width - glyphWidth - textBoundsWidthOffset - ellipsisWidth)) - { - DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); - } - else if (!textOverflow) - { - textOverflow = true; - - for (int j = 0; j < ellipsisWidth; j += ellipsisWidth/3) - { - DrawTextCodepoint(guiFont, '.', RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX + j, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); - } - } - } - else + if (textOffsetX <= (textBounds.width - glyphWidth)) { DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); } } - else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) + else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) { // Draw only glyphs inside the bounds if ((textBoundsPosition.y + textOffsetY) <= (textBounds.y + textBounds.height - GuiGetStyle(DEFAULT, TEXT_SIZE))) @@ -5305,7 +4935,7 @@ static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, // Draw tooltip using control bounds static void GuiTooltip(Rectangle controlRec) { - if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiControlExclusiveMode) + if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiSliderDragging) { Vector2 textSize = MeasureTextEx(GuiGetFont(), guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); @@ -5371,7 +5001,7 @@ static const char **GuiTextSplit(const char *text, char delimiter, int *count, i buffer[i] = '\0'; // Set an end of string at this point counter++; - if (counter >= RAYGUI_TEXTSPLIT_MAX_ITEMS) break; + if (counter == RAYGUI_TEXTSPLIT_MAX_ITEMS) break; } } @@ -5531,11 +5161,8 @@ static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) if (value > maxValue) value = maxValue; if (value < minValue) value = minValue; - int valueRange = maxValue - minValue; - if (valueRange <= 0) valueRange = 1; - + const int valueRange = maxValue - minValue; int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); - if (sliderSize < 1) sliderSize = 1; // TODO: Consider a minimum slider size // Calculate rectangles for all of the components arrowUpLeft = RAYGUI_CLITERAL(Rectangle){ @@ -5576,13 +5203,13 @@ static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) { Vector2 mousePoint = GetMousePosition(); - if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + if (guiSliderDragging) // Keep dragging outside of bounds { if (IsMouseButtonDown(MOUSE_LEFT_BUTTON) && !CheckCollisionPointRec(mousePoint, arrowUpLeft) && !CheckCollisionPointRec(mousePoint, arrowDownRight)) { - if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + if (CHECK_BOUNDS_ID(bounds, guiSliderActive)) { state = STATE_PRESSED; @@ -5592,8 +5219,8 @@ static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) } else { - guiControlExclusiveMode = false; - guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + guiSliderDragging = false; + guiSliderActive = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; } } else if (CheckCollisionPointRec(mousePoint, bounds)) @@ -5607,8 +5234,8 @@ static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) // Handle mouse button down if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { - guiControlExclusiveMode = true; - guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + guiSliderDragging = true; + guiSliderActive = bounds; // Store bounds as an identifier when dragging starts // Check arrows click if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); @@ -5808,37 +5435,6 @@ static int TextToInteger(const char *text) return value*sign; } -// Get float value from text -// NOTE: This function replaces atof() [stdlib.h] -// WARNING: Only '.' character is understood as decimal point -static float TextToFloat(const char *text) -{ - float value = 0.0f; - float sign = 1.0f; - - if ((text[0] == '+') || (text[0] == '-')) - { - if (text[0] == '-') sign = -1.0f; - text++; - } - - int i = 0; - for (; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10.0f + (float)(text[i] - '0'); - - if (text[i++] != '.') value *= sign; - else - { - float divisor = 10.0f; - for (; ((text[i] >= '0') && (text[i] <= '9')); i++) - { - value += ((float)(text[i] - '0'))/divisor; - divisor = divisor*10.0f; - } - } - - return value; -} - // Encode codepoint into UTF-8 text (char array size returned as parameter) static const char *CodepointToUTF8(int codepoint, int *byteSize) { @@ -5892,21 +5488,21 @@ static int GetCodepointNext(const char *text, int *codepointSize) if (0xf0 == (0xf8 & ptr[0])) { // 4 byte UTF-8 codepoint - if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80) || ((ptr[3] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks + if(((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80) || ((ptr[3] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks codepoint = ((0x07 & ptr[0]) << 18) | ((0x3f & ptr[1]) << 12) | ((0x3f & ptr[2]) << 6) | (0x3f & ptr[3]); *codepointSize = 4; } else if (0xe0 == (0xf0 & ptr[0])) { // 3 byte UTF-8 codepoint */ - if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks + if(((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks codepoint = ((0x0f & ptr[0]) << 12) | ((0x3f & ptr[1]) << 6) | (0x3f & ptr[2]); *codepointSize = 3; } else if (0xc0 == (0xe0 & ptr[0])) { // 2 byte UTF-8 codepoint - if ((ptr[1] & 0xC0) ^ 0x80) { return codepoint; } //10xxxxxx checks + if((ptr[1] & 0xC0) ^ 0x80) { return codepoint; } //10xxxxxx checks codepoint = ((0x1f & ptr[0]) << 6) | (0x3f & ptr[1]); *codepointSize = 2; } @@ -5917,6 +5513,7 @@ static int GetCodepointNext(const char *text, int *codepointSize) *codepointSize = 1; } + return codepoint; } #endif // RAYGUI_STANDALONE