2021-05-14 05:59:33 +00:00
/*******************************************************************************************
*
* raygui v2 .9 - dev - 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
* available as a standalone library , as long as input and drawing functions are provided .
*
* Controls provided :
*
* # Container / separators Controls
* - WindowBox
* - GroupBox
* - Line
* - Panel
*
* # Basic Controls
* - Label
* - Button
* - LabelButton - - > Label
* - ImageButton - - > Button
* - ImageButtonEx - - > Button
* - Toggle
* - ToggleGroup - - > Toggle
* - CheckBox
* - ComboBox
* - DropdownBox
* - TextBox
* - TextBoxMulti
* - ValueBox - - > TextBox
* - Spinner - - > Button , ValueBox
* - Slider
* - SliderBar - - > Slider
* - ProgressBar
* - StatusBar
* - ScrollBar
* - ScrollPanel
* - DummyRec
* - Grid
*
* # Advance Controls
* - ListView
* - ColorPicker - - > ColorPanel , ColorBarHue
* - MessageBox - - > Window , Label , Button
* - TextInputBox - - > Window , Label , TextBox , Button
*
* It also provides a set of functions for styling the controls based on its properties ( size , color ) .
*
* CONFIGURATION :
*
* # define RAYGUI_IMPLEMENTATION
* Generates the implementation of the library into the included file .
* If not defined , the library is in header only mode and can be included in other headers
* or source files without problems . But only ONE file should hold the implementation .
*
* # define RAYGUI_STATIC ( defined by default )
* The generated implementation will stay private inside implementation file and all
* internal symbols and functions will only be visible inside that file .
*
* # define RAYGUI_STANDALONE
* Avoid raylib . h header inclusion in this file . Data types defined on raylib are defined
* internally in the library and input management and drawing functions must be provided by
* the user ( check library implementation for further details ) .
*
* # define RAYGUI_SUPPORT_ICONS
* Includes riconsdata . h header defining a set of 128 icons ( binary format ) to be used on
* multiple controls and following raygui styles
*
*
* VERSIONS HISTORY :
* 2.9 ( 17 - Mar - 2021 ) Removed tooltip API
* 2.8 ( 03 - May - 2020 ) Centralized rectangles drawing to GuiDrawRectangle ( )
* 2.7 ( 20 - Feb - 2020 ) Added possible tooltips API
* 2.6 ( 09 - Sep - 2019 ) ADDED : GuiTextInputBox ( )
* REDESIGNED : GuiListView * ( ) , GuiDropdownBox ( ) , GuiSlider * ( ) , GuiProgressBar ( ) , GuiMessageBox ( )
* REVIEWED : GuiTextBox ( ) , GuiSpinner ( ) , GuiValueBox ( ) , GuiLoadStyle ( )
* Replaced property INNER_PADDING by TEXT_PADDING , renamed some properties
* Added 8 new custom styles ready to use
* Multiple minor tweaks and bugs corrected
* 2.5 ( 28 - May - 2019 ) Implemented extended GuiTextBox ( ) , GuiValueBox ( ) , GuiSpinner ( )
* 2.3 ( 29 - Apr - 2019 ) Added rIcons auxiliar library and support for it , multiple controls reviewed
* Refactor all controls drawing mechanism to use control state
* 2.2 ( 05 - Feb - 2019 ) Added GuiScrollBar ( ) , GuiScrollPanel ( ) , reviewed GuiListView ( ) , removed Gui * Ex ( ) controls
* 2.1 ( 26 - Dec - 2018 ) Redesign of GuiCheckBox ( ) , GuiComboBox ( ) , GuiDropdownBox ( ) , GuiToggleGroup ( ) > Use combined text string
* Complete redesign of style system ( breaking change )
* 2.0 ( 08 - Nov - 2018 ) Support controls guiLock and custom fonts , reviewed GuiComboBox ( ) , GuiListView ( ) . . .
* 1.9 ( 09 - Oct - 2018 ) Controls review : GuiGrid ( ) , GuiTextBox ( ) , GuiTextBoxMulti ( ) , GuiValueBox ( ) . . .
* 1.8 ( 01 - May - 2018 ) Lot of rework and redesign to align with rGuiStyler and rGuiLayout
* 1.5 ( 21 - Jun - 2017 ) Working in an improved styles system
* 1.4 ( 15 - Jun - 2017 ) Rewritten all GUI functions ( removed useless ones )
* 1.3 ( 12 - Jun - 2017 ) Redesigned styles system
* 1.1 ( 01 - Jun - 2017 ) Complete review of the library
* 1.0 ( 07 - Jun - 2016 ) Converted to header - only by Ramon Santamaria .
* 0.9 ( 07 - Mar - 2016 ) Reviewed and tested by Albert Martos , Ian Eito , Sergio Martinez and Ramon Santamaria .
* 0.8 ( 27 - Aug - 2015 ) Initial release . Implemented by Kevin Gato , Daniel Nicol á s and Ramon Santamaria .
*
* CONTRIBUTORS :
* Ramon Santamaria : Supervision , review , redesign , update and maintenance . . .
* Vlad Adrian : Complete rewrite of GuiTextBox ( ) to support extended features ( 2019 )
* Sergio Martinez : Review , testing ( 2015 ) and redesign of multiple controls ( 2018 )
* Adria Arranz : Testing and Implementation of additional controls ( 2018 )
* Jordi Jorba : Testing and Implementation of additional controls ( 2018 )
* Albert Martos : Review and testing of the library ( 2015 )
* Ian Eito : Review and testing of the library ( 2015 )
* Kevin Gato : Initial implementation of basic components ( 2014 )
* Daniel Nicolas : Initial implementation of basic components ( 2014 )
*
*
* LICENSE : zlib / libpng
*
* Copyright ( c ) 2014 - 2020 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 .
*
* Permission is granted to anyone to use this software for any purpose , including commercial
* applications , and to alter it and redistribute it freely , subject to the following restrictions :
*
* 1. The origin of this software must not be misrepresented ; you must not claim that you
* wrote the original software . If you use this software in a product , an acknowledgment
* in the product documentation would be appreciated but is not required .
*
* 2. Altered source versions must be plainly marked as such , and must not be misrepresented
* as being the original software .
*
* 3. This notice may not be removed or altered from any source distribution .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifndef RAYGUI_H
# define RAYGUI_H
# define RAYGUI_VERSION "2.9-dev"
# if !defined(RAYGUI_STANDALONE)
2021-06-01 13:20:04 +00:00
# include "raylib.h"
2021-05-14 05:59:33 +00:00
# endif
// Define functions scope to be used internally (static) or externally (extern) to the module including this file
# if defined(_WIN32)
2021-06-01 13:20:04 +00:00
// Microsoft attibutes to tell compiler that symbols are imported/exported from a .dll
# if defined(BUILD_LIBTYPE_SHARED)
# define RAYGUIDEF __declspec(dllexport) // We are building raygui as a Win32 shared library (.dll)
# elif defined(USE_LIBTYPE_SHARED)
# define RAYGUIDEF __declspec(dllimport) // We are using raygui as a Win32 shared library (.dll)
# else
# define RAYGUIDEF // We are building or using raygui as a static library
# endif
2021-05-14 05:59:33 +00:00
# else
2021-06-01 13:20:04 +00:00
# define RAYGUIDEF // We are building or using raygui as a static library (or Linux shared library)
2021-05-14 05:59:33 +00:00
# endif
# if !defined(RAYGUI_MALLOC) && !defined(RAYGUI_CALLOC) && !defined(RAYGUI_FREE)
2021-06-01 13:20:04 +00:00
# include <stdlib.h> // Required for: malloc(), calloc(), free()
2021-05-14 05:59:33 +00:00
# endif
// Allow custom memory allocators
# ifndef RAYGUI_MALLOC
2021-06-01 13:20:04 +00:00
# define RAYGUI_MALLOC(sz) malloc(sz)
2021-05-14 05:59:33 +00:00
# endif
# ifndef RAYGUI_CALLOC
2021-06-01 13:20:04 +00:00
# define RAYGUI_CALLOC(n,sz) calloc(n,sz)
2021-05-14 05:59:33 +00:00
# endif
# ifndef RAYGUI_FREE
2021-06-01 13:20:04 +00:00
# define RAYGUI_FREE(p) free(p)
2021-05-14 05:59:33 +00:00
# endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
# define NUM_CONTROLS 16 // Number of standard controls
# define NUM_PROPS_DEFAULT 16 // Number of standard properties
# define NUM_PROPS_EXTENDED 8 // Number of extended properties
# define TEXTEDIT_CURSOR_BLINK_FRAMES 20 // Text edit controls cursor blink timming
# if defined(__cplusplus)
extern " C " { // Prevents name mangling of functions
# endif
2021-06-01 13:20:04 +00:00
//----------------------------------------------------------------------------------
// Types and Structures Definition
// NOTE: Some types are required for RAYGUI_STANDALONE usage
//----------------------------------------------------------------------------------
2021-05-14 05:59:33 +00:00
# if defined(RAYGUI_STANDALONE)
2021-06-01 13:20:04 +00:00
# ifndef __cplusplus
2021-05-14 05:59:33 +00:00
// Boolean type
2021-06-01 13:20:04 +00:00
# ifndef true
typedef enum { false , true } bool ;
# endif
# endif
2021-05-14 05:59:33 +00:00
// Vector2 type
typedef struct Vector2 {
float x ;
float y ;
} Vector2 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Vector3 type
typedef struct Vector3 {
float x ;
float y ;
float z ;
} Vector3 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Color type, RGBA (32bit)
typedef struct Color {
unsigned char r ;
unsigned char g ;
unsigned char b ;
unsigned char a ;
} Color ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Rectangle type
typedef struct Rectangle {
float x ;
float y ;
float width ;
float height ;
} Rectangle ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// TODO: Texture2D type is very coupled to raylib, mostly required by GuiImageButton()
// It should be redesigned to be provided by user
typedef struct Texture2D {
unsigned int id ; // OpenGL texture id
int width ; // Texture base width
int height ; // Texture base height
int mipmaps ; // Mipmap levels, 1 by default
int format ; // Data format (PixelFormat type)
} Texture2D ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Font character info
typedef struct CharInfo CharInfo ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// TODO: Font type is very coupled to raylib, mostly required by GuiLoadStyle()
// It should be redesigned to be provided by user
typedef struct Font {
int baseSize ; // Base size (default chars height)
int charsCount ; // Number of characters
Texture2D texture ; // Characters texture atlas
Rectangle * recs ; // Characters rectangles in texture
CharInfo * chars ; // Characters info data
} Font ;
# endif
2021-06-01 13:20:04 +00:00
// Style property
typedef struct GuiStyleProp {
unsigned short controlId ;
unsigned short propertyId ;
int propertyValue ;
} GuiStyleProp ;
// Gui control state
typedef enum {
GUI_STATE_NORMAL = 0 ,
GUI_STATE_FOCUSED ,
GUI_STATE_PRESSED ,
GUI_STATE_DISABLED ,
} GuiControlState ;
// Gui control text alignment
typedef enum {
GUI_TEXT_ALIGN_LEFT = 0 ,
GUI_TEXT_ALIGN_CENTER ,
GUI_TEXT_ALIGN_RIGHT ,
} GuiTextAlignment ;
// Gui controls
typedef enum {
DEFAULT = 0 ,
LABEL , // LABELBUTTON
BUTTON , // IMAGEBUTTON
TOGGLE , // TOGGLEGROUP
SLIDER , // SLIDERBAR
PROGRESSBAR ,
CHECKBOX ,
COMBOBOX ,
DROPDOWNBOX ,
TEXTBOX , // TEXTBOXMULTI
VALUEBOX ,
SPINNER ,
LISTVIEW ,
COLORPICKER ,
SCROLLBAR ,
STATUSBAR
} GuiControl ;
// Gui base properties for every control
typedef enum {
BORDER_COLOR_NORMAL = 0 ,
BASE_COLOR_NORMAL ,
TEXT_COLOR_NORMAL ,
BORDER_COLOR_FOCUSED ,
BASE_COLOR_FOCUSED ,
TEXT_COLOR_FOCUSED ,
BORDER_COLOR_PRESSED ,
BASE_COLOR_PRESSED ,
TEXT_COLOR_PRESSED ,
BORDER_COLOR_DISABLED ,
BASE_COLOR_DISABLED ,
TEXT_COLOR_DISABLED ,
BORDER_WIDTH ,
TEXT_PADDING ,
TEXT_ALIGNMENT ,
RESERVED
} GuiControlProperty ;
// Gui extended properties depend on control
// NOTE: We reserve a fixed size of additional properties per control
// DEFAULT properties
typedef enum {
TEXT_SIZE = 16 ,
TEXT_SPACING ,
LINE_COLOR ,
BACKGROUND_COLOR ,
} GuiDefaultProperty ;
// Label
//typedef enum { } GuiLabelProperty;
// Button
//typedef enum { } GuiButtonProperty;
// Toggle / ToggleGroup
typedef enum {
GROUP_PADDING = 16 ,
} GuiToggleProperty ;
// Slider / SliderBar
typedef enum {
SLIDER_WIDTH = 16 ,
SLIDER_PADDING
} GuiSliderProperty ;
// ProgressBar
typedef enum {
PROGRESS_PADDING = 16 ,
} GuiProgressBarProperty ;
// CheckBox
typedef enum {
CHECK_PADDING = 16
} GuiCheckBoxProperty ;
// ComboBox
typedef enum {
COMBO_BUTTON_WIDTH = 16 ,
COMBO_BUTTON_PADDING
} GuiComboBoxProperty ;
// DropdownBox
typedef enum {
ARROW_PADDING = 16 ,
DROPDOWN_ITEMS_PADDING
} GuiDropdownBoxProperty ;
// TextBox / TextBoxMulti / ValueBox / Spinner
typedef enum {
TEXT_INNER_PADDING = 16 ,
TEXT_LINES_PADDING ,
COLOR_SELECTED_FG ,
COLOR_SELECTED_BG
} GuiTextBoxProperty ;
// Spinner
typedef enum {
SPIN_BUTTON_WIDTH = 16 ,
SPIN_BUTTON_PADDING ,
} GuiSpinnerProperty ;
// ScrollBar
typedef enum {
ARROWS_SIZE = 16 ,
ARROWS_VISIBLE ,
SCROLL_SLIDER_PADDING ,
SCROLL_SLIDER_SIZE ,
SCROLL_PADDING ,
SCROLL_SPEED ,
} GuiScrollBarProperty ;
// ScrollBar side
typedef enum {
SCROLLBAR_LEFT_SIDE = 0 ,
SCROLLBAR_RIGHT_SIDE
} GuiScrollBarSide ;
// ListView
typedef enum {
LIST_ITEMS_HEIGHT = 16 ,
LIST_ITEMS_PADDING ,
SCROLLBAR_WIDTH ,
SCROLLBAR_SIDE ,
} GuiListViewProperty ;
// ColorPicker
typedef enum {
COLOR_SELECTOR_SIZE = 16 ,
HUEBAR_WIDTH , // Right hue bar width
HUEBAR_PADDING , // Right hue bar separation from panel
HUEBAR_SELECTOR_HEIGHT , // Right hue bar selector height
HUEBAR_SELECTOR_OVERFLOW // Right hue bar selector overflow
} GuiColorPickerProperty ;
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
// ...
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
// State modification functions
RAYGUIDEF void GuiEnable ( void ) ; // Enable gui controls (global state)
RAYGUIDEF void GuiDisable ( void ) ; // Disable gui controls (global state)
RAYGUIDEF void GuiLock ( void ) ; // Lock gui controls (global state)
RAYGUIDEF void GuiUnlock ( void ) ; // Unlock gui controls (global state)
RAYGUIDEF void GuiFade ( float alpha ) ; // Set gui controls alpha (global state), alpha goes from 0.0f to 1.0f
RAYGUIDEF void GuiSetState ( int state ) ; // Set gui state (global state)
RAYGUIDEF int GuiGetState ( void ) ; // Get gui state (global state)
// Font set/get functions
RAYGUIDEF void GuiSetFont ( Font font ) ; // Set gui custom font (global state)
RAYGUIDEF Font GuiGetFont ( void ) ; // Get gui custom font (global state)
// Style set/get functions
RAYGUIDEF void GuiSetStyle ( int control , int property , int value ) ; // Set one style property
RAYGUIDEF int GuiGetStyle ( int control , int property ) ; // Get one style property
// Container/separator controls, useful for controls organization
RAYGUIDEF bool GuiWindowBox ( Rectangle bounds , const char * title ) ; // Window Box control, shows a window that can be closed
RAYGUIDEF void GuiGroupBox ( Rectangle bounds , const char * text ) ; // Group Box control with text name
RAYGUIDEF void GuiLine ( Rectangle bounds , const char * text ) ; // Line separator control, could contain text
RAYGUIDEF void GuiPanel ( Rectangle bounds ) ; // Panel control, useful to group controls
RAYGUIDEF Rectangle GuiScrollPanel ( Rectangle bounds , Rectangle content , Vector2 * scroll ) ; // Scroll Panel control
// Basic controls set
RAYGUIDEF void GuiLabel ( Rectangle bounds , const char * text ) ; // Label control, shows text
RAYGUIDEF bool GuiButton ( Rectangle bounds , const char * text ) ; // Button control, returns true when clicked
RAYGUIDEF bool GuiLabelButton ( Rectangle bounds , const char * text ) ; // Label button control, show true when clicked
RAYGUIDEF bool GuiImageButton ( Rectangle bounds , const char * text , Texture2D texture ) ; // Image button control, returns true when clicked
RAYGUIDEF bool GuiImageButtonEx ( Rectangle bounds , const char * text , Texture2D texture , Rectangle texSource ) ; // Image button extended control, returns true when clicked
RAYGUIDEF bool GuiToggle ( Rectangle bounds , const char * text , bool active ) ; // Toggle Button control, returns true when active
RAYGUIDEF int GuiToggleGroup ( Rectangle bounds , const char * text , int active ) ; // Toggle Group control, returns active toggle index
RAYGUIDEF bool GuiCheckBox ( Rectangle bounds , const char * text , bool checked ) ; // Check Box control, returns true when active
RAYGUIDEF int GuiComboBox ( Rectangle bounds , const char * text , int active ) ; // Combo Box control, returns selected item index
RAYGUIDEF bool GuiDropdownBox ( Rectangle bounds , const char * text , int * active , bool editMode ) ; // Dropdown Box control, returns selected item
RAYGUIDEF bool GuiSpinner ( Rectangle bounds , const char * text , int * value , int minValue , int maxValue , bool editMode ) ; // Spinner control, returns selected value
RAYGUIDEF bool GuiValueBox ( Rectangle bounds , const char * text , int * value , int minValue , int maxValue , bool editMode ) ; // Value Box control, updates input text with numbers
RAYGUIDEF bool GuiTextBox ( Rectangle bounds , char * text , int textSize , bool editMode ) ; // Text Box control, updates input text
RAYGUIDEF bool GuiTextBoxMulti ( Rectangle bounds , char * text , int textSize , bool editMode ) ; // Text Box control with multiple lines
RAYGUIDEF float GuiSlider ( Rectangle bounds , const char * textLeft , const char * textRight , float value , float minValue , float maxValue ) ; // Slider control, returns selected value
RAYGUIDEF float GuiSliderBar ( Rectangle bounds , const char * textLeft , const char * textRight , float value , float minValue , float maxValue ) ; // Slider Bar control, returns selected value
RAYGUIDEF float GuiProgressBar ( Rectangle bounds , const char * textLeft , const char * textRight , float value , float minValue , float maxValue ) ; // Progress Bar control, shows current progress value
RAYGUIDEF void GuiStatusBar ( Rectangle bounds , const char * text ) ; // Status Bar control, shows info text
RAYGUIDEF void GuiDummyRec ( Rectangle bounds , const char * text ) ; // Dummy control for placeholders
RAYGUIDEF int GuiScrollBar ( Rectangle bounds , int value , int minValue , int maxValue ) ; // Scroll Bar control
RAYGUIDEF Vector2 GuiGrid ( Rectangle bounds , float spacing , int subdivs ) ; // Grid control
// Advance controls set
RAYGUIDEF int GuiListView ( Rectangle bounds , const char * text , int * scrollIndex , int active ) ; // List View control, returns selected list item index
RAYGUIDEF int GuiListViewEx ( Rectangle bounds , const char * * text , int count , int * focus , int * scrollIndex , int active ) ; // List View with extended parameters
RAYGUIDEF int GuiMessageBox ( Rectangle bounds , const char * title , const char * message , const char * buttons ) ; // Message Box control, displays a message
RAYGUIDEF int GuiTextInputBox ( Rectangle bounds , const char * title , const char * message , const char * buttons , char * text ) ; // Text Input Box control, ask for text
RAYGUIDEF Color GuiColorPicker ( Rectangle bounds , Color color ) ; // Color Picker control (multiple color controls)
RAYGUIDEF Color GuiColorPanel ( Rectangle bounds , Color color ) ; // Color Panel control
RAYGUIDEF float GuiColorBarAlpha ( Rectangle bounds , float alpha ) ; // Color Bar Alpha control
RAYGUIDEF float GuiColorBarHue ( Rectangle bounds , float value ) ; // Color Bar Hue control
// Styles loading functions
RAYGUIDEF void GuiLoadStyle ( const char * fileName ) ; // Load style file (.rgs)
RAYGUIDEF void GuiLoadStyleDefault ( void ) ; // Load style default over global style
/*
typedef GuiStyle ( unsigned int * )
RAYGUIDEF GuiStyle LoadGuiStyle ( const char * fileName ) ; // Load style from file (.rgs)
RAYGUIDEF void UnloadGuiStyle ( GuiStyle style ) ; // Unload style
*/
RAYGUIDEF const char * GuiIconText ( int iconId , const char * text ) ; // Get text with icon id prepended (if supported)
2021-05-14 05:59:33 +00:00
# if defined(RAYGUI_SUPPORT_ICONS)
2021-06-01 13:20:04 +00:00
// Gui icons functionality
RAYGUIDEF void GuiDrawIcon ( int iconId , Vector2 position , int pixelSize , Color color ) ;
RAYGUIDEF unsigned int * GuiGetIcons ( void ) ; // Get full icons data pointer
RAYGUIDEF unsigned int * GuiGetIconData ( int iconId ) ; // Get icon bit data
RAYGUIDEF void GuiSetIconData ( int iconId , unsigned int * data ) ; // Set icon bit data
RAYGUIDEF void GuiSetIconPixel ( int iconId , int x , int y ) ; // Set icon pixel value
RAYGUIDEF void GuiClearIconPixel ( int iconId , int x , int y ) ; // Clear icon pixel value
RAYGUIDEF bool GuiCheckIconPixel ( int iconId , int x , int y ) ; // Check icon pixel value
2021-05-14 05:59:33 +00:00
# endif
/***********************************************************************************
*
* RAYGUI IMPLEMENTATION
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# if defined(RAYGUI_IMPLEMENTATION)
# if defined(RAYGUI_SUPPORT_ICONS)
2021-06-01 13:20:04 +00:00
# define RICONS_IMPLEMENTATION
# include "ricons.h" // Required for: raygui icons data
2021-05-14 05:59:33 +00:00
# endif
# include <stdio.h> // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), vsprintf()
# include <string.h> // Required for: strlen() on GuiTextBox()
# include <math.h> // Required for: roundf() on GuiColorPicker()
# if defined(RAYGUI_STANDALONE)
2021-06-01 13:20:04 +00:00
# include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end()
2021-05-14 05:59:33 +00:00
# endif
# ifdef __cplusplus
2021-06-01 13:20:04 +00:00
# define RAYGUI_CLITERAL(name) name
2021-05-14 05:59:33 +00:00
# else
2021-06-01 13:20:04 +00:00
# define RAYGUI_CLITERAL(name) (name)
2021-05-14 05:59:33 +00:00
# endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// Gui control property style color element
typedef enum { BORDER = 0 , BASE , TEXT , OTHER } GuiPropertyElement ;
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
static GuiControlState guiState = GUI_STATE_NORMAL ;
static Font guiFont = { 0 } ; // Gui current font (WARNING: highly coupled to raylib)
static bool guiLocked = false ; // Gui lock state (no inputs processed)
static float guiAlpha = 1.0f ; // Gui element transpacency on drawing
// Global gui style array (allocated on data segment by default)
// NOTE: In raygui we manage a single int array with all the possible style properties.
// When a new style is loaded, it loads over the global style... but default gui style
// could always be recovered with GuiLoadStyleDefault()
static unsigned int guiStyle [ NUM_CONTROLS * ( NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED ) ] = { 0 } ;
static bool guiStyleLoaded = false ; // Style loaded flag for lazy style initialization
//----------------------------------------------------------------------------------
// Standalone Mode Functions Declaration
//
// NOTE: raygui depend on some raylib input and drawing functions
// To use raygui as standalone library, below functions must be defined by the user
//----------------------------------------------------------------------------------
# if defined(RAYGUI_STANDALONE)
# define KEY_RIGHT 262
# define KEY_LEFT 263
# define KEY_DOWN 264
# define KEY_UP 265
# define KEY_BACKSPACE 259
# define KEY_ENTER 257
# define MOUSE_LEFT_BUTTON 0
// Input required functions
//-------------------------------------------------------------------------------
static Vector2 GetMousePosition ( void ) ;
static int GetMouseWheelMove ( void ) ;
static bool IsMouseButtonDown ( int button ) ;
static bool IsMouseButtonPressed ( int button ) ;
static bool IsMouseButtonReleased ( int button ) ;
static bool IsKeyDown ( int key ) ;
static bool IsKeyPressed ( int key ) ;
static int GetCharPressed ( void ) ; // -- GuiTextBox(), GuiTextBoxMulti(), GuiValueBox()
//-------------------------------------------------------------------------------
// Drawing required functions
//-------------------------------------------------------------------------------
static void DrawRectangle ( int x , int y , int width , int height , Color color ) ; // -- GuiDrawRectangle(), GuiDrawIcon()
static void DrawRectangleGradientEx ( Rectangle rec , Color col1 , Color col2 , Color col3 , Color col4 ) ; // -- GuiColorPicker()
static void DrawTriangle ( Vector2 v1 , Vector2 v2 , Vector2 v3 , Color color ) ; // -- GuiDropdownBox(), GuiScrollBar()
static void DrawTextureRec ( Texture2D texture , Rectangle sourceRec , Vector2 position , Color tint ) ; // -- GuiImageButtonEx()
static void DrawTextRec ( Font font , const char * text , Rectangle rec , float fontSize , float spacing , bool wordWrap , Color tint ) ; // -- GuiTextBoxMulti()
//-------------------------------------------------------------------------------
// Text required functions
//-------------------------------------------------------------------------------
static Font GetFontDefault ( void ) ; // -- GuiLoadStyleDefault()
static Vector2 MeasureTextEx ( Font font , const char * text , float fontSize , float spacing ) ; // -- GetTextWidth(), GuiTextBoxMulti()
static void DrawTextEx ( Font font , const char * text , Vector2 position , float fontSize , float spacing , Color tint ) ; // -- GuiDrawText()
static Font LoadFontEx ( const char * fileName , int fontSize , int * fontChars , int charsCount ) ; // -- GuiLoadStyle()
static char * LoadFileText ( const char * fileName ) ; // -- GuiLoadStyle()
static const char * GetDirectoryPath ( const char * filePath ) ; // -- GuiLoadStyle()
//-------------------------------------------------------------------------------
// raylib functions already implemented in raygui
//-------------------------------------------------------------------------------
static Color GetColor ( int hexValue ) ; // Returns a Color struct from hexadecimal value
static int ColorToInt ( Color color ) ; // Returns hexadecimal value for a Color
static Color Fade ( Color color , float alpha ) ; // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
static bool CheckCollisionPointRec ( Vector2 point , Rectangle rec ) ; // Check if point is inside rectangle
static const char * TextFormat ( const char * text , . . . ) ; // Formatting of text with variables to 'embed'
static const char * * 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 void DrawRectangleGradientV ( int posX , int posY , int width , int height , Color color1 , Color color2 ) ; // Draw rectangle vertical gradient
//-------------------------------------------------------------------------------
# endif // RAYGUI_STANDALONE
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
static int GetTextWidth ( const char * text ) ; // Gui get text width using default font
static Rectangle GetTextBounds ( int control , Rectangle bounds ) ; // Get text bounds considering control bounds
static const char * GetTextIcon ( const char * text , int * iconId ) ; // Get text icon if provided and move text cursor
static void GuiDrawText ( const char * text , Rectangle bounds , int alignment , Color tint ) ; // Gui draw text using default font
static void GuiDrawRectangle ( Rectangle rec , int borderWidth , Color borderColor , Color color ) ; // Gui draw rectangle using default raygui style
static const char * * GuiTextSplit ( const char * text , int * count , int * textRow ) ; // Split controls text into multiple strings
static Vector3 ConvertHSVtoRGB ( Vector3 hsv ) ; // Convert color data from HSV to RGB
static Vector3 ConvertRGBtoHSV ( Vector3 rgb ) ; // Convert color data from RGB to HSV
//----------------------------------------------------------------------------------
// Gui Setup Functions Definition
//----------------------------------------------------------------------------------
// Enable gui global state
void GuiEnable ( void ) { guiState = GUI_STATE_NORMAL ; }
// Disable gui global state
void GuiDisable ( void ) { guiState = GUI_STATE_DISABLED ; }
// Lock gui global state
void GuiLock ( void ) { guiLocked = true ; }
// Unlock gui global state
void GuiUnlock ( void ) { guiLocked = false ; }
// Set gui controls alpha global state
void GuiFade ( float alpha )
{
if ( alpha < 0.0f ) alpha = 0.0f ;
else if ( alpha > 1.0f ) alpha = 1.0f ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
guiAlpha = alpha ;
}
// Set gui state (global state)
void GuiSetState ( int state ) { guiState = ( GuiControlState ) state ; }
// Get gui state (global state)
int GuiGetState ( void ) { return guiState ; }
// Set custom gui font
// NOTE: Font loading/unloading is external to raygui
void GuiSetFont ( Font font )
{
if ( font . texture . id > 0 )
{
// NOTE: If we try to setup a font but default style has not been
// lazily loaded before, it will be overwritten, so we need to force
// default style loading first
if ( ! guiStyleLoaded ) GuiLoadStyleDefault ( ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
guiFont = font ;
GuiSetStyle ( DEFAULT , TEXT_SIZE , font . baseSize ) ;
}
}
// Get custom gui font
Font GuiGetFont ( void )
{
return guiFont ;
}
// Set control style property value
void GuiSetStyle ( int control , int property , int value )
{
if ( ! guiStyleLoaded ) GuiLoadStyleDefault ( ) ;
guiStyle [ control * ( NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED ) + property ] = value ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Default properties are propagated to all controls
if ( ( control = = 0 ) & & ( property < NUM_PROPS_DEFAULT ) )
{
for ( int i = 1 ; i < NUM_CONTROLS ; i + + ) guiStyle [ i * ( NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED ) + property ] = value ;
}
}
// Get control style property value
int GuiGetStyle ( int control , int property )
{
if ( ! guiStyleLoaded ) GuiLoadStyleDefault ( ) ;
return guiStyle [ control * ( NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED ) + property ] ;
}
//----------------------------------------------------------------------------------
// Gui Controls Functions Definition
//----------------------------------------------------------------------------------
// Window Box control
bool GuiWindowBox ( Rectangle bounds , const char * title )
{
// NOTE: This define is also used by GuiMessageBox() and GuiTextInputBox()
2021-06-01 13:20:04 +00:00
# define WINDOW_STATUSBAR_HEIGHT 22
2021-05-14 05:59:33 +00:00
//GuiControlState state = guiState;
bool clicked = false ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
int statusBarHeight = WINDOW_STATUSBAR_HEIGHT + 2 * GuiGetStyle ( STATUSBAR , BORDER_WIDTH ) ;
statusBarHeight + = ( statusBarHeight % 2 ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Rectangle statusBar = { bounds . x , bounds . y , bounds . width , ( float ) statusBarHeight } ;
if ( bounds . height < statusBarHeight * 2.0f ) bounds . height = statusBarHeight * 2.0f ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Rectangle windowPanel = { bounds . x , bounds . y + ( float ) statusBarHeight - 1 , bounds . width , bounds . height - ( float ) statusBarHeight } ;
Rectangle closeButtonRec = { statusBar . x + statusBar . width - GuiGetStyle ( STATUSBAR , BORDER_WIDTH ) - 20 ,
2021-06-01 13:20:04 +00:00
statusBar . y + statusBarHeight / 2.0f - 18.0f / 2.0f , 18 , 18 } ;
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
// NOTE: Logic is directly managed by button
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
GuiStatusBar ( statusBar , title ) ; // Draw window header as status bar
GuiPanel ( windowPanel ) ; // Draw window base
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw window close button
int tempBorderWidth = GuiGetStyle ( BUTTON , BORDER_WIDTH ) ;
int tempTextAlignment = GuiGetStyle ( BUTTON , TEXT_ALIGNMENT ) ;
GuiSetStyle ( BUTTON , BORDER_WIDTH , 1 ) ;
GuiSetStyle ( BUTTON , TEXT_ALIGNMENT , GUI_TEXT_ALIGN_CENTER ) ;
# if defined(RAYGUI_SUPPORT_ICONS)
clicked = GuiButton ( closeButtonRec , GuiIconText ( RICON_CROSS_SMALL , NULL ) ) ;
# else
clicked = GuiButton ( closeButtonRec , " x " ) ;
# endif
GuiSetStyle ( BUTTON , BORDER_WIDTH , tempBorderWidth ) ;
GuiSetStyle ( BUTTON , TEXT_ALIGNMENT , tempTextAlignment ) ;
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return clicked ;
}
// Group Box control with text name
void GuiGroupBox ( Rectangle bounds , const char * text )
{
2021-06-01 13:20:04 +00:00
# define GROUPBOX_LINE_THICK 1
# define GROUPBOX_TEXT_PADDING 10
2021-05-14 05:59:33 +00:00
GuiControlState state = guiState ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
GuiDrawRectangle ( RAYGUI_CLITERAL ( Rectangle ) { bounds . x , bounds . y , GROUPBOX_LINE_THICK , bounds . height } , 0 , BLANK , Fade ( GetColor ( GuiGetStyle ( DEFAULT , ( state = = GUI_STATE_DISABLED ) ? BORDER_COLOR_DISABLED : LINE_COLOR ) ) , guiAlpha ) ) ;
GuiDrawRectangle ( RAYGUI_CLITERAL ( Rectangle ) { bounds . x , bounds . y + bounds . height - 1 , bounds . width , GROUPBOX_LINE_THICK } , 0 , BLANK , Fade ( GetColor ( GuiGetStyle ( DEFAULT , ( state = = GUI_STATE_DISABLED ) ? BORDER_COLOR_DISABLED : LINE_COLOR ) ) , guiAlpha ) ) ;
GuiDrawRectangle ( RAYGUI_CLITERAL ( Rectangle ) { bounds . x + bounds . width - 1 , bounds . y , GROUPBOX_LINE_THICK , bounds . height } , 0 , BLANK , Fade ( GetColor ( GuiGetStyle ( DEFAULT , ( state = = GUI_STATE_DISABLED ) ? BORDER_COLOR_DISABLED : LINE_COLOR ) ) , guiAlpha ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiLine ( RAYGUI_CLITERAL ( Rectangle ) { bounds . x , bounds . y , bounds . width , 1 } , text ) ;
//--------------------------------------------------------------------
}
// Line control
void GuiLine ( Rectangle bounds , const char * text )
{
2021-06-01 13:20:04 +00:00
# define LINE_TEXT_PADDING 10
2021-05-14 05:59:33 +00:00
GuiControlState state = guiState ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Color color = Fade ( GetColor ( GuiGetStyle ( DEFAULT , ( state = = GUI_STATE_DISABLED ) ? BORDER_COLOR_DISABLED : LINE_COLOR ) ) , guiAlpha ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
if ( text = = NULL ) GuiDrawRectangle ( RAYGUI_CLITERAL ( Rectangle ) { bounds . x , bounds . y + bounds . height / 2 , bounds . width , 1 } , 0 , BLANK , color ) ;
else
{
Rectangle textBounds = { 0 } ;
textBounds . width = ( float ) GetTextWidth ( text ) ; // TODO: Consider text icon
textBounds . height = ( float ) GuiGetStyle ( DEFAULT , TEXT_SIZE ) ;
textBounds . x = bounds . x + LINE_TEXT_PADDING ;
textBounds . y = bounds . y - ( float ) GuiGetStyle ( DEFAULT , TEXT_SIZE ) / 2 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw line with embedded text label: "--- text --------------"
GuiDrawRectangle ( RAYGUI_CLITERAL ( Rectangle ) { bounds . x , bounds . y , LINE_TEXT_PADDING - 2 , 1 } , 0 , BLANK , color ) ;
GuiLabel ( textBounds , text ) ;
GuiDrawRectangle ( RAYGUI_CLITERAL ( Rectangle ) { bounds . x + LINE_TEXT_PADDING + textBounds . width + 4 , bounds . y , bounds . width - textBounds . width - LINE_TEXT_PADDING - 4 , 1 } , 0 , BLANK , color ) ;
}
//--------------------------------------------------------------------
}
// Panel control
void GuiPanel ( Rectangle bounds )
{
2021-06-01 13:20:04 +00:00
# define PANEL_BORDER_WIDTH 1
2021-05-14 05:59:33 +00:00
GuiControlState state = guiState ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
GuiDrawRectangle ( bounds , PANEL_BORDER_WIDTH , Fade ( GetColor ( GuiGetStyle ( DEFAULT , ( state = = GUI_STATE_DISABLED ) ? BORDER_COLOR_DISABLED : LINE_COLOR ) ) , guiAlpha ) ,
Fade ( GetColor ( GuiGetStyle ( DEFAULT , ( state = = GUI_STATE_DISABLED ) ? BASE_COLOR_DISABLED : BACKGROUND_COLOR ) ) , guiAlpha ) ) ;
//--------------------------------------------------------------------
}
// Scroll Panel control
Rectangle GuiScrollPanel ( Rectangle bounds , Rectangle content , Vector2 * scroll )
{
GuiControlState state = guiState ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Vector2 scrollPos = { 0.0f , 0.0f } ;
if ( scroll ! = NULL ) scrollPos = * scroll ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
bool hasHorizontalScrollBar = ( content . width > bounds . width - 2 * GuiGetStyle ( DEFAULT , BORDER_WIDTH ) ) ? true : false ;
bool hasVerticalScrollBar = ( content . height > bounds . height - 2 * GuiGetStyle ( DEFAULT , BORDER_WIDTH ) ) ? true : false ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Recheck to account for the other scrollbar being visible
if ( ! hasHorizontalScrollBar ) hasHorizontalScrollBar = ( hasVerticalScrollBar & & ( content . width > ( bounds . width - 2 * GuiGetStyle ( DEFAULT , BORDER_WIDTH ) - GuiGetStyle ( LISTVIEW , SCROLLBAR_WIDTH ) ) ) ) ? true : false ;
if ( ! hasVerticalScrollBar ) hasVerticalScrollBar = ( hasHorizontalScrollBar & & ( content . height > ( bounds . height - 2 * GuiGetStyle ( DEFAULT , BORDER_WIDTH ) - GuiGetStyle ( LISTVIEW , SCROLLBAR_WIDTH ) ) ) ) ? true : false ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
const int horizontalScrollBarWidth = hasHorizontalScrollBar ? GuiGetStyle ( LISTVIEW , SCROLLBAR_WIDTH ) : 0 ;
const int verticalScrollBarWidth = hasVerticalScrollBar ? GuiGetStyle ( LISTVIEW , SCROLLBAR_WIDTH ) : 0 ;
const 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 } ;
const 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 ) } ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Calculate view area (area without the scrollbars)
Rectangle view = ( GuiGetStyle ( LISTVIEW , SCROLLBAR_SIDE ) = = SCROLLBAR_LEFT_SIDE ) ?
2021-06-01 13:20:04 +00:00
RAYGUI_CLITERAL ( Rectangle ) { bounds . x + verticalScrollBarWidth + GuiGetStyle ( DEFAULT , BORDER_WIDTH ) , bounds . y + GuiGetStyle ( DEFAULT , BORDER_WIDTH ) , bounds . width - 2 * GuiGetStyle ( DEFAULT , BORDER_WIDTH ) - verticalScrollBarWidth , bounds . height - 2 * GuiGetStyle ( DEFAULT , BORDER_WIDTH ) - horizontalScrollBarWidth } :
RAYGUI_CLITERAL ( Rectangle ) { bounds . x + GuiGetStyle ( DEFAULT , BORDER_WIDTH ) , bounds . y + GuiGetStyle ( DEFAULT , BORDER_WIDTH ) , bounds . width - 2 * GuiGetStyle ( DEFAULT , BORDER_WIDTH ) - verticalScrollBarWidth , bounds . height - 2 * GuiGetStyle ( DEFAULT , BORDER_WIDTH ) - horizontalScrollBarWidth } ;
2021-05-14 05:59:33 +00:00
// Clip view area to the actual content size
if ( view . width > content . width ) view . width = content . width ;
if ( view . height > content . height ) view . height = content . height ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// TODO: Review!
const float horizontalMin = hasHorizontalScrollBar ? ( ( GuiGetStyle ( LISTVIEW , SCROLLBAR_SIDE ) = = SCROLLBAR_LEFT_SIDE ) ? ( float ) - verticalScrollBarWidth : 0 ) - ( float ) GuiGetStyle ( DEFAULT , BORDER_WIDTH ) : ( ( ( float ) GuiGetStyle ( LISTVIEW , SCROLLBAR_SIDE ) = = SCROLLBAR_LEFT_SIDE ) ? ( float ) - verticalScrollBarWidth : 0 ) - ( float ) GuiGetStyle ( DEFAULT , BORDER_WIDTH ) ;
const float horizontalMax = hasHorizontalScrollBar ? content . width - bounds . width + ( float ) verticalScrollBarWidth + GuiGetStyle ( DEFAULT , BORDER_WIDTH ) - ( ( ( float ) GuiGetStyle ( LISTVIEW , SCROLLBAR_SIDE ) = = SCROLLBAR_LEFT_SIDE ) ? ( float ) verticalScrollBarWidth : 0 ) : ( float ) - GuiGetStyle ( DEFAULT , BORDER_WIDTH ) ;
const float verticalMin = hasVerticalScrollBar ? ( float ) - GuiGetStyle ( DEFAULT , BORDER_WIDTH ) : ( float ) - GuiGetStyle ( DEFAULT , BORDER_WIDTH ) ;
const float verticalMax = hasVerticalScrollBar ? content . height - bounds . height + ( float ) horizontalScrollBarWidth + ( float ) GuiGetStyle ( DEFAULT , BORDER_WIDTH ) : ( float ) - GuiGetStyle ( DEFAULT , BORDER_WIDTH ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
if ( ( state ! = GUI_STATE_DISABLED ) & & ! guiLocked )
{
Vector2 mousePoint = GetMousePosition ( ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Check button state
if ( CheckCollisionPointRec ( mousePoint , bounds ) )
{
if ( IsMouseButtonDown ( MOUSE_LEFT_BUTTON ) ) state = GUI_STATE_PRESSED ;
else state = GUI_STATE_FOCUSED ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( hasHorizontalScrollBar )
{
if ( IsKeyDown ( KEY_RIGHT ) ) scrollPos . x - = GuiGetStyle ( SCROLLBAR , SCROLL_SPEED ) ;
if ( IsKeyDown ( KEY_LEFT ) ) scrollPos . x + = GuiGetStyle ( SCROLLBAR , SCROLL_SPEED ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( hasVerticalScrollBar )
{
if ( IsKeyDown ( KEY_DOWN ) ) scrollPos . y - = GuiGetStyle ( SCROLLBAR , SCROLL_SPEED ) ;
if ( IsKeyDown ( KEY_UP ) ) scrollPos . y + = GuiGetStyle ( SCROLLBAR , SCROLL_SPEED ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
float wheelMove = GetMouseWheelMove ( ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Horizontal scroll (Shift + Mouse wheel)
if ( hasHorizontalScrollBar & & ( IsKeyDown ( KEY_LEFT_SHIFT ) | | IsKeyDown ( KEY_RIGHT_SHIFT ) ) ) scrollPos . x + = wheelMove * 20 ;
else scrollPos . y + = wheelMove * 20 ; // Vertical scroll
}
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Normalize scroll values
if ( scrollPos . x > - horizontalMin ) scrollPos . x = - horizontalMin ;
if ( scrollPos . x < - horizontalMax ) scrollPos . x = - horizontalMax ;
if ( scrollPos . y > - verticalMin ) scrollPos . y = - verticalMin ;
if ( scrollPos . y < - verticalMax ) scrollPos . y = - verticalMax ;
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
GuiDrawRectangle ( bounds , 0 , BLANK , GetColor ( GuiGetStyle ( DEFAULT , BACKGROUND_COLOR ) ) ) ; // Draw background
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Save size of the scrollbar slider
const int slider = GuiGetStyle ( SCROLLBAR , SCROLL_SLIDER_SIZE ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw horizontal scrollbar if visible
if ( hasHorizontalScrollBar )
{
// Change scrollbar slider size to show the diff in size between the content width and the widget width
GuiSetStyle ( SCROLLBAR , SCROLL_SLIDER_SIZE , ( int ) ( ( ( bounds . width - 2 * GuiGetStyle ( DEFAULT , BORDER_WIDTH ) - verticalScrollBarWidth ) / ( int ) content . width ) * ( ( int ) bounds . width - 2 * GuiGetStyle ( DEFAULT , BORDER_WIDTH ) - verticalScrollBarWidth ) ) ) ;
scrollPos . x = ( float ) - GuiScrollBar ( horizontalScrollBar , ( int ) - scrollPos . x , ( int ) horizontalMin , ( int ) horizontalMax ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw vertical scrollbar if visible
if ( hasVerticalScrollBar )
{
// Change scrollbar slider size to show the diff in size between the content height and the widget height
GuiSetStyle ( SCROLLBAR , SCROLL_SLIDER_SIZE , ( int ) ( ( ( bounds . height - 2 * GuiGetStyle ( DEFAULT , BORDER_WIDTH ) - horizontalScrollBarWidth ) / ( int ) content . height ) * ( ( int ) bounds . height - 2 * GuiGetStyle ( DEFAULT , BORDER_WIDTH ) - horizontalScrollBarWidth ) ) ) ;
scrollPos . y = ( float ) - GuiScrollBar ( verticalScrollBar , ( int ) - scrollPos . y , ( int ) verticalMin , ( int ) verticalMax ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw detail corner rectangle if both scroll bars are visible
if ( hasHorizontalScrollBar & & hasVerticalScrollBar )
{
Rectangle corner = { ( GuiGetStyle ( LISTVIEW , SCROLLBAR_SIDE ) = = SCROLLBAR_LEFT_SIDE ) ? ( bounds . x + GuiGetStyle ( DEFAULT , BORDER_WIDTH ) + 2 ) : ( horizontalScrollBar . x + horizontalScrollBar . width + 2 ) , verticalScrollBar . y + verticalScrollBar . height + 2 , ( float ) horizontalScrollBarWidth - 4 , ( float ) verticalScrollBarWidth - 4 } ;
GuiDrawRectangle ( corner , 0 , BLANK , Fade ( GetColor ( GuiGetStyle ( LISTVIEW , TEXT + ( state * 3 ) ) ) , guiAlpha ) ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw scrollbar lines depending on current state
GuiDrawRectangle ( bounds , GuiGetStyle ( DEFAULT , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( LISTVIEW , BORDER + ( state * 3 ) ) ) , guiAlpha ) , BLANK ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Set scrollbar slider size back to the way it was before
GuiSetStyle ( SCROLLBAR , SCROLL_SLIDER_SIZE , slider ) ;
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( scroll ! = NULL ) * scroll = scrollPos ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return view ;
}
// Label control
void GuiLabel ( Rectangle bounds , const char * text )
{
GuiControlState state = guiState ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
// ...
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
GuiDrawText ( text , GetTextBounds ( LABEL , bounds ) , GuiGetStyle ( LABEL , TEXT_ALIGNMENT ) , Fade ( GetColor ( GuiGetStyle ( LABEL , ( state = = GUI_STATE_DISABLED ) ? TEXT_COLOR_DISABLED : TEXT_COLOR_NORMAL ) ) , guiAlpha ) ) ;
//--------------------------------------------------------------------
}
// Button control, returns true when clicked
bool GuiButton ( Rectangle bounds , const char * text )
{
GuiControlState state = guiState ;
bool pressed = false ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
if ( ( state ! = GUI_STATE_DISABLED ) & & ! guiLocked )
{
Vector2 mousePoint = GetMousePosition ( ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Check button state
if ( CheckCollisionPointRec ( mousePoint , bounds ) )
{
if ( IsMouseButtonDown ( MOUSE_LEFT_BUTTON ) ) state = GUI_STATE_PRESSED ;
else state = GUI_STATE_FOCUSED ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( IsMouseButtonReleased ( MOUSE_LEFT_BUTTON ) ) pressed = true ;
}
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
GuiDrawRectangle ( bounds , GuiGetStyle ( BUTTON , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( BUTTON , BORDER + ( state * 3 ) ) ) , guiAlpha ) , Fade ( GetColor ( GuiGetStyle ( BUTTON , BASE + ( state * 3 ) ) ) , guiAlpha ) ) ;
GuiDrawText ( text , GetTextBounds ( BUTTON , bounds ) , GuiGetStyle ( BUTTON , TEXT_ALIGNMENT ) , Fade ( GetColor ( GuiGetStyle ( BUTTON , TEXT + ( state * 3 ) ) ) , guiAlpha ) ) ;
//------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return pressed ;
}
// Label button control
bool GuiLabelButton ( Rectangle bounds , const char * text )
{
GuiControlState state = guiState ;
bool pressed = false ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// NOTE: We force bounds.width to be all text
float textWidth = MeasureTextEx ( guiFont , text , ( float ) GuiGetStyle ( DEFAULT , TEXT_SIZE ) , ( float ) GuiGetStyle ( DEFAULT , TEXT_SPACING ) ) . x ;
if ( bounds . width < textWidth ) bounds . width = textWidth ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
if ( ( state ! = GUI_STATE_DISABLED ) & & ! guiLocked )
{
Vector2 mousePoint = GetMousePosition ( ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Check checkbox state
if ( CheckCollisionPointRec ( mousePoint , bounds ) )
{
if ( IsMouseButtonDown ( MOUSE_LEFT_BUTTON ) ) state = GUI_STATE_PRESSED ;
else state = GUI_STATE_FOCUSED ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( IsMouseButtonReleased ( MOUSE_LEFT_BUTTON ) ) pressed = true ;
}
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
GuiDrawText ( text , GetTextBounds ( LABEL , bounds ) , GuiGetStyle ( LABEL , TEXT_ALIGNMENT ) , Fade ( GetColor ( GuiGetStyle ( LABEL , TEXT + ( state * 3 ) ) ) , guiAlpha ) ) ;
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return pressed ;
}
// Image button control, returns true when clicked
bool GuiImageButton ( Rectangle bounds , const char * text , Texture2D texture )
{
return GuiImageButtonEx ( bounds , text , texture , RAYGUI_CLITERAL ( Rectangle ) { 0 , 0 , ( float ) texture . width , ( float ) texture . height } ) ;
}
// Image button control, returns true when clicked
bool GuiImageButtonEx ( Rectangle bounds , const char * text , Texture2D texture , Rectangle texSource )
{
GuiControlState state = guiState ;
bool clicked = false ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
if ( ( state ! = GUI_STATE_DISABLED ) & & ! guiLocked )
{
Vector2 mousePoint = GetMousePosition ( ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Check button state
if ( CheckCollisionPointRec ( mousePoint , bounds ) )
{
if ( IsMouseButtonDown ( MOUSE_LEFT_BUTTON ) ) state = GUI_STATE_PRESSED ;
else if ( IsMouseButtonReleased ( MOUSE_LEFT_BUTTON ) ) clicked = true ;
else state = GUI_STATE_FOCUSED ;
}
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
GuiDrawRectangle ( bounds , GuiGetStyle ( BUTTON , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( BUTTON , BORDER + ( state * 3 ) ) ) , guiAlpha ) , Fade ( GetColor ( GuiGetStyle ( BUTTON , BASE + ( state * 3 ) ) ) , guiAlpha ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( text ! = NULL ) GuiDrawText ( text , GetTextBounds ( BUTTON , bounds ) , GuiGetStyle ( BUTTON , TEXT_ALIGNMENT ) , Fade ( GetColor ( GuiGetStyle ( BUTTON , TEXT + ( state * 3 ) ) ) , guiAlpha ) ) ;
if ( texture . id > 0 ) DrawTextureRec ( texture , texSource , RAYGUI_CLITERAL ( Vector2 ) { bounds . x + bounds . width / 2 - texSource . width / 2 , bounds . y + bounds . height / 2 - texSource . height / 2 } , Fade ( GetColor ( GuiGetStyle ( BUTTON , TEXT + ( state * 3 ) ) ) , guiAlpha ) ) ;
//------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return clicked ;
}
// Toggle Button control, returns true when active
bool GuiToggle ( Rectangle bounds , const char * text , bool active )
{
GuiControlState state = guiState ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
if ( ( state ! = GUI_STATE_DISABLED ) & & ! guiLocked )
{
Vector2 mousePoint = GetMousePosition ( ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Check toggle button state
if ( CheckCollisionPointRec ( mousePoint , bounds ) )
{
if ( IsMouseButtonDown ( MOUSE_LEFT_BUTTON ) ) state = GUI_STATE_PRESSED ;
else if ( IsMouseButtonReleased ( MOUSE_LEFT_BUTTON ) )
{
state = GUI_STATE_NORMAL ;
active = ! active ;
}
else state = GUI_STATE_FOCUSED ;
}
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
if ( state = = GUI_STATE_NORMAL )
{
GuiDrawRectangle ( bounds , GuiGetStyle ( TOGGLE , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( TOGGLE , ( active ? BORDER_COLOR_PRESSED : ( BORDER + state * 3 ) ) ) ) , guiAlpha ) , Fade ( GetColor ( GuiGetStyle ( TOGGLE , ( active ? BASE_COLOR_PRESSED : ( BASE + state * 3 ) ) ) ) , guiAlpha ) ) ;
GuiDrawText ( text , GetTextBounds ( TOGGLE , bounds ) , GuiGetStyle ( TOGGLE , TEXT_ALIGNMENT ) , Fade ( GetColor ( GuiGetStyle ( TOGGLE , ( active ? TEXT_COLOR_PRESSED : ( TEXT + state * 3 ) ) ) ) , guiAlpha ) ) ;
}
else
{
GuiDrawRectangle ( bounds , GuiGetStyle ( TOGGLE , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( TOGGLE , BORDER + state * 3 ) ) , guiAlpha ) , Fade ( GetColor ( GuiGetStyle ( TOGGLE , BASE + state * 3 ) ) , guiAlpha ) ) ;
GuiDrawText ( text , GetTextBounds ( TOGGLE , bounds ) , GuiGetStyle ( TOGGLE , TEXT_ALIGNMENT ) , Fade ( GetColor ( GuiGetStyle ( TOGGLE , TEXT + state * 3 ) ) , guiAlpha ) ) ;
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return active ;
}
// Toggle Group control, returns toggled button index
int GuiToggleGroup ( Rectangle bounds , const char * text , int active )
{
2021-06-01 13:20:04 +00:00
# if !defined(TOGGLEGROUP_MAX_ELEMENTS)
# define TOGGLEGROUP_MAX_ELEMENTS 32
# endif
2021-05-14 05:59:33 +00:00
float initBoundsX = bounds . x ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Get substrings items from text (items pointers)
int rows [ TOGGLEGROUP_MAX_ELEMENTS ] = { 0 } ;
int itemsCount = 0 ;
const char * * items = GuiTextSplit ( text , & itemsCount , rows ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
int prevRow = rows [ 0 ] ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
for ( int i = 0 ; i < itemsCount ; i + + )
{
if ( prevRow ! = rows [ i ] )
{
bounds . x = initBoundsX ;
bounds . y + = ( bounds . height + GuiGetStyle ( TOGGLE , GROUP_PADDING ) ) ;
prevRow = rows [ i ] ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( i = = active ) GuiToggle ( bounds , items [ i ] , true ) ;
else if ( GuiToggle ( bounds , items [ i ] , false ) = = true ) active = i ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
bounds . x + = ( bounds . width + GuiGetStyle ( TOGGLE , GROUP_PADDING ) ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return active ;
}
// Check Box control, returns true when active
bool GuiCheckBox ( Rectangle bounds , const char * text , bool checked )
{
GuiControlState state = guiState ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Rectangle textBounds = { 0 } ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( text ! = NULL )
{
textBounds . width = ( float ) GetTextWidth ( text ) ;
textBounds . height = ( float ) GuiGetStyle ( DEFAULT , TEXT_SIZE ) ;
textBounds . x = bounds . x + bounds . width + GuiGetStyle ( CHECKBOX , TEXT_PADDING ) ;
textBounds . y = bounds . y + bounds . height / 2 - GuiGetStyle ( DEFAULT , TEXT_SIZE ) / 2 ;
if ( GuiGetStyle ( CHECKBOX , TEXT_ALIGNMENT ) = = GUI_TEXT_ALIGN_LEFT ) textBounds . x = bounds . x - textBounds . width - GuiGetStyle ( CHECKBOX , TEXT_PADDING ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
if ( ( state ! = GUI_STATE_DISABLED ) & & ! guiLocked )
{
Vector2 mousePoint = GetMousePosition ( ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Rectangle totalBounds = {
( GuiGetStyle ( CHECKBOX , TEXT_ALIGNMENT ) = = GUI_TEXT_ALIGN_LEFT ) ? textBounds . x : bounds . x ,
bounds . y ,
bounds . width + textBounds . width + GuiGetStyle ( CHECKBOX , TEXT_PADDING ) ,
bounds . height ,
} ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Check checkbox state
if ( CheckCollisionPointRec ( mousePoint , totalBounds ) )
{
if ( IsMouseButtonDown ( MOUSE_LEFT_BUTTON ) ) state = GUI_STATE_PRESSED ;
else state = GUI_STATE_FOCUSED ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( IsMouseButtonReleased ( MOUSE_LEFT_BUTTON ) ) checked = ! checked ;
}
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
GuiDrawRectangle ( bounds , GuiGetStyle ( CHECKBOX , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( CHECKBOX , BORDER + ( state * 3 ) ) ) , guiAlpha ) , BLANK ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( checked )
{
Rectangle check = { bounds . x + GuiGetStyle ( CHECKBOX , BORDER_WIDTH ) + GuiGetStyle ( CHECKBOX , CHECK_PADDING ) ,
2021-06-01 13:20:04 +00:00
bounds . y + GuiGetStyle ( CHECKBOX , BORDER_WIDTH ) + GuiGetStyle ( CHECKBOX , CHECK_PADDING ) ,
bounds . width - 2 * ( GuiGetStyle ( CHECKBOX , BORDER_WIDTH ) + GuiGetStyle ( CHECKBOX , CHECK_PADDING ) ) ,
bounds . height - 2 * ( GuiGetStyle ( CHECKBOX , BORDER_WIDTH ) + GuiGetStyle ( CHECKBOX , CHECK_PADDING ) ) } ;
2021-05-14 05:59:33 +00:00
GuiDrawRectangle ( check , 0 , BLANK , Fade ( GetColor ( GuiGetStyle ( CHECKBOX , TEXT + state * 3 ) ) , guiAlpha ) ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( text ! = NULL ) GuiDrawText ( text , textBounds , ( GuiGetStyle ( CHECKBOX , TEXT_ALIGNMENT ) = = GUI_TEXT_ALIGN_RIGHT ) ? GUI_TEXT_ALIGN_LEFT : GUI_TEXT_ALIGN_RIGHT , Fade ( GetColor ( GuiGetStyle ( LABEL , TEXT + ( state * 3 ) ) ) , guiAlpha ) ) ;
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return checked ;
}
// Combo Box control, returns selected item index
int GuiComboBox ( Rectangle bounds , const char * text , int active )
{
GuiControlState state = guiState ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
bounds . width - = ( GuiGetStyle ( COMBOBOX , COMBO_BUTTON_WIDTH ) + GuiGetStyle ( COMBOBOX , COMBO_BUTTON_PADDING ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Rectangle selector = { ( float ) bounds . x + bounds . width + GuiGetStyle ( COMBOBOX , COMBO_BUTTON_PADDING ) ,
2021-06-01 13:20:04 +00:00
( float ) bounds . y , ( float ) GuiGetStyle ( COMBOBOX , COMBO_BUTTON_WIDTH ) , ( float ) bounds . height } ;
2021-05-14 05:59:33 +00:00
// Get substrings items from text (items pointers, lengths and count)
int itemsCount = 0 ;
const char * * items = GuiTextSplit ( text , & itemsCount , NULL ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( active < 0 ) active = 0 ;
else if ( active > itemsCount - 1 ) active = itemsCount - 1 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
if ( ( state ! = GUI_STATE_DISABLED ) & & ! guiLocked & & ( itemsCount > 1 ) )
{
Vector2 mousePoint = GetMousePosition ( ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( CheckCollisionPointRec ( mousePoint , bounds ) | |
CheckCollisionPointRec ( mousePoint , selector ) )
{
if ( IsMouseButtonPressed ( MOUSE_LEFT_BUTTON ) )
{
active + = 1 ;
if ( active > = itemsCount ) active = 0 ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( IsMouseButtonDown ( MOUSE_LEFT_BUTTON ) ) state = GUI_STATE_PRESSED ;
else state = GUI_STATE_FOCUSED ;
}
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
// Draw combo box main
GuiDrawRectangle ( bounds , GuiGetStyle ( COMBOBOX , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( COMBOBOX , BORDER + ( state * 3 ) ) ) , guiAlpha ) , Fade ( GetColor ( GuiGetStyle ( COMBOBOX , BASE + ( state * 3 ) ) ) , guiAlpha ) ) ;
GuiDrawText ( items [ active ] , GetTextBounds ( COMBOBOX , bounds ) , GuiGetStyle ( COMBOBOX , TEXT_ALIGNMENT ) , Fade ( GetColor ( GuiGetStyle ( COMBOBOX , TEXT + ( state * 3 ) ) ) , guiAlpha ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw selector using a custom button
// NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values
int tempBorderWidth = GuiGetStyle ( BUTTON , BORDER_WIDTH ) ;
int tempTextAlign = GuiGetStyle ( BUTTON , TEXT_ALIGNMENT ) ;
GuiSetStyle ( BUTTON , BORDER_WIDTH , 1 ) ;
GuiSetStyle ( BUTTON , TEXT_ALIGNMENT , GUI_TEXT_ALIGN_CENTER ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiButton ( selector , TextFormat ( " %i/%i " , active + 1 , itemsCount ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiSetStyle ( BUTTON , TEXT_ALIGNMENT , tempTextAlign ) ;
GuiSetStyle ( BUTTON , BORDER_WIDTH , tempBorderWidth ) ;
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return active ;
}
// Dropdown Box control
// NOTE: Returns mouse click
bool GuiDropdownBox ( Rectangle bounds , const char * text , int * active , bool editMode )
{
GuiControlState state = guiState ;
int itemSelected = * active ;
int itemFocused = - 1 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Get substrings items from text (items pointers, lengths and count)
int itemsCount = 0 ;
const char * * items = GuiTextSplit ( text , & itemsCount , NULL ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Rectangle boundsOpen = bounds ;
boundsOpen . height = ( itemsCount + 1 ) * ( bounds . height + GuiGetStyle ( DROPDOWNBOX , DROPDOWN_ITEMS_PADDING ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Rectangle itemBounds = bounds ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
bool pressed = false ; // Check mouse button pressed
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
if ( ( state ! = GUI_STATE_DISABLED ) & & ! guiLocked & & ( itemsCount > 1 ) )
{
Vector2 mousePoint = GetMousePosition ( ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( editMode )
{
state = GUI_STATE_PRESSED ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Check if mouse has been pressed or released outside limits
if ( ! CheckCollisionPointRec ( mousePoint , boundsOpen ) )
{
if ( IsMouseButtonPressed ( MOUSE_LEFT_BUTTON ) | | IsMouseButtonReleased ( MOUSE_LEFT_BUTTON ) ) pressed = true ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Check if already selected item has been pressed again
if ( CheckCollisionPointRec ( mousePoint , bounds ) & & IsMouseButtonPressed ( MOUSE_LEFT_BUTTON ) ) pressed = true ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Check focused and selected item
for ( int i = 0 ; i < itemsCount ; i + + )
{
// Update item rectangle y position for next item
itemBounds . y + = ( bounds . height + GuiGetStyle ( DROPDOWNBOX , DROPDOWN_ITEMS_PADDING ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( CheckCollisionPointRec ( mousePoint , itemBounds ) )
{
itemFocused = i ;
if ( IsMouseButtonReleased ( MOUSE_LEFT_BUTTON ) )
{
itemSelected = i ;
pressed = true ; // Item selected, change to editMode = false
}
break ;
}
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
itemBounds = bounds ;
}
else
{
if ( CheckCollisionPointRec ( mousePoint , bounds ) )
{
if ( IsMouseButtonPressed ( MOUSE_LEFT_BUTTON ) )
{
pressed = true ;
state = GUI_STATE_PRESSED ;
}
else state = GUI_STATE_FOCUSED ;
}
}
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
if ( editMode ) GuiPanel ( boundsOpen ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiDrawRectangle ( bounds , GuiGetStyle ( DROPDOWNBOX , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( DROPDOWNBOX , BORDER + state * 3 ) ) , guiAlpha ) , Fade ( GetColor ( GuiGetStyle ( DROPDOWNBOX , BASE + state * 3 ) ) , guiAlpha ) ) ;
GuiDrawText ( items [ itemSelected ] , GetTextBounds ( DEFAULT , bounds ) , GuiGetStyle ( DROPDOWNBOX , TEXT_ALIGNMENT ) , Fade ( GetColor ( GuiGetStyle ( DROPDOWNBOX , TEXT + state * 3 ) ) , guiAlpha ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( editMode )
{
// Draw visible items
for ( int i = 0 ; i < itemsCount ; i + + )
{
// Update item rectangle y position for next item
itemBounds . y + = ( bounds . height + GuiGetStyle ( DROPDOWNBOX , DROPDOWN_ITEMS_PADDING ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( i = = itemSelected )
{
GuiDrawRectangle ( itemBounds , GuiGetStyle ( DROPDOWNBOX , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( DROPDOWNBOX , BORDER_COLOR_PRESSED ) ) , guiAlpha ) , Fade ( GetColor ( GuiGetStyle ( DROPDOWNBOX , BASE_COLOR_PRESSED ) ) , guiAlpha ) ) ;
GuiDrawText ( items [ i ] , GetTextBounds ( DEFAULT , itemBounds ) , GuiGetStyle ( DROPDOWNBOX , TEXT_ALIGNMENT ) , Fade ( GetColor ( GuiGetStyle ( DROPDOWNBOX , TEXT_COLOR_PRESSED ) ) , guiAlpha ) ) ;
}
else if ( i = = itemFocused )
{
GuiDrawRectangle ( itemBounds , GuiGetStyle ( DROPDOWNBOX , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( DROPDOWNBOX , BORDER_COLOR_FOCUSED ) ) , guiAlpha ) , Fade ( GetColor ( GuiGetStyle ( DROPDOWNBOX , BASE_COLOR_FOCUSED ) ) , guiAlpha ) ) ;
GuiDrawText ( items [ i ] , GetTextBounds ( DEFAULT , itemBounds ) , GuiGetStyle ( DROPDOWNBOX , TEXT_ALIGNMENT ) , Fade ( GetColor ( GuiGetStyle ( DROPDOWNBOX , TEXT_COLOR_FOCUSED ) ) , guiAlpha ) ) ;
}
else GuiDrawText ( items [ i ] , GetTextBounds ( DEFAULT , itemBounds ) , GuiGetStyle ( DROPDOWNBOX , TEXT_ALIGNMENT ) , Fade ( GetColor ( GuiGetStyle ( DROPDOWNBOX , TEXT_COLOR_NORMAL ) ) , guiAlpha ) ) ;
}
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// TODO: Avoid this function, use icon instead or 'v'
DrawTriangle ( RAYGUI_CLITERAL ( Vector2 ) { bounds . x + bounds . width - GuiGetStyle ( DROPDOWNBOX , ARROW_PADDING ) , bounds . y + bounds . height / 2 - 2 } ,
RAYGUI_CLITERAL ( Vector2 ) { bounds . x + bounds . width - GuiGetStyle ( DROPDOWNBOX , ARROW_PADDING ) + 5 , bounds . y + bounds . height / 2 - 2 + 5 } ,
RAYGUI_CLITERAL ( Vector2 ) { bounds . x + bounds . width - GuiGetStyle ( DROPDOWNBOX , ARROW_PADDING ) + 10 , bounds . y + bounds . height / 2 - 2 } ,
Fade ( GetColor ( GuiGetStyle ( DROPDOWNBOX , TEXT + ( state * 3 ) ) ) , guiAlpha ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
//GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 },
// GUI_TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))), guiAlpha));
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
* active = itemSelected ;
return pressed ;
}
// Text Box control, updates input text
// NOTE 1: Requires static variables: framesCounter
// NOTE 2: Returns if KEY_ENTER pressed (useful for data validation)
bool GuiTextBox ( Rectangle bounds , char * text , int textSize , bool editMode )
{
static int framesCounter = 0 ; // Required for blinking cursor
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiControlState state = guiState ;
bool pressed = false ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Rectangle cursor = {
bounds . x + GuiGetStyle ( TEXTBOX , TEXT_PADDING ) + GetTextWidth ( text ) + 2 ,
bounds . y + bounds . height / 2 - GuiGetStyle ( DEFAULT , TEXT_SIZE ) ,
1 ,
( float ) GuiGetStyle ( DEFAULT , TEXT_SIZE ) * 2
} ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
if ( ( state ! = GUI_STATE_DISABLED ) & & ! guiLocked )
{
Vector2 mousePoint = GetMousePosition ( ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( editMode )
{
state = GUI_STATE_PRESSED ;
framesCounter + + ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
int key = GetCharPressed ( ) ; // Returns codepoint as Unicode
int keyCount = ( int ) strlen ( text ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Only allow keys in range [32..125]
if ( keyCount < ( textSize - 1 ) )
{
float maxWidth = ( bounds . width - ( GuiGetStyle ( TEXTBOX , TEXT_INNER_PADDING ) * 2 ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( ( GetTextWidth ( text ) < ( maxWidth - GuiGetStyle ( DEFAULT , TEXT_SIZE ) ) ) & & ( key > = 32 ) )
{
int byteLength = 0 ;
const char * textUtf8 = CodepointToUtf8 ( key , & byteLength ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
for ( int i = 0 ; i < byteLength ; i + + )
{
text [ keyCount ] = textUtf8 [ i ] ;
keyCount + + ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
text [ keyCount ] = ' \0 ' ;
}
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Delete text
if ( keyCount > 0 )
{
if ( IsKeyPressed ( KEY_BACKSPACE ) )
{
keyCount - - ;
text [ keyCount ] = ' \0 ' ;
framesCounter = 0 ;
if ( keyCount < 0 ) keyCount = 0 ;
}
else if ( IsKeyDown ( KEY_BACKSPACE ) )
{
if ( ( framesCounter > TEXTEDIT_CURSOR_BLINK_FRAMES ) & & ( framesCounter % 2 ) = = 0 ) keyCount - - ;
text [ keyCount ] = ' \0 ' ;
if ( keyCount < 0 ) keyCount = 0 ;
}
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( IsKeyPressed ( KEY_ENTER ) | | ( ! CheckCollisionPointRec ( mousePoint , bounds ) & & IsMouseButtonPressed ( MOUSE_LEFT_BUTTON ) ) ) pressed = true ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Check text alignment to position cursor properly
int textAlignment = GuiGetStyle ( TEXTBOX , TEXT_ALIGNMENT ) ;
if ( textAlignment = = GUI_TEXT_ALIGN_CENTER ) cursor . x = bounds . x + GetTextWidth ( text ) / 2 + bounds . width / 2 + 1 ;
else if ( textAlignment = = GUI_TEXT_ALIGN_RIGHT ) cursor . x = bounds . x + bounds . width - GuiGetStyle ( TEXTBOX , TEXT_INNER_PADDING ) ;
}
else
{
if ( CheckCollisionPointRec ( mousePoint , bounds ) )
{
state = GUI_STATE_FOCUSED ;
if ( IsMouseButtonPressed ( MOUSE_LEFT_BUTTON ) ) pressed = true ;
}
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( pressed ) framesCounter = 0 ;
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
if ( state = = GUI_STATE_PRESSED )
{
GuiDrawRectangle ( bounds , GuiGetStyle ( TEXTBOX , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( TEXTBOX , BORDER + ( state * 3 ) ) ) , guiAlpha ) , Fade ( GetColor ( GuiGetStyle ( TEXTBOX , BASE_COLOR_PRESSED ) ) , guiAlpha ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw blinking cursor
if ( editMode & & ( ( framesCounter / 20 ) % 2 = = 0 ) ) GuiDrawRectangle ( cursor , 0 , BLANK , Fade ( GetColor ( GuiGetStyle ( TEXTBOX , BORDER_COLOR_PRESSED ) ) , guiAlpha ) ) ;
}
else if ( state = = GUI_STATE_DISABLED )
{
GuiDrawRectangle ( bounds , GuiGetStyle ( TEXTBOX , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( TEXTBOX , BORDER + ( state * 3 ) ) ) , guiAlpha ) , Fade ( GetColor ( GuiGetStyle ( TEXTBOX , BASE_COLOR_DISABLED ) ) , guiAlpha ) ) ;
}
else GuiDrawRectangle ( bounds , 1 , Fade ( GetColor ( GuiGetStyle ( TEXTBOX , BORDER + ( state * 3 ) ) ) , guiAlpha ) , BLANK ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiDrawText ( text , GetTextBounds ( TEXTBOX , bounds ) , GuiGetStyle ( TEXTBOX , TEXT_ALIGNMENT ) , Fade ( GetColor ( GuiGetStyle ( TEXTBOX , TEXT + ( state * 3 ) ) ) , guiAlpha ) ) ;
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return pressed ;
}
// Spinner control, returns selected value
bool GuiSpinner ( Rectangle bounds , const char * text , int * value , int minValue , int maxValue , bool editMode )
{
GuiControlState state = guiState ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
bool pressed = false ;
int tempValue = * value ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Rectangle spinner = { bounds . x + GuiGetStyle ( SPINNER , SPIN_BUTTON_WIDTH ) + GuiGetStyle ( SPINNER , SPIN_BUTTON_PADDING ) , bounds . y ,
2021-06-01 13:20:04 +00:00
bounds . width - 2 * ( GuiGetStyle ( SPINNER , SPIN_BUTTON_WIDTH ) + GuiGetStyle ( SPINNER , SPIN_BUTTON_PADDING ) ) , bounds . height } ;
2021-05-14 05:59:33 +00:00
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 } ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Rectangle textBounds = { 0 } ;
if ( text ! = NULL )
{
textBounds . width = ( float ) GetTextWidth ( text ) ;
textBounds . height = ( float ) GuiGetStyle ( DEFAULT , TEXT_SIZE ) ;
textBounds . x = bounds . x + bounds . width + GuiGetStyle ( SPINNER , TEXT_PADDING ) ;
textBounds . y = bounds . y + bounds . height / 2 - GuiGetStyle ( DEFAULT , TEXT_SIZE ) / 2 ;
if ( GuiGetStyle ( SPINNER , TEXT_ALIGNMENT ) = = GUI_TEXT_ALIGN_LEFT ) textBounds . x = bounds . x - textBounds . width - GuiGetStyle ( SPINNER , TEXT_PADDING ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
if ( ( state ! = GUI_STATE_DISABLED ) & & ! guiLocked )
{
Vector2 mousePoint = GetMousePosition ( ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Check spinner state
if ( CheckCollisionPointRec ( mousePoint , bounds ) )
{
if ( IsMouseButtonDown ( MOUSE_LEFT_BUTTON ) ) state = GUI_STATE_PRESSED ;
else state = GUI_STATE_FOCUSED ;
}
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( ! editMode )
{
if ( tempValue < minValue ) tempValue = minValue ;
if ( tempValue > maxValue ) tempValue = maxValue ;
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
// TODO: Set Spinner properties for ValueBox
pressed = GuiValueBox ( spinner , NULL , & tempValue , minValue , maxValue , editMode ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// 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 ( SPINNER , BORDER_WIDTH ) ) ;
GuiSetStyle ( BUTTON , TEXT_ALIGNMENT , GUI_TEXT_ALIGN_CENTER ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
# if defined(RAYGUI_SUPPORT_ICONS)
if ( GuiButton ( leftButtonBound , GuiIconText ( RICON_ARROW_LEFT_FILL , NULL ) ) ) tempValue - - ;
if ( GuiButton ( rightButtonBound , GuiIconText ( RICON_ARROW_RIGHT_FILL , NULL ) ) ) tempValue + + ;
# else
if ( GuiButton ( leftButtonBound , " < " ) ) tempValue - - ;
if ( GuiButton ( rightButtonBound , " > " ) ) tempValue + + ;
# endif
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiSetStyle ( BUTTON , TEXT_ALIGNMENT , tempTextAlign ) ;
GuiSetStyle ( BUTTON , BORDER_WIDTH , tempBorderWidth ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw text label if provided
if ( text ! = NULL ) GuiDrawText ( text , textBounds , ( GuiGetStyle ( S PINNER , TEXT_ALIGNMENT ) = = GUI_TEXT_ALIGN_RIGHT ) ? GUI_TEXT_ALIGN_LEFT : GUI_TEXT_ALIGN_RIGHT , Fade ( GetColor ( GuiGetStyle ( LABEL , TEXT + ( state * 3 ) ) ) , guiAlpha ) ) ;
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
* value = tempValue ;
return pressed ;
}
// Value Box control, updates input text with numbers
// NOTE: Requires static variables: framesCounter
bool GuiValueBox ( Rectangle bounds , const char * text , int * value , int minValue , int maxValue , bool editMode )
{
2021-06-01 13:20:04 +00:00
# if !defined(VALUEBOX_MAX_CHARS)
# define VALUEBOX_MAX_CHARS 32
# endif
2021-05-14 05:59:33 +00:00
static int framesCounter = 0 ; // Required for blinking cursor
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiControlState state = guiState ;
bool pressed = false ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
char textValue [ VALUEBOX_MAX_CHARS + 1 ] = " \0 " ;
sprintf ( textValue , " %i " , * value ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Rectangle textBounds = { 0 } ;
if ( text ! = NULL )
{
textBounds . width = ( float ) GetTextWidth ( text ) ;
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 ) = = GUI_TEXT_ALIGN_LEFT ) textBounds . x = bounds . x - textBounds . width - GuiGetStyle ( VALUEBOX , TEXT_PADDING ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
if ( ( state ! = GUI_STATE_DISABLED ) & & ! guiLocked )
{
Vector2 mousePoint = GetMousePosition ( ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
bool valueHasChanged = false ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( editMode )
{
state = GUI_STATE_PRESSED ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
framesCounter + + ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
int keyCount = ( int ) strlen ( textValue ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Only allow keys in range [48..57]
if ( keyCount < VALUEBOX_MAX_CHARS )
{
if ( GetTextWidth ( textValue ) < bounds . width )
{
int key = GetCharPressed ( ) ;
if ( ( key > = 48 ) & & ( key < = 57 ) )
{
textValue [ keyCount ] = ( char ) key ;
keyCount + + ;
valueHasChanged = true ;
}
}
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Delete text
if ( keyCount > 0 )
{
if ( IsKeyPressed ( KEY_BACKSPACE ) )
{
keyCount - - ;
textValue [ keyCount ] = ' \0 ' ;
framesCounter = 0 ;
if ( keyCount < 0 ) keyCount = 0 ;
valueHasChanged = true ;
}
else if ( IsKeyDown ( KEY_BACKSPACE ) )
{
if ( ( framesCounter > TEXTEDIT_CURSOR_BLINK_FRAMES ) & & ( framesCounter % 2 ) = = 0 ) keyCount - - ;
textValue [ keyCount ] = ' \0 ' ;
if ( keyCount < 0 ) keyCount = 0 ;
valueHasChanged = true ;
}
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( valueHasChanged ) * value = TextToInteger ( textValue ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( IsKeyPressed ( KEY_ENTER ) | | ( ! CheckCollisionPointRec ( mousePoint , bounds ) & & IsMouseButtonPressed ( MOUSE_LEFT_BUTTON ) ) ) pressed = true ;
}
else
{
if ( * value > maxValue ) * value = maxValue ;
else if ( * value < minValue ) * value = minValue ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( CheckCollisionPointRec ( mousePoint , bounds ) )
{
state = GUI_STATE_FOCUSED ;
if ( IsMouseButtonPressed ( MOUSE_LEFT_BUTTON ) ) pressed = true ;
}
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( pressed ) framesCounter = 0 ;
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
Color baseColor = BLANK ;
if ( state = = GUI_STATE_PRESSED ) baseColor = GetColor ( GuiGetStyle ( VALUEBOX , BASE_COLOR_PRESSED ) ) ;
else if ( state = = GUI_STATE_DISABLED ) baseColor = GetColor ( GuiGetStyle ( VALUEBOX , BASE_COLOR_DISABLED ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// WARNING: BLANK color does not work properly with Fade()
GuiDrawRectangle ( bounds , GuiGetStyle ( VALUEBOX , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( VALUEBOX , BORDER + ( state * 3 ) ) ) , guiAlpha ) , baseColor ) ;
GuiDrawText ( textValue , GetTextBounds ( VALUEBOX , bounds ) , GUI_TEXT_ALIGN_CENTER , Fade ( GetColor ( GuiGetStyle ( VALUEBOX , TEXT + ( state * 3 ) ) ) , guiAlpha ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw blinking cursor
if ( ( state = = GUI_STATE_PRESSED ) & & ( editMode & & ( ( framesCounter / 20 ) % 2 = = 0 ) ) )
{
// NOTE: ValueBox internal text is always centered
Rectangle cursor = { bounds . x + GetTextWidth ( textValue ) / 2 + bounds . width / 2 + 2 , bounds . y + 2 * GuiGetStyle ( VALUEBOX , BORDER_WIDTH ) , 1 , bounds . height - 4 * GuiGetStyle ( VALUEBOX , BORDER_WIDTH ) } ;
GuiDrawRectangle ( cursor , 0 , BLANK , Fade ( GetColor ( GuiGetStyle ( VALUEBOX , BORDER_COLOR_PRESSED ) ) , guiAlpha ) ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw text label if provided
if ( text ! = NULL ) GuiDrawText ( text , textBounds , ( GuiGetStyle ( VALUEBOX , TEXT_ALIGNMENT ) = = GUI_TEXT_ALIGN_RIGHT ) ? GUI_TEXT_ALIGN_LEFT : GUI_TEXT_ALIGN_RIGHT , Fade ( GetColor ( GuiGetStyle ( LABEL , TEXT + ( state * 3 ) ) ) , guiAlpha ) ) ;
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return pressed ;
}
// Text Box control with multiple lines
bool GuiTextBoxMulti ( Rectangle bounds , char * text , int textSize , bool editMode )
{
static int framesCounter = 0 ; // Required for blinking cursor
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiControlState state = guiState ;
bool pressed = false ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Rectangle textAreaBounds = {
2021-06-01 13:20:04 +00:00
bounds . x + GuiGetStyle ( TEXTBOX , BORDER_WIDTH ) + GuiGetStyle ( TEXTBOX , TEXT_INNER_PADDING ) ,
bounds . y + GuiGetStyle ( TEXTBOX , BORDER_WIDTH ) + GuiGetStyle ( TEXTBOX , TEXT_INNER_PADDING ) ,
bounds . width - 2 * ( GuiGetStyle ( TEXTBOX , BORDER_WIDTH ) + GuiGetStyle ( TEXTBOX , TEXT_INNER_PADDING ) ) ,
bounds . height - 2 * ( GuiGetStyle ( TEXTBOX , BORDER_WIDTH ) + GuiGetStyle ( TEXTBOX , TEXT_INNER_PADDING ) )
2021-05-14 05:59:33 +00:00
} ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Cursor position, [x, y] values should be updated
2021-06-01 13:20:04 +00:00
Rectangle cursor = { 0 , 0 , ( GuiGetStyle ( DEFAULT , TEXT_SIZE ) < 10 ) ? 1 : ( GuiGetStyle ( DEFAULT , TEXT_SIZE ) * 0.1f ) , ( float ) GuiGetStyle ( DEFAULT , TEXT_SIZE ) + 2 } ;
2021-05-14 05:59:33 +00:00
int textWidth = 0 ;
int currentLine = 0 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
if ( ( state ! = GUI_STATE_DISABLED ) & & ! guiLocked )
{
Vector2 mousePoint = GetMousePosition ( ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( editMode )
{
state = GUI_STATE_PRESSED ;
framesCounter + + ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
int character = GetCharPressed ( ) ;
int keyCount = ( int ) strlen ( text ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Introduce characters
if ( keyCount < ( textSize - 1 ) )
{
Vector2 textSize = MeasureTextEx ( guiFont , text , ( float ) GuiGetStyle ( DEFAULT , TEXT_SIZE ) , ( float ) GuiGetStyle ( DEFAULT , TEXT_SPACING ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( textSize . y < ( textAreaBounds . height - GuiGetStyle ( DEFAULT , TEXT_SIZE ) ) )
{
if ( IsKeyPressed ( KEY_ENTER ) )
{
text [ keyCount ] = ' \n ' ;
keyCount + + ;
}
else if ( ( ( character > = 32 ) & & ( character < 255 ) ) ) // TODO: Support Unicode inputs
{
text [ keyCount ] = ( char ) character ;
keyCount + + ;
}
}
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Delete characters
if ( keyCount > 0 )
{
if ( IsKeyPressed ( KEY_BACKSPACE ) )
{
keyCount - - ;
text [ keyCount ] = ' \0 ' ;
framesCounter = 0 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( keyCount < 0 ) keyCount = 0 ;
}
else if ( IsKeyDown ( KEY_BACKSPACE ) )
{
if ( ( framesCounter > TEXTEDIT_CURSOR_BLINK_FRAMES ) & & ( framesCounter % 2 ) = = 0 ) keyCount - - ;
text [ keyCount ] = ' \0 ' ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( keyCount < 0 ) keyCount = 0 ;
}
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Calculate cursor position considering text
char oneCharText [ 2 ] = { 0 } ;
int lastBreakingPos = - 1 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
for ( int i = 0 ; i < keyCount & & currentLine < keyCount ; i + + )
{
oneCharText [ 0 ] = text [ i ] ;
textWidth + = ( GetTextWidth ( oneCharText ) + GuiGetStyle ( DEFAULT , TEXT_SPACING ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( text [ i ] = = ' ' | | text [ i ] = = ' \n ' ) lastBreakingPos = i ;
2021-06-01 13:20:04 +00:00
if ( text [ i ] = = ' \n ' | | textWidth + 1 > = textAreaBounds . width )
2021-05-14 05:59:33 +00:00
{
currentLine + + ;
textWidth = 0 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( lastBreakingPos > 0 ) i = lastBreakingPos ;
else textWidth + = ( GetTextWidth ( oneCharText ) + GuiGetStyle ( DEFAULT , TEXT_SPACING ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
lastBreakingPos = - 1 ;
}
}
2021-06-01 13:20:04 +00:00
cursor . x = textAreaBounds . x + textWidth - GuiGetStyle ( DEFAULT , TEXT_SPACING ) ;
cursor . y = textAreaBounds . y + ( ( GuiGetStyle ( DEFAULT , TEXT_SIZE ) + GuiGetStyle ( DEFAULT , TEXT_SIZE ) / 2 ) * currentLine ) ;
2021-05-14 05:59:33 +00:00
// Exit edit mode
if ( ! CheckCollisionPointRec ( mousePoint , bounds ) & & IsMouseButtonPressed ( MOUSE_LEFT_BUTTON ) ) pressed = true ;
}
else
{
if ( CheckCollisionPointRec ( mousePoint , bounds ) )
{
state = GUI_STATE_FOCUSED ;
if ( IsMouseButtonPressed ( MOUSE_LEFT_BUTTON ) ) pressed = true ;
}
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( pressed ) framesCounter = 0 ; // Reset blinking cursor
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
if ( state = = GUI_STATE_PRESSED )
{
GuiDrawRectangle ( bounds , GuiGetStyle ( TEXTBOX , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( TEXTBOX , BORDER + ( state * 3 ) ) ) , guiAlpha ) , Fade ( GetColor ( GuiGetStyle ( TEXTBOX , BASE_COLOR_PRESSED ) ) , guiAlpha ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw blinking cursor
if ( editMode & & ( ( framesCounter / 20 ) % 2 = = 0 ) ) GuiDrawRectangle ( cursor , 0 , BLANK , Fade ( GetColor ( GuiGetStyle ( TEXTBOX , BORDER_COLOR_PRESSED ) ) , guiAlpha ) ) ;
}
else if ( state = = GUI_STATE_DISABLED )
{
GuiDrawRectangle ( bounds , GuiGetStyle ( TEXTBOX , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( TEXTBOX , BORDER + ( state * 3 ) ) ) , guiAlpha ) , Fade ( GetColor ( GuiGetStyle ( TEXTBOX , BASE_COLOR_DISABLED ) ) , guiAlpha ) ) ;
}
else GuiDrawRectangle ( bounds , 1 , Fade ( GetColor ( GuiGetStyle ( TEXTBOX , BORDER + ( state * 3 ) ) ) , guiAlpha ) , BLANK ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
DrawTextRec ( guiFont , text , textAreaBounds , ( float ) GuiGetStyle ( DEFAULT , TEXT_SIZE ) , ( float ) GuiGetStyle ( DEFAULT , TEXT_SPACING ) , true , Fade ( GetColor ( GuiGetStyle ( TEXTBOX , TEXT + ( state * 3 ) ) ) , guiAlpha ) ) ;
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return pressed ;
}
// Slider control with pro parameters
// NOTE: Other GuiSlider*() controls use this one
float GuiSliderPro ( Rectangle bounds , const char * textLeft , const char * textRight , float value , float minValue , float maxValue , int sliderWidth )
{
GuiControlState state = guiState ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
int sliderValue = ( int ) ( ( ( value - minValue ) / ( maxValue - minValue ) ) * ( bounds . width - 2 * GuiGetStyle ( SLIDER , BORDER_WIDTH ) ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Rectangle slider = { bounds . x , bounds . y + GuiGetStyle ( SLIDER , BORDER_WIDTH ) + GuiGetStyle ( SLIDER , SLIDER_PADDING ) ,
2021-06-01 13:20:04 +00:00
0 , bounds . height - 2 * GuiGetStyle ( SLIDER , BORDER_WIDTH ) - 2 * GuiGetStyle ( SLIDER , SLIDER_PADDING ) } ;
2021-05-14 05:59:33 +00:00
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 ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
if ( ( state ! = GUI_STATE_DISABLED ) & & ! guiLocked )
{
Vector2 mousePoint = GetMousePosition ( ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( CheckCollisionPointRec ( mousePoint , bounds ) )
{
if ( IsMouseButtonDown ( MOUSE_LEFT_BUTTON ) )
{
state = GUI_STATE_PRESSED ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Get equivalent value and slider position from mousePoint.x
value = ( ( maxValue - minValue ) * ( mousePoint . x - ( float ) ( bounds . x + sliderWidth / 2 ) ) ) / ( float ) ( bounds . width - sliderWidth ) + minValue ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( sliderWidth > 0 ) slider . x = mousePoint . x - slider . width / 2 ; // Slider
else if ( sliderWidth = = 0 ) slider . width = ( float ) sliderValue ; // SliderBar
}
else state = GUI_STATE_FOCUSED ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( value > maxValue ) value = maxValue ;
else if ( value < minValue ) value = minValue ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Bar limits check
if ( sliderWidth > 0 ) // Slider
{
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
{
if ( slider . width > bounds . width ) slider . width = bounds . width - 2 * GuiGetStyle ( SLIDER , BORDER_WIDTH ) ;
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
GuiDrawRectangle ( bounds , GuiGetStyle ( SLIDER , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( SLIDER , BORDER + ( state * 3 ) ) ) , guiAlpha ) , Fade ( GetColor ( GuiGetStyle ( SLIDER , ( state ! = GUI_STATE_DISABLED ) ? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED ) ) , guiAlpha ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw slider internal bar (depends on state)
if ( ( state = = GUI_STATE_NORMAL ) | | ( state = = GUI_STATE_PRESSED ) ) GuiDrawRectangle ( slider , 0 , BLANK , Fade ( GetColor ( GuiGetStyle ( SLIDER , BASE_COLOR_PRESSED ) ) , guiAlpha ) ) ;
else if ( state = = GUI_STATE_FOCUSED ) GuiDrawRectangle ( slider , 0 , BLANK , Fade ( GetColor ( GuiGetStyle ( SLIDER , TEXT_COLOR_FOCUSED ) ) , guiAlpha ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw left/right text if provided
if ( textLeft ! = NULL )
{
Rectangle textBounds = { 0 } ;
textBounds . width = ( float ) GetTextWidth ( textLeft ) ; // TODO: Consider text icon
textBounds . height = ( float ) GuiGetStyle ( DEFAULT , TEXT_SIZE ) ;
textBounds . x = bounds . x - textBounds . width - GuiGetStyle ( SLIDER , TEXT_PADDING ) ;
textBounds . y = bounds . y + bounds . height / 2 - GuiGetStyle ( DEFAULT , TEXT_SIZE ) / 2 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiDrawText ( textLeft , textBounds , GUI_TEXT_ALIGN_RIGHT , Fade ( GetColor ( GuiGetStyle ( SLIDER , TEXT + ( state * 3 ) ) ) , guiAlpha ) ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( textRight ! = NULL )
{
Rectangle textBounds = { 0 } ;
textBounds . width = ( float ) GetTextWidth ( textRight ) ; // TODO: Consider text icon
textBounds . height = ( float ) GuiGetStyle ( DEFAULT , TEXT_SIZE ) ;
textBounds . x = bounds . x + bounds . width + GuiGetStyle ( SLIDER , TEXT_PADDING ) ;
textBounds . y = bounds . y + bounds . height / 2 - GuiGetStyle ( DEFAULT , TEXT_SIZE ) / 2 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiDrawText ( textRight , textBounds , GUI_TEXT_ALIGN_LEFT , Fade ( GetColor ( GuiGetStyle ( SLIDER , TEXT + ( state * 3 ) ) ) , guiAlpha ) ) ;
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return value ;
}
// Slider control extended, returns selected value and has text
float GuiSlider ( Rectangle bounds , const char * textLeft , const char * textRight , float value , float minValue , float maxValue )
{
return GuiSliderPro ( bounds , textLeft , textRight , value , minValue , maxValue , GuiGetStyle ( SLIDER , SLIDER_WIDTH ) ) ;
}
// Slider Bar control extended, returns selected value
float GuiSliderBar ( Rectangle bounds , const char * textLeft , const char * textRight , float value , float minValue , float maxValue )
{
return GuiSliderPro ( bounds , textLeft , textRight , value , minValue , maxValue , 0 ) ;
}
// Progress Bar control extended, shows current progress value
float GuiProgressBar ( Rectangle bounds , const char * textLeft , const char * textRight , float value , float minValue , float maxValue )
{
GuiControlState state = guiState ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Rectangle progress = { bounds . x + GuiGetStyle ( PROGRESSBAR , BORDER_WIDTH ) ,
2021-06-01 13:20:04 +00:00
bounds . y + GuiGetStyle ( PROGRESSBAR , BORDER_WIDTH ) + GuiGetStyle ( PROGRESSBAR , PROGRESS_PADDING ) , 0 ,
bounds . height - 2 * GuiGetStyle ( PROGRESSBAR , BORDER_WIDTH ) - 2 * GuiGetStyle ( PROGRESSBAR , PROGRESS_PADDING ) } ;
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
if ( state ! = GUI_STATE_DISABLED ) progress . width = ( ( float ) ( value / ( maxValue - minValue ) ) * ( float ) ( bounds . width - 2 * GuiGetStyle ( PROGRESSBAR , BORDER_WIDTH ) ) ) ;
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
GuiDrawRectangle ( bounds , GuiGetStyle ( PROGRESSBAR , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( PROGRESSBAR , BORDER + ( state * 3 ) ) ) , guiAlpha ) , BLANK ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw slider internal progress bar (depends on state)
if ( ( state = = GUI_STATE_NORMAL ) | | ( state = = GUI_STATE_PRESSED ) ) GuiDrawRectangle ( progress , 0 , BLANK , Fade ( GetColor ( GuiGetStyle ( PROGRESSBAR , BASE_COLOR_PRESSED ) ) , guiAlpha ) ) ;
else if ( state = = GUI_STATE_FOCUSED ) GuiDrawRectangle ( progress , 0 , BLANK , Fade ( GetColor ( GuiGetStyle ( PROGRESSBAR , TEXT_COLOR_FOCUSED ) ) , guiAlpha ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw left/right text if provided
if ( textLeft ! = NULL )
{
Rectangle textBounds = { 0 } ;
textBounds . width = ( float ) GetTextWidth ( textLeft ) ; // TODO: Consider text icon
textBounds . height = ( float ) GuiGetStyle ( DEFAULT , TEXT_SIZE ) ;
textBounds . x = bounds . x - textBounds . width - GuiGetStyle ( PROGRESSBAR , TEXT_PADDING ) ;
textBounds . y = bounds . y + bounds . height / 2 - GuiGetStyle ( DEFAULT , TEXT_SIZE ) / 2 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiDrawText ( textLeft , textBounds , GUI_TEXT_ALIGN_RIGHT , Fade ( GetColor ( GuiGetStyle ( PROGRESSBAR , TEXT + ( state * 3 ) ) ) , guiAlpha ) ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( textRight ! = NULL )
{
Rectangle textBounds = { 0 } ;
textBounds . width = ( float ) GetTextWidth ( textRight ) ; // TODO: Consider text icon
textBounds . height = ( float ) GuiGetStyle ( DEFAULT , TEXT_SIZE ) ;
textBounds . x = bounds . x + bounds . width + GuiGetStyle ( PROGRESSBAR , TEXT_PADDING ) ;
textBounds . y = bounds . y + bounds . height / 2 - GuiGetStyle ( DEFAULT , TEXT_SIZE ) / 2 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiDrawText ( textRight , textBounds , GUI_TEXT_ALIGN_LEFT , Fade ( GetColor ( GuiGetStyle ( PROGRESSBAR , TEXT + ( state * 3 ) ) ) , guiAlpha ) ) ;
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return value ;
}
// Status Bar control
void GuiStatusBar ( Rectangle bounds , const char * text )
{
GuiControlState state = guiState ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
GuiDrawRectangle ( bounds , GuiGetStyle ( STATUSBAR , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( STATUSBAR , ( state ! = GUI_STATE_DISABLED ) ? BORDER_COLOR_NORMAL : BORDER_COLOR_DISABLED ) ) , guiAlpha ) ,
Fade ( GetColor ( GuiGetStyle ( STATUSBAR , ( state ! = GUI_STATE_DISABLED ) ? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED ) ) , guiAlpha ) ) ;
GuiDrawText ( text , GetTextBounds ( STATUSBAR , bounds ) , GuiGetStyle ( STATUSBAR , TEXT_ALIGNMENT ) , Fade ( GetColor ( GuiGetStyle ( STATUSBAR , ( state ! = GUI_STATE_DISABLED ) ? TEXT_COLOR_NORMAL : TEXT_COLOR_DISABLED ) ) , guiAlpha ) ) ;
//--------------------------------------------------------------------
}
// Dummy rectangle control, intended for placeholding
void GuiDummyRec ( Rectangle bounds , const char * text )
{
GuiControlState state = guiState ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
if ( ( state ! = GUI_STATE_DISABLED ) & & ! guiLocked )
{
Vector2 mousePoint = GetMousePosition ( ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Check button state
if ( CheckCollisionPointRec ( mousePoint , bounds ) )
{
if ( IsMouseButtonDown ( MOUSE_LEFT_BUTTON ) ) state = GUI_STATE_PRESSED ;
else state = GUI_STATE_FOCUSED ;
}
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
GuiDrawRectangle ( bounds , 0 , BLANK , Fade ( GetColor ( GuiGetStyle ( DEFAULT , ( state ! = GUI_STATE_DISABLED ) ? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED ) ) , guiAlpha ) ) ;
GuiDrawText ( text , GetTextBounds ( DEFAULT , bounds ) , GUI_TEXT_ALIGN_CENTER , Fade ( GetColor ( GuiGetStyle ( BUTTON , ( state ! = GUI_STATE_DISABLED ) ? TEXT_COLOR_NORMAL : TEXT_COLOR_DISABLED ) ) , guiAlpha ) ) ;
//------------------------------------------------------------------
}
// Scroll Bar control
// TODO: I feel GuiScrollBar could be simplified...
int GuiScrollBar ( Rectangle bounds , int value , int minValue , int maxValue )
{
GuiControlState state = guiState ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Is the scrollbar horizontal or vertical?
bool isVertical = ( bounds . width > bounds . height ) ? false : true ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// The size (width or height depending on scrollbar type) of the spinner buttons
const int spinnerSize = GuiGetStyle ( SCROLLBAR , ARROWS_VISIBLE ) ? ( isVertical ? ( int ) bounds . width - 2 * GuiGetStyle ( SCROLLBAR , BORDER_WIDTH ) : ( int ) bounds . height - 2 * GuiGetStyle ( SCROLLBAR , BORDER_WIDTH ) ) : 0 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Arrow buttons [<] [>] [∧] [∨ ]
Rectangle arrowUpLeft = { 0 } ;
Rectangle arrowDownRight = { 0 } ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Actual area of the scrollbar excluding the arrow buttons
Rectangle scrollbar = { 0 } ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Slider bar that moves --[///]-----
Rectangle slider = { 0 } ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Normalize value
if ( value > maxValue ) value = maxValue ;
if ( value < minValue ) value = minValue ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
const int range = maxValue - minValue ;
int sliderSize = GuiGetStyle ( SCROLLBAR , SCROLL_SLIDER_SIZE ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Calculate rectangles for all of the components
arrowUpLeft = RAYGUI_CLITERAL ( Rectangle ) { ( float ) bounds . x + GuiGetStyle ( SCROLLBAR , BORDER_WIDTH ) , ( float ) bounds . y + GuiGetStyle ( SCROLLBAR , BORDER_WIDTH ) , ( float ) spinnerSize , ( float ) spinnerSize } ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( isVertical )
{
arrowDownRight = RAYGUI_CLITERAL ( Rectangle ) { ( float ) bounds . x + GuiGetStyle ( SCROLLBAR , BORDER_WIDTH ) , ( float ) bounds . y + bounds . height - spinnerSize - GuiGetStyle ( SCROLLBAR , BORDER_WIDTH ) , ( float ) spinnerSize , ( float ) spinnerSize } ;
scrollbar = RAYGUI_CLITERAL ( Rectangle ) { bounds . x + GuiGetStyle ( SCROLLBAR , BORDER_WIDTH ) + GuiGetStyle ( SCROLLBAR , SCROLL_PADDING ) , arrowUpLeft . y + arrowUpLeft . height , bounds . width - 2 * ( GuiGetStyle ( SCROLLBAR , BORDER_WIDTH ) + GuiGetStyle ( SCROLLBAR , SCROLL_PADDING ) ) , bounds . height - arrowUpLeft . height - arrowDownRight . height - 2 * GuiGetStyle ( SCROLLBAR , BORDER_WIDTH ) } ;
sliderSize = ( sliderSize > = scrollbar . height ) ? ( ( int ) scrollbar . height - 2 ) : sliderSize ; // Make sure the slider won't get outside of the scrollbar
slider = RAYGUI_CLITERAL ( Rectangle ) { ( float ) bounds . x + GuiGetStyle ( SCROLLBAR , BORDER_WIDTH ) + GuiGetStyle ( SCROLLBAR , SCROLL_SLIDER_PADDING ) , ( float ) scrollbar . y + ( int ) ( ( ( float ) ( value - minValue ) / range ) * ( scrollbar . height - sliderSize ) ) , ( float ) bounds . width - 2 * ( GuiGetStyle ( SCROLLBAR , BORDER_WIDTH ) + GuiGetStyle ( SCROLLBAR , SCROLL_SLIDER_PADDING ) ) , ( float ) sliderSize } ;
}
else
{
arrowDownRight = RAYGUI_CLITERAL ( Rectangle ) { ( float ) bounds . x + bounds . width - spinnerSize - GuiGetStyle ( SCROLLBAR , BORDER_WIDTH ) , ( float ) bounds . y + GuiGetStyle ( SCROLLBAR , BORDER_WIDTH ) , ( float ) spinnerSize , ( float ) spinnerSize } ;
scrollbar = RAYGUI_CLITERAL ( Rectangle ) { arrowUpLeft . x + arrowUpLeft . width , bounds . y + GuiGetStyle ( SCROLLBAR , BORDER_WIDTH ) + GuiGetStyle ( SCROLLBAR , SCROLL_PADDING ) , bounds . width - arrowUpLeft . width - arrowDownRight . width - 2 * GuiGetStyle ( SCROLLBAR , BORDER_WIDTH ) , bounds . height - 2 * ( GuiGetStyle ( SCROLLBAR , BORDER_WIDTH ) + GuiGetStyle ( SCROLLBAR , SCROLL_PADDING ) ) } ;
sliderSize = ( sliderSize > = scrollbar . width ) ? ( ( int ) scrollbar . width - 2 ) : sliderSize ; // Make sure the slider won't get outside of the scrollbar
slider = RAYGUI_CLITERAL ( Rectangle ) { ( float ) scrollbar . x + ( int ) ( ( ( float ) ( value - minValue ) / range ) * ( scrollbar . width - sliderSize ) ) , ( float ) bounds . y + GuiGetStyle ( SCROLLBAR , BORDER_WIDTH ) + GuiGetStyle ( SCROLLBAR , SCROLL_SLIDER_PADDING ) , ( float ) sliderSize , ( float ) bounds . height - 2 * ( GuiGetStyle ( SCROLLBAR , BORDER_WIDTH ) + GuiGetStyle ( SCROLLBAR , SCROLL_SLIDER_PADDING ) ) } ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
if ( ( state ! = GUI_STATE_DISABLED ) & & ! guiLocked )
{
Vector2 mousePoint = GetMousePosition ( ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( CheckCollisionPointRec ( mousePoint , bounds ) )
{
state = GUI_STATE_FOCUSED ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Handle mouse wheel
int wheel = ( int ) GetMouseWheelMove ( ) ;
if ( wheel ! = 0 ) value + = wheel ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( IsMouseButtonPressed ( MOUSE_LEFT_BUTTON ) )
{
if ( CheckCollisionPointRec ( mousePoint , arrowUpLeft ) ) value - = range / GuiGetStyle ( SCROLLBAR , SCROLL_SPEED ) ;
else if ( CheckCollisionPointRec ( mousePoint , arrowDownRight ) ) value + = range / GuiGetStyle ( SCROLLBAR , SCROLL_SPEED ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
state = GUI_STATE_PRESSED ;
}
else if ( IsMouseButtonDown ( MOUSE_LEFT_BUTTON ) )
{
if ( ! isVertical )
{
Rectangle scrollArea = { arrowUpLeft . x + arrowUpLeft . width , arrowUpLeft . y , scrollbar . width , bounds . height - 2 * GuiGetStyle ( SCROLLBAR , BORDER_WIDTH ) } ;
if ( CheckCollisionPointRec ( mousePoint , scrollArea ) ) value = ( int ) ( ( ( float ) ( mousePoint . x - scrollArea . x - slider . width / 2 ) * range ) / ( scrollArea . width - slider . width ) + minValue ) ;
}
else
{
Rectangle scrollArea = { arrowUpLeft . x , arrowUpLeft . y + arrowUpLeft . height , bounds . width - 2 * GuiGetStyle ( SCROLLBAR , BORDER_WIDTH ) , scrollbar . height } ;
if ( CheckCollisionPointRec ( mousePoint , scrollArea ) ) value = ( int ) ( ( ( float ) ( mousePoint . y - scrollArea . y - slider . height / 2 ) * range ) / ( scrollArea . height - slider . height ) + minValue ) ;
}
}
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Normalize value
if ( value > maxValue ) value = maxValue ;
if ( value < minValue ) value = minValue ;
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
GuiDrawRectangle ( bounds , GuiGetStyle ( SCROLLBAR , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( LISTVIEW , BORDER + state * 3 ) ) , guiAlpha ) , Fade ( GetColor ( GuiGetStyle ( DEFAULT , BORDER_COLOR_DISABLED ) ) , guiAlpha ) ) ; // Draw the background
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiDrawRectangle ( scrollbar , 0 , BLANK , Fade ( GetColor ( GuiGetStyle ( BUTTON , BASE_COLOR_NORMAL ) ) , guiAlpha ) ) ; // Draw the scrollbar active area background
GuiDrawRectangle ( slider , 0 , BLANK , Fade ( GetColor ( GuiGetStyle ( SLIDER , BORDER + state * 3 ) ) , guiAlpha ) ) ; // Draw the slider bar
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw arrows
const int padding = ( spinnerSize - GuiGetStyle ( SCROLLBAR , ARROWS_SIZE ) ) / 2 ;
const Vector2 lineCoords [ ] =
{
// Coordinates for < 0,1,2
{ arrowUpLeft . x + padding , arrowUpLeft . y + spinnerSize / 2 } ,
{ arrowUpLeft . x + spinnerSize - padding , arrowUpLeft . y + padding } ,
{ arrowUpLeft . x + spinnerSize - padding , arrowUpLeft . y + spinnerSize - padding } ,
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Coordinates for > 3,4,5
{ arrowDownRight . x + padding , arrowDownRight . y + padding } ,
{ arrowDownRight . x + spinnerSize - padding , arrowDownRight . y + spinnerSize / 2 } ,
{ arrowDownRight . x + padding , arrowDownRight . y + spinnerSize - padding } ,
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Coordinates for ∧ 6,7,8
{ arrowUpLeft . x + spinnerSize / 2 , arrowUpLeft . y + padding } ,
{ arrowUpLeft . x + padding , arrowUpLeft . y + spinnerSize - padding } ,
{ arrowUpLeft . x + spinnerSize - padding , arrowUpLeft . y + spinnerSize - padding } ,
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Coordinates for ∨ 9,10,11
{ arrowDownRight . x + padding , arrowDownRight . y + padding } ,
{ arrowDownRight . x + spinnerSize / 2 , arrowDownRight . y + spinnerSize - padding } ,
{ arrowDownRight . x + spinnerSize - padding , arrowDownRight . y + padding }
} ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Color lineColor = Fade ( GetColor ( GuiGetStyle ( BUTTON , TEXT + state * 3 ) ) , guiAlpha ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( GuiGetStyle ( SCROLLBAR , ARROWS_VISIBLE ) )
{
if ( isVertical )
{
DrawTriangle ( lineCoords [ 6 ] , lineCoords [ 7 ] , lineCoords [ 8 ] , lineColor ) ;
DrawTriangle ( lineCoords [ 9 ] , lineCoords [ 10 ] , lineCoords [ 11 ] , lineColor ) ;
}
else
{
DrawTriangle ( lineCoords [ 2 ] , lineCoords [ 1 ] , lineCoords [ 0 ] , lineColor ) ;
DrawTriangle ( lineCoords [ 5 ] , lineCoords [ 4 ] , lineCoords [ 3 ] , lineColor ) ;
}
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return value ;
}
// List View control
int GuiListView ( Rectangle bounds , const char * text , int * scrollIndex , int active )
{
int itemsCount = 0 ;
const char * * items = NULL ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( text ! = NULL ) items = GuiTextSplit ( text , & itemsCount , NULL ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return GuiListViewEx ( bounds , items , itemsCount , NULL , scrollIndex , active ) ;
}
// List View control with extended parameters
int GuiListViewEx ( Rectangle bounds , const char * * text , int count , int * focus , int * scrollIndex , int active )
{
GuiControlState state = guiState ;
int itemFocused = ( focus = = NULL ) ? - 1 : * focus ;
int itemSelected = active ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Check if we need a scroll bar
bool useScrollBar = false ;
if ( ( GuiGetStyle ( LISTVIEW , LIST_ITEMS_HEIGHT ) + GuiGetStyle ( LISTVIEW , LIST_ITEMS_PADDING ) ) * count > bounds . height ) useScrollBar = true ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Define base item rectangle [0]
Rectangle itemBounds = { 0 } ;
itemBounds . x = bounds . x + GuiGetStyle ( LISTVIEW , LIST_ITEMS_PADDING ) ;
itemBounds . y = bounds . y + GuiGetStyle ( LISTVIEW , LIST_ITEMS_PADDING ) + GuiGetStyle ( DEFAULT , BORDER_WIDTH ) ;
itemBounds . width = bounds . width - 2 * GuiGetStyle ( LISTVIEW , LIST_ITEMS_PADDING ) - GuiGetStyle ( DEFAULT , BORDER_WIDTH ) ;
itemBounds . height = ( float ) GuiGetStyle ( LISTVIEW , LIST_ITEMS_HEIGHT ) ;
if ( useScrollBar ) itemBounds . width - = GuiGetStyle ( LISTVIEW , SCROLLBAR_WIDTH ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Get items on the list
int visibleItems = ( int ) bounds . height / ( GuiGetStyle ( LISTVIEW , LIST_ITEMS_HEIGHT ) + GuiGetStyle ( LISTVIEW , LIST_ITEMS_PADDING ) ) ;
if ( visibleItems > count ) visibleItems = count ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
int startIndex = ( scrollIndex = = NULL ) ? 0 : * scrollIndex ;
if ( ( startIndex < 0 ) | | ( startIndex > ( count - visibleItems ) ) ) startIndex = 0 ;
int endIndex = startIndex + visibleItems ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
if ( ( state ! = GUI_STATE_DISABLED ) & & ! guiLocked )
{
Vector2 mousePoint = GetMousePosition ( ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Check mouse inside list view
if ( CheckCollisionPointRec ( mousePoint , bounds ) )
{
state = GUI_STATE_FOCUSED ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Check focused and selected item
for ( int i = 0 ; i < visibleItems ; i + + )
{
if ( CheckCollisionPointRec ( mousePoint , itemBounds ) )
{
itemFocused = startIndex + i ;
if ( IsMouseButtonPressed ( MOUSE_LEFT_BUTTON ) )
{
if ( itemSelected = = ( startIndex + i ) ) itemSelected = - 1 ;
else itemSelected = startIndex + i ;
}
break ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update item rectangle y position for next item
itemBounds . y + = ( GuiGetStyle ( LISTVIEW , LIST_ITEMS_HEIGHT ) + GuiGetStyle ( LISTVIEW , LIST_ITEMS_PADDING ) ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( useScrollBar )
{
int wheelMove = ( int ) GetMouseWheelMove ( ) ;
startIndex - = wheelMove ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( startIndex < 0 ) startIndex = 0 ;
else if ( startIndex > ( count - visibleItems ) ) startIndex = count - visibleItems ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
endIndex = startIndex + visibleItems ;
if ( endIndex > count ) endIndex = count ;
}
}
else itemFocused = - 1 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Reset item rectangle y to [0]
itemBounds . y = bounds . y + GuiGetStyle ( LISTVIEW , LIST_ITEMS_PADDING ) + GuiGetStyle ( DEFAULT , BORDER_WIDTH ) ;
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
GuiDrawRectangle ( bounds , GuiGetStyle ( DEFAULT , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( LISTVIEW , BORDER + state * 3 ) ) , guiAlpha ) , GetColor ( GuiGetStyle ( DEFAULT , BACKGROUND_COLOR ) ) ) ; // Draw background
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw visible items
for ( int i = 0 ; ( ( i < visibleItems ) & & ( text ! = NULL ) ) ; i + + )
{
if ( state = = GUI_STATE_DISABLED )
{
if ( ( startIndex + i ) = = itemSelected ) GuiDrawRectangle ( itemBounds , GuiGetStyle ( LISTVIEW , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( LISTVIEW , BORDER_COLOR_DISABLED ) ) , guiAlpha ) , Fade ( GetColor ( GuiGetStyle ( LISTVIEW , BASE_COLOR_DISABLED ) ) , guiAlpha ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiDrawText ( text [ startIndex + i ] , GetTextBounds ( DEFAULT , itemBounds ) , GuiGetStyle ( LISTVIEW , TEXT_ALIGNMENT ) , Fade ( GetColor ( GuiGetStyle ( LISTVIEW , TEXT_COLOR_DISABLED ) ) , guiAlpha ) ) ;
}
else
{
if ( ( startIndex + i ) = = itemSelected )
{
// Draw item selected
GuiDrawRectangle ( itemBounds , GuiGetStyle ( LISTVIEW , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( LISTVIEW , BORDER_COLOR_PRESSED ) ) , guiAlpha ) , Fade ( GetColor ( GuiGetStyle ( LISTVIEW , BASE_COLOR_PRESSED ) ) , guiAlpha ) ) ;
GuiDrawText ( text [ startIndex + i ] , GetTextBounds ( DEFAULT , itemBounds ) , GuiGetStyle ( LISTVIEW , TEXT_ALIGNMENT ) , Fade ( GetColor ( GuiGetStyle ( LISTVIEW , TEXT_COLOR_PRESSED ) ) , guiAlpha ) ) ;
}
else if ( ( startIndex + i ) = = itemFocused )
{
// Draw item focused
GuiDrawRectangle ( itemBounds , GuiGetStyle ( LISTVIEW , BORDER_WIDTH ) , Fade ( GetColor ( GuiGetStyle ( LISTVIEW , BORDER_COLOR_FOCUSED ) ) , guiAlpha ) , Fade ( GetColor ( GuiGetStyle ( LISTVIEW , BASE_COLOR_FOCUSED ) ) , guiAlpha ) ) ;
GuiDrawText ( text [ startIndex + i ] , GetTextBounds ( DEFAULT , itemBounds ) , GuiGetStyle ( LISTVIEW , TEXT_ALIGNMENT ) , Fade ( GetColor ( GuiGetStyle ( LISTVIEW , TEXT_COLOR_FOCUSED ) ) , guiAlpha ) ) ;
}
else
{
// Draw item normal
GuiDrawText ( text [ startIndex + i ] , GetTextBounds ( DEFAULT , itemBounds ) , GuiGetStyle ( LISTVIEW , TEXT_ALIGNMENT ) , Fade ( GetColor ( GuiGetStyle ( LISTVIEW , TEXT_COLOR_NORMAL ) ) , guiAlpha ) ) ;
}
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update item rectangle y position for next item
itemBounds . y + = ( GuiGetStyle ( LISTVIEW , LIST_ITEMS_HEIGHT ) + GuiGetStyle ( LISTVIEW , LIST_ITEMS_PADDING ) ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( useScrollBar )
{
Rectangle scrollBarBounds = {
bounds . x + bounds . width - GuiGetStyle ( LISTVIEW , BORDER_WIDTH ) - GuiGetStyle ( LISTVIEW , SCROLLBAR_WIDTH ) ,
bounds . y + GuiGetStyle ( LISTVIEW , BORDER_WIDTH ) , ( float ) GuiGetStyle ( LISTVIEW , SCROLLBAR_WIDTH ) ,
bounds . height - 2 * GuiGetStyle ( DEFAULT , BORDER_WIDTH )
} ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Calculate percentage of visible items and apply same percentage to scrollbar
float percentVisible = ( float ) ( endIndex - startIndex ) / count ;
float sliderSize = bounds . height * percentVisible ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
int prevSliderSize = GuiGetStyle ( SCROLLBAR , SCROLL_SLIDER_SIZE ) ; // Save default slider size
int prevScrollSpeed = GuiGetStyle ( SCROLLBAR , SCROLL_SPEED ) ; // Save default scroll speed
GuiSetStyle ( SCROLLBAR , SCROLL_SLIDER_SIZE , ( int ) sliderSize ) ; // Change slider size
GuiSetStyle ( SCROLLBAR , SCROLL_SPEED , count - visibleItems ) ; // Change scroll speed
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
startIndex = GuiScrollBar ( scrollBarBounds , startIndex , 0 , count - visibleItems ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiSetStyle ( SCROLLBAR , SCROLL_SPEED , prevScrollSpeed ) ; // Reset scroll speed to default
GuiSetStyle ( SCROLLBAR , SCROLL_SLIDER_SIZE , prevSliderSize ) ; // Reset slider size to default
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( focus ! = NULL ) * focus = itemFocused ;
if ( scrollIndex ! = NULL ) * scrollIndex = startIndex ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return itemSelected ;
}
// Color Panel control
Color GuiColorPanelEx ( Rectangle bounds , Color color , float hue )
{
GuiControlState state = guiState ;
Vector2 pickerSelector = { 0 } ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Vector3 vcolor = { ( float ) color . r / 255.0f , ( float ) color . g / 255.0f , ( float ) color . b / 255.0f } ;
Vector3 hsv = ConvertRGBtoHSV ( vcolor ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
pickerSelector . x = bounds . x + ( float ) hsv . y * bounds . width ; // HSV: Saturation
pickerSelector . y = bounds . y + ( 1.0f - ( float ) hsv . z ) * bounds . height ; // HSV: Value
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Vector3 maxHue = { hue > = 0.0f ? hue : hsv . x , 1.0f , 1.0f } ;
Vector3 rgbHue = ConvertHSVtoRGB ( maxHue ) ;
Color maxHueCol = { ( unsigned char ) ( 255.0f * rgbHue . x ) ,
2021-06-01 13:20:04 +00:00
( unsigned char ) ( 255.0f * rgbHue . y ) ,
( unsigned char ) ( 255.0f * rgbHue . z ) , 255 } ;
2021-05-14 05:59:33 +00:00
const Color colWhite = { 255 , 255 , 255 , 255 } ;
const Color colBlack = { 0 , 0 , 0 , 255 } ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
if ( ( state ! = GUI_STATE_DISABLED ) & & ! guiLocked )
{
Vector2 mousePoint = GetMousePosition ( ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( CheckCollisionPointRec ( mousePoint , bounds ) )
{
if ( IsMouseButtonDown ( MOUSE_LEFT_BUTTON ) )
{
state = GUI_STATE_PRESSED ;
pickerSelector = mousePoint ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Calculate color from picker
Vector2 colorPick = { pickerSelector . x - bounds . x , pickerSelector . y - bounds . y } ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
colorPick . x / = ( float ) bounds . width ; // Get normalized value on x
colorPick . y / = ( float ) bounds . height ; // Get normalized value on y
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
hsv . y = colorPick . x ;
hsv . z = 1.0f - colorPick . y ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Vector3 rgb = ConvertHSVtoRGB ( hsv ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// NOTE: Vector3ToColor() only available on raylib 1.8.1
color = RAYGUI_CLITERAL ( Color ) { ( unsigned char ) ( 255.0f * rgb . x ) ,
2021-06-01 13:20:04 +00:00
( unsigned char ) ( 255.0f * rgb . y ) ,
( unsigned char ) ( 255.0f * rgb . z ) ,
( unsigned char ) ( 255.0f * ( float ) color . a / 255.0f ) } ;
2021-05-14 05:59:33 +00:00
}
else state = GUI_STATE_FOCUSED ;
}
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
if ( state ! = GUI_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 ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// 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 , Fade ( colWhite , guiAlpha ) ) ;
}
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 ) ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiDrawRectangle ( bounds , 1 , Fade ( GetColor ( GuiGetStyle ( COLORPICKER , BORDER + state * 3 ) ) , guiAlpha ) , BLANK ) ;
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return color ;
}
Color GuiColorPanel ( Rectangle bounds , Color color )
{
return GuiColorPanelEx ( bounds , color , - 1.0f ) ;
}
// Color Bar Alpha control
// NOTE: Returns alpha value normalized [0..1]
float GuiColorBarAlpha ( Rectangle bounds , float alpha )
{
2021-06-01 13:20:04 +00:00
# define COLORBARALPHA_CHECKED_SIZE 10
2021-05-14 05:59:33 +00:00
GuiControlState state = guiState ;
Rectangle selector = { ( float ) bounds . x + alpha * bounds . width - GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) , ( float ) bounds . y - GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) , ( float ) GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_HEIGHT ) , ( float ) bounds . height + GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) * 2 } ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
if ( ( state ! = GUI_STATE_DISABLED ) & & ! guiLocked )
{
Vector2 mousePoint = GetMousePosition ( ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( CheckCollisionPointRec ( mousePoint , bounds ) | |
CheckCollisionPointRec ( mousePoint , selector ) )
{
if ( IsMouseButtonDown ( MOUSE_LEFT_BUTTON ) )
{
state = GUI_STATE_PRESSED ;
selector . x = mousePoint . x - selector . width / 2 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
alpha = ( mousePoint . x - bounds . x ) / bounds . width ;
if ( alpha < = 0.0f ) alpha = 0.0f ;
if ( alpha > = 1.0f ) alpha = 1.0f ;
//selector.x = bounds.x + (int)(((alpha - 0)/(100 - 0))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))) - selector.width/2;
}
else state = GUI_STATE_FOCUSED ;
}
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw alpha bar: checked background
if ( state ! = GUI_STATE_DISABLED )
{
int checksX = ( int ) bounds . width / COLORBARALPHA_CHECKED_SIZE ;
int checksY = ( int ) bounds . height / COLORBARALPHA_CHECKED_SIZE ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
for ( int x = 0 ; x < checksX ; x + + )
{
for ( int y = 0 ; y < checksY ; y + + )
{
Rectangle check = { bounds . x + x * COLORBARALPHA_CHECKED_SIZE , bounds . y + y * COLORBARALPHA_CHECKED_SIZE , COLORBARALPHA_CHECKED_SIZE , COLORBARALPHA_CHECKED_SIZE } ;
GuiDrawRectangle ( check , 0 , BLANK , ( ( x + y ) % 2 ) ? Fade ( Fade ( GetColor ( GuiGetStyle ( COLORPICKER , BORDER_COLOR_DISABLED ) ) , 0.4f ) , guiAlpha ) : Fade ( Fade ( GetColor ( GuiGetStyle ( COLORPICKER , BASE_COLOR_DISABLED ) ) , 0.4f ) , guiAlpha ) ) ;
}
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
DrawRectangleGradientEx ( bounds , RAYGUI_CLITERAL ( Color ) { 255 , 255 , 255 , 0 } , RAYGUI_CLITERAL ( Color ) { 255 , 255 , 255 , 0 } , Fade ( RAYGUI_CLITERAL ( Color ) { 0 , 0 , 0 , 255 } , guiAlpha ) , Fade ( RAYGUI_CLITERAL ( Color ) { 0 , 0 , 0 , 255 } , guiAlpha ) ) ;
}
else DrawRectangleGradientEx ( bounds , Fade ( GetColor ( GuiGetStyle ( COLORPICKER , BASE_COLOR_DISABLED ) ) , 0.1f ) , Fade ( GetColor ( GuiGetStyle ( COLORPICKER , BASE_COLOR_DISABLED ) ) , 0.1f ) , Fade ( GetColor ( GuiGetStyle ( COLORPICKER , BORDER_COLOR_DISABLED ) ) , guiAlpha ) , Fade ( GetColor ( GuiGetStyle ( COLORPICKER , BORDER_COLOR_DISABLED ) ) , guiAlpha ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiDrawRectangle ( bounds , 1 , Fade ( GetColor ( GuiGetStyle ( COLORPICKER , BORDER + state * 3 ) ) , guiAlpha ) , BLANK ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw alpha bar: selector
GuiDrawRectangle ( selector , 0 , BLANK , Fade ( GetColor ( GuiGetStyle ( COLORPICKER , BORDER + state * 3 ) ) , guiAlpha ) ) ;
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return alpha ;
}
// Color Bar Hue control
// NOTE: Returns hue value normalized [0..1]
float GuiColorBarHue ( Rectangle bounds , float hue )
{
GuiControlState state = guiState ;
Rectangle selector = { ( float ) bounds . x - GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) , ( float ) bounds . y + hue / 360.0f * bounds . height - GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) , ( float ) bounds . width + GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) * 2 , ( float ) GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_HEIGHT ) } ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
if ( ( state ! = GUI_STATE_DISABLED ) & & ! guiLocked )
{
Vector2 mousePoint = GetMousePosition ( ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( CheckCollisionPointRec ( mousePoint , bounds ) | |
CheckCollisionPointRec ( mousePoint , selector ) )
{
if ( IsMouseButtonDown ( MOUSE_LEFT_BUTTON ) )
{
state = GUI_STATE_PRESSED ;
selector . y = mousePoint . y - selector . height / 2 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
hue = ( mousePoint . y - bounds . y ) * 360 / bounds . height ;
if ( hue < = 0.0f ) hue = 0.0f ;
if ( hue > = 359.0f ) hue = 359.0f ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
}
else state = GUI_STATE_FOCUSED ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
/*if (IsKeyDown(KEY_UP))
{
hue - = 2.0f ;
if ( hue < = 0.0f ) hue = 0.0f ;
}
else if ( IsKeyDown ( KEY_DOWN ) )
{
hue + = 2.0f ;
if ( hue > = 360.0f ) hue = 360.0f ;
} */
}
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
if ( state ! = GUI_STATE_DISABLED )
{
// Draw hue bar:color bars
DrawRectangleGradientV ( ( int ) bounds . x + GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) / 2 , ( int ) bounds . y + GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) / 2 , ( int ) bounds . width - GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) , ( int ) bounds . height / 6 , Fade ( RAYGUI_CLITERAL ( Color ) { 255 , 0 , 0 , 255 } , guiAlpha ) , Fade ( RAYGUI_CLITERAL ( Color ) { 255 , 255 , 0 , 255 } , guiAlpha ) ) ;
DrawRectangleGradientV ( ( int ) bounds . x + GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) / 2 , ( int ) bounds . y + ( int ) bounds . height / 6 + GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) / 2 , ( int ) bounds . width - GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) , ( int ) bounds . height / 6 , Fade ( RAYGUI_CLITERAL ( Color ) { 255 , 255 , 0 , 255 } , guiAlpha ) , Fade ( RAYGUI_CLITERAL ( Color ) { 0 , 255 , 0 , 255 } , guiAlpha ) ) ;
DrawRectangleGradientV ( ( int ) bounds . x + GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) / 2 , ( int ) bounds . y + 2 * ( ( int ) bounds . height / 6 ) + GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) / 2 , ( int ) bounds . width - GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) , ( int ) bounds . height / 6 , Fade ( RAYGUI_CLITERAL ( Color ) { 0 , 255 , 0 , 255 } , guiAlpha ) , Fade ( RAYGUI_CLITERAL ( Color ) { 0 , 255 , 255 , 255 } , guiAlpha ) ) ;
DrawRectangleGradientV ( ( int ) bounds . x + GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) / 2 , ( int ) bounds . y + 3 * ( ( int ) bounds . height / 6 ) + GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) / 2 , ( int ) bounds . width - GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) , ( int ) bounds . height / 6 , Fade ( RAYGUI_CLITERAL ( Color ) { 0 , 255 , 255 , 255 } , guiAlpha ) , Fade ( RAYGUI_CLITERAL ( Color ) { 0 , 0 , 255 , 255 } , guiAlpha ) ) ;
DrawRectangleGradientV ( ( int ) bounds . x + GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) / 2 , ( int ) bounds . y + 4 * ( ( int ) bounds . height / 6 ) + GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) / 2 , ( int ) bounds . width - GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) , ( int ) bounds . height / 6 , Fade ( RAYGUI_CLITERAL ( Color ) { 0 , 0 , 255 , 255 } , guiAlpha ) , Fade ( RAYGUI_CLITERAL ( Color ) { 255 , 0 , 255 , 255 } , guiAlpha ) ) ;
DrawRectangleGradientV ( ( int ) bounds . x + GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) / 2 , ( int ) bounds . y + 5 * ( ( int ) bounds . height / 6 ) + GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) / 2 , ( int ) bounds . width - GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) , ( int ) bounds . height / 6 - GuiGetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW ) , Fade ( RAYGUI_CLITERAL ( Color ) { 255 , 0 , 255 , 255 } , guiAlpha ) , Fade ( RAYGUI_CLITERAL ( Color ) { 255 , 0 , 0 , 255 } , guiAlpha ) ) ;
}
else DrawRectangleGradientV ( ( int ) bounds . x , ( int ) bounds . y , ( int ) bounds . width , ( int ) bounds . height , Fade ( Fade ( GetColor ( GuiGetStyle ( COLORPICKER , BASE_COLOR_DISABLED ) ) , 0.1f ) , guiAlpha ) , Fade ( GetColor ( GuiGetStyle ( COLORPICKER , BORDER_COLOR_DISABLED ) ) , guiAlpha ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiDrawRectangle ( bounds , 1 , Fade ( GetColor ( GuiGetStyle ( COLORPICKER , BORDER + state * 3 ) ) , guiAlpha ) , BLANK ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw hue bar: selector
GuiDrawRectangle ( selector , 0 , BLANK , Fade ( GetColor ( GuiGetStyle ( COLORPICKER , BORDER + state * 3 ) ) , guiAlpha ) ) ;
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return hue ;
}
// TODO: Color GuiColorBarSat() [WHITE->color]
// TODO: Color GuiColorBarValue() [BLACK->color], HSV / HSL
// TODO: float GuiColorBarLuminance() [BLACK->WHITE]
// Color Picker control
// NOTE: It's divided in multiple controls:
// Color GuiColorPanel(Rectangle bounds, Color color)
// float GuiColorBarAlpha(Rectangle bounds, float alpha)
// float GuiColorBarHue(Rectangle bounds, float value)
// NOTE: bounds define GuiColorPanel() size
Color GuiColorPicker ( Rectangle bounds , Color color )
{
color = GuiColorPanel ( bounds , color ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Rectangle boundsHue = { ( float ) bounds . x + bounds . width + GuiGetStyle ( COLORPICKER , HUEBAR_PADDING ) , ( float ) bounds . y , ( float ) GuiGetStyle ( COLORPICKER , HUEBAR_WIDTH ) , ( float ) bounds . height } ;
2021-06-01 13:20:04 +00:00
//Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) };
2021-05-14 05:59:33 +00:00
Vector3 hsv = ConvertRGBtoHSV ( RAYGUI_CLITERAL ( Vector3 ) { color . r / 255.0f , color . g / 255.0f , color . b / 255.0f } ) ;
hsv . x = GuiColorBarHue ( boundsHue , hsv . x ) ;
2021-06-01 13:20:04 +00:00
//color.a = (unsigned char)(GuiColorBarAlpha(boundsAlpha, (float)color.a/255.0f)*255.0f);
2021-05-14 05:59:33 +00:00
Vector3 rgb = ConvertHSVtoRGB ( hsv ) ;
color = RAYGUI_CLITERAL ( Color ) { ( unsigned char ) roundf ( rgb . x * 255.0f ) , ( unsigned char ) roundf ( rgb . y * 255.0f ) , ( unsigned char ) roundf ( rgb . z * 255.0f ) , color . a } ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return color ;
}
// Message Box control
int GuiMessageBox ( Rectangle bounds , const char * title , const char * message , const char * buttons )
{
2021-06-01 13:20:04 +00:00
# define MESSAGEBOX_BUTTON_HEIGHT 24
# define MESSAGEBOX_BUTTON_PADDING 10
2021-05-14 05:59:33 +00:00
int clicked = - 1 ; // Returns clicked button from buttons list, 0 refers to closed window button
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
int buttonsCount = 0 ;
const char * * buttonsText = GuiTextSplit ( buttons , & buttonsCount , NULL ) ;
Rectangle buttonBounds = { 0 } ;
buttonBounds . x = bounds . x + MESSAGEBOX_BUTTON_PADDING ;
buttonBounds . y = bounds . y + bounds . height - MESSAGEBOX_BUTTON_HEIGHT - MESSAGEBOX_BUTTON_PADDING ;
buttonBounds . width = ( bounds . width - MESSAGEBOX_BUTTON_PADDING * ( buttonsCount + 1 ) ) / buttonsCount ;
buttonBounds . height = MESSAGEBOX_BUTTON_HEIGHT ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Vector2 textSize = MeasureTextEx ( guiFont , message , ( float ) GuiGetStyle ( DEFAULT , TEXT_SIZE ) , 1 ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Rectangle textBounds = { 0 } ;
textBounds . x = bounds . x + bounds . width / 2 - textSize . x / 2 ;
textBounds . y = bounds . y + WINDOW_STATUSBAR_HEIGHT + ( bounds . height - WINDOW_STATUSBAR_HEIGHT - MESSAGEBOX_BUTTON_HEIGHT - MESSAGEBOX_BUTTON_PADDING ) / 2 - textSize . y / 2 ;
textBounds . width = textSize . x ;
textBounds . height = textSize . y ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
if ( GuiWindowBox ( bounds , title ) ) clicked = 0 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
int prevTextAlignment = GuiGetStyle ( LABEL , TEXT_ALIGNMENT ) ;
GuiSetStyle ( LABEL , TEXT_ALIGNMENT , GUI_TEXT_ALIGN_CENTER ) ;
GuiLabel ( textBounds , message ) ;
GuiSetStyle ( LABEL , TEXT_ALIGNMENT , prevTextAlignment ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
prevTextAlignment = GuiGetStyle ( BUTTON , TEXT_ALIGNMENT ) ;
GuiSetStyle ( BUTTON , TEXT_ALIGNMENT , GUI_TEXT_ALIGN_CENTER ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
for ( int i = 0 ; i < buttonsCount ; i + + )
{
if ( GuiButton ( buttonBounds , buttonsText [ i ] ) ) clicked = i + 1 ;
buttonBounds . x + = ( buttonBounds . width + MESSAGEBOX_BUTTON_PADDING ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiSetStyle ( BUTTON , TEXT_ALIGNMENT , prevTextAlignment ) ;
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return clicked ;
}
// Text Input Box control, ask for text
int GuiTextInputBox ( Rectangle bounds , const char * title , const char * message , const char * buttons , char * text )
{
2021-06-01 13:20:04 +00:00
# define TEXTINPUTBOX_BUTTON_HEIGHT 24
# define TEXTINPUTBOX_BUTTON_PADDING 10
# define TEXTINPUTBOX_HEIGHT 30
# define TEXTINPUTBOX_MAX_TEXT_LENGTH 256
2021-05-14 05:59:33 +00:00
// Used to enable text edit mode
// WARNING: No more than one GuiTextInputBox() should be open at the same time
static bool textEditMode = false ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
int btnIndex = - 1 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
int buttonsCount = 0 ;
const char * * buttonsText = GuiTextSplit ( buttons , & buttonsCount , NULL ) ;
Rectangle buttonBounds = { 0 } ;
buttonBounds . x = bounds . x + TEXTINPUTBOX_BUTTON_PADDING ;
buttonBounds . y = bounds . y + bounds . height - TEXTINPUTBOX_BUTTON_HEIGHT - TEXTINPUTBOX_BUTTON_PADDING ;
buttonBounds . width = ( bounds . width - TEXTINPUTBOX_BUTTON_PADDING * ( buttonsCount + 1 ) ) / buttonsCount ;
buttonBounds . height = TEXTINPUTBOX_BUTTON_HEIGHT ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
int messageInputHeight = ( int ) bounds . height - WINDOW_STATUSBAR_HEIGHT - GuiGetStyle ( STATUSBAR , BORDER_WIDTH ) - TEXTINPUTBOX_BUTTON_HEIGHT - 2 * TEXTINPUTBOX_BUTTON_PADDING ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Rectangle textBounds = { 0 } ;
if ( message ! = NULL )
{
Vector2 textSize = MeasureTextEx ( guiFont , message , ( float ) GuiGetStyle ( DEFAULT , TEXT_SIZE ) , 1 ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
textBounds . x = bounds . x + bounds . width / 2 - textSize . x / 2 ;
textBounds . y = bounds . y + WINDOW_STATUSBAR_HEIGHT + messageInputHeight / 4 - textSize . y / 2 ;
textBounds . width = textSize . x ;
textBounds . height = textSize . y ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Rectangle textBoxBounds = { 0 } ;
textBoxBounds . x = bounds . x + TEXTINPUTBOX_BUTTON_PADDING ;
textBoxBounds . y = bounds . y + WINDOW_STATUSBAR_HEIGHT - TEXTINPUTBOX_HEIGHT / 2 ;
if ( message = = NULL ) textBoxBounds . y + = messageInputHeight / 2 ;
else textBoxBounds . y + = ( messageInputHeight / 2 + messageInputHeight / 4 ) ;
textBoxBounds . width = bounds . width - TEXTINPUTBOX_BUTTON_PADDING * 2 ;
textBoxBounds . height = TEXTINPUTBOX_HEIGHT ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
if ( GuiWindowBox ( bounds , title ) ) btnIndex = 0 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw message if available
if ( message ! = NULL )
{
int prevTextAlignment = GuiGetStyle ( LABEL , TEXT_ALIGNMENT ) ;
GuiSetStyle ( LABEL , TEXT_ALIGNMENT , GUI_TEXT_ALIGN_CENTER ) ;
GuiLabel ( textBounds , message ) ;
GuiSetStyle ( LABEL , TEXT_ALIGNMENT , prevTextAlignment ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( GuiTextBox ( textBoxBounds , text , TEXTINPUTBOX_MAX_TEXT_LENGTH , textEditMode ) ) textEditMode = ! textEditMode ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
int prevBtnTextAlignment = GuiGetStyle ( BUTTON , TEXT_ALIGNMENT ) ;
GuiSetStyle ( BUTTON , TEXT_ALIGNMENT , GUI_TEXT_ALIGN_CENTER ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
for ( int i = 0 ; i < buttonsCount ; i + + )
{
if ( GuiButton ( buttonBounds , buttonsText [ i ] ) ) btnIndex = i + 1 ;
buttonBounds . x + = ( buttonBounds . width + MESSAGEBOX_BUTTON_PADDING ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiSetStyle ( BUTTON , TEXT_ALIGNMENT , prevBtnTextAlignment ) ;
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return btnIndex ;
}
// Grid control
// NOTE: Returns grid mouse-hover selected cell
// About drawing lines at subpixel spacing, simple put, not easy solution:
// https://stackoverflow.com/questions/4435450/2d-opengl-drawing-lines-that-dont-exactly-fit-pixel-raster
Vector2 GuiGrid ( Rectangle bounds , float spacing , int subdivs )
{
2021-06-01 13:20:04 +00:00
# if !defined(GRID_COLOR_ALPHA)
# define GRID_COLOR_ALPHA 0.15f // Grid lines alpha amount
# endif
2021-05-14 05:59:33 +00:00
GuiControlState state = guiState ;
Vector2 mousePoint = GetMousePosition ( ) ;
Vector2 currentCell = { - 1 , - 1 } ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
int linesV = ( ( int ) ( bounds . width / spacing ) ) * subdivs + 1 ;
int linesH = ( ( int ) ( bounds . height / spacing ) ) * subdivs + 1 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Update control
//--------------------------------------------------------------------
if ( ( state ! = GUI_STATE_DISABLED ) & & ! guiLocked )
{
if ( CheckCollisionPointRec ( mousePoint , bounds ) )
{
currentCell . x = ( mousePoint . x - bounds . x ) / spacing ;
currentCell . y = ( mousePoint . y - bounds . y ) / spacing ;
}
}
//--------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw control
//--------------------------------------------------------------------
switch ( state )
{
case GUI_STATE_NORMAL :
{
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 ) ? Fade ( GetColor ( GuiGetStyle ( DEFAULT , LINE_COLOR ) ) , GRID_COLOR_ALPHA * 4 ) : Fade ( GetColor ( GuiGetStyle ( DEFAULT , LINE_COLOR ) ) , GRID_COLOR_ALPHA ) ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// 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 ) ? Fade ( GetColor ( GuiGetStyle ( DEFAULT , LINE_COLOR ) ) , GRID_COLOR_ALPHA * 4 ) : Fade ( GetColor ( GuiGetStyle ( DEFAULT , LINE_COLOR ) ) , GRID_COLOR_ALPHA ) ) ;
}
}
} break ;
default : break ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return currentCell ;
}
//----------------------------------------------------------------------------------
// Styles loading functions
//----------------------------------------------------------------------------------
// Load raygui style file (.rgs)
void GuiLoadStyle ( const char * fileName )
{
bool tryBinary = false ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Try reading the files as text file first
FILE * rgsFile = fopen ( fileName , " rt " ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( rgsFile ! = NULL )
{
char buffer [ 256 ] = { 0 } ;
fgets ( buffer , 256 , rgsFile ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( buffer [ 0 ] = = ' # ' )
{
int controlId = 0 ;
int propertyId = 0 ;
unsigned int propertyValue = 0 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
while ( ! feof ( rgsFile ) )
{
switch ( buffer [ 0 ] )
{
case ' p ' :
{
// Style property: p <control_id> <property_id> <property_value> <property_name>
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
sscanf ( buffer , " p %d %d 0x%x " , & controlId , & propertyId , & propertyValue ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiSetStyle ( controlId , propertyId , ( int ) propertyValue ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
} break ;
case ' f ' :
{
// Style font: f <gen_font_size> <charmap_file> <font_file>
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
int fontSize = 0 ;
char charmapFileName [ 256 ] = { 0 } ;
char fontFileName [ 256 ] = { 0 } ;
sscanf ( buffer , " f %d %s %[^ \r \n ]s " , & fontSize , charmapFileName , fontFileName ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Font font = { 0 } ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( charmapFileName [ 0 ] ! = ' 0 ' )
{
// Load characters from charmap file,
// expected '\n' separated list of integer values
char * charValues = LoadFileText ( charmapFileName ) ;
if ( charValues ! = NULL )
{
int charsCount = 0 ;
const char * * chars = TextSplit ( charValues , ' \n ' , & charsCount ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
int * values = ( int * ) RAYGUI_MALLOC ( charsCount * sizeof ( int ) ) ;
for ( int i = 0 ; i < charsCount ; i + + ) values [ i ] = TextToInteger ( chars [ i ] ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
font = LoadFontEx ( TextFormat ( " %s/%s " , GetDirectoryPath ( fileName ) , fontFileName ) , fontSize , values , charsCount ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
RAYGUI_FREE ( values ) ;
}
}
else font = LoadFontEx ( TextFormat ( " %s/%s " , GetDirectoryPath ( fileName ) , fontFileName ) , fontSize , NULL , 0 ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( ( font . texture . id > 0 ) & & ( font . charsCount > 0 ) ) GuiSetFont ( font ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
} break ;
default : break ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
fgets ( buffer , 256 , rgsFile ) ;
}
}
else tryBinary = true ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
fclose ( rgsFile ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( tryBinary )
{
rgsFile = fopen ( fileName , " rb " ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( rgsFile = = NULL ) return ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
char signature [ 5 ] = " " ;
short version = 0 ;
short reserved = 0 ;
int propertiesCount = 0 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
fread ( signature , 1 , 4 , rgsFile ) ;
fread ( & version , 1 , sizeof ( short ) , rgsFile ) ;
fread ( & reserved , 1 , sizeof ( short ) , rgsFile ) ;
fread ( & propertiesCount , 1 , sizeof ( int ) , rgsFile ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( ( signature [ 0 ] = = ' r ' ) & &
( signature [ 1 ] = = ' G ' ) & &
( signature [ 2 ] = = ' S ' ) & &
( signature [ 3 ] = = ' ' ) )
{
short controlId = 0 ;
short propertyId = 0 ;
int propertyValue = 0 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
for ( int i = 0 ; i < propertiesCount ; i + + )
{
fread ( & controlId , 1 , sizeof ( short ) , rgsFile ) ;
fread ( & propertyId , 1 , sizeof ( short ) , rgsFile ) ;
fread ( & propertyValue , 1 , sizeof ( int ) , rgsFile ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( controlId = = 0 ) // DEFAULT control
{
// If a DEFAULT property is loaded, it is propagated to all controls
// NOTE: All DEFAULT properties should be defined first in the file
GuiSetStyle ( 0 , ( int ) propertyId , propertyValue ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( propertyId < NUM_PROPS_DEFAULT ) for ( int i = 1 ; i < NUM_CONTROLS ; i + + ) GuiSetStyle ( i , ( int ) propertyId , propertyValue ) ;
}
else GuiSetStyle ( ( int ) controlId , ( int ) propertyId , propertyValue ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Font loading is highly dependant on raylib API to load font data and image
// TODO: Find some mechanism to support it in standalone mode
# if !defined(RAYGUI_STANDALONE)
// Load custom font if available
int fontDataSize = 0 ;
fread ( & fontDataSize , 1 , sizeof ( int ) , rgsFile ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( fontDataSize > 0 )
{
Font font = { 0 } ;
int fontType = 0 ; // 0-Normal, 1-SDF
Rectangle whiteRec = { 0 } ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
fread ( & font . baseSize , 1 , sizeof ( int ) , rgsFile ) ;
fread ( & font . charsCount , 1 , sizeof ( int ) , rgsFile ) ;
fread ( & fontType , 1 , sizeof ( int ) , rgsFile ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Load font white rectangle
fread ( & whiteRec , 1 , sizeof ( Rectangle ) , rgsFile ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Load font image parameters
int fontImageSize = 0 ;
fread ( & fontImageSize , 1 , sizeof ( int ) , rgsFile ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( fontImageSize > 0 )
{
Image imFont = { 0 } ;
imFont . mipmaps = 1 ;
fread ( & imFont . width , 1 , sizeof ( int ) , rgsFile ) ;
fread ( & imFont . height , 1 , sizeof ( int ) , rgsFile ) ;
fread ( & imFont . format , 1 , sizeof ( int ) , rgsFile ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
imFont . data = ( unsigned char * ) RAYGUI_MALLOC ( fontImageSize ) ;
fread ( imFont . data , 1 , fontImageSize , rgsFile ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
font . texture = LoadTextureFromImage ( imFont ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
UnloadImage ( imFont ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Load font recs data
font . recs = ( Rectangle * ) RAYGUI_CALLOC ( font . charsCount , sizeof ( Rectangle ) ) ;
for ( int i = 0 ; i < font . charsCount ; i + + ) fread ( & font . recs [ i ] , 1 , sizeof ( Rectangle ) , rgsFile ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Load font chars info data
font . chars = ( CharInfo * ) RAYGUI_CALLOC ( font . charsCount , sizeof ( CharInfo ) ) ;
for ( int i = 0 ; i < font . charsCount ; i + + )
{
fread ( & font . chars [ i ] . value , 1 , sizeof ( int ) , rgsFile ) ;
fread ( & font . chars [ i ] . offsetX , 1 , sizeof ( int ) , rgsFile ) ;
fread ( & font . chars [ i ] . offsetY , 1 , sizeof ( int ) , rgsFile ) ;
fread ( & font . chars [ i ] . advanceX , 1 , sizeof ( int ) , rgsFile ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
GuiSetFont ( font ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Set font texture source rectangle to be used as white texture to draw shapes
// NOTE: This way, all gui can be draw using a single draw call
if ( ( whiteRec . width ! = 0 ) & & ( whiteRec . height ! = 0 ) ) SetShapesTexture ( font . texture , whiteRec ) ;
}
# endif
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
fclose ( rgsFile ) ;
}
}
// Load style default over global style
void GuiLoadStyleDefault ( void )
{
// We set this variable first to avoid cyclic function calls
// when calling GuiSetStyle() and GuiGetStyle()
guiStyleLoaded = true ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Initialize default LIGHT style property values
GuiSetStyle ( DEFAULT , BORDER_COLOR_NORMAL , 0x838383ff ) ;
GuiSetStyle ( DEFAULT , BASE_COLOR_NORMAL , 0xc9c9c9ff ) ;
GuiSetStyle ( DEFAULT , TEXT_COLOR_NORMAL , 0x686868ff ) ;
GuiSetStyle ( DEFAULT , BORDER_COLOR_FOCUSED , 0x5bb2d9ff ) ;
GuiSetStyle ( DEFAULT , BASE_COLOR_FOCUSED , 0xc9effeff ) ;
GuiSetStyle ( DEFAULT , TEXT_COLOR_FOCUSED , 0x6c9bbcff ) ;
GuiSetStyle ( DEFAULT , BORDER_COLOR_PRESSED , 0x0492c7ff ) ;
GuiSetStyle ( DEFAULT , BASE_COLOR_PRESSED , 0x97e8ffff ) ;
GuiSetStyle ( DEFAULT , TEXT_COLOR_PRESSED , 0x368bafff ) ;
GuiSetStyle ( DEFAULT , BORDER_COLOR_DISABLED , 0xb5c1c2ff ) ;
GuiSetStyle ( DEFAULT , BASE_COLOR_DISABLED , 0xe6e9e9ff ) ;
GuiSetStyle ( DEFAULT , TEXT_COLOR_DISABLED , 0xaeb7b8ff ) ;
GuiSetStyle ( DEFAULT , BORDER_WIDTH , 1 ) ; // WARNING: Some controls use other values
GuiSetStyle ( DEFAULT , TEXT_PADDING , 0 ) ; // WARNING: Some controls use other values
GuiSetStyle ( DEFAULT , TEXT_ALIGNMENT , GUI_TEXT_ALIGN_CENTER ) ; // WARNING: Some controls use other values
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Initialize control-specific property values
// NOTE: Those properties are in default list but require specific values by control type
GuiSetStyle ( LABEL , TEXT_ALIGNMENT , GUI_TEXT_ALIGN_LEFT ) ;
GuiSetStyle ( BUTTON , BORDER_WIDTH , 2 ) ;
GuiSetStyle ( SLIDER , TEXT_PADDING , 5 ) ;
GuiSetStyle ( CHECKBOX , TEXT_PADDING , 5 ) ;
GuiSetStyle ( CHECKBOX , TEXT_ALIGNMENT , GUI_TEXT_ALIGN_RIGHT ) ;
GuiSetStyle ( TEXTBOX , TEXT_PADDING , 5 ) ;
GuiSetStyle ( TEXTBOX , TEXT_ALIGNMENT , GUI_TEXT_ALIGN_LEFT ) ;
GuiSetStyle ( VALUEBOX , TEXT_PADDING , 4 ) ;
GuiSetStyle ( VALUEBOX , TEXT_ALIGNMENT , GUI_TEXT_ALIGN_LEFT ) ;
GuiSetStyle ( SPINNER , TEXT_PADDING , 4 ) ;
GuiSetStyle ( SPINNER , TEXT_ALIGNMENT , GUI_TEXT_ALIGN_LEFT ) ;
GuiSetStyle ( STATUSBAR , TEXT_PADDING , 6 ) ;
GuiSetStyle ( STATUSBAR , TEXT_ALIGNMENT , GUI_TEXT_ALIGN_LEFT ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Initialize extended property values
// NOTE: By default, extended property values are initialized to 0
GuiSetStyle ( DEFAULT , TEXT_SIZE , 10 ) ; // DEFAULT, shared by all controls
GuiSetStyle ( DEFAULT , TEXT_SPACING , 1 ) ; // DEFAULT, shared by all controls
GuiSetStyle ( DEFAULT , LINE_COLOR , 0x90abb5ff ) ; // DEFAULT specific property
GuiSetStyle ( DEFAULT , BACKGROUND_COLOR , 0xf5f5f5ff ) ; // DEFAULT specific property
GuiSetStyle ( TOGGLE , GROUP_PADDING , 2 ) ;
GuiSetStyle ( SLIDER , SLIDER_WIDTH , 15 ) ;
GuiSetStyle ( SLIDER , SLIDER_PADDING , 1 ) ;
GuiSetStyle ( PROGRESSBAR , PROGRESS_PADDING , 1 ) ;
GuiSetStyle ( CHECKBOX , CHECK_PADDING , 1 ) ;
GuiSetStyle ( COMBOBOX , COMBO_BUTTON_WIDTH , 30 ) ;
GuiSetStyle ( COMBOBOX , COMBO_BUTTON_PADDING , 2 ) ;
GuiSetStyle ( DROPDOWNBOX , ARROW_PADDING , 16 ) ;
GuiSetStyle ( DROPDOWNBOX , DROPDOWN_ITEMS_PADDING , 2 ) ;
GuiSetStyle ( TEXTBOX , TEXT_LINES_PADDING , 5 ) ;
GuiSetStyle ( TEXTBOX , TEXT_INNER_PADDING , 4 ) ;
GuiSetStyle ( TEXTBOX , COLOR_SELECTED_FG , 0xf0fffeff ) ;
GuiSetStyle ( TEXTBOX , COLOR_SELECTED_BG , 0x839affe0 ) ;
GuiSetStyle ( SPINNER , SPIN_BUTTON_WIDTH , 20 ) ;
GuiSetStyle ( SPINNER , SPIN_BUTTON_PADDING , 2 ) ;
GuiSetStyle ( SCROLLBAR , BORDER_WIDTH , 0 ) ;
GuiSetStyle ( SCROLLBAR , ARROWS_VISIBLE , 0 ) ;
GuiSetStyle ( SCROLLBAR , ARROWS_SIZE , 6 ) ;
GuiSetStyle ( SCROLLBAR , SCROLL_SLIDER_PADDING , 0 ) ;
GuiSetStyle ( SCROLLBAR , SCROLL_SLIDER_SIZE , 16 ) ;
GuiSetStyle ( SCROLLBAR , SCROLL_PADDING , 0 ) ;
GuiSetStyle ( SCROLLBAR , SCROLL_SPEED , 10 ) ;
GuiSetStyle ( LISTVIEW , LIST_ITEMS_HEIGHT , 0x1e ) ;
GuiSetStyle ( LISTVIEW , LIST_ITEMS_PADDING , 2 ) ;
GuiSetStyle ( LISTVIEW , SCROLLBAR_WIDTH , 10 ) ;
GuiSetStyle ( LISTVIEW , SCROLLBAR_SIDE , SCROLLBAR_RIGHT_SIDE ) ;
GuiSetStyle ( COLORPICKER , COLOR_SELECTOR_SIZE , 6 ) ;
GuiSetStyle ( COLORPICKER , HUEBAR_WIDTH , 0x14 ) ;
GuiSetStyle ( COLORPICKER , HUEBAR_PADDING , 0xa ) ;
GuiSetStyle ( COLORPICKER , HUEBAR_SELECTOR_HEIGHT , 6 ) ;
GuiSetStyle ( COLORPICKER , HUEBAR_SELECTOR_OVERFLOW , 2 ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
guiFont = GetFontDefault ( ) ; // Initialize default font
}
// Get text with icon id prepended
// NOTE: Useful to add icons by name id (enum) instead of
// a number that can change between ricon versions
const char * GuiIconText ( int iconId , const char * text )
{
# if defined(RAYGUI_SUPPORT_ICONS)
static char buffer [ 1024 ] = { 0 } ;
memset ( buffer , 0 , 1024 ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
sprintf ( buffer , " #%03i# " , iconId ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( text ! = NULL )
{
for ( int i = 5 ; i < 1024 ; i + + )
{
buffer [ i ] = text [ i - 5 ] ;
if ( text [ i - 5 ] = = ' \0 ' ) break ;
}
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return buffer ;
# else
return NULL ;
# endif
}
# if defined(RAYGUI_SUPPORT_ICONS)
// Get full icons data pointer
unsigned int * GuiGetIcons ( void ) { return guiIcons ; }
// Load raygui icons file (.rgi)
// NOTE: In case nameIds are required, they can be requested with loadIconsName,
// they are returned as a guiIconsName[iconsCount][RICON_MAX_NAME_LENGTH],
// guiIconsName[]][] memory should be manually freed!
char * * GuiLoadIcons ( const char * fileName , bool loadIconsName )
{
// Style File Structure (.rgi)
// ------------------------------------------------------
// Offset | Size | Type | Description
// ------------------------------------------------------
// 0 | 4 | char | Signature: "rGI "
// 4 | 2 | short | Version: 100
// 6 | 2 | short | reserved
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// 8 | 2 | short | Num icons (N)
// 10 | 2 | short | Icons size (Options: 16, 32, 64) (S)
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Icons name id (32 bytes per name id)
// foreach (icon)
// {
// 12+32*i | 32 | char | Icon NameId
// }
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Icons data: One bit per pixel, stored as unsigned int array (depends on icon size)
// S*S pixels/32bit per unsigned int = K unsigned int per icon
// foreach (icon)
// {
// ... | K | unsigned int | Icon Data
// }
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
FILE * rgiFile = fopen ( fileName , " rb " ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
char * * guiIconsName = NULL ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( rgiFile ! = NULL )
{
char signature [ 5 ] = " " ;
short version = 0 ;
short reserved = 0 ;
short iconsCount = 0 ;
short iconsSize = 0 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
fread ( signature , 1 , 4 , rgiFile ) ;
fread ( & version , 1 , sizeof ( short ) , rgiFile ) ;
fread ( & reserved , 1 , sizeof ( short ) , rgiFile ) ;
fread ( & iconsCount , 1 , sizeof ( short ) , rgiFile ) ;
fread ( & iconsSize , 1 , sizeof ( short ) , rgiFile ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( ( signature [ 0 ] = = ' r ' ) & &
( signature [ 1 ] = = ' G ' ) & &
( signature [ 2 ] = = ' I ' ) & &
( signature [ 3 ] = = ' ' ) )
{
if ( loadIconsName )
{
guiIconsName = ( char * * ) RAYGUI_MALLOC ( iconsCount * sizeof ( char * * ) ) ;
for ( int i = 0 ; i < iconsCount ; i + + )
{
guiIconsName [ i ] = ( char * ) RAYGUI_MALLOC ( RICON_MAX_NAME_LENGTH ) ;
fread ( guiIconsName [ i ] , 32 , 1 , rgiFile ) ;
}
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Read icons data directly over guiIcons data array
fread ( guiIcons , iconsCount * ( iconsSize * iconsSize / 32 ) , sizeof ( unsigned int ) , rgiFile ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
fclose ( rgiFile ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return guiIconsName ;
}
// Draw selected icon using rectangles pixel-by-pixel
void GuiDrawIcon ( int iconId , Vector2 position , int pixelSize , Color color )
{
2021-06-01 13:20:04 +00:00
# define BIT_CHECK(a,b) ((a) & (1<<(b)))
2021-05-14 05:59:33 +00:00
for ( int i = 0 , y = 0 ; i < RICON_SIZE * RICON_SIZE / 32 ; i + + )
{
for ( int k = 0 ; k < 32 ; k + + )
{
if ( BIT_CHECK ( guiIcons [ iconId * RICON_DATA_ELEMENTS + i ] , k ) )
{
2021-06-01 13:20:04 +00:00
# if !defined(RAYGUI_STANDALONE)
2021-05-14 05:59:33 +00:00
DrawRectangle ( position . x + ( k % RICON_SIZE ) * pixelSize , position . y + y * pixelSize , pixelSize , pixelSize , color ) ;
2021-06-01 13:20:04 +00:00
# endif
2021-05-14 05:59:33 +00:00
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( ( k = = 15 ) | | ( k = = 31 ) ) y + + ;
}
}
}
// Get icon bit data
// NOTE: Bit data array grouped as unsigned int (ICON_SIZE*ICON_SIZE/32 elements)
unsigned int * GuiGetIconData ( int iconId )
{
static unsigned int iconData [ RICON_DATA_ELEMENTS ] = { 0 } ;
memset ( iconData , 0 , RICON_DATA_ELEMENTS * sizeof ( unsigned int ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( iconId < RICON_MAX_ICONS ) memcpy ( iconData , & guiIcons [ iconId * RICON_DATA_ELEMENTS ] , RICON_DATA_ELEMENTS * sizeof ( unsigned int ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return iconData ;
}
// Set icon bit data
// NOTE: Data must be provided as unsigned int array (ICON_SIZE*ICON_SIZE/32 elements)
void GuiSetIconData ( int iconId , unsigned int * data )
{
if ( iconId < RICON_MAX_ICONS ) memcpy ( & guiIcons [ iconId * RICON_DATA_ELEMENTS ] , data , RICON_DATA_ELEMENTS * sizeof ( unsigned int ) ) ;
}
// Set icon pixel value
void GuiSetIconPixel ( int iconId , int x , int y )
{
2021-06-01 13:20:04 +00:00
# define BIT_SET(a,b) ((a) |= (1<<(b)))
2021-05-14 05:59:33 +00:00
// This logic works for any RICON_SIZE pixels icons,
// For example, in case of 16x16 pixels, every 2 lines fit in one unsigned int data element
BIT_SET ( guiIcons [ iconId * RICON_DATA_ELEMENTS + y / ( sizeof ( unsigned int ) * 8 / RICON_SIZE ) ] , x + ( y % ( sizeof ( unsigned int ) * 8 / RICON_SIZE ) * RICON_SIZE ) ) ;
}
// Clear icon pixel value
void GuiClearIconPixel ( int iconId , int x , int y )
{
2021-06-01 13:20:04 +00:00
# define BIT_CLEAR(a,b) ((a) &= ~((1)<<(b)))
2021-05-14 05:59:33 +00:00
// This logic works for any RICON_SIZE pixels icons,
// For example, in case of 16x16 pixels, every 2 lines fit in one unsigned int data element
BIT_CLEAR ( guiIcons [ iconId * RICON_DATA_ELEMENTS + y / ( sizeof ( unsigned int ) * 8 / RICON_SIZE ) ] , x + ( y % ( sizeof ( unsigned int ) * 8 / RICON_SIZE ) * RICON_SIZE ) ) ;
}
// Check icon pixel value
bool GuiCheckIconPixel ( int iconId , int x , int y )
{
2021-06-01 13:20:04 +00:00
# define BIT_CHECK(a,b) ((a) & (1<<(b)))
2021-05-14 05:59:33 +00:00
return ( BIT_CHECK ( guiIcons [ iconId * 8 + y / 2 ] , x + ( y % 2 * 16 ) ) ) ;
}
# endif // RAYGUI_SUPPORT_ICONS
//----------------------------------------------------------------------------------
// Module specific Functions Definition
//----------------------------------------------------------------------------------
// Gui get text width using default font
static int GetTextWidth ( const char * text )
{
Vector2 size = { 0 } ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( ( text ! = NULL ) & & ( text [ 0 ] ! = ' \0 ' ) ) size = MeasureTextEx ( guiFont , text , ( float ) GuiGetStyle ( DEFAULT , TEXT_SIZE ) , ( float ) GuiGetStyle ( DEFAULT , TEXT_SPACING ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// TODO: Consider text icon width here???
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return ( int ) size . x ;
}
// Get text bounds considering control bounds
static Rectangle GetTextBounds ( int control , Rectangle bounds )
{
Rectangle textBounds = bounds ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
textBounds . x = bounds . x + GuiGetStyle ( control , BORDER_WIDTH ) ;
textBounds . y = bounds . y + GuiGetStyle ( control , BORDER_WIDTH ) ;
textBounds . width = bounds . width - 2 * GuiGetStyle ( control , BORDER_WIDTH ) ;
textBounds . height = bounds . height - 2 * GuiGetStyle ( control , BORDER_WIDTH ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Consider TEXT_PADDING properly, depends on control type and TEXT_ALIGNMENT
switch ( control )
{
case COMBOBOX : bounds . width - = ( GuiGetStyle ( control , COMBO_BUTTON_WIDTH ) + GuiGetStyle ( control , COMBO_BUTTON_PADDING ) ) ; break ;
case VALUEBOX : break ; // NOTE: ValueBox text value always centered, text padding applies to label
default :
{
if ( GuiGetStyle ( control , TEXT_ALIGNMENT ) = = GUI_TEXT_ALIGN_RIGHT ) textBounds . x - = GuiGetStyle ( control , TEXT_PADDING ) ;
else textBounds . x + = GuiGetStyle ( control , TEXT_PADDING ) ;
} break ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// TODO: Special cases (no label): COMBOBOX, DROPDOWNBOX, LISTVIEW (scrollbar?)
// More special cases (label side): CHECKBOX, SLIDER, VALUEBOX, SPINNER
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return textBounds ;
}
// Get text icon if provided and move text cursor
// NOTE: We support up to 999 values for iconId
static const char * GetTextIcon ( const char * text , int * iconId )
{
# if defined(RAYGUI_SUPPORT_ICONS)
* iconId = - 1 ;
if ( text [ 0 ] = = ' # ' ) // Maybe we have an icon!
{
char iconValue [ 4 ] = { 0 } ; // Maximum length for icon value: 3 digits + '\0'
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
int pos = 1 ;
while ( ( pos < 4 ) & & ( text [ pos ] > = ' 0 ' ) & & ( text [ pos ] < = ' 9 ' ) )
{
iconValue [ pos - 1 ] = text [ pos ] ;
pos + + ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( text [ pos ] = = ' # ' )
{
* iconId = TextToInteger ( iconValue ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Move text pointer after icon
// WARNING: If only icon provided, it could point to EOL character!
if ( * iconId > = 0 ) text + = ( pos + 1 ) ;
}
}
# endif
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return text ;
}
// Gui draw text using default font
static void GuiDrawText ( const char * text , Rectangle bounds , int alignment , Color tint )
{
2021-06-01 13:20:04 +00:00
# define TEXT_VALIGN_PIXEL_OFFSET(h) ((int)h%2) // Vertical alignment for pixel perfect
2021-05-14 05:59:33 +00:00
if ( ( text ! = NULL ) & & ( text [ 0 ] ! = ' \0 ' ) )
{
int iconId = 0 ;
text = GetTextIcon ( text , & iconId ) ; // Check text for icon and move cursor
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Get text position depending on alignment and iconId
//---------------------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
# define ICON_TEXT_PADDING 4
2021-05-14 05:59:33 +00:00
Vector2 position = { bounds . x , bounds . y } ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// NOTE: We get text size after icon been processed
int textWidth = GetTextWidth ( text ) ;
int textHeight = GuiGetStyle ( DEFAULT , TEXT_SIZE ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
# if defined(RAYGUI_SUPPORT_ICONS)
if ( iconId > = 0 )
{
textWidth + = RICON_SIZE ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// WARNING: If only icon provided, text could be pointing to eof character!
if ( ( text ! = NULL ) & & ( text [ 0 ] ! = ' \0 ' ) ) textWidth + = ICON_TEXT_PADDING ;
}
# endif
// Check guiTextAlign global variables
switch ( alignment )
{
case GUI_TEXT_ALIGN_LEFT :
{
position . x = bounds . x ;
position . y = bounds . y + bounds . height / 2 - textHeight / 2 + TEXT_VALIGN_PIXEL_OFFSET ( bounds . height ) ;
} break ;
case GUI_TEXT_ALIGN_CENTER :
{
position . x = bounds . x + bounds . width / 2 - textWidth / 2 ;
position . y = bounds . y + bounds . height / 2 - textHeight / 2 + TEXT_VALIGN_PIXEL_OFFSET ( bounds . height ) ;
} break ;
case GUI_TEXT_ALIGN_RIGHT :
{
position . x = bounds . x + bounds . width - textWidth ;
position . y = bounds . y + bounds . height / 2 - textHeight / 2 + TEXT_VALIGN_PIXEL_OFFSET ( bounds . height ) ;
} break ;
default : break ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// NOTE: Make sure we get pixel-perfect coordinates,
// In case of decimals we got weird text positioning
position . x = ( float ) ( ( int ) position . x ) ;
position . y = ( float ) ( ( int ) position . y ) ;
//---------------------------------------------------------------------------------
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Draw text (with icon if available)
//---------------------------------------------------------------------------------
# if defined(RAYGUI_SUPPORT_ICONS)
if ( iconId > = 0 )
{
// NOTE: We consider icon height, probably different than text size
GuiDrawIcon ( iconId , RAYGUI_CLITERAL ( Vector2 ) { position . x , bounds . y + bounds . height / 2 - RICON_SIZE / 2 + TEXT_VALIGN_PIXEL_OFFSET ( bounds . height ) } , 1 , tint ) ;
position . x + = ( RICON_SIZE + ICON_TEXT_PADDING ) ;
}
# endif
DrawTextEx ( guiFont , text , position , ( float ) GuiGetStyle ( DEFAULT , TEXT_SIZE ) , ( float ) GuiGetStyle ( DEFAULT , TEXT_SPACING ) , tint ) ;
//---------------------------------------------------------------------------------
}
}
// Gui draw rectangle using default raygui plain style with borders
static void GuiDrawRectangle ( Rectangle rec , int borderWidth , Color borderColor , Color color )
{
if ( color . a > 0 )
{
// Draw rectangle filled with color
DrawRectangle ( ( int ) rec . x , ( int ) rec . y , ( int ) rec . width , ( int ) rec . height , color ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( borderWidth > 0 )
{
// Draw rectangle border lines with color
DrawRectangle ( ( int ) rec . x , ( int ) rec . y , ( int ) rec . width , borderWidth , borderColor ) ;
DrawRectangle ( ( int ) rec . x , ( int ) rec . y + borderWidth , borderWidth , ( int ) rec . height - 2 * borderWidth , borderColor ) ;
DrawRectangle ( ( int ) rec . x + ( int ) rec . width - borderWidth , ( int ) rec . y + borderWidth , borderWidth , ( int ) rec . height - 2 * borderWidth , borderColor ) ;
DrawRectangle ( ( int ) rec . x , ( int ) rec . y + ( int ) rec . height - borderWidth , ( int ) rec . width , borderWidth , borderColor ) ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// TODO: For n-patch-based style we would need: [state] and maybe [control]
// In this case all controls drawing logic should be moved to this function... I don't like it...
}
// Split controls text into multiple strings
// Also check for multiple columns (required by GuiToggleGroup())
static const char * * GuiTextSplit ( const char * text , int * count , int * textRow )
{
// NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
// inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
// all used memory is static... it has some limitations:
// 1. Maximum number of possible split strings is set by TEXTSPLIT_MAX_TEXT_ELEMENTS
// 2. Maximum size of text to split is TEXTSPLIT_MAX_TEXT_LENGTH
// NOTE: Those definitions could be externally provided if required
2021-06-01 13:20:04 +00:00
# if !defined(TEXTSPLIT_MAX_TEXT_LENGTH)
# define TEXTSPLIT_MAX_TEXT_LENGTH 1024
# endif
# if !defined(TEXTSPLIT_MAX_TEXT_ELEMENTS)
# define TEXTSPLIT_MAX_TEXT_ELEMENTS 128
# endif
2021-05-14 05:59:33 +00:00
static const char * result [ TEXTSPLIT_MAX_TEXT_ELEMENTS ] = { NULL } ;
static char buffer [ TEXTSPLIT_MAX_TEXT_LENGTH ] = { 0 } ;
memset ( buffer , 0 , TEXTSPLIT_MAX_TEXT_LENGTH ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
result [ 0 ] = buffer ;
int counter = 1 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( textRow ! = NULL ) textRow [ 0 ] = 0 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Count how many substrings we have on text and point to every one
for ( int i = 0 ; i < TEXTSPLIT_MAX_TEXT_LENGTH ; i + + )
{
buffer [ i ] = text [ i ] ;
if ( buffer [ i ] = = ' \0 ' ) break ;
else if ( ( buffer [ i ] = = ' ; ' ) | | ( buffer [ i ] = = ' \n ' ) )
{
result [ counter ] = buffer + i + 1 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( textRow ! = NULL )
{
if ( buffer [ i ] = = ' \n ' ) textRow [ counter ] = textRow [ counter - 1 ] + 1 ;
else textRow [ counter ] = textRow [ counter - 1 ] ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
buffer [ i ] = ' \0 ' ; // Set an end of string at this point
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
counter + + ;
if ( counter = = TEXTSPLIT_MAX_TEXT_ELEMENTS ) break ;
}
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
* count = counter ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return result ;
}
// Convert color data from RGB to HSV
// NOTE: Color data should be passed normalized
static Vector3 ConvertRGBtoHSV ( Vector3 rgb )
{
Vector3 hsv = { 0 } ;
float min = 0.0f ;
float max = 0.0f ;
float delta = 0.0f ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
min = ( rgb . x < rgb . y ) ? rgb . x : rgb . y ;
min = ( min < rgb . z ) ? min : rgb . z ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
max = ( rgb . x > rgb . y ) ? rgb . x : rgb . y ;
max = ( max > rgb . z ) ? max : rgb . z ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
hsv . z = max ; // Value
delta = max - min ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( delta < 0.00001f )
{
hsv . y = 0.0f ;
hsv . x = 0.0f ; // Undefined, maybe NAN?
return hsv ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( max > 0.0f )
{
// NOTE: If max is 0, this divide would cause a crash
hsv . y = ( delta / max ) ; // Saturation
}
else
{
// NOTE: If max is 0, then r = g = b = 0, s = 0, h is undefined
hsv . y = 0.0f ;
hsv . x = 0.0f ; // Undefined, maybe NAN?
return hsv ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// NOTE: Comparing float values could not work properly
if ( rgb . x > = max ) hsv . x = ( rgb . y - rgb . z ) / delta ; // Between yellow & magenta
else
{
if ( rgb . y > = max ) hsv . x = 2.0f + ( rgb . z - rgb . x ) / delta ; // Between cyan & yellow
else hsv . x = 4.0f + ( rgb . x - rgb . y ) / delta ; // Between magenta & cyan
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
hsv . x * = 60.0f ; // Convert to degrees
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( hsv . x < 0.0f ) hsv . x + = 360.0f ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return hsv ;
}
// Convert color data from HSV to RGB
// NOTE: Color data should be passed normalized
static Vector3 ConvertHSVtoRGB ( Vector3 hsv )
{
Vector3 rgb = { 0 } ;
float hh = 0.0f , p = 0.0f , q = 0.0f , t = 0.0f , ff = 0.0f ;
long i = 0 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// NOTE: Comparing float values could not work properly
if ( hsv . y < = 0.0f )
{
rgb . x = hsv . z ;
rgb . y = hsv . z ;
rgb . z = hsv . z ;
return rgb ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
hh = hsv . x ;
if ( hh > = 360.0f ) hh = 0.0f ;
hh / = 60.0f ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
i = ( long ) hh ;
ff = hh - i ;
p = hsv . z * ( 1.0f - hsv . y ) ;
q = hsv . z * ( 1.0f - ( hsv . y * ff ) ) ;
t = hsv . z * ( 1.0f - ( hsv . y * ( 1.0f - ff ) ) ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
switch ( i )
{
case 0 :
{
rgb . x = hsv . z ;
rgb . y = t ;
rgb . z = p ;
} break ;
case 1 :
{
rgb . x = q ;
rgb . y = hsv . z ;
rgb . z = p ;
} break ;
case 2 :
{
rgb . x = p ;
rgb . y = hsv . z ;
rgb . z = t ;
} break ;
case 3 :
{
rgb . x = p ;
rgb . y = q ;
rgb . z = hsv . z ;
} break ;
case 4 :
{
rgb . x = t ;
rgb . y = p ;
rgb . z = hsv . z ;
} break ;
case 5 :
default :
{
rgb . x = hsv . z ;
rgb . y = p ;
rgb . z = q ;
} break ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return rgb ;
}
# if defined(RAYGUI_STANDALONE)
// Returns a Color struct from hexadecimal value
static Color GetColor ( int hexValue )
{
Color color ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
color . r = ( unsigned char ) ( hexValue > > 24 ) & 0xFF ;
color . g = ( unsigned char ) ( hexValue > > 16 ) & 0xFF ;
color . b = ( unsigned char ) ( hexValue > > 8 ) & 0xFF ;
color . a = ( unsigned char ) hexValue & 0xFF ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return color ;
}
// Returns hexadecimal value for a Color
static int ColorToInt ( Color color )
{
return ( ( ( int ) color . r < < 24 ) | ( ( int ) color . g < < 16 ) | ( ( int ) color . b < < 8 ) | ( int ) color . a ) ;
}
// Check if point is inside rectangle
static bool CheckCollisionPointRec ( Vector2 point , Rectangle rec )
{
bool collision = false ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( ( point . x > = rec . x ) & & ( point . x < = ( rec . x + rec . width ) ) & &
( point . y > = rec . y ) & & ( point . y < = ( rec . y + rec . height ) ) ) collision = true ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return collision ;
}
// Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
static Color Fade ( Color color , float alpha )
{
if ( alpha < 0.0f ) alpha = 0.0f ;
else if ( alpha > 1.0f ) alpha = 1.0f ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
Color result = { color . r , color . g , color . b , ( unsigned char ) ( 255.0f * alpha ) } ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return result ;
}
// Formatting of text with variables to 'embed'
static const char * TextFormat ( const char * text , . . . )
{
2021-06-01 13:20:04 +00:00
# define MAX_FORMATTEXT_LENGTH 64
2021-05-14 05:59:33 +00:00
static char buffer [ MAX_FORMATTEXT_LENGTH ] ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
va_list args ;
va_start ( args , text ) ;
vsprintf ( buffer , text , args ) ;
va_end ( args ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return buffer ;
}
// Draw rectangle with vertical gradient fill color
// NOTE: This function is only used by GuiColorPicker()
static void DrawRectangleGradientV ( int posX , int posY , int width , int height , Color color1 , Color color2 )
{
Rectangle bounds = { ( float ) posX , ( float ) posY , ( float ) width , ( float ) height } ;
DrawRectangleGradientEx ( bounds , color1 , color2 , color2 , color1 ) ;
}
# define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH 1024 // Size of static buffer: TextSplit()
# define TEXTSPLIT_MAX_SUBSTRINGS_COUNT 128 // Size of static pointers array: TextSplit()
// Split string into multiple strings
const char * * TextSplit ( const char * text , char delimiter , int * count )
{
// NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
// inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
// all used memory is static... it has some limitations:
// 1. Maximum number of possible split strings is set by TEXTSPLIT_MAX_SUBSTRINGS_COUNT
// 2. Maximum size of text to split is TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
static const char * result [ TEXTSPLIT_MAX_SUBSTRINGS_COUNT ] = { NULL } ;
static char buffer [ TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH ] = { 0 } ;
memset ( buffer , 0 , TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
result [ 0 ] = buffer ;
int counter = 0 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( text ! = NULL )
{
counter = 1 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
// Count how many substrings we have on text and point to every one
for ( int i = 0 ; i < TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH ; i + + )
{
buffer [ i ] = text [ i ] ;
if ( buffer [ i ] = = ' \0 ' ) break ;
else if ( buffer [ i ] = = delimiter )
{
buffer [ i ] = ' \0 ' ; // Set an end of string at this point
result [ counter ] = buffer + i + 1 ;
counter + + ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( counter = = TEXTSPLIT_MAX_SUBSTRINGS_COUNT ) break ;
}
}
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
* count = counter ;
return result ;
}
// Get integer value from text
// NOTE: This function replaces atoi() [stdlib.h]
static int TextToInteger ( const char * text )
{
int value = 0 ;
int sign = 1 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( ( text [ 0 ] = = ' + ' ) | | ( text [ 0 ] = = ' - ' ) )
{
if ( text [ 0 ] = = ' - ' ) sign = - 1 ;
text + + ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
for ( int i = 0 ; ( ( text [ i ] > = ' 0 ' ) & & ( text [ i ] < = ' 9 ' ) ) ; + + i ) value = value * 10 + ( int ) ( text [ i ] - ' 0 ' ) ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return value * sign ;
}
// Encode codepoint into utf8 text (char array length returned as parameter)
static const char * CodepointToUtf8 ( int codepoint , int * byteLength )
{
static char utf8 [ 6 ] = { 0 } ;
int length = 0 ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
if ( codepoint < = 0x7f )
{
utf8 [ 0 ] = ( char ) codepoint ;
length = 1 ;
}
else if ( codepoint < = 0x7ff )
{
utf8 [ 0 ] = ( char ) ( ( ( codepoint > > 6 ) & 0x1f ) | 0xc0 ) ;
utf8 [ 1 ] = ( char ) ( ( codepoint & 0x3f ) | 0x80 ) ;
length = 2 ;
}
else if ( codepoint < = 0xffff )
{
utf8 [ 0 ] = ( char ) ( ( ( codepoint > > 12 ) & 0x0f ) | 0xe0 ) ;
utf8 [ 1 ] = ( char ) ( ( ( codepoint > > 6 ) & 0x3f ) | 0x80 ) ;
utf8 [ 2 ] = ( char ) ( ( codepoint & 0x3f ) | 0x80 ) ;
length = 3 ;
}
else if ( codepoint < = 0x10ffff )
{
utf8 [ 0 ] = ( char ) ( ( ( codepoint > > 18 ) & 0x07 ) | 0xf0 ) ;
utf8 [ 1 ] = ( char ) ( ( ( codepoint > > 12 ) & 0x3f ) | 0x80 ) ;
utf8 [ 2 ] = ( char ) ( ( ( codepoint > > 6 ) & 0x3f ) | 0x80 ) ;
utf8 [ 3 ] = ( char ) ( ( codepoint & 0x3f ) | 0x80 ) ;
length = 4 ;
}
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
* byteLength = length ;
2021-06-01 13:20:04 +00:00
2021-05-14 05:59:33 +00:00
return utf8 ;
}
# endif // RAYGUI_STANDALONE
# endif // RAYGUI_IMPLEMENTATION
2021-06-01 13:20:04 +00:00
# if defined(__cplusplus)
} // Prevents name mangling of functions
# endif
# endif // RAYGUI_H