raygui-widget
raygui.h
1 /*******************************************************************************************
2 *
3 * raygui v4.1-dev - A simple and easy-to-use immediate-mode gui library
4 *
5 * DESCRIPTION:
6 * raygui is a tools-dev-focused immediate-mode-gui library based on raylib but also
7 * available as a standalone library, as long as input and drawing functions are provided.
8 *
9 * FEATURES:
10 * - Immediate-mode gui, minimal retained data
11 * - +25 controls provided (basic and advanced)
12 * - Styling system for colors, font and metrics
13 * - Icons supported, embedded as a 1-bit icons pack
14 * - Standalone mode option (custom input/graphics backend)
15 * - Multiple support tools provided for raygui development
16 *
17 * POSSIBLE IMPROVEMENTS:
18 * - Better standalone mode API for easy plug of custom backends
19 * - Externalize required inputs, allow user easier customization
20 *
21 * LIMITATIONS:
22 * - No editable multi-line word-wraped text box supported
23 * - No auto-layout mechanism, up to the user to define controls position and size
24 * - Standalone mode requires library modification and some user work to plug another backend
25 *
26 * NOTES:
27 * - WARNING: GuiLoadStyle() and GuiLoadStyle{Custom}() functions, allocate memory for
28 * font atlas recs and glyphs, freeing that memory is (usually) up to the user,
29 * no unload function is explicitly provided... but note that GuiLoadStyleDefault() unloads
30 * by default any previously loaded font (texture, recs, glyphs).
31 * - Global UI alpha (guiAlpha) is applied inside GuiDrawRectangle() and GuiDrawText() functions
32 *
33 * CONTROLS PROVIDED:
34 * # Container/separators Controls
35 * - WindowBox --> StatusBar, Panel
36 * - GroupBox --> Line
37 * - Line
38 * - Panel --> StatusBar
39 * - ScrollPanel --> StatusBar
40 * - TabBar --> Button
41 *
42 * # Basic Controls
43 * - Label
44 * - LabelButton --> Label
45 * - Button
46 * - Toggle
47 * - ToggleGroup --> Toggle
48 * - ToggleSlider
49 * - CheckBox
50 * - ComboBox
51 * - DropdownBox
52 * - TextBox
53 * - ValueBox --> TextBox
54 * - Spinner --> Button, ValueBox
55 * - Slider
56 * - SliderBar --> Slider
57 * - ProgressBar
58 * - StatusBar
59 * - DummyRec
60 * - Grid
61 *
62 * # Advance Controls
63 * - ListView
64 * - ColorPicker --> ColorPanel, ColorBarHue
65 * - MessageBox --> Window, Label, Button
66 * - TextInputBox --> Window, Label, TextBox, Button
67 *
68 * It also provides a set of functions for styling the controls based on its properties (size, color).
69 *
70 *
71 * RAYGUI STYLE (guiStyle):
72 * raygui uses a global data array for all gui style properties (allocated on data segment by default),
73 * when a new style is loaded, it is loaded over the global style... but a default gui style could always be
74 * recovered with GuiLoadStyleDefault() function, that overwrites the current style to the default one
75 *
76 * The global style array size is fixed and depends on the number of controls and properties:
77 *
78 * static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)];
79 *
80 * guiStyle size is by default: 16*(16 + 8) = 384*4 = 1536 bytes = 1.5 KB
81 *
82 * Note that the first set of BASE properties (by default guiStyle[0..15]) belong to the generic style
83 * used for all controls, when any of those base values is set, it is automatically populated to all
84 * controls, so, specific control values overwriting generic style should be set after base values.
85 *
86 * After the first BASE set we have the EXTENDED properties (by default guiStyle[16..23]), those
87 * properties are actually common to all controls and can not be overwritten individually (like BASE ones)
88 * Some of those properties are: TEXT_SIZE, TEXT_SPACING, LINE_COLOR, BACKGROUND_COLOR
89 *
90 * Custom control properties can be defined using the EXTENDED properties for each independent control.
91 *
92 * TOOL: rGuiStyler is a visual tool to customize raygui style: github.com/raysan5/rguistyler
93 *
94 *
95 * RAYGUI ICONS (guiIcons):
96 * raygui could use a global array containing icons data (allocated on data segment by default),
97 * a custom icons set could be loaded over this array using GuiLoadIcons(), but loaded icons set
98 * must be same RAYGUI_ICON_SIZE and no more than RAYGUI_ICON_MAX_ICONS will be loaded
99 *
100 * Every icon is codified in binary form, using 1 bit per pixel, so, every 16x16 icon
101 * requires 8 integers (16*16/32) to be stored in memory.
102 *
103 * When the icon is draw, actually one quad per pixel is drawn if the bit for that pixel is set.
104 *
105 * The global icons array size is fixed and depends on the number of icons and size:
106 *
107 * static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS];
108 *
109 * guiIcons size is by default: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 KB
110 *
111 * TOOL: rGuiIcons is a visual tool to customize/create raygui icons: github.com/raysan5/rguiicons
112 *
113 * RAYGUI LAYOUT:
114 * raygui currently does not provide an auto-layout mechanism like other libraries,
115 * layouts must be defined manually on controls drawing, providing the right bounds Rectangle for it.
116 *
117 * TOOL: rGuiLayout is a visual tool to create raygui layouts: github.com/raysan5/rguilayout
118 *
119 * CONFIGURATION:
120 * #define RAYGUI_IMPLEMENTATION
121 * Generates the implementation of the library into the included file.
122 * If not defined, the library is in header only mode and can be included in other headers
123 * or source files without problems. But only ONE file should hold the implementation.
124 *
125 * #define RAYGUI_STANDALONE
126 * Avoid raylib.h header inclusion in this file. Data types defined on raylib are defined
127 * internally in the library and input management and drawing functions must be provided by
128 * the user (check library implementation for further details).
129 *
130 * #define RAYGUI_NO_ICONS
131 * Avoid including embedded ricons data (256 icons, 16x16 pixels, 1-bit per pixel, 2KB)
132 *
133 * #define RAYGUI_CUSTOM_ICONS
134 * Includes custom ricons.h header defining a set of custom icons,
135 * this file can be generated using rGuiIcons tool
136 *
137 * #define RAYGUI_DEBUG_RECS_BOUNDS
138 * Draw control bounds rectangles for debug
139 *
140 * #define RAYGUI_DEBUG_TEXT_BOUNDS
141 * Draw text bounds rectangles for debug
142 *
143 * VERSIONS HISTORY:
144 * 4.1-dev (2024) Current dev version...
145 * ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes
146 *
147 * 4.0 (12-Sep-2023) ADDED: GuiToggleSlider()
148 * ADDED: GuiColorPickerHSV() and GuiColorPanelHSV()
149 * ADDED: Multiple new icons, mostly compiler related
150 * ADDED: New DEFAULT properties: TEXT_LINE_SPACING, TEXT_ALIGNMENT_VERTICAL, TEXT_WRAP_MODE
151 * ADDED: New enum values: GuiTextAlignment, GuiTextAlignmentVertical, GuiTextWrapMode
152 * ADDED: Support loading styles with custom font charset from external file
153 * REDESIGNED: GuiTextBox(), support mouse cursor positioning
154 * REDESIGNED: GuiDrawText(), support multiline and word-wrap modes (read only)
155 * REDESIGNED: GuiProgressBar() to be more visual, progress affects border color
156 * REDESIGNED: Global alpha consideration moved to GuiDrawRectangle() and GuiDrawText()
157 * REDESIGNED: GuiScrollPanel(), get parameters by reference and return result value
158 * REDESIGNED: GuiToggleGroup(), get parameters by reference and return result value
159 * REDESIGNED: GuiComboBox(), get parameters by reference and return result value
160 * REDESIGNED: GuiCheckBox(), get parameters by reference and return result value
161 * REDESIGNED: GuiSlider(), get parameters by reference and return result value
162 * REDESIGNED: GuiSliderBar(), get parameters by reference and return result value
163 * REDESIGNED: GuiProgressBar(), get parameters by reference and return result value
164 * REDESIGNED: GuiListView(), get parameters by reference and return result value
165 * REDESIGNED: GuiColorPicker(), get parameters by reference and return result value
166 * REDESIGNED: GuiColorPanel(), get parameters by reference and return result value
167 * REDESIGNED: GuiColorBarAlpha(), get parameters by reference and return result value
168 * REDESIGNED: GuiColorBarHue(), get parameters by reference and return result value
169 * REDESIGNED: GuiGrid(), get parameters by reference and return result value
170 * REDESIGNED: GuiGrid(), added extra parameter
171 * REDESIGNED: GuiListViewEx(), change parameters order
172 * REDESIGNED: All controls return result as int value
173 * REVIEWED: GuiScrollPanel() to avoid smallish scroll-bars
174 * REVIEWED: All examples and specially controls_test_suite
175 * RENAMED: gui_file_dialog module to gui_window_file_dialog
176 * UPDATED: All styles to include ISO-8859-15 charset (as much as possible)
177 *
178 * 3.6 (10-May-2023) ADDED: New icon: SAND_TIMER
179 * ADDED: GuiLoadStyleFromMemory() (binary only)
180 * REVIEWED: GuiScrollBar() horizontal movement key
181 * REVIEWED: GuiTextBox() crash on cursor movement
182 * REVIEWED: GuiTextBox(), additional inputs support
183 * REVIEWED: GuiLabelButton(), avoid text cut
184 * REVIEWED: GuiTextInputBox(), password input
185 * REVIEWED: Local GetCodepointNext(), aligned with raylib
186 * REDESIGNED: GuiSlider*()/GuiScrollBar() to support out-of-bounds
187 *
188 * 3.5 (20-Apr-2023) ADDED: GuiTabBar(), based on GuiToggle()
189 * ADDED: Helper functions to split text in separate lines
190 * ADDED: Multiple new icons, useful for code editing tools
191 * REMOVED: Unneeded icon editing functions
192 * REMOVED: GuiTextBoxMulti(), very limited and broken
193 * REMOVED: MeasureTextEx() dependency, logic directly implemented
194 * REMOVED: DrawTextEx() dependency, logic directly implemented
195 * REVIEWED: GuiScrollBar(), improve mouse-click behaviour
196 * REVIEWED: Library header info, more info, better organized
197 * REDESIGNED: GuiTextBox() to support cursor movement
198 * REDESIGNED: GuiDrawText() to divide drawing by lines
199 *
200 * 3.2 (22-May-2022) RENAMED: Some enum values, for unification, avoiding prefixes
201 * REMOVED: GuiScrollBar(), only internal
202 * REDESIGNED: GuiPanel() to support text parameter
203 * REDESIGNED: GuiScrollPanel() to support text parameter
204 * REDESIGNED: GuiColorPicker() to support text parameter
205 * REDESIGNED: GuiColorPanel() to support text parameter
206 * REDESIGNED: GuiColorBarAlpha() to support text parameter
207 * REDESIGNED: GuiColorBarHue() to support text parameter
208 * REDESIGNED: GuiTextInputBox() to support password
209 *
210 * 3.1 (12-Jan-2022) REVIEWED: Default style for consistency (aligned with rGuiLayout v2.5 tool)
211 * REVIEWED: GuiLoadStyle() to support compressed font atlas image data and unload previous textures
212 * REVIEWED: External icons usage logic
213 * REVIEWED: GuiLine() for centered alignment when including text
214 * RENAMED: Multiple controls properties definitions to prepend RAYGUI_
215 * RENAMED: RICON_ references to RAYGUI_ICON_ for library consistency
216 * Projects updated and multiple tweaks
217 *
218 * 3.0 (04-Nov-2021) Integrated ricons data to avoid external file
219 * REDESIGNED: GuiTextBoxMulti()
220 * REMOVED: GuiImageButton*()
221 * Multiple minor tweaks and bugs corrected
222 *
223 * 2.9 (17-Mar-2021) REMOVED: Tooltip API
224 * 2.8 (03-May-2020) Centralized rectangles drawing to GuiDrawRectangle()
225 * 2.7 (20-Feb-2020) ADDED: Possible tooltips API
226 * 2.6 (09-Sep-2019) ADDED: GuiTextInputBox()
227 * REDESIGNED: GuiListView*(), GuiDropdownBox(), GuiSlider*(), GuiProgressBar(), GuiMessageBox()
228 * REVIEWED: GuiTextBox(), GuiSpinner(), GuiValueBox(), GuiLoadStyle()
229 * Replaced property INNER_PADDING by TEXT_PADDING, renamed some properties
230 * ADDED: 8 new custom styles ready to use
231 * Multiple minor tweaks and bugs corrected
232 *
233 * 2.5 (28-May-2019) Implemented extended GuiTextBox(), GuiValueBox(), GuiSpinner()
234 * 2.3 (29-Apr-2019) ADDED: rIcons auxiliar library and support for it, multiple controls reviewed
235 * Refactor all controls drawing mechanism to use control state
236 * 2.2 (05-Feb-2019) ADDED: GuiScrollBar(), GuiScrollPanel(), reviewed GuiListView(), removed Gui*Ex() controls
237 * 2.1 (26-Dec-2018) REDESIGNED: GuiCheckBox(), GuiComboBox(), GuiDropdownBox(), GuiToggleGroup() > Use combined text string
238 * REDESIGNED: Style system (breaking change)
239 * 2.0 (08-Nov-2018) ADDED: Support controls guiLock and custom fonts
240 * REVIEWED: GuiComboBox(), GuiListView()...
241 * 1.9 (09-Oct-2018) REVIEWED: GuiGrid(), GuiTextBox(), GuiTextBoxMulti(), GuiValueBox()...
242 * 1.8 (01-May-2018) Lot of rework and redesign to align with rGuiStyler and rGuiLayout
243 * 1.5 (21-Jun-2017) Working in an improved styles system
244 * 1.4 (15-Jun-2017) Rewritten all GUI functions (removed useless ones)
245 * 1.3 (12-Jun-2017) Complete redesign of style system
246 * 1.1 (01-Jun-2017) Complete review of the library
247 * 1.0 (07-Jun-2016) Converted to header-only by Ramon Santamaria.
248 * 0.9 (07-Mar-2016) Reviewed and tested by Albert Martos, Ian Eito, Sergio Martinez and Ramon Santamaria.
249 * 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria.
250 *
251 * DEPENDENCIES:
252 * raylib 5.0 - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing
253 *
254 * STANDALONE MODE:
255 * By default raygui depends on raylib mostly for the inputs and the drawing functionality but that dependency can be disabled
256 * with the config flag RAYGUI_STANDALONE. In that case is up to the user to provide another backend to cover library needs.
257 *
258 * The following functions should be redefined for a custom backend:
259 *
260 * - Vector2 GetMousePosition(void);
261 * - float GetMouseWheelMove(void);
262 * - bool IsMouseButtonDown(int button);
263 * - bool IsMouseButtonPressed(int button);
264 * - bool IsMouseButtonReleased(int button);
265 * - bool IsKeyDown(int key);
266 * - bool IsKeyPressed(int key);
267 * - int GetCharPressed(void); // -- GuiTextBox(), GuiValueBox()
268 *
269 * - void DrawRectangle(int x, int y, int width, int height, Color color); // -- GuiDrawRectangle()
270 * - void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // -- GuiColorPicker()
271 *
272 * - Font GetFontDefault(void); // -- GuiLoadStyleDefault()
273 * - Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // -- GuiLoadStyle()
274 * - Texture2D LoadTextureFromImage(Image image); // -- GuiLoadStyle(), required to load texture from embedded font atlas image
275 * - void SetShapesTexture(Texture2D tex, Rectangle rec); // -- GuiLoadStyle(), required to set shapes rec to font white rec (optimization)
276 * - char *LoadFileText(const char *fileName); // -- GuiLoadStyle(), required to load charset data
277 * - void UnloadFileText(char *text); // -- GuiLoadStyle(), required to unload charset data
278 * - const char *GetDirectoryPath(const char *filePath); // -- GuiLoadStyle(), required to find charset/font file from text .rgs
279 * - int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle(), required to load required font codepoints list
280 * - void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list
281 * - unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle()
282 *
283 * CONTRIBUTORS:
284 * Ramon Santamaria: Supervision, review, redesign, update and maintenance
285 * Vlad Adrian: Complete rewrite of GuiTextBox() to support extended features (2019)
286 * Sergio Martinez: Review, testing (2015) and redesign of multiple controls (2018)
287 * Adria Arranz: Testing and implementation of additional controls (2018)
288 * Jordi Jorba: Testing and implementation of additional controls (2018)
289 * Albert Martos: Review and testing of the library (2015)
290 * Ian Eito: Review and testing of the library (2015)
291 * Kevin Gato: Initial implementation of basic components (2014)
292 * Daniel Nicolas: Initial implementation of basic components (2014)
293 *
294 *
295 * LICENSE: zlib/libpng
296 *
297 * Copyright (c) 2014-2024 Ramon Santamaria (@raysan5)
298 *
299 * This software is provided "as-is", without any express or implied warranty. In no event
300 * will the authors be held liable for any damages arising from the use of this software.
301 *
302 * Permission is granted to anyone to use this software for any purpose, including commercial
303 * applications, and to alter it and redistribute it freely, subject to the following restrictions:
304 *
305 * 1. The origin of this software must not be misrepresented; you must not claim that you
306 * wrote the original software. If you use this software in a product, an acknowledgment
307 * in the product documentation would be appreciated but is not required.
308 *
309 * 2. Altered source versions must be plainly marked as such, and must not be misrepresented
310 * as being the original software.
311 *
312 * 3. This notice may not be removed or altered from any source distribution.
313 *
314 **********************************************************************************************/
315 
316 #ifndef RAYGUI_H
317 #define RAYGUI_H
318 
319 #define RAYGUI_VERSION_MAJOR 4
320 #define RAYGUI_VERSION_MINOR 1
321 #define RAYGUI_VERSION_PATCH 0
322 #define RAYGUI_VERSION "4.1-dev"
323 
324 #if !defined(RAYGUI_STANDALONE)
325  #include "raylib.h"
326 #endif
327 
328 // Function specifiers in case library is build/used as a shared library (Windows)
329 // NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll
330 #if defined(_WIN32)
331  #if defined(BUILD_LIBTYPE_SHARED)
332  #define RAYGUIAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll)
333  #elif defined(USE_LIBTYPE_SHARED)
334  #define RAYGUIAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll)
335  #endif
336 #endif
337 
338 // Function specifiers definition
339 #ifndef RAYGUIAPI
340  #define RAYGUIAPI // Functions defined as 'extern' by default (implicit specifiers)
341 #endif
342 
343 //----------------------------------------------------------------------------------
344 // Defines and Macros
345 //----------------------------------------------------------------------------------
346 // Allow custom memory allocators
347 #ifndef RAYGUI_MALLOC
348  #define RAYGUI_MALLOC(sz) malloc(sz)
349 #endif
350 #ifndef RAYGUI_CALLOC
351  #define RAYGUI_CALLOC(n,sz) calloc(n,sz)
352 #endif
353 #ifndef RAYGUI_FREE
354  #define RAYGUI_FREE(p) free(p)
355 #endif
356 
357 // Simple log system to avoid printf() calls if required
358 // NOTE: Avoiding those calls, also avoids const strings memory usage
359 #define RAYGUI_SUPPORT_LOG_INFO
360 #if defined(RAYGUI_SUPPORT_LOG_INFO)
361  #define RAYGUI_LOG(...) printf(__VA_ARGS__)
362 #else
363  #define RAYGUI_LOG(...)
364 #endif
365 
366 //----------------------------------------------------------------------------------
367 // Types and Structures Definition
368 // NOTE: Some types are required for RAYGUI_STANDALONE usage
369 //----------------------------------------------------------------------------------
370 #if defined(RAYGUI_STANDALONE)
371  #ifndef __cplusplus
372  // Boolean type
373  #ifndef true
374  typedef enum { false, true } bool;
375  #endif
376  #endif
377 
378  // Vector2 type
379  typedef struct Vector2 {
380  float x;
381  float y;
382  } Vector2;
383 
384  // Vector3 type // -- ConvertHSVtoRGB(), ConvertRGBtoHSV()
385  typedef struct Vector3 {
386  float x;
387  float y;
388  float z;
389  } Vector3;
390 
391  // Color type, RGBA (32bit)
392  typedef struct Color {
393  unsigned char r;
394  unsigned char g;
395  unsigned char b;
396  unsigned char a;
397  } Color;
398 
399  // Rectangle type
400  typedef struct Rectangle {
401  float x;
402  float y;
403  float width;
404  float height;
405  } Rectangle;
406 
407  // TODO: Texture2D type is very coupled to raylib, required by Font type
408  // It should be redesigned to be provided by user
409  typedef struct Texture2D {
410  unsigned int id; // OpenGL texture id
411  int width; // Texture base width
412  int height; // Texture base height
413  int mipmaps; // Mipmap levels, 1 by default
414  int format; // Data format (PixelFormat type)
415  } Texture2D;
416 
417  // Image, pixel data stored in CPU memory (RAM)
418  typedef struct Image {
419  void *data; // Image raw data
420  int width; // Image base width
421  int height; // Image base height
422  int mipmaps; // Mipmap levels, 1 by default
423  int format; // Data format (PixelFormat type)
424  } Image;
425 
426  // GlyphInfo, font characters glyphs info
427  typedef struct GlyphInfo {
428  int value; // Character value (Unicode)
429  int offsetX; // Character offset X when drawing
430  int offsetY; // Character offset Y when drawing
431  int advanceX; // Character advance position X
432  Image image; // Character image data
433  } GlyphInfo;
434 
435  // TODO: Font type is very coupled to raylib, mostly required by GuiLoadStyle()
436  // It should be redesigned to be provided by user
437  typedef struct Font {
438  int baseSize; // Base size (default chars height)
439  int glyphCount; // Number of glyph characters
440  int glyphPadding; // Padding around the glyph characters
441  Texture2D texture; // Texture atlas containing the glyphs
442  Rectangle *recs; // Rectangles in texture for the glyphs
443  GlyphInfo *glyphs; // Glyphs info data
444  } Font;
445 #endif
446 
447 // Style property
448 // NOTE: Used when exporting style as code for convenience
449 typedef struct GuiStyleProp {
450  unsigned short controlId; // Control identifier
451  unsigned short propertyId; // Property identifier
452  int propertyValue; // Property value
453 } GuiStyleProp;
454 
455 /*
456 // Controls text style -NOT USED-
457 // NOTE: Text style is defined by control
458 typedef struct GuiTextStyle {
459  unsigned int size;
460  int charSpacing;
461  int lineSpacing;
462  int alignmentH;
463  int alignmentV;
464  int padding;
465 } GuiTextStyle;
466 */
467 
468 // Gui control state
469 typedef enum {
470  STATE_NORMAL = 0,
471  STATE_FOCUSED,
472  STATE_PRESSED,
473  STATE_DISABLED
474 } GuiState;
475 
476 // Gui control text alignment
477 typedef enum {
478  TEXT_ALIGN_LEFT = 0,
479  TEXT_ALIGN_CENTER,
480  TEXT_ALIGN_RIGHT
481 } GuiTextAlignment;
482 
483 // Gui control text alignment vertical
484 // NOTE: Text vertical position inside the text bounds
485 typedef enum {
486  TEXT_ALIGN_TOP = 0,
487  TEXT_ALIGN_MIDDLE,
488  TEXT_ALIGN_BOTTOM
489 } GuiTextAlignmentVertical;
490 
491 // Gui control text wrap mode
492 // NOTE: Useful for multiline text
493 typedef enum {
494  TEXT_WRAP_NONE = 0,
495  TEXT_WRAP_CHAR,
496  TEXT_WRAP_WORD
497 } GuiTextWrapMode;
498 
499 // Gui controls
500 typedef enum {
501  // Default -> populates to all controls when set
502  DEFAULT = 0,
503 
504  // Basic controls
505  LABEL, // Used also for: LABELBUTTON
506  BUTTON,
507  TOGGLE, // Used also for: TOGGLEGROUP
508  SLIDER, // Used also for: SLIDERBAR, TOGGLESLIDER
509  PROGRESSBAR,
510  CHECKBOX,
511  COMBOBOX,
512  DROPDOWNBOX,
513  TEXTBOX, // Used also for: TEXTBOXMULTI
514  VALUEBOX,
515  SPINNER, // Uses: BUTTON, VALUEBOX
516  LISTVIEW,
517  COLORPICKER,
518  SCROLLBAR,
519  STATUSBAR
520 } GuiControl;
521 
522 // Gui base properties for every control
523 // NOTE: RAYGUI_MAX_PROPS_BASE properties (by default 16 properties)
524 typedef enum {
525  BORDER_COLOR_NORMAL = 0, // Control border color in STATE_NORMAL
526  BASE_COLOR_NORMAL, // Control base color in STATE_NORMAL
527  TEXT_COLOR_NORMAL, // Control text color in STATE_NORMAL
528  BORDER_COLOR_FOCUSED, // Control border color in STATE_FOCUSED
529  BASE_COLOR_FOCUSED, // Control base color in STATE_FOCUSED
530  TEXT_COLOR_FOCUSED, // Control text color in STATE_FOCUSED
531  BORDER_COLOR_PRESSED, // Control border color in STATE_PRESSED
532  BASE_COLOR_PRESSED, // Control base color in STATE_PRESSED
533  TEXT_COLOR_PRESSED, // Control text color in STATE_PRESSED
534  BORDER_COLOR_DISABLED, // Control border color in STATE_DISABLED
535  BASE_COLOR_DISABLED, // Control base color in STATE_DISABLED
536  TEXT_COLOR_DISABLED, // Control text color in STATE_DISABLED
537  BORDER_WIDTH, // Control border size, 0 for no border
538  //TEXT_SIZE, // Control text size (glyphs max height) -> GLOBAL for all controls
539  //TEXT_SPACING, // Control text spacing between glyphs -> GLOBAL for all controls
540  //TEXT_LINE_SPACING // Control text spacing between lines -> GLOBAL for all controls
541  TEXT_PADDING, // Control text padding, not considering border
542  TEXT_ALIGNMENT, // Control text horizontal alignment inside control text bound (after border and padding)
543  //TEXT_WRAP_MODE // Control text wrap-mode inside text bounds -> GLOBAL for all controls
544 } GuiControlProperty;
545 
546 // TODO: Which text styling properties should be global or per-control?
547 // At this moment TEXT_PADDING and TEXT_ALIGNMENT is configured and saved per control while
548 // TEXT_SIZE, TEXT_SPACING, TEXT_LINE_SPACING, TEXT_ALIGNMENT_VERTICAL, TEXT_WRAP_MODE are global and
549 // should be configured by user as needed while defining the UI layout
550 
551 // Gui extended properties depend on control
552 // NOTE: RAYGUI_MAX_PROPS_EXTENDED properties (by default, max 8 properties)
553 //----------------------------------------------------------------------------------
554 // DEFAULT extended properties
555 // NOTE: Those properties are common to all controls or global
556 // WARNING: We only have 8 slots for those properties by default!!! -> New global control: TEXT?
557 typedef enum {
558  TEXT_SIZE = 16, // Text size (glyphs max height)
559  TEXT_SPACING, // Text spacing between glyphs
560  LINE_COLOR, // Line control color
561  BACKGROUND_COLOR, // Background color
562  TEXT_LINE_SPACING, // Text spacing between lines
563  TEXT_ALIGNMENT_VERTICAL, // Text vertical alignment inside text bounds (after border and padding)
564  TEXT_WRAP_MODE // Text wrap-mode inside text bounds
565  //TEXT_DECORATION // Text decoration: 0-None, 1-Underline, 2-Line-through, 3-Overline
566  //TEXT_DECORATION_THICK // Text decoration line thickness
567 } GuiDefaultProperty;
568 
569 // Other possible text properties:
570 // TEXT_WEIGHT // Normal, Italic, Bold -> Requires specific font change
571 // TEXT_INDENT // Text indentation -> Now using TEXT_PADDING...
572 
573 // Label
574 //typedef enum { } GuiLabelProperty;
575 
576 // Button/Spinner
577 //typedef enum { } GuiButtonProperty;
578 
579 // Toggle/ToggleGroup
580 typedef enum {
581  GROUP_PADDING = 16, // ToggleGroup separation between toggles
582 } GuiToggleProperty;
583 
584 // Slider/SliderBar
585 typedef enum {
586  SLIDER_WIDTH = 16, // Slider size of internal bar
587  SLIDER_PADDING // Slider/SliderBar internal bar padding
588 } GuiSliderProperty;
589 
590 // ProgressBar
591 typedef enum {
592  PROGRESS_PADDING = 16, // ProgressBar internal padding
593 } GuiProgressBarProperty;
594 
595 // ScrollBar
596 typedef enum {
597  ARROWS_SIZE = 16, // ScrollBar arrows size
598  ARROWS_VISIBLE, // ScrollBar arrows visible
599  SCROLL_SLIDER_PADDING, // ScrollBar slider internal padding
600  SCROLL_SLIDER_SIZE, // ScrollBar slider size
601  SCROLL_PADDING, // ScrollBar scroll padding from arrows
602  SCROLL_SPEED, // ScrollBar scrolling speed
603 } GuiScrollBarProperty;
604 
605 // CheckBox
606 typedef enum {
607  CHECK_PADDING = 16 // CheckBox internal check padding
608 } GuiCheckBoxProperty;
609 
610 // ComboBox
611 typedef enum {
612  COMBO_BUTTON_WIDTH = 16, // ComboBox right button width
613  COMBO_BUTTON_SPACING // ComboBox button separation
614 } GuiComboBoxProperty;
615 
616 // DropdownBox
617 typedef enum {
618  ARROW_PADDING = 16, // DropdownBox arrow separation from border and items
619  DROPDOWN_ITEMS_SPACING, // DropdownBox items separation
620  DROPDOWN_ARROW_HIDDEN // DropdownBox arrow hidden
621 } GuiDropdownBoxProperty;
622 
623 // TextBox/TextBoxMulti/ValueBox/Spinner
624 typedef enum {
625  TEXT_READONLY = 16, // TextBox in read-only mode: 0-text editable, 1-text no-editable
626 } GuiTextBoxProperty;
627 
628 // Spinner
629 typedef enum {
630  SPIN_BUTTON_WIDTH = 16, // Spinner left/right buttons width
631  SPIN_BUTTON_SPACING, // Spinner buttons separation
632 } GuiSpinnerProperty;
633 
634 // ListView
635 typedef enum {
636  LIST_ITEMS_HEIGHT = 16, // ListView items height
637  LIST_ITEMS_SPACING, // ListView items separation
638  SCROLLBAR_WIDTH, // ListView scrollbar size (usually width)
639  SCROLLBAR_SIDE, // ListView scrollbar side (0-SCROLLBAR_LEFT_SIDE, 1-SCROLLBAR_RIGHT_SIDE)
640  LIST_ITEMS_BORDER_WIDTH // ListView items border width
641 } GuiListViewProperty;
642 
643 // ColorPicker
644 typedef enum {
645  COLOR_SELECTOR_SIZE = 16,
646  HUEBAR_WIDTH, // ColorPicker right hue bar width
647  HUEBAR_PADDING, // ColorPicker right hue bar separation from panel
648  HUEBAR_SELECTOR_HEIGHT, // ColorPicker right hue bar selector height
649  HUEBAR_SELECTOR_OVERFLOW // ColorPicker right hue bar selector overflow
650 } GuiColorPickerProperty;
651 
652 #define SCROLLBAR_LEFT_SIDE 0
653 #define SCROLLBAR_RIGHT_SIDE 1
654 
655 //----------------------------------------------------------------------------------
656 // Global Variables Definition
657 //----------------------------------------------------------------------------------
658 // ...
659 
660 //----------------------------------------------------------------------------------
661 // Module Functions Declaration
662 //----------------------------------------------------------------------------------
663 
664 #if defined(__cplusplus)
665 extern "C" { // Prevents name mangling of functions
666 #endif
667 
668 // Global gui state control functions
669 RAYGUIAPI void GuiEnable(void); // Enable gui controls (global state)
670 RAYGUIAPI void GuiDisable(void); // Disable gui controls (global state)
671 RAYGUIAPI void GuiLock(void); // Lock gui controls (global state)
672 RAYGUIAPI void GuiUnlock(void); // Unlock gui controls (global state)
673 RAYGUIAPI bool GuiIsLocked(void); // Check if gui is locked (global state)
674 RAYGUIAPI void GuiSetAlpha(float alpha); // Set gui controls alpha (global state), alpha goes from 0.0f to 1.0f
675 RAYGUIAPI void GuiSetState(int state); // Set gui state (global state)
676 RAYGUIAPI int GuiGetState(void); // Get gui state (global state)
677 
678 // Font set/get functions
679 RAYGUIAPI void GuiSetFont(Font font); // Set gui custom font (global state)
680 RAYGUIAPI Font GuiGetFont(void); // Get gui custom font (global state)
681 
682 // Style set/get functions
683 RAYGUIAPI void GuiSetStyle(int control, int property, int value); // Set one style property
684 RAYGUIAPI int GuiGetStyle(int control, int property); // Get one style property
685 
686 // Styles loading functions
687 RAYGUIAPI void GuiLoadStyle(const char *fileName); // Load style file over global style variable (.rgs)
688 RAYGUIAPI void GuiLoadStyleDefault(void); // Load style default over global style
689 
690 // Tooltips management functions
691 RAYGUIAPI void GuiEnableTooltip(void); // Enable gui tooltips (global state)
692 RAYGUIAPI void GuiDisableTooltip(void); // Disable gui tooltips (global state)
693 RAYGUIAPI void GuiSetTooltip(const char *tooltip); // Set tooltip string
694 
695 // Icons functionality
696 RAYGUIAPI const char *GuiIconText(int iconId, const char *text); // Get text with icon id prepended (if supported)
697 #if !defined(RAYGUI_NO_ICONS)
698 RAYGUIAPI void GuiSetIconScale(int scale); // Set default icon drawing size
699 RAYGUIAPI unsigned int *GuiGetIcons(void); // Get raygui icons data pointer
700 RAYGUIAPI char **GuiLoadIcons(const char *fileName, bool loadIconsName); // Load raygui icons file (.rgi) into internal icons data
701 RAYGUIAPI void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color); // Draw icon using pixel size at specified position
702 #endif
703 
704 // Controls
705 //----------------------------------------------------------------------------------------------------------
706 // Container/separator controls, useful for controls organization
707 RAYGUIAPI int GuiWindowBox(Rectangle bounds, const char *title); // Window Box control, shows a window that can be closed
708 RAYGUIAPI int GuiGroupBox(Rectangle bounds, const char *text); // Group Box control with text name
709 RAYGUIAPI int GuiLine(Rectangle bounds, const char *text); // Line separator control, could contain text
710 RAYGUIAPI int GuiPanel(Rectangle bounds, const char *text); // Panel control, useful to group controls
711 RAYGUIAPI int GuiTabBar(Rectangle bounds, const char **text, int count, int *active); // Tab Bar control, returns TAB to be closed or -1
712 RAYGUIAPI int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view); // Scroll Panel control
713 
714 // Basic controls set
715 RAYGUIAPI int GuiLabel(Rectangle bounds, const char *text); // Label control
716 RAYGUIAPI int GuiButton(Rectangle bounds, const char *text); // Button control, returns true when clicked
717 RAYGUIAPI int GuiLabelButton(Rectangle bounds, const char *text); // Label button control, returns true when clicked
718 RAYGUIAPI int GuiToggle(Rectangle bounds, const char *text, bool *active); // Toggle Button control
719 RAYGUIAPI int GuiToggleGroup(Rectangle bounds, const char *text, int *active); // Toggle Group control
720 RAYGUIAPI int GuiToggleSlider(Rectangle bounds, const char *text, int *active); // Toggle Slider control
721 RAYGUIAPI int GuiCheckBox(Rectangle bounds, const char *text, bool *checked); // Check Box control, returns true when active
722 RAYGUIAPI int GuiComboBox(Rectangle bounds, const char *text, int *active); // Combo Box control
723 
724 RAYGUIAPI int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode); // Dropdown Box control
725 RAYGUIAPI int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Spinner control
726 RAYGUIAPI int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Value Box control, updates input text with numbers
727 RAYGUIAPI int GuiValueBoxFloat(Rectangle bounds, const char* text, char *textValue, float *value, bool editMode); // Value box control for float values
728 RAYGUIAPI int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode); // Text Box control, updates input text
729 
730 RAYGUIAPI int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider control
731 RAYGUIAPI int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider Bar control
732 RAYGUIAPI int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Progress Bar control
733 RAYGUIAPI int GuiStatusBar(Rectangle bounds, const char *text); // Status Bar control, shows info text
734 RAYGUIAPI int GuiDummyRec(Rectangle bounds, const char *text); // Dummy control for placeholders
735 RAYGUIAPI int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vector2 *mouseCell); // Grid control
736 
737 // Advance controls set
738 RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active); // List View control
739 RAYGUIAPI int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollIndex, int *active, int *focus); // List View with extended parameters
740 RAYGUIAPI int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons); // Message Box control, displays a message
741 RAYGUIAPI int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive); // Text Input Box control, ask for text, supports secret
742 RAYGUIAPI int GuiColorPicker(Rectangle bounds, const char *text, Color *color); // Color Picker control (multiple color controls)
743 RAYGUIAPI int GuiColorPanel(Rectangle bounds, const char *text, Color *color); // Color Panel control
744 RAYGUIAPI int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha); // Color Bar Alpha control
745 RAYGUIAPI int GuiColorBarHue(Rectangle bounds, const char *text, float *value); // Color Bar Hue control
746 RAYGUIAPI int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Picker control that avoids conversion to RGB on each call (multiple color controls)
747 RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control that updates Hue-Saturation-Value color value, used by GuiColorPickerHSV()
748 //----------------------------------------------------------------------------------------------------------
749 
750 #if !defined(RAYGUI_NO_ICONS)
751 
752 #if !defined(RAYGUI_CUSTOM_ICONS)
753 //----------------------------------------------------------------------------------
754 // Icons enumeration
755 //----------------------------------------------------------------------------------
756 typedef enum {
757  ICON_NONE = 0,
758  ICON_FOLDER_FILE_OPEN = 1,
759  ICON_FILE_SAVE_CLASSIC = 2,
760  ICON_FOLDER_OPEN = 3,
761  ICON_FOLDER_SAVE = 4,
762  ICON_FILE_OPEN = 5,
763  ICON_FILE_SAVE = 6,
764  ICON_FILE_EXPORT = 7,
765  ICON_FILE_ADD = 8,
766  ICON_FILE_DELETE = 9,
767  ICON_FILETYPE_TEXT = 10,
768  ICON_FILETYPE_AUDIO = 11,
769  ICON_FILETYPE_IMAGE = 12,
770  ICON_FILETYPE_PLAY = 13,
771  ICON_FILETYPE_VIDEO = 14,
772  ICON_FILETYPE_INFO = 15,
773  ICON_FILE_COPY = 16,
774  ICON_FILE_CUT = 17,
775  ICON_FILE_PASTE = 18,
776  ICON_CURSOR_HAND = 19,
777  ICON_CURSOR_POINTER = 20,
778  ICON_CURSOR_CLASSIC = 21,
779  ICON_PENCIL = 22,
780  ICON_PENCIL_BIG = 23,
781  ICON_BRUSH_CLASSIC = 24,
782  ICON_BRUSH_PAINTER = 25,
783  ICON_WATER_DROP = 26,
784  ICON_COLOR_PICKER = 27,
785  ICON_RUBBER = 28,
786  ICON_COLOR_BUCKET = 29,
787  ICON_TEXT_T = 30,
788  ICON_TEXT_A = 31,
789  ICON_SCALE = 32,
790  ICON_RESIZE = 33,
791  ICON_FILTER_POINT = 34,
792  ICON_FILTER_BILINEAR = 35,
793  ICON_CROP = 36,
794  ICON_CROP_ALPHA = 37,
795  ICON_SQUARE_TOGGLE = 38,
796  ICON_SYMMETRY = 39,
797  ICON_SYMMETRY_HORIZONTAL = 40,
798  ICON_SYMMETRY_VERTICAL = 41,
799  ICON_LENS = 42,
800  ICON_LENS_BIG = 43,
801  ICON_EYE_ON = 44,
802  ICON_EYE_OFF = 45,
803  ICON_FILTER_TOP = 46,
804  ICON_FILTER = 47,
805  ICON_TARGET_POINT = 48,
806  ICON_TARGET_SMALL = 49,
807  ICON_TARGET_BIG = 50,
808  ICON_TARGET_MOVE = 51,
809  ICON_CURSOR_MOVE = 52,
810  ICON_CURSOR_SCALE = 53,
811  ICON_CURSOR_SCALE_RIGHT = 54,
812  ICON_CURSOR_SCALE_LEFT = 55,
813  ICON_UNDO = 56,
814  ICON_REDO = 57,
815  ICON_REREDO = 58,
816  ICON_MUTATE = 59,
817  ICON_ROTATE = 60,
818  ICON_REPEAT = 61,
819  ICON_SHUFFLE = 62,
820  ICON_EMPTYBOX = 63,
821  ICON_TARGET = 64,
822  ICON_TARGET_SMALL_FILL = 65,
823  ICON_TARGET_BIG_FILL = 66,
824  ICON_TARGET_MOVE_FILL = 67,
825  ICON_CURSOR_MOVE_FILL = 68,
826  ICON_CURSOR_SCALE_FILL = 69,
827  ICON_CURSOR_SCALE_RIGHT_FILL = 70,
828  ICON_CURSOR_SCALE_LEFT_FILL = 71,
829  ICON_UNDO_FILL = 72,
830  ICON_REDO_FILL = 73,
831  ICON_REREDO_FILL = 74,
832  ICON_MUTATE_FILL = 75,
833  ICON_ROTATE_FILL = 76,
834  ICON_REPEAT_FILL = 77,
835  ICON_SHUFFLE_FILL = 78,
836  ICON_EMPTYBOX_SMALL = 79,
837  ICON_BOX = 80,
838  ICON_BOX_TOP = 81,
839  ICON_BOX_TOP_RIGHT = 82,
840  ICON_BOX_RIGHT = 83,
841  ICON_BOX_BOTTOM_RIGHT = 84,
842  ICON_BOX_BOTTOM = 85,
843  ICON_BOX_BOTTOM_LEFT = 86,
844  ICON_BOX_LEFT = 87,
845  ICON_BOX_TOP_LEFT = 88,
846  ICON_BOX_CENTER = 89,
847  ICON_BOX_CIRCLE_MASK = 90,
848  ICON_POT = 91,
849  ICON_ALPHA_MULTIPLY = 92,
850  ICON_ALPHA_CLEAR = 93,
851  ICON_DITHERING = 94,
852  ICON_MIPMAPS = 95,
853  ICON_BOX_GRID = 96,
854  ICON_GRID = 97,
855  ICON_BOX_CORNERS_SMALL = 98,
856  ICON_BOX_CORNERS_BIG = 99,
857  ICON_FOUR_BOXES = 100,
858  ICON_GRID_FILL = 101,
859  ICON_BOX_MULTISIZE = 102,
860  ICON_ZOOM_SMALL = 103,
861  ICON_ZOOM_MEDIUM = 104,
862  ICON_ZOOM_BIG = 105,
863  ICON_ZOOM_ALL = 106,
864  ICON_ZOOM_CENTER = 107,
865  ICON_BOX_DOTS_SMALL = 108,
866  ICON_BOX_DOTS_BIG = 109,
867  ICON_BOX_CONCENTRIC = 110,
868  ICON_BOX_GRID_BIG = 111,
869  ICON_OK_TICK = 112,
870  ICON_CROSS = 113,
871  ICON_ARROW_LEFT = 114,
872  ICON_ARROW_RIGHT = 115,
873  ICON_ARROW_DOWN = 116,
874  ICON_ARROW_UP = 117,
875  ICON_ARROW_LEFT_FILL = 118,
876  ICON_ARROW_RIGHT_FILL = 119,
877  ICON_ARROW_DOWN_FILL = 120,
878  ICON_ARROW_UP_FILL = 121,
879  ICON_AUDIO = 122,
880  ICON_FX = 123,
881  ICON_WAVE = 124,
882  ICON_WAVE_SINUS = 125,
883  ICON_WAVE_SQUARE = 126,
884  ICON_WAVE_TRIANGULAR = 127,
885  ICON_CROSS_SMALL = 128,
886  ICON_PLAYER_PREVIOUS = 129,
887  ICON_PLAYER_PLAY_BACK = 130,
888  ICON_PLAYER_PLAY = 131,
889  ICON_PLAYER_PAUSE = 132,
890  ICON_PLAYER_STOP = 133,
891  ICON_PLAYER_NEXT = 134,
892  ICON_PLAYER_RECORD = 135,
893  ICON_MAGNET = 136,
894  ICON_LOCK_CLOSE = 137,
895  ICON_LOCK_OPEN = 138,
896  ICON_CLOCK = 139,
897  ICON_TOOLS = 140,
898  ICON_GEAR = 141,
899  ICON_GEAR_BIG = 142,
900  ICON_BIN = 143,
901  ICON_HAND_POINTER = 144,
902  ICON_LASER = 145,
903  ICON_COIN = 146,
904  ICON_EXPLOSION = 147,
905  ICON_1UP = 148,
906  ICON_PLAYER = 149,
907  ICON_PLAYER_JUMP = 150,
908  ICON_KEY = 151,
909  ICON_DEMON = 152,
910  ICON_TEXT_POPUP = 153,
911  ICON_GEAR_EX = 154,
912  ICON_CRACK = 155,
913  ICON_CRACK_POINTS = 156,
914  ICON_STAR = 157,
915  ICON_DOOR = 158,
916  ICON_EXIT = 159,
917  ICON_MODE_2D = 160,
918  ICON_MODE_3D = 161,
919  ICON_CUBE = 162,
920  ICON_CUBE_FACE_TOP = 163,
921  ICON_CUBE_FACE_LEFT = 164,
922  ICON_CUBE_FACE_FRONT = 165,
923  ICON_CUBE_FACE_BOTTOM = 166,
924  ICON_CUBE_FACE_RIGHT = 167,
925  ICON_CUBE_FACE_BACK = 168,
926  ICON_CAMERA = 169,
927  ICON_SPECIAL = 170,
928  ICON_LINK_NET = 171,
929  ICON_LINK_BOXES = 172,
930  ICON_LINK_MULTI = 173,
931  ICON_LINK = 174,
932  ICON_LINK_BROKE = 175,
933  ICON_TEXT_NOTES = 176,
934  ICON_NOTEBOOK = 177,
935  ICON_SUITCASE = 178,
936  ICON_SUITCASE_ZIP = 179,
937  ICON_MAILBOX = 180,
938  ICON_MONITOR = 181,
939  ICON_PRINTER = 182,
940  ICON_PHOTO_CAMERA = 183,
941  ICON_PHOTO_CAMERA_FLASH = 184,
942  ICON_HOUSE = 185,
943  ICON_HEART = 186,
944  ICON_CORNER = 187,
945  ICON_VERTICAL_BARS = 188,
946  ICON_VERTICAL_BARS_FILL = 189,
947  ICON_LIFE_BARS = 190,
948  ICON_INFO = 191,
949  ICON_CROSSLINE = 192,
950  ICON_HELP = 193,
951  ICON_FILETYPE_ALPHA = 194,
952  ICON_FILETYPE_HOME = 195,
953  ICON_LAYERS_VISIBLE = 196,
954  ICON_LAYERS = 197,
955  ICON_WINDOW = 198,
956  ICON_HIDPI = 199,
957  ICON_FILETYPE_BINARY = 200,
958  ICON_HEX = 201,
959  ICON_SHIELD = 202,
960  ICON_FILE_NEW = 203,
961  ICON_FOLDER_ADD = 204,
962  ICON_ALARM = 205,
963  ICON_CPU = 206,
964  ICON_ROM = 207,
965  ICON_STEP_OVER = 208,
966  ICON_STEP_INTO = 209,
967  ICON_STEP_OUT = 210,
968  ICON_RESTART = 211,
969  ICON_BREAKPOINT_ON = 212,
970  ICON_BREAKPOINT_OFF = 213,
971  ICON_BURGER_MENU = 214,
972  ICON_CASE_SENSITIVE = 215,
973  ICON_REG_EXP = 216,
974  ICON_FOLDER = 217,
975  ICON_FILE = 218,
976  ICON_SAND_TIMER = 219,
977  ICON_WARNING = 220,
978  ICON_HELP_BOX = 221,
979  ICON_INFO_BOX = 222,
980  ICON_223 = 223,
981  ICON_224 = 224,
982  ICON_225 = 225,
983  ICON_226 = 226,
984  ICON_227 = 227,
985  ICON_228 = 228,
986  ICON_229 = 229,
987  ICON_230 = 230,
988  ICON_231 = 231,
989  ICON_232 = 232,
990  ICON_233 = 233,
991  ICON_234 = 234,
992  ICON_235 = 235,
993  ICON_236 = 236,
994  ICON_237 = 237,
995  ICON_238 = 238,
996  ICON_239 = 239,
997  ICON_240 = 240,
998  ICON_241 = 241,
999  ICON_242 = 242,
1000  ICON_243 = 243,
1001  ICON_244 = 244,
1002  ICON_245 = 245,
1003  ICON_246 = 246,
1004  ICON_247 = 247,
1005  ICON_248 = 248,
1006  ICON_249 = 249,
1007  ICON_250 = 250,
1008  ICON_251 = 251,
1009  ICON_252 = 252,
1010  ICON_253 = 253,
1011  ICON_254 = 254,
1012  ICON_255 = 255,
1013 } GuiIconName;
1014 #endif
1015 
1016 #endif
1017 
1018 #if defined(__cplusplus)
1019 } // Prevents name mangling of functions
1020 #endif
1021 
1022 #endif // RAYGUI_H
1023 
1024 /***********************************************************************************
1025 *
1026 * RAYGUI IMPLEMENTATION
1027 *
1028 ************************************************************************************/
1029 
1030 #if defined(RAYGUI_IMPLEMENTATION)
1031 
1032 #include <stdio.h> // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()]
1033 #include <stdlib.h> // Required for: malloc(), calloc(), free() [GuiLoadStyle(), GuiLoadIcons()]
1034 #include <string.h> // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy()
1035 #include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()]
1036 #include <math.h> // Required for: roundf() [GuiColorPicker()]
1037 
1038 #ifdef __cplusplus
1039  #define RAYGUI_CLITERAL(name) name
1040 #else
1041  #define RAYGUI_CLITERAL(name) (name)
1042 #endif
1043 
1044 // Check if two rectangles are equal, used to validate a slider bounds as an id
1045 #ifndef CHECK_BOUNDS_ID
1046  #define CHECK_BOUNDS_ID(src, dst) ((src.x == dst.x) && (src.y == dst.y) && (src.width == dst.width) && (src.height == dst.height))
1047 #endif
1048 
1049 #if !defined(RAYGUI_NO_ICONS) && !defined(RAYGUI_CUSTOM_ICONS)
1050 
1051 // Embedded icons, no external file provided
1052 #define RAYGUI_ICON_SIZE 16 // Size of icons in pixels (squared)
1053 #define RAYGUI_ICON_MAX_ICONS 256 // Maximum number of icons
1054 #define RAYGUI_ICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id
1055 
1056 // Icons data is defined by bit array (every bit represents one pixel)
1057 // Those arrays are stored as unsigned int data arrays, so,
1058 // every array element defines 32 pixels (bits) of information
1059 // One icon is defined by 8 int, (8 int * 32 bit = 256 bit = 16*16 pixels)
1060 // NOTE: Number of elemens depend on RAYGUI_ICON_SIZE (by default 16x16 pixels)
1061 #define RAYGUI_ICON_DATA_ELEMENTS (RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32)
1062 
1063 //----------------------------------------------------------------------------------
1064 // Icons data for all gui possible icons (allocated on data segment by default)
1065 //
1066 // NOTE 1: Every icon is codified in binary form, using 1 bit per pixel, so,
1067 // every 16x16 icon requires 8 integers (16*16/32) to be stored
1068 //
1069 // NOTE 2: A different icon set could be loaded over this array using GuiLoadIcons(),
1070 // but loaded icons set must be same RAYGUI_ICON_SIZE and no more than RAYGUI_ICON_MAX_ICONS
1071 //
1072 // guiIcons size is by default: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 KB
1073 //----------------------------------------------------------------------------------
1074 static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = {
1075  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_NONE
1076  0x3ff80000, 0x2f082008, 0x2042207e, 0x40027fc2, 0x40024002, 0x40024002, 0x40024002, 0x00007ffe, // ICON_FOLDER_FILE_OPEN
1077  0x3ffe0000, 0x44226422, 0x400247e2, 0x5ffa4002, 0x57ea500a, 0x500a500a, 0x40025ffa, 0x00007ffe, // ICON_FILE_SAVE_CLASSIC
1078  0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024002, 0x44424282, 0x793e4102, 0x00000100, // ICON_FOLDER_OPEN
1079  0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024102, 0x44424102, 0x793e4282, 0x00000000, // ICON_FOLDER_SAVE
1080  0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x24442284, 0x21042104, 0x20042104, 0x00003ffc, // ICON_FILE_OPEN
1081  0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x21042104, 0x22842444, 0x20042104, 0x00003ffc, // ICON_FILE_SAVE
1082  0x3ff00000, 0x201c2010, 0x00042004, 0x20041004, 0x20844784, 0x00841384, 0x20042784, 0x00003ffc, // ICON_FILE_EXPORT
1083  0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x22042204, 0x22042f84, 0x20042204, 0x00003ffc, // ICON_FILE_ADD
1084  0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x25042884, 0x25042204, 0x20042884, 0x00003ffc, // ICON_FILE_DELETE
1085  0x3ff00000, 0x201c2010, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // ICON_FILETYPE_TEXT
1086  0x3ff00000, 0x201c2010, 0x27042004, 0x244424c4, 0x26442444, 0x20642664, 0x20042004, 0x00003ffc, // ICON_FILETYPE_AUDIO
1087  0x3ff00000, 0x201c2010, 0x26042604, 0x20042004, 0x35442884, 0x2414222c, 0x20042004, 0x00003ffc, // ICON_FILETYPE_IMAGE
1088  0x3ff00000, 0x201c2010, 0x20c42004, 0x22442144, 0x22442444, 0x20c42144, 0x20042004, 0x00003ffc, // ICON_FILETYPE_PLAY
1089  0x3ff00000, 0x3ffc2ff0, 0x3f3c2ff4, 0x3dbc2eb4, 0x3dbc2bb4, 0x3f3c2eb4, 0x3ffc2ff4, 0x00002ff4, // ICON_FILETYPE_VIDEO
1090  0x3ff00000, 0x201c2010, 0x21842184, 0x21842004, 0x21842184, 0x21842184, 0x20042184, 0x00003ffc, // ICON_FILETYPE_INFO
1091  0x0ff00000, 0x381c0810, 0x28042804, 0x28042804, 0x28042804, 0x28042804, 0x20102ffc, 0x00003ff0, // ICON_FILE_COPY
1092  0x00000000, 0x701c0000, 0x079c1e14, 0x55a000f0, 0x079c00f0, 0x701c1e14, 0x00000000, 0x00000000, // ICON_FILE_CUT
1093  0x01c00000, 0x13e41bec, 0x3f841004, 0x204420c4, 0x20442044, 0x20442044, 0x207c2044, 0x00003fc0, // ICON_FILE_PASTE
1094  0x00000000, 0x3aa00fe0, 0x2abc2aa0, 0x2aa42aa4, 0x20042aa4, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_CURSOR_HAND
1095  0x00000000, 0x003c000c, 0x030800c8, 0x30100c10, 0x10202020, 0x04400840, 0x01800280, 0x00000000, // ICON_CURSOR_POINTER
1096  0x00000000, 0x00180000, 0x01f00078, 0x03e007f0, 0x07c003e0, 0x04000e40, 0x00000000, 0x00000000, // ICON_CURSOR_CLASSIC
1097  0x00000000, 0x04000000, 0x11000a00, 0x04400a80, 0x01100220, 0x00580088, 0x00000038, 0x00000000, // ICON_PENCIL
1098  0x04000000, 0x15000a00, 0x50402880, 0x14102820, 0x05040a08, 0x015c028c, 0x007c00bc, 0x00000000, // ICON_PENCIL_BIG
1099  0x01c00000, 0x01400140, 0x01400140, 0x0ff80140, 0x0ff80808, 0x0aa80808, 0x0aa80aa8, 0x00000ff8, // ICON_BRUSH_CLASSIC
1100  0x1ffc0000, 0x5ffc7ffe, 0x40004000, 0x00807f80, 0x01c001c0, 0x01c001c0, 0x01c001c0, 0x00000080, // ICON_BRUSH_PAINTER
1101  0x00000000, 0x00800000, 0x01c00080, 0x03e001c0, 0x07f003e0, 0x036006f0, 0x000001c0, 0x00000000, // ICON_WATER_DROP
1102  0x00000000, 0x3e003800, 0x1f803f80, 0x0c201e40, 0x02080c10, 0x00840104, 0x00380044, 0x00000000, // ICON_COLOR_PICKER
1103  0x00000000, 0x07800300, 0x1fe00fc0, 0x3f883fd0, 0x0e021f04, 0x02040402, 0x00f00108, 0x00000000, // ICON_RUBBER
1104  0x00c00000, 0x02800140, 0x08200440, 0x20081010, 0x2ffe3004, 0x03f807fc, 0x00e001f0, 0x00000040, // ICON_COLOR_BUCKET
1105  0x00000000, 0x21843ffc, 0x01800180, 0x01800180, 0x01800180, 0x01800180, 0x03c00180, 0x00000000, // ICON_TEXT_T
1106  0x00800000, 0x01400180, 0x06200340, 0x0c100620, 0x1ff80c10, 0x380c1808, 0x70067004, 0x0000f80f, // ICON_TEXT_A
1107  0x78000000, 0x50004000, 0x00004800, 0x03c003c0, 0x03c003c0, 0x00100000, 0x0002000a, 0x0000000e, // ICON_SCALE
1108  0x75560000, 0x5e004002, 0x54001002, 0x41001202, 0x408200fe, 0x40820082, 0x40820082, 0x00006afe, // ICON_RESIZE
1109  0x00000000, 0x3f003f00, 0x3f003f00, 0x3f003f00, 0x00400080, 0x001c0020, 0x001c001c, 0x00000000, // ICON_FILTER_POINT
1110  0x6d800000, 0x00004080, 0x40804080, 0x40800000, 0x00406d80, 0x001c0020, 0x001c001c, 0x00000000, // ICON_FILTER_BILINEAR
1111  0x40080000, 0x1ffe2008, 0x14081008, 0x11081208, 0x10481088, 0x10081028, 0x10047ff8, 0x00001002, // ICON_CROP
1112  0x00100000, 0x3ffc0010, 0x2ab03550, 0x22b02550, 0x20b02150, 0x20302050, 0x2000fff0, 0x00002000, // ICON_CROP_ALPHA
1113  0x40000000, 0x1ff82000, 0x04082808, 0x01082208, 0x00482088, 0x00182028, 0x35542008, 0x00000002, // ICON_SQUARE_TOGGLE
1114  0x00000000, 0x02800280, 0x06c006c0, 0x0ea00ee0, 0x1e901eb0, 0x3e883e98, 0x7efc7e8c, 0x00000000, // ICON_SYMMETRY
1115  0x01000000, 0x05600100, 0x1d480d50, 0x7d423d44, 0x3d447d42, 0x0d501d48, 0x01000560, 0x00000100, // ICON_SYMMETRY_HORIZONTAL
1116  0x01800000, 0x04200240, 0x10080810, 0x00001ff8, 0x00007ffe, 0x0ff01ff8, 0x03c007e0, 0x00000180, // ICON_SYMMETRY_VERTICAL
1117  0x00000000, 0x010800f0, 0x02040204, 0x02040204, 0x07f00308, 0x1c000e00, 0x30003800, 0x00000000, // ICON_LENS
1118  0x00000000, 0x061803f0, 0x08240c0c, 0x08040814, 0x0c0c0804, 0x23f01618, 0x18002400, 0x00000000, // ICON_LENS_BIG
1119  0x00000000, 0x00000000, 0x1c7007c0, 0x638e3398, 0x1c703398, 0x000007c0, 0x00000000, 0x00000000, // ICON_EYE_ON
1120  0x00000000, 0x10002000, 0x04700fc0, 0x610e3218, 0x1c703098, 0x001007a0, 0x00000008, 0x00000000, // ICON_EYE_OFF
1121  0x00000000, 0x00007ffc, 0x40047ffc, 0x10102008, 0x04400820, 0x02800280, 0x02800280, 0x00000100, // ICON_FILTER_TOP
1122  0x00000000, 0x40027ffe, 0x10082004, 0x04200810, 0x02400240, 0x02400240, 0x01400240, 0x000000c0, // ICON_FILTER
1123  0x00800000, 0x00800080, 0x00000080, 0x3c9e0000, 0x00000000, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_POINT
1124  0x00800000, 0x00800080, 0x00800080, 0x3f7e01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_SMALL
1125  0x00800000, 0x00800080, 0x03e00080, 0x3e3e0220, 0x03e00220, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_BIG
1126  0x01000000, 0x04400280, 0x01000100, 0x43842008, 0x43849ab2, 0x01002008, 0x04400100, 0x01000280, // ICON_TARGET_MOVE
1127  0x01000000, 0x04400280, 0x01000100, 0x41042108, 0x41049ff2, 0x01002108, 0x04400100, 0x01000280, // ICON_CURSOR_MOVE
1128  0x781e0000, 0x500a4002, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x4002500a, 0x0000781e, // ICON_CURSOR_SCALE
1129  0x00000000, 0x20003c00, 0x24002800, 0x01000200, 0x00400080, 0x00140024, 0x003c0004, 0x00000000, // ICON_CURSOR_SCALE_RIGHT
1130  0x00000000, 0x0004003c, 0x00240014, 0x00800040, 0x02000100, 0x28002400, 0x3c002000, 0x00000000, // ICON_CURSOR_SCALE_LEFT
1131  0x00000000, 0x00100020, 0x10101fc8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // ICON_UNDO
1132  0x00000000, 0x08000400, 0x080813f8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // ICON_REDO
1133  0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3f902020, 0x00400020, 0x00000000, // ICON_REREDO
1134  0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3fc82010, 0x00200010, 0x00000000, // ICON_MUTATE
1135  0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18101020, 0x00100fc8, 0x00000020, // ICON_ROTATE
1136  0x00000000, 0x04000200, 0x240429fc, 0x20042204, 0x20442004, 0x3f942024, 0x00400020, 0x00000000, // ICON_REPEAT
1137  0x00000000, 0x20001000, 0x22104c0e, 0x00801120, 0x11200040, 0x4c0e2210, 0x10002000, 0x00000000, // ICON_SHUFFLE
1138  0x7ffe0000, 0x50024002, 0x44024802, 0x41024202, 0x40424082, 0x40124022, 0x4002400a, 0x00007ffe, // ICON_EMPTYBOX
1139  0x00800000, 0x03e00080, 0x08080490, 0x3c9e0808, 0x08080808, 0x03e00490, 0x00800080, 0x00000000, // ICON_TARGET
1140  0x00800000, 0x00800080, 0x00800080, 0x3ffe01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_SMALL_FILL
1141  0x00800000, 0x00800080, 0x03e00080, 0x3ffe03e0, 0x03e003e0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_BIG_FILL
1142  0x01000000, 0x07c00380, 0x01000100, 0x638c2008, 0x638cfbbe, 0x01002008, 0x07c00100, 0x01000380, // ICON_TARGET_MOVE_FILL
1143  0x01000000, 0x07c00380, 0x01000100, 0x610c2108, 0x610cfffe, 0x01002108, 0x07c00100, 0x01000380, // ICON_CURSOR_MOVE_FILL
1144  0x781e0000, 0x6006700e, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x700e6006, 0x0000781e, // ICON_CURSOR_SCALE_FILL
1145  0x00000000, 0x38003c00, 0x24003000, 0x01000200, 0x00400080, 0x000c0024, 0x003c001c, 0x00000000, // ICON_CURSOR_SCALE_RIGHT_FILL
1146  0x00000000, 0x001c003c, 0x0024000c, 0x00800040, 0x02000100, 0x30002400, 0x3c003800, 0x00000000, // ICON_CURSOR_SCALE_LEFT_FILL
1147  0x00000000, 0x00300020, 0x10301ff8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // ICON_UNDO_FILL
1148  0x00000000, 0x0c000400, 0x0c081ff8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // ICON_REDO_FILL
1149  0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3ff02060, 0x00400060, 0x00000000, // ICON_REREDO_FILL
1150  0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3ff82030, 0x00200030, 0x00000000, // ICON_MUTATE_FILL
1151  0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18301020, 0x00300ff8, 0x00000020, // ICON_ROTATE_FILL
1152  0x00000000, 0x06000200, 0x26042ffc, 0x20042204, 0x20442004, 0x3ff42064, 0x00400060, 0x00000000, // ICON_REPEAT_FILL
1153  0x00000000, 0x30001000, 0x32107c0e, 0x00801120, 0x11200040, 0x7c0e3210, 0x10003000, 0x00000000, // ICON_SHUFFLE_FILL
1154  0x00000000, 0x30043ffc, 0x24042804, 0x21042204, 0x20442084, 0x20142024, 0x3ffc200c, 0x00000000, // ICON_EMPTYBOX_SMALL
1155  0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX
1156  0x00000000, 0x23c43ffc, 0x23c423c4, 0x200423c4, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP
1157  0x00000000, 0x3e043ffc, 0x3e043e04, 0x20043e04, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP_RIGHT
1158  0x00000000, 0x20043ffc, 0x20042004, 0x3e043e04, 0x3e043e04, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_RIGHT
1159  0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x3e042004, 0x3e043e04, 0x3ffc3e04, 0x00000000, // ICON_BOX_BOTTOM_RIGHT
1160  0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x23c42004, 0x23c423c4, 0x3ffc23c4, 0x00000000, // ICON_BOX_BOTTOM
1161  0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x207c2004, 0x207c207c, 0x3ffc207c, 0x00000000, // ICON_BOX_BOTTOM_LEFT
1162  0x00000000, 0x20043ffc, 0x20042004, 0x207c207c, 0x207c207c, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_LEFT
1163  0x00000000, 0x207c3ffc, 0x207c207c, 0x2004207c, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP_LEFT
1164  0x00000000, 0x20043ffc, 0x20042004, 0x23c423c4, 0x23c423c4, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_CENTER
1165  0x7ffe0000, 0x40024002, 0x47e24182, 0x4ff247e2, 0x47e24ff2, 0x418247e2, 0x40024002, 0x00007ffe, // ICON_BOX_CIRCLE_MASK
1166  0x7fff0000, 0x40014001, 0x40014001, 0x49555ddd, 0x4945495d, 0x400149c5, 0x40014001, 0x00007fff, // ICON_POT
1167  0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x404e40ce, 0x48125432, 0x4006540e, 0x00007ffe, // ICON_ALPHA_MULTIPLY
1168  0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x5c4e40ce, 0x44124432, 0x40065c0e, 0x00007ffe, // ICON_ALPHA_CLEAR
1169  0x7ffe0000, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x00007ffe, // ICON_DITHERING
1170  0x07fe0000, 0x1ffa0002, 0x7fea000a, 0x402a402a, 0x5b2a512a, 0x5128552a, 0x40205128, 0x00007fe0, // ICON_MIPMAPS
1171  0x00000000, 0x1ff80000, 0x12481248, 0x12481ff8, 0x1ff81248, 0x12481248, 0x00001ff8, 0x00000000, // ICON_BOX_GRID
1172  0x12480000, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x00001248, // ICON_GRID
1173  0x00000000, 0x1c380000, 0x1c3817e8, 0x08100810, 0x08100810, 0x17e81c38, 0x00001c38, 0x00000000, // ICON_BOX_CORNERS_SMALL
1174  0x700e0000, 0x700e5ffa, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x5ffa700e, 0x0000700e, // ICON_BOX_CORNERS_BIG
1175  0x3f7e0000, 0x21422142, 0x21422142, 0x00003f7e, 0x21423f7e, 0x21422142, 0x3f7e2142, 0x00000000, // ICON_FOUR_BOXES
1176  0x00000000, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x00000000, // ICON_GRID_FILL
1177  0x7ffe0000, 0x7ffe7ffe, 0x77fe7000, 0x77fe77fe, 0x777e7700, 0x777e777e, 0x777e777e, 0x0000777e, // ICON_BOX_MULTISIZE
1178  0x781e0000, 0x40024002, 0x00004002, 0x01800000, 0x00000180, 0x40020000, 0x40024002, 0x0000781e, // ICON_ZOOM_SMALL
1179  0x781e0000, 0x40024002, 0x00004002, 0x03c003c0, 0x03c003c0, 0x40020000, 0x40024002, 0x0000781e, // ICON_ZOOM_MEDIUM
1180  0x781e0000, 0x40024002, 0x07e04002, 0x07e007e0, 0x07e007e0, 0x400207e0, 0x40024002, 0x0000781e, // ICON_ZOOM_BIG
1181  0x781e0000, 0x5ffa4002, 0x1ff85ffa, 0x1ff81ff8, 0x1ff81ff8, 0x5ffa1ff8, 0x40025ffa, 0x0000781e, // ICON_ZOOM_ALL
1182  0x00000000, 0x2004381c, 0x00002004, 0x00000000, 0x00000000, 0x20040000, 0x381c2004, 0x00000000, // ICON_ZOOM_CENTER
1183  0x00000000, 0x1db80000, 0x10081008, 0x10080000, 0x00001008, 0x10081008, 0x00001db8, 0x00000000, // ICON_BOX_DOTS_SMALL
1184  0x35560000, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x35562002, 0x00000000, // ICON_BOX_DOTS_BIG
1185  0x7ffe0000, 0x40024002, 0x48124ff2, 0x49924812, 0x48124992, 0x4ff24812, 0x40024002, 0x00007ffe, // ICON_BOX_CONCENTRIC
1186  0x00000000, 0x10841ffc, 0x10841084, 0x1ffc1084, 0x10841084, 0x10841084, 0x00001ffc, 0x00000000, // ICON_BOX_GRID_BIG
1187  0x00000000, 0x00000000, 0x10000000, 0x04000800, 0x01040200, 0x00500088, 0x00000020, 0x00000000, // ICON_OK_TICK
1188  0x00000000, 0x10080000, 0x04200810, 0x01800240, 0x02400180, 0x08100420, 0x00001008, 0x00000000, // ICON_CROSS
1189  0x00000000, 0x02000000, 0x00800100, 0x00200040, 0x00200010, 0x00800040, 0x02000100, 0x00000000, // ICON_ARROW_LEFT
1190  0x00000000, 0x00400000, 0x01000080, 0x04000200, 0x04000800, 0x01000200, 0x00400080, 0x00000000, // ICON_ARROW_RIGHT
1191  0x00000000, 0x00000000, 0x00000000, 0x08081004, 0x02200410, 0x00800140, 0x00000000, 0x00000000, // ICON_ARROW_DOWN
1192  0x00000000, 0x00000000, 0x01400080, 0x04100220, 0x10040808, 0x00000000, 0x00000000, 0x00000000, // ICON_ARROW_UP
1193  0x00000000, 0x02000000, 0x03800300, 0x03e003c0, 0x03e003f0, 0x038003c0, 0x02000300, 0x00000000, // ICON_ARROW_LEFT_FILL
1194  0x00000000, 0x00400000, 0x01c000c0, 0x07c003c0, 0x07c00fc0, 0x01c003c0, 0x004000c0, 0x00000000, // ICON_ARROW_RIGHT_FILL
1195  0x00000000, 0x00000000, 0x00000000, 0x0ff81ffc, 0x03e007f0, 0x008001c0, 0x00000000, 0x00000000, // ICON_ARROW_DOWN_FILL
1196  0x00000000, 0x00000000, 0x01c00080, 0x07f003e0, 0x1ffc0ff8, 0x00000000, 0x00000000, 0x00000000, // ICON_ARROW_UP_FILL
1197  0x00000000, 0x18a008c0, 0x32881290, 0x24822686, 0x26862482, 0x12903288, 0x08c018a0, 0x00000000, // ICON_AUDIO
1198  0x00000000, 0x04800780, 0x004000c0, 0x662000f0, 0x08103c30, 0x130a0e18, 0x0000318e, 0x00000000, // ICON_FX
1199  0x00000000, 0x00800000, 0x08880888, 0x2aaa0a8a, 0x0a8a2aaa, 0x08880888, 0x00000080, 0x00000000, // ICON_WAVE
1200  0x00000000, 0x00600000, 0x01080090, 0x02040108, 0x42044204, 0x24022402, 0x00001800, 0x00000000, // ICON_WAVE_SINUS
1201  0x00000000, 0x07f80000, 0x04080408, 0x04080408, 0x04080408, 0x7c0e0408, 0x00000000, 0x00000000, // ICON_WAVE_SQUARE
1202  0x00000000, 0x00000000, 0x00a00040, 0x22084110, 0x08021404, 0x00000000, 0x00000000, 0x00000000, // ICON_WAVE_TRIANGULAR
1203  0x00000000, 0x00000000, 0x04200000, 0x01800240, 0x02400180, 0x00000420, 0x00000000, 0x00000000, // ICON_CROSS_SMALL
1204  0x00000000, 0x18380000, 0x12281428, 0x10a81128, 0x112810a8, 0x14281228, 0x00001838, 0x00000000, // ICON_PLAYER_PREVIOUS
1205  0x00000000, 0x18000000, 0x11801600, 0x10181060, 0x10601018, 0x16001180, 0x00001800, 0x00000000, // ICON_PLAYER_PLAY_BACK
1206  0x00000000, 0x00180000, 0x01880068, 0x18080608, 0x06081808, 0x00680188, 0x00000018, 0x00000000, // ICON_PLAYER_PLAY
1207  0x00000000, 0x1e780000, 0x12481248, 0x12481248, 0x12481248, 0x12481248, 0x00001e78, 0x00000000, // ICON_PLAYER_PAUSE
1208  0x00000000, 0x1ff80000, 0x10081008, 0x10081008, 0x10081008, 0x10081008, 0x00001ff8, 0x00000000, // ICON_PLAYER_STOP
1209  0x00000000, 0x1c180000, 0x14481428, 0x15081488, 0x14881508, 0x14281448, 0x00001c18, 0x00000000, // ICON_PLAYER_NEXT
1210  0x00000000, 0x03c00000, 0x08100420, 0x10081008, 0x10081008, 0x04200810, 0x000003c0, 0x00000000, // ICON_PLAYER_RECORD
1211  0x00000000, 0x0c3007e0, 0x13c81818, 0x14281668, 0x14281428, 0x1c381c38, 0x08102244, 0x00000000, // ICON_MAGNET
1212  0x07c00000, 0x08200820, 0x3ff80820, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // ICON_LOCK_CLOSE
1213  0x07c00000, 0x08000800, 0x3ff80800, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // ICON_LOCK_OPEN
1214  0x01c00000, 0x0c180770, 0x3086188c, 0x60832082, 0x60034781, 0x30062002, 0x0c18180c, 0x01c00770, // ICON_CLOCK
1215  0x0a200000, 0x1b201b20, 0x04200e20, 0x04200420, 0x04700420, 0x0e700e70, 0x0e700e70, 0x04200e70, // ICON_TOOLS
1216  0x01800000, 0x3bdc318c, 0x0ff01ff8, 0x7c3e1e78, 0x1e787c3e, 0x1ff80ff0, 0x318c3bdc, 0x00000180, // ICON_GEAR
1217  0x01800000, 0x3ffc318c, 0x1c381ff8, 0x781e1818, 0x1818781e, 0x1ff81c38, 0x318c3ffc, 0x00000180, // ICON_GEAR_BIG
1218  0x00000000, 0x08080ff8, 0x08081ffc, 0x0aa80aa8, 0x0aa80aa8, 0x0aa80aa8, 0x08080aa8, 0x00000ff8, // ICON_BIN
1219  0x00000000, 0x00000000, 0x20043ffc, 0x08043f84, 0x04040f84, 0x04040784, 0x000007fc, 0x00000000, // ICON_HAND_POINTER
1220  0x00000000, 0x24400400, 0x00001480, 0x6efe0e00, 0x00000e00, 0x24401480, 0x00000400, 0x00000000, // ICON_LASER
1221  0x00000000, 0x03c00000, 0x08300460, 0x11181118, 0x11181118, 0x04600830, 0x000003c0, 0x00000000, // ICON_COIN
1222  0x00000000, 0x10880080, 0x06c00810, 0x366c07e0, 0x07e00240, 0x00001768, 0x04200240, 0x00000000, // ICON_EXPLOSION
1223  0x00000000, 0x3d280000, 0x2528252c, 0x3d282528, 0x05280528, 0x05e80528, 0x00000000, 0x00000000, // ICON_1UP
1224  0x01800000, 0x03c003c0, 0x018003c0, 0x0ff007e0, 0x0bd00bd0, 0x0a500bd0, 0x02400240, 0x02400240, // ICON_PLAYER
1225  0x01800000, 0x03c003c0, 0x118013c0, 0x03c81ff8, 0x07c003c8, 0x04400440, 0x0c080478, 0x00000000, // ICON_PLAYER_JUMP
1226  0x3ff80000, 0x30183ff8, 0x30183018, 0x3ff83ff8, 0x03000300, 0x03c003c0, 0x03e00300, 0x000003e0, // ICON_KEY
1227  0x3ff80000, 0x3ff83ff8, 0x33983ff8, 0x3ff83398, 0x3ff83ff8, 0x00000540, 0x0fe00aa0, 0x00000fe0, // ICON_DEMON
1228  0x00000000, 0x0ff00000, 0x20041008, 0x25442004, 0x10082004, 0x06000bf0, 0x00000300, 0x00000000, // ICON_TEXT_POPUP
1229  0x00000000, 0x11440000, 0x07f00be8, 0x1c1c0e38, 0x1c1c0c18, 0x07f00e38, 0x11440be8, 0x00000000, // ICON_GEAR_EX
1230  0x00000000, 0x20080000, 0x0c601010, 0x07c00fe0, 0x07c007c0, 0x0c600fe0, 0x20081010, 0x00000000, // ICON_CRACK
1231  0x00000000, 0x20080000, 0x0c601010, 0x04400fe0, 0x04405554, 0x0c600fe0, 0x20081010, 0x00000000, // ICON_CRACK_POINTS
1232  0x00000000, 0x00800080, 0x01c001c0, 0x1ffc3ffe, 0x03e007f0, 0x07f003e0, 0x0c180770, 0x00000808, // ICON_STAR
1233  0x0ff00000, 0x08180810, 0x08100818, 0x0a100810, 0x08180810, 0x08100818, 0x08100810, 0x00001ff8, // ICON_DOOR
1234  0x0ff00000, 0x08100810, 0x08100810, 0x10100010, 0x4f902010, 0x10102010, 0x08100010, 0x00000ff0, // ICON_EXIT
1235  0x00040000, 0x001f000e, 0x0ef40004, 0x12f41284, 0x0ef41214, 0x10040004, 0x7ffc3004, 0x10003000, // ICON_MODE_2D
1236  0x78040000, 0x501f600e, 0x0ef44004, 0x12f41284, 0x0ef41284, 0x10140004, 0x7ffc300c, 0x10003000, // ICON_MODE_3D
1237  0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // ICON_CUBE
1238  0x7fe00000, 0x5ff87ff0, 0x47fe4ffc, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // ICON_CUBE_FACE_TOP
1239  0x7fe00000, 0x50386030, 0x47c2483c, 0x443e443e, 0x443e443e, 0x241e75fe, 0x0c06140e, 0x000007fe, // ICON_CUBE_FACE_LEFT
1240  0x7fe00000, 0x50286030, 0x47fe4804, 0x47fe47fe, 0x47fe47fe, 0x27fe77fe, 0x0ffe17fe, 0x000007fe, // ICON_CUBE_FACE_FRONT
1241  0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x3bf27be2, 0x0bfe1bfa, 0x000007fe, // ICON_CUBE_FACE_BOTTOM
1242  0x7fe00000, 0x70286030, 0x7ffe7804, 0x7c227c02, 0x7c227c22, 0x3c127de2, 0x0c061c0a, 0x000007fe, // ICON_CUBE_FACE_RIGHT
1243  0x7fe00000, 0x6fe85ff0, 0x781e77e4, 0x7be27be2, 0x7be27be2, 0x24127be2, 0x0c06140a, 0x000007fe, // ICON_CUBE_FACE_BACK
1244  0x00000000, 0x2a0233fe, 0x22022602, 0x22022202, 0x2a022602, 0x00a033fe, 0x02080110, 0x00000000, // ICON_CAMERA
1245  0x00000000, 0x200c3ffc, 0x000c000c, 0x3ffc000c, 0x30003000, 0x30003000, 0x3ffc3004, 0x00000000, // ICON_SPECIAL
1246  0x00000000, 0x0022003e, 0x012201e2, 0x0100013e, 0x01000100, 0x79000100, 0x4f004900, 0x00007800, // ICON_LINK_NET
1247  0x00000000, 0x44007c00, 0x45004600, 0x00627cbe, 0x00620022, 0x45007cbe, 0x44004600, 0x00007c00, // ICON_LINK_BOXES
1248  0x00000000, 0x0044007c, 0x0010007c, 0x3f100010, 0x3f1021f0, 0x3f100010, 0x3f0021f0, 0x00000000, // ICON_LINK_MULTI
1249  0x00000000, 0x0044007c, 0x00440044, 0x0010007c, 0x00100010, 0x44107c10, 0x440047f0, 0x00007c00, // ICON_LINK
1250  0x00000000, 0x0044007c, 0x00440044, 0x0000007c, 0x00000010, 0x44007c10, 0x44004550, 0x00007c00, // ICON_LINK_BROKE
1251  0x02a00000, 0x22a43ffc, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // ICON_TEXT_NOTES
1252  0x3ffc0000, 0x20042004, 0x245e27c4, 0x27c42444, 0x2004201e, 0x201e2004, 0x20042004, 0x00003ffc, // ICON_NOTEBOOK
1253  0x00000000, 0x07e00000, 0x04200420, 0x24243ffc, 0x24242424, 0x24242424, 0x3ffc2424, 0x00000000, // ICON_SUITCASE
1254  0x00000000, 0x0fe00000, 0x08200820, 0x40047ffc, 0x7ffc5554, 0x40045554, 0x7ffc4004, 0x00000000, // ICON_SUITCASE_ZIP
1255  0x00000000, 0x20043ffc, 0x3ffc2004, 0x13c81008, 0x100813c8, 0x10081008, 0x1ff81008, 0x00000000, // ICON_MAILBOX
1256  0x00000000, 0x40027ffe, 0x5ffa5ffa, 0x5ffa5ffa, 0x40025ffa, 0x03c07ffe, 0x1ff81ff8, 0x00000000, // ICON_MONITOR
1257  0x0ff00000, 0x6bfe7ffe, 0x7ffe7ffe, 0x68167ffe, 0x08106816, 0x08100810, 0x0ff00810, 0x00000000, // ICON_PRINTER
1258  0x3ff80000, 0xfffe2008, 0x870a8002, 0x904a888a, 0x904a904a, 0x870a888a, 0xfffe8002, 0x00000000, // ICON_PHOTO_CAMERA
1259  0x0fc00000, 0xfcfe0cd8, 0x8002fffe, 0x84428382, 0x84428442, 0x80028382, 0xfffe8002, 0x00000000, // ICON_PHOTO_CAMERA_FLASH
1260  0x00000000, 0x02400180, 0x08100420, 0x20041008, 0x23c42004, 0x22442244, 0x3ffc2244, 0x00000000, // ICON_HOUSE
1261  0x00000000, 0x1c700000, 0x3ff83ef8, 0x3ff83ff8, 0x0fe01ff0, 0x038007c0, 0x00000100, 0x00000000, // ICON_HEART
1262  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xe000c000, // ICON_CORNER
1263  0x00000000, 0x14001c00, 0x15c01400, 0x15401540, 0x155c1540, 0x15541554, 0x1ddc1554, 0x00000000, // ICON_VERTICAL_BARS
1264  0x00000000, 0x03000300, 0x1b001b00, 0x1b601b60, 0x1b6c1b60, 0x1b6c1b6c, 0x1b6c1b6c, 0x00000000, // ICON_VERTICAL_BARS_FILL
1265  0x00000000, 0x00000000, 0x403e7ffe, 0x7ffe403e, 0x7ffe0000, 0x43fe43fe, 0x00007ffe, 0x00000000, // ICON_LIFE_BARS
1266  0x7ffc0000, 0x43844004, 0x43844284, 0x43844004, 0x42844284, 0x42844284, 0x40044384, 0x00007ffc, // ICON_INFO
1267  0x40008000, 0x10002000, 0x04000800, 0x01000200, 0x00400080, 0x00100020, 0x00040008, 0x00010002, // ICON_CROSSLINE
1268  0x00000000, 0x1ff01ff0, 0x18301830, 0x1f001830, 0x03001f00, 0x00000300, 0x03000300, 0x00000000, // ICON_HELP
1269  0x3ff00000, 0x2abc3550, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x00003ffc, // ICON_FILETYPE_ALPHA
1270  0x3ff00000, 0x201c2010, 0x22442184, 0x28142424, 0x29942814, 0x2ff42994, 0x20042004, 0x00003ffc, // ICON_FILETYPE_HOME
1271  0x07fe0000, 0x04020402, 0x7fe20402, 0x44224422, 0x44224422, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_LAYERS_VISIBLE
1272  0x07fe0000, 0x04020402, 0x7c020402, 0x44024402, 0x44024402, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_LAYERS
1273  0x00000000, 0x40027ffe, 0x7ffe4002, 0x40024002, 0x40024002, 0x40024002, 0x7ffe4002, 0x00000000, // ICON_WINDOW
1274  0x09100000, 0x09f00910, 0x09100910, 0x00000910, 0x24a2779e, 0x27a224a2, 0x709e20a2, 0x00000000, // ICON_HIDPI
1275  0x3ff00000, 0x201c2010, 0x2a842e84, 0x2e842a84, 0x2ba42004, 0x2aa42aa4, 0x20042ba4, 0x00003ffc, // ICON_FILETYPE_BINARY
1276  0x00000000, 0x00000000, 0x00120012, 0x4a5e4bd2, 0x485233d2, 0x00004bd2, 0x00000000, 0x00000000, // ICON_HEX
1277  0x01800000, 0x381c0660, 0x23c42004, 0x23c42044, 0x13c82204, 0x08101008, 0x02400420, 0x00000180, // ICON_SHIELD
1278  0x007e0000, 0x20023fc2, 0x40227fe2, 0x400a403a, 0x400a400a, 0x400a400a, 0x4008400e, 0x00007ff8, // ICON_FILE_NEW
1279  0x00000000, 0x0042007e, 0x40027fc2, 0x44024002, 0x5f024402, 0x44024402, 0x7ffe4002, 0x00000000, // ICON_FOLDER_ADD
1280  0x44220000, 0x12482244, 0xf3cf0000, 0x14280420, 0x48122424, 0x08100810, 0x1ff81008, 0x03c00420, // ICON_ALARM
1281  0x0aa00000, 0x1ff80aa0, 0x1068700e, 0x1008706e, 0x1008700e, 0x1008700e, 0x0aa01ff8, 0x00000aa0, // ICON_CPU
1282  0x07e00000, 0x04201db8, 0x04a01c38, 0x04a01d38, 0x04a01d38, 0x04a01d38, 0x04201d38, 0x000007e0, // ICON_ROM
1283  0x00000000, 0x03c00000, 0x3c382ff0, 0x3c04380c, 0x01800000, 0x03c003c0, 0x00000180, 0x00000000, // ICON_STEP_OVER
1284  0x01800000, 0x01800180, 0x01800180, 0x03c007e0, 0x00000180, 0x01800000, 0x03c003c0, 0x00000180, // ICON_STEP_INTO
1285  0x01800000, 0x07e003c0, 0x01800180, 0x01800180, 0x00000180, 0x01800000, 0x03c003c0, 0x00000180, // ICON_STEP_OUT
1286  0x00000000, 0x0ff003c0, 0x181c1c34, 0x303c301c, 0x30003000, 0x1c301800, 0x03c00ff0, 0x00000000, // ICON_RESTART
1287  0x00000000, 0x00000000, 0x07e003c0, 0x0ff00ff0, 0x0ff00ff0, 0x03c007e0, 0x00000000, 0x00000000, // ICON_BREAKPOINT_ON
1288  0x00000000, 0x00000000, 0x042003c0, 0x08100810, 0x08100810, 0x03c00420, 0x00000000, 0x00000000, // ICON_BREAKPOINT_OFF
1289  0x00000000, 0x00000000, 0x1ff81ff8, 0x1ff80000, 0x00001ff8, 0x1ff81ff8, 0x00000000, 0x00000000, // ICON_BURGER_MENU
1290  0x00000000, 0x00000000, 0x00880070, 0x0c880088, 0x1e8810f8, 0x3e881288, 0x00000000, 0x00000000, // ICON_CASE_SENSITIVE
1291  0x00000000, 0x02000000, 0x07000a80, 0x07001fc0, 0x02000a80, 0x00300030, 0x00000000, 0x00000000, // ICON_REG_EXP
1292  0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x40024002, 0x40024002, 0x7ffe4002, 0x00000000, // ICON_FOLDER
1293  0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x00003ffc, // ICON_FILE
1294  0x1ff00000, 0x20082008, 0x17d02fe8, 0x05400ba0, 0x09200540, 0x23881010, 0x2fe827c8, 0x00001ff0, // ICON_SAND_TIMER
1295  0x01800000, 0x02400240, 0x05a00420, 0x09900990, 0x11881188, 0x21842004, 0x40024182, 0x00003ffc, // ICON_WARNING
1296  0x7ffe0000, 0x4ff24002, 0x4c324ff2, 0x4f824c02, 0x41824f82, 0x41824002, 0x40024182, 0x00007ffe, // ICON_HELP_BOX
1297  0x7ffe0000, 0x41824002, 0x40024182, 0x41824182, 0x41824182, 0x41824182, 0x40024182, 0x00007ffe, // ICON_INFO_BOX
1298  0x01800000, 0x04200240, 0x10080810, 0x7bde2004, 0x0a500a50, 0x08500bd0, 0x08100850, 0x00000ff0, // ICON_PRIORITY
1299  0x01800000, 0x18180660, 0x80016006, 0x98196006, 0x99996666, 0x19986666, 0x01800660, 0x00000000, // ICON_LAYERS_ISO
1300  0x07fe0000, 0x1c020402, 0x74021402, 0x54025402, 0x54025402, 0x500857fe, 0x40205ff8, 0x00007fe0, // ICON_LAYERS2
1301  0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x422a422a, 0x422e422a, 0x40384e28, 0x00007fe0, // ICON_MLAYERS
1302  0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x5b2a512a, 0x512e552a, 0x40385128, 0x00007fe0, // ICON_MAPS
1303  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_228
1304  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_229
1305  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_230
1306  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_231
1307  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_232
1308  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_233
1309  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_234
1310  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_235
1311  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_236
1312  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_237
1313  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_238
1314  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_239
1315  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_240
1316  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_241
1317  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_242
1318  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_243
1319  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_244
1320  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_245
1321  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_246
1322  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_247
1323  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_248
1324  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_249
1325  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_250
1326  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_251
1327  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_252
1328  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_253
1329  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_254
1330  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_255
1331 };
1332 
1333 // NOTE: A pointer to current icons array should be defined
1334 static unsigned int *guiIconsPtr = guiIcons;
1335 
1336 #endif // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS
1337 
1338 #ifndef RAYGUI_ICON_SIZE
1339  #define RAYGUI_ICON_SIZE 0
1340 #endif
1341 
1342 // WARNING: Those values define the total size of the style data array,
1343 // if changed, previous saved styles could become incompatible
1344 #define RAYGUI_MAX_CONTROLS 16 // Maximum number of controls
1345 #define RAYGUI_MAX_PROPS_BASE 16 // Maximum number of base properties
1346 #define RAYGUI_MAX_PROPS_EXTENDED 8 // Maximum number of extended properties
1347 
1348 //----------------------------------------------------------------------------------
1349 // Types and Structures Definition
1350 //----------------------------------------------------------------------------------
1351 // Gui control property style color element
1352 typedef enum { BORDER = 0, BASE, TEXT, OTHER } GuiPropertyElement;
1353 
1354 //----------------------------------------------------------------------------------
1355 // Global Variables Definition
1356 //----------------------------------------------------------------------------------
1357 static GuiState guiState = STATE_NORMAL; // Gui global state, if !STATE_NORMAL, forces defined state
1358 
1359 static Font guiFont = { 0 }; // Gui current font (WARNING: highly coupled to raylib)
1360 static bool guiLocked = false; // Gui lock state (no inputs processed)
1361 static float guiAlpha = 1.0f; // Gui controls transparency
1362 
1363 static unsigned int guiIconScale = 1; // Gui icon default scale (if icons enabled)
1364 
1365 static bool guiTooltip = false; // Tooltip enabled/disabled
1366 static const char *guiTooltipPtr = NULL; // Tooltip string pointer (string provided by user)
1367 
1368 static bool guiControlExclusiveMode = false; // Gui control exclusive mode (no inputs processed except current control)
1369 static Rectangle guiControlExclusiveRec = { 0 }; // Gui control exclusive bounds rectangle, used as an unique identifier
1370 
1371 static int textBoxCursorIndex = 0; // Cursor index, shared by all GuiTextBox*()
1372 //static int blinkCursorFrameCounter = 0; // Frame counter for cursor blinking
1373 static int autoCursorCooldownCounter = 0; // Cooldown frame counter for automatic cursor movement on key-down
1374 static int autoCursorDelayCounter = 0; // Delay frame counter for automatic cursor movement
1375 
1376 //----------------------------------------------------------------------------------
1377 // Style data array for all gui style properties (allocated on data segment by default)
1378 //
1379 // NOTE 1: First set of BASE properties are generic to all controls but could be individually
1380 // overwritten per control, first set of EXTENDED properties are generic to all controls and
1381 // can not be overwritten individually but custom EXTENDED properties can be used by control
1382 //
1383 // NOTE 2: A new style set could be loaded over this array using GuiLoadStyle(),
1384 // but default gui style could always be recovered with GuiLoadStyleDefault()
1385 //
1386 // guiStyle size is by default: 16*(16 + 8) = 384*4 = 1536 bytes = 1.5 KB
1387 //----------------------------------------------------------------------------------
1388 static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)] = { 0 };
1389 
1390 static bool guiStyleLoaded = false; // Style loaded flag for lazy style initialization
1391 
1392 //----------------------------------------------------------------------------------
1393 // Standalone Mode Functions Declaration
1394 //
1395 // NOTE: raygui depend on some raylib input and drawing functions
1396 // To use raygui as standalone library, below functions must be defined by the user
1397 //----------------------------------------------------------------------------------
1398 #if defined(RAYGUI_STANDALONE)
1399 
1400 #define KEY_RIGHT 262
1401 #define KEY_LEFT 263
1402 #define KEY_DOWN 264
1403 #define KEY_UP 265
1404 #define KEY_BACKSPACE 259
1405 #define KEY_ENTER 257
1406 
1407 #define MOUSE_LEFT_BUTTON 0
1408 
1409 // Input required functions
1410 //-------------------------------------------------------------------------------
1411 static Vector2 GetMousePosition(void);
1412 static float GetMouseWheelMove(void);
1413 static bool IsMouseButtonDown(int button);
1414 static bool IsMouseButtonPressed(int button);
1415 static bool IsMouseButtonReleased(int button);
1416 
1417 static bool IsKeyDown(int key);
1418 static bool IsKeyPressed(int key);
1419 static int GetCharPressed(void); // -- GuiTextBox(), GuiValueBox()
1420 //-------------------------------------------------------------------------------
1421 
1422 // Drawing required functions
1423 //-------------------------------------------------------------------------------
1424 static void DrawRectangle(int x, int y, int width, int height, Color color); // -- GuiDrawRectangle()
1425 static void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // -- GuiColorPicker()
1426 //-------------------------------------------------------------------------------
1427 
1428 // Text required functions
1429 //-------------------------------------------------------------------------------
1430 static Font GetFontDefault(void); // -- GuiLoadStyleDefault()
1431 static Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // -- GuiLoadStyle(), load font
1432 
1433 static Texture2D LoadTextureFromImage(Image image); // -- GuiLoadStyle(), required to load texture from embedded font atlas image
1434 static void SetShapesTexture(Texture2D tex, Rectangle rec); // -- GuiLoadStyle(), required to set shapes rec to font white rec (optimization)
1435 
1436 static char *LoadFileText(const char *fileName); // -- GuiLoadStyle(), required to load charset data
1437 static void UnloadFileText(char *text); // -- GuiLoadStyle(), required to unload charset data
1438 
1439 static const char *GetDirectoryPath(const char *filePath); // -- GuiLoadStyle(), required to find charset/font file from text .rgs
1440 
1441 static int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle(), required to load required font codepoints list
1442 static void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list
1443 
1444 static unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle()
1445 //-------------------------------------------------------------------------------
1446 
1447 // raylib functions already implemented in raygui
1448 //-------------------------------------------------------------------------------
1449 static Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value
1450 static int ColorToInt(Color color); // Returns hexadecimal value for a Color
1451 static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle
1452 static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed'
1453 static const char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings
1454 static int TextToInteger(const char *text); // Get integer value from text
1455 static float TextToFloat(const char *text); // Get float value from text
1456 
1457 static int GetCodepointNext(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded text
1458 static const char *CodepointToUTF8(int codepoint, int *byteSize); // Encode codepoint into UTF-8 text (char array size returned as parameter)
1459 
1460 static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2); // Draw rectangle vertical gradient
1461 //-------------------------------------------------------------------------------
1462 
1463 #endif // RAYGUI_STANDALONE
1464 
1465 //----------------------------------------------------------------------------------
1466 // Module specific Functions Declaration
1467 //----------------------------------------------------------------------------------
1468 static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only)
1469 
1470 static int GetTextWidth(const char *text); // Gui get text width using gui font and style
1471 static Rectangle GetTextBounds(int control, Rectangle bounds); // Get text bounds considering control bounds
1472 static const char *GetTextIcon(const char *text, int *iconId); // Get text icon if provided and move text cursor
1473 
1474 static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint); // Gui draw text using default font
1475 static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // Gui draw rectangle using default raygui style
1476 
1477 static const char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow); // Split controls text into multiple strings
1478 static Vector3 ConvertHSVtoRGB(Vector3 hsv); // Convert color data from HSV to RGB
1479 static Vector3 ConvertRGBtoHSV(Vector3 rgb); // Convert color data from RGB to HSV
1480 
1481 static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel()
1482 static void GuiTooltip(Rectangle controlRec); // Draw tooltip using control rec position
1483 
1484 static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor
1485 
1486 //----------------------------------------------------------------------------------
1487 // Gui Setup Functions Definition
1488 //----------------------------------------------------------------------------------
1489 // Enable gui global state
1490 // NOTE: We check for STATE_DISABLED to avoid messing custom global state setups
1491 void GuiEnable(void) { if (guiState == STATE_DISABLED) guiState = STATE_NORMAL; }
1492 
1493 // Disable gui global state
1494 // NOTE: We check for STATE_NORMAL to avoid messing custom global state setups
1495 void GuiDisable(void) { if (guiState == STATE_NORMAL) guiState = STATE_DISABLED; }
1496 
1497 // Lock gui global state
1498 void GuiLock(void) { guiLocked = true; }
1499 
1500 // Unlock gui global state
1501 void GuiUnlock(void) { guiLocked = false; }
1502 
1503 // Check if gui is locked (global state)
1504 bool GuiIsLocked(void) { return guiLocked; }
1505 
1506 // Set gui controls alpha global state
1507 void GuiSetAlpha(float alpha)
1508 {
1509  if (alpha < 0.0f) alpha = 0.0f;
1510  else if (alpha > 1.0f) alpha = 1.0f;
1511 
1512  guiAlpha = alpha;
1513 }
1514 
1515 // Set gui state (global state)
1516 void GuiSetState(int state) { guiState = (GuiState)state; }
1517 
1518 // Get gui state (global state)
1519 int GuiGetState(void) { return guiState; }
1520 
1521 // Set custom gui font
1522 // NOTE: Font loading/unloading is external to raygui
1523 void GuiSetFont(Font font)
1524 {
1525  if (font.texture.id > 0)
1526  {
1527  // NOTE: If we try to setup a font but default style has not been
1528  // lazily loaded before, it will be overwritten, so we need to force
1529  // default style loading first
1530  if (!guiStyleLoaded) GuiLoadStyleDefault();
1531 
1532  guiFont = font;
1533  }
1534 }
1535 
1536 // Get custom gui font
1537 Font GuiGetFont(void)
1538 {
1539  return guiFont;
1540 }
1541 
1542 // Set control style property value
1543 void GuiSetStyle(int control, int property, int value)
1544 {
1545  if (!guiStyleLoaded) GuiLoadStyleDefault();
1546  guiStyle[control*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property] = value;
1547 
1548  // Default properties are propagated to all controls
1549  if ((control == 0) && (property < RAYGUI_MAX_PROPS_BASE))
1550  {
1551  for (int i = 1; i < RAYGUI_MAX_CONTROLS; i++) guiStyle[i*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property] = value;
1552  }
1553 }
1554 
1555 // Get control style property value
1556 int GuiGetStyle(int control, int property)
1557 {
1558  if (!guiStyleLoaded) GuiLoadStyleDefault();
1559  return guiStyle[control*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property];
1560 }
1561 
1562 //----------------------------------------------------------------------------------
1563 // Gui Controls Functions Definition
1564 //----------------------------------------------------------------------------------
1565 
1566 // Window Box control
1567 int GuiWindowBox(Rectangle bounds, const char *title)
1568 {
1569  // Window title bar height (including borders)
1570  // NOTE: This define is also used by GuiMessageBox() and GuiTextInputBox()
1571  #if !defined(RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT)
1572  #define RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT 24
1573  #endif
1574 
1575  int result = 0;
1576  //GuiState state = guiState;
1577 
1578  int statusBarHeight = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT;
1579 
1580  Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)statusBarHeight };
1581  if (bounds.height < statusBarHeight*2.0f) bounds.height = statusBarHeight*2.0f;
1582 
1583  Rectangle windowPanel = { bounds.x, bounds.y + (float)statusBarHeight - 1, bounds.width, bounds.height - (float)statusBarHeight + 1 };
1584  Rectangle closeButtonRec = { statusBar.x + statusBar.width - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - 20,
1585  statusBar.y + statusBarHeight/2.0f - 18.0f/2.0f, 18, 18 };
1586 
1587  // Update control
1588  //--------------------------------------------------------------------
1589  // NOTE: Logic is directly managed by button
1590  //--------------------------------------------------------------------
1591 
1592  // Draw control
1593  //--------------------------------------------------------------------
1594  GuiStatusBar(statusBar, title); // Draw window header as status bar
1595  GuiPanel(windowPanel, NULL); // Draw window base
1596 
1597  // Draw window close button
1598  int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
1599  int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
1600  GuiSetStyle(BUTTON, BORDER_WIDTH, 1);
1601  GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
1602 #if defined(RAYGUI_NO_ICONS)
1603  result = GuiButton(closeButtonRec, "x");
1604 #else
1605  result = GuiButton(closeButtonRec, GuiIconText(ICON_CROSS_SMALL, NULL));
1606 #endif
1607  GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
1608  GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment);
1609  //--------------------------------------------------------------------
1610 
1611  return result; // Window close button clicked: result = 1
1612 }
1613 
1614 // Group Box control with text name
1615 int GuiGroupBox(Rectangle bounds, const char *text)
1616 {
1617  #if !defined(RAYGUI_GROUPBOX_LINE_THICK)
1618  #define RAYGUI_GROUPBOX_LINE_THICK 1
1619  #endif
1620 
1621  int result = 0;
1622  GuiState state = guiState;
1623 
1624  // Draw control
1625  //--------------------------------------------------------------------
1626  GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)));
1627  GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, RAYGUI_GROUPBOX_LINE_THICK }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)));
1628  GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)));
1629 
1630  GuiLine(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y - GuiGetStyle(DEFAULT, TEXT_SIZE)/2, bounds.width, (float)GuiGetStyle(DEFAULT, TEXT_SIZE) }, text);
1631  //--------------------------------------------------------------------
1632 
1633  return result;
1634 }
1635 
1636 // Line control
1637 int GuiLine(Rectangle bounds, const char *text)
1638 {
1639  #if !defined(RAYGUI_LINE_ORIGIN_SIZE)
1640  #define RAYGUI_LINE_MARGIN_TEXT 12
1641  #endif
1642  #if !defined(RAYGUI_LINE_TEXT_PADDING)
1643  #define RAYGUI_LINE_TEXT_PADDING 4
1644  #endif
1645 
1646  int result = 0;
1647  GuiState state = guiState;
1648 
1649  Color color = GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR));
1650 
1651  // Draw control
1652  //--------------------------------------------------------------------
1653  if (text == NULL) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height/2, bounds.width, 1 }, 0, BLANK, color);
1654  else
1655  {
1656  Rectangle textBounds = { 0 };
1657  textBounds.width = (float)GetTextWidth(text) + 2;
1658  textBounds.height = bounds.height;
1659  textBounds.x = bounds.x + RAYGUI_LINE_MARGIN_TEXT;
1660  textBounds.y = bounds.y;
1661 
1662  // Draw line with embedded text label: "--- text --------------"
1663  GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height/2, RAYGUI_LINE_MARGIN_TEXT - RAYGUI_LINE_TEXT_PADDING, 1 }, 0, BLANK, color);
1664  GuiDrawText(text, textBounds, TEXT_ALIGN_LEFT, color);
1665  GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + 12 + textBounds.width + 4, bounds.y + bounds.height/2, bounds.width - textBounds.width - RAYGUI_LINE_MARGIN_TEXT - RAYGUI_LINE_TEXT_PADDING, 1 }, 0, BLANK, color);
1666  }
1667  //--------------------------------------------------------------------
1668 
1669  return result;
1670 }
1671 
1672 // Panel control
1673 int GuiPanel(Rectangle bounds, const char *text)
1674 {
1675  #if !defined(RAYGUI_PANEL_BORDER_WIDTH)
1676  #define RAYGUI_PANEL_BORDER_WIDTH 1
1677  #endif
1678 
1679  int result = 0;
1680  GuiState state = guiState;
1681 
1682  // Text will be drawn as a header bar (if provided)
1683  Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT };
1684  if ((text != NULL) && (bounds.height < RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f)) bounds.height = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f;
1685 
1686  if (text != NULL)
1687  {
1688  // Move panel bounds after the header bar
1689  bounds.y += (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1;
1690  bounds.height -= (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1;
1691  }
1692 
1693  // Draw control
1694  //--------------------------------------------------------------------
1695  if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar
1696 
1697  GuiDrawRectangle(bounds, RAYGUI_PANEL_BORDER_WIDTH, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BORDER_COLOR_DISABLED: LINE_COLOR)),
1698  GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BASE_COLOR_DISABLED : BACKGROUND_COLOR)));
1699  //--------------------------------------------------------------------
1700 
1701  return result;
1702 }
1703 
1704 // Tab Bar control
1705 // NOTE: Using GuiToggle() for the TABS
1706 int GuiTabBar(Rectangle bounds, const char **text, int count, int *active)
1707 {
1708  #define RAYGUI_TABBAR_ITEM_WIDTH 160
1709 
1710  int result = -1;
1711  //GuiState state = guiState;
1712 
1713  Rectangle tabBounds = { bounds.x, bounds.y, RAYGUI_TABBAR_ITEM_WIDTH, bounds.height };
1714 
1715  if (*active < 0) *active = 0;
1716  else if (*active > count - 1) *active = count - 1;
1717 
1718  int offsetX = 0; // Required in case tabs go out of screen
1719  offsetX = (*active + 2)*RAYGUI_TABBAR_ITEM_WIDTH - GetScreenWidth();
1720  if (offsetX < 0) offsetX = 0;
1721 
1722  bool toggle = false; // Required for individual toggles
1723 
1724  // Draw control
1725  //--------------------------------------------------------------------
1726  for (int i = 0; i < count; i++)
1727  {
1728  tabBounds.x = bounds.x + (RAYGUI_TABBAR_ITEM_WIDTH + 4)*i - offsetX;
1729 
1730  if (tabBounds.x < GetScreenWidth())
1731  {
1732  // Draw tabs as toggle controls
1733  int textAlignment = GuiGetStyle(TOGGLE, TEXT_ALIGNMENT);
1734  int textPadding = GuiGetStyle(TOGGLE, TEXT_PADDING);
1735  GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
1736  GuiSetStyle(TOGGLE, TEXT_PADDING, 8);
1737 
1738  if (i == (*active))
1739  {
1740  toggle = true;
1741  GuiToggle(tabBounds, GuiIconText(12, text[i]), &toggle);
1742  }
1743  else
1744  {
1745  toggle = false;
1746  GuiToggle(tabBounds, GuiIconText(12, text[i]), &toggle);
1747  if (toggle) *active = i;
1748  }
1749 
1750  // Close tab with middle mouse button pressed
1751  if (CheckCollisionPointRec(GetMousePosition(), tabBounds) && IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON)) result = i;
1752 
1753  GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding);
1754  GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment);
1755 
1756  // Draw tab close button
1757  // NOTE: Only draw close button for current tab: if (CheckCollisionPointRec(mousePosition, tabBounds))
1758  int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
1759  int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
1760  GuiSetStyle(BUTTON, BORDER_WIDTH, 1);
1761  GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
1762 #if defined(RAYGUI_NO_ICONS)
1763  if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, "x")) result = i;
1764 #else
1765  if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, GuiIconText(ICON_CROSS_SMALL, NULL))) result = i;
1766 #endif
1767  GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
1768  GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment);
1769  }
1770  }
1771 
1772  // Draw tab-bar bottom line
1773  GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, 1 }, 0, BLANK, GetColor(GuiGetStyle(TOGGLE, BORDER_COLOR_NORMAL)));
1774  //--------------------------------------------------------------------
1775 
1776  return result; // Return as result the current TAB closing requested
1777 }
1778 
1779 // Scroll Panel control
1780 int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view)
1781 {
1782  #define RAYGUI_MIN_SCROLLBAR_WIDTH 40
1783  #define RAYGUI_MIN_SCROLLBAR_HEIGHT 40
1784  #define RAYGUI_MIN_MOUSE_WHEEL_SPEED 20
1785 
1786  int result = 0;
1787  GuiState state = guiState;
1788 
1789  Rectangle temp = { 0 };
1790  if (view == NULL) view = &temp;
1791 
1792  Vector2 scrollPos = { 0.0f, 0.0f };
1793  if (scroll != NULL) scrollPos = *scroll;
1794 
1795  // Text will be drawn as a header bar (if provided)
1796  Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT };
1797  if (bounds.height < RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f) bounds.height = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f;
1798 
1799  if (text != NULL)
1800  {
1801  // Move panel bounds after the header bar
1802  bounds.y += (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1;
1803  bounds.height -= (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + 1;
1804  }
1805 
1806  bool hasHorizontalScrollBar = (content.width > bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false;
1807  bool hasVerticalScrollBar = (content.height > bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false;
1808 
1809  // Recheck to account for the other scrollbar being visible
1810  if (!hasHorizontalScrollBar) hasHorizontalScrollBar = (hasVerticalScrollBar && (content.width > (bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false;
1811  if (!hasVerticalScrollBar) hasVerticalScrollBar = (hasHorizontalScrollBar && (content.height > (bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false;
1812 
1813  int horizontalScrollBarWidth = hasHorizontalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0;
1814  int verticalScrollBarWidth = hasVerticalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0;
1815  Rectangle horizontalScrollBar = {
1816  (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + verticalScrollBarWidth : (float)bounds.x) + GuiGetStyle(DEFAULT, BORDER_WIDTH),
1817  (float)bounds.y + bounds.height - horizontalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH),
1818  (float)bounds.width - verticalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH),
1819  (float)horizontalScrollBarWidth
1820  };
1821  Rectangle verticalScrollBar = {
1822  (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)),
1823  (float)bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH),
1824  (float)verticalScrollBarWidth,
1825  (float)bounds.height - horizontalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH)
1826  };
1827 
1828  // Make sure scroll bars have a minimum width/height
1829  if (horizontalScrollBar.width < RAYGUI_MIN_SCROLLBAR_WIDTH) horizontalScrollBar.width = RAYGUI_MIN_SCROLLBAR_WIDTH;
1830  if (verticalScrollBar.height < RAYGUI_MIN_SCROLLBAR_HEIGHT) verticalScrollBar.height = RAYGUI_MIN_SCROLLBAR_HEIGHT;
1831 
1832  // Calculate view area (area without the scrollbars)
1833  *view = (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)?
1834  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 } :
1835  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 };
1836 
1837  // Clip view area to the actual content size
1838  if (view->width > content.width) view->width = content.width;
1839  if (view->height > content.height) view->height = content.height;
1840 
1841  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);
1842  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);
1843  float verticalMin = hasVerticalScrollBar? 0.0f : -1.0f;
1844  float verticalMax = hasVerticalScrollBar? content.height - bounds.height + (float)horizontalScrollBarWidth + (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH);
1845 
1846  // Update control
1847  //--------------------------------------------------------------------
1848  if ((state != STATE_DISABLED) && !guiLocked)
1849  {
1850  Vector2 mousePoint = GetMousePosition();
1851 
1852  // Check button state
1853  if (CheckCollisionPointRec(mousePoint, bounds))
1854  {
1855  if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
1856  else state = STATE_FOCUSED;
1857 
1858 #if defined(SUPPORT_SCROLLBAR_KEY_INPUT)
1859  if (hasHorizontalScrollBar)
1860  {
1861  if (IsKeyDown(KEY_RIGHT)) scrollPos.x -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
1862  if (IsKeyDown(KEY_LEFT)) scrollPos.x += GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
1863  }
1864 
1865  if (hasVerticalScrollBar)
1866  {
1867  if (IsKeyDown(KEY_DOWN)) scrollPos.y -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
1868  if (IsKeyDown(KEY_UP)) scrollPos.y += GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
1869  }
1870 #endif
1871  float wheelMove = GetMouseWheelMove();
1872 
1873  // Set scrolling speed with mouse wheel based on ratio between bounds and content
1874  Vector2 mouseWheelSpeed = { content.width / bounds.width, content.height / bounds.height };
1875  if (mouseWheelSpeed.x < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.x = RAYGUI_MIN_MOUSE_WHEEL_SPEED;
1876  if (mouseWheelSpeed.y < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.y = RAYGUI_MIN_MOUSE_WHEEL_SPEED;
1877 
1878  // Horizontal and vertical scrolling with mouse wheel
1879  if (hasHorizontalScrollBar && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_LEFT_SHIFT))) scrollPos.x += wheelMove*mouseWheelSpeed.x;
1880  else scrollPos.y += wheelMove*mouseWheelSpeed.y; // Vertical scroll
1881  }
1882  }
1883 
1884  // Normalize scroll values
1885  if (scrollPos.x > -horizontalMin) scrollPos.x = -horizontalMin;
1886  if (scrollPos.x < -horizontalMax) scrollPos.x = -horizontalMax;
1887  if (scrollPos.y > -verticalMin) scrollPos.y = -verticalMin;
1888  if (scrollPos.y < -verticalMax) scrollPos.y = -verticalMax;
1889  //--------------------------------------------------------------------
1890 
1891  // Draw control
1892  //--------------------------------------------------------------------
1893  if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar
1894 
1895  GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background
1896 
1897  // Save size of the scrollbar slider
1898  const int slider = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE);
1899 
1900  // Draw horizontal scrollbar if visible
1901  if (hasHorizontalScrollBar)
1902  {
1903  // Change scrollbar slider size to show the diff in size between the content width and the widget width
1904  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)));
1905  scrollPos.x = (float)-GuiScrollBar(horizontalScrollBar, (int)-scrollPos.x, (int)horizontalMin, (int)horizontalMax);
1906  }
1907  else scrollPos.x = 0.0f;
1908 
1909  // Draw vertical scrollbar if visible
1910  if (hasVerticalScrollBar)
1911  {
1912  // Change scrollbar slider size to show the diff in size between the content height and the widget height
1913  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)));
1914  scrollPos.y = (float)-GuiScrollBar(verticalScrollBar, (int)-scrollPos.y, (int)verticalMin, (int)verticalMax);
1915  }
1916  else scrollPos.y = 0.0f;
1917 
1918  // Draw detail corner rectangle if both scroll bars are visible
1919  if (hasHorizontalScrollBar && hasVerticalScrollBar)
1920  {
1921  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 };
1922  GuiDrawRectangle(corner, 0, BLANK, GetColor(GuiGetStyle(LISTVIEW, TEXT + (state*3))));
1923  }
1924 
1925  // Draw scrollbar lines depending on current state
1926  GuiDrawRectangle(bounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + (state*3))), BLANK);
1927 
1928  // Set scrollbar slider size back to the way it was before
1929  GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, slider);
1930  //--------------------------------------------------------------------
1931 
1932  if (scroll != NULL) *scroll = scrollPos;
1933 
1934  return result;
1935 }
1936 
1937 // Label control
1938 int GuiLabel(Rectangle bounds, const char *text)
1939 {
1940  int result = 0;
1941  GuiState state = guiState;
1942 
1943  // Update control
1944  //--------------------------------------------------------------------
1945  //...
1946  //--------------------------------------------------------------------
1947 
1948  // Draw control
1949  //--------------------------------------------------------------------
1950  GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
1951  //--------------------------------------------------------------------
1952 
1953  return result;
1954 }
1955 
1956 // Button control, returns true when clicked
1957 int GuiButton(Rectangle bounds, const char *text)
1958 {
1959  int result = 0;
1960  GuiState state = guiState;
1961 
1962  // Update control
1963  //--------------------------------------------------------------------
1964  if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
1965  {
1966  Vector2 mousePoint = GetMousePosition();
1967 
1968  // Check button state
1969  if (CheckCollisionPointRec(mousePoint, bounds))
1970  {
1971  if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
1972  else state = STATE_FOCUSED;
1973 
1974  if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) result = 1;
1975  }
1976  }
1977  //--------------------------------------------------------------------
1978 
1979  // Draw control
1980  //--------------------------------------------------------------------
1981  GuiDrawRectangle(bounds, GuiGetStyle(BUTTON, BORDER_WIDTH), GetColor(GuiGetStyle(BUTTON, BORDER + (state*3))), GetColor(GuiGetStyle(BUTTON, BASE + (state*3))));
1982  GuiDrawText(text, GetTextBounds(BUTTON, bounds), GuiGetStyle(BUTTON, TEXT_ALIGNMENT), GetColor(GuiGetStyle(BUTTON, TEXT + (state*3))));
1983 
1984  if (state == STATE_FOCUSED) GuiTooltip(bounds);
1985  //------------------------------------------------------------------
1986 
1987  return result; // Button pressed: result = 1
1988 }
1989 
1990 // Label button control
1991 int GuiLabelButton(Rectangle bounds, const char *text)
1992 {
1993  GuiState state = guiState;
1994  bool pressed = false;
1995 
1996  // NOTE: We force bounds.width to be all text
1997  float textWidth = (float)GetTextWidth(text);
1998  if ((bounds.width - 2*GuiGetStyle(LABEL, BORDER_WIDTH) - 2*GuiGetStyle(LABEL, TEXT_PADDING)) < textWidth) bounds.width = textWidth + 2*GuiGetStyle(LABEL, BORDER_WIDTH) + 2*GuiGetStyle(LABEL, TEXT_PADDING) + 2;
1999 
2000  // Update control
2001  //--------------------------------------------------------------------
2002  if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
2003  {
2004  Vector2 mousePoint = GetMousePosition();
2005 
2006  // Check checkbox state
2007  if (CheckCollisionPointRec(mousePoint, bounds))
2008  {
2009  if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
2010  else state = STATE_FOCUSED;
2011 
2012  if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true;
2013  }
2014  }
2015  //--------------------------------------------------------------------
2016 
2017  // Draw control
2018  //--------------------------------------------------------------------
2019  GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
2020  //--------------------------------------------------------------------
2021 
2022  return pressed;
2023 }
2024 
2025 // Toggle Button control
2026 int GuiToggle(Rectangle bounds, const char *text, bool *active)
2027 {
2028  int result = 0;
2029  GuiState state = guiState;
2030 
2031  bool temp = false;
2032  if (active == NULL) active = &temp;
2033 
2034  // Update control
2035  //--------------------------------------------------------------------
2036  if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
2037  {
2038  Vector2 mousePoint = GetMousePosition();
2039 
2040  // Check toggle button state
2041  if (CheckCollisionPointRec(mousePoint, bounds))
2042  {
2043  if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
2044  else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
2045  {
2046  state = STATE_NORMAL;
2047  *active = !(*active);
2048  }
2049  else state = STATE_FOCUSED;
2050  }
2051  }
2052  //--------------------------------------------------------------------
2053 
2054  // Draw control
2055  //--------------------------------------------------------------------
2056  if (state == STATE_NORMAL)
2057  {
2058  GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, ((*active)? BORDER_COLOR_PRESSED : (BORDER + state*3)))), GetColor(GuiGetStyle(TOGGLE, ((*active)? BASE_COLOR_PRESSED : (BASE + state*3)))));
2059  GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TOGGLE, ((*active)? TEXT_COLOR_PRESSED : (TEXT + state*3)))));
2060  }
2061  else
2062  {
2063  GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, BORDER + state*3)), GetColor(GuiGetStyle(TOGGLE, BASE + state*3)));
2064  GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TOGGLE, TEXT + state*3)));
2065  }
2066 
2067  if (state == STATE_FOCUSED) GuiTooltip(bounds);
2068  //--------------------------------------------------------------------
2069 
2070  return result;
2071 }
2072 
2073 // Toggle Group control
2074 int GuiToggleGroup(Rectangle bounds, const char *text, int *active)
2075 {
2076  #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEMS)
2077  #define RAYGUI_TOGGLEGROUP_MAX_ITEMS 32
2078  #endif
2079 
2080  int result = 0;
2081  float initBoundsX = bounds.x;
2082 
2083  int temp = 0;
2084  if (active == NULL) active = &temp;
2085 
2086  bool toggle = false; // Required for individual toggles
2087 
2088  // Get substrings items from text (items pointers)
2089  int rows[RAYGUI_TOGGLEGROUP_MAX_ITEMS] = { 0 };
2090  int itemCount = 0;
2091  const char **items = GuiTextSplit(text, ';', &itemCount, rows);
2092 
2093  int prevRow = rows[0];
2094 
2095  for (int i = 0; i < itemCount; i++)
2096  {
2097  if (prevRow != rows[i])
2098  {
2099  bounds.x = initBoundsX;
2100  bounds.y += (bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING));
2101  prevRow = rows[i];
2102  }
2103 
2104  if (i == (*active))
2105  {
2106  toggle = true;
2107  GuiToggle(bounds, items[i], &toggle);
2108  }
2109  else
2110  {
2111  toggle = false;
2112  GuiToggle(bounds, items[i], &toggle);
2113  if (toggle) *active = i;
2114  }
2115 
2116  bounds.x += (bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING));
2117  }
2118 
2119  return result;
2120 }
2121 
2122 // Toggle Slider control extended
2123 int GuiToggleSlider(Rectangle bounds, const char *text, int *active)
2124 {
2125  int result = 0;
2126  GuiState state = guiState;
2127 
2128  int temp = 0;
2129  if (active == NULL) active = &temp;
2130 
2131  //bool toggle = false; // Required for individual toggles
2132 
2133  // Get substrings items from text (items pointers)
2134  int itemCount = 0;
2135  const char **items = GuiTextSplit(text, ';', &itemCount, NULL);
2136 
2137  Rectangle slider = {
2138  0, // Calculated later depending on the active toggle
2139  bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING),
2140  (bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - (itemCount + 1)*GuiGetStyle(SLIDER, SLIDER_PADDING))/itemCount,
2141  bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) };
2142 
2143  // Update control
2144  //--------------------------------------------------------------------
2145  if ((state != STATE_DISABLED) && !guiLocked)
2146  {
2147  Vector2 mousePoint = GetMousePosition();
2148 
2149  if (CheckCollisionPointRec(mousePoint, bounds))
2150  {
2151  if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
2152  else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
2153  {
2154  state = STATE_PRESSED;
2155  (*active)++;
2156  result = 1;
2157  }
2158  else state = STATE_FOCUSED;
2159  }
2160 
2161  if ((*active) && (state != STATE_FOCUSED)) state = STATE_PRESSED;
2162  }
2163 
2164  if (*active >= itemCount) *active = 0;
2165  slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH) + (*active + 1)*GuiGetStyle(SLIDER, SLIDER_PADDING) + (*active)*slider.width;
2166  //--------------------------------------------------------------------
2167 
2168  // Draw control
2169  //--------------------------------------------------------------------
2170  GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, BORDER + (state*3))),
2171  GetColor(GuiGetStyle(TOGGLE, BASE_COLOR_NORMAL)));
2172 
2173  // Draw internal slider
2174  if (state == STATE_NORMAL) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED)));
2175  else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_FOCUSED)));
2176  else if (state == STATE_PRESSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED)));
2177 
2178  // Draw text in slider
2179  if (text != NULL)
2180  {
2181  Rectangle textBounds = { 0 };
2182  textBounds.width = (float)GetTextWidth(text);
2183  textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
2184  textBounds.x = slider.x + slider.width/2 - textBounds.width/2;
2185  textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
2186 
2187  GuiDrawText(items[*active], textBounds, GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TOGGLE, TEXT + (state*3))), guiAlpha));
2188  }
2189  //--------------------------------------------------------------------
2190 
2191  return result;
2192 }
2193 
2194 // Check Box control, returns 1 when state changed
2195 int GuiCheckBox(Rectangle bounds, const char *text, bool *checked)
2196 {
2197  int result = 0;
2198  GuiState state = guiState;
2199 
2200  bool temp = false;
2201  if (checked == NULL) checked = &temp;
2202 
2203  Rectangle textBounds = { 0 };
2204 
2205  if (text != NULL)
2206  {
2207  textBounds.width = (float)GetTextWidth(text) + 2;
2208  textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
2209  textBounds.x = bounds.x + bounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING);
2210  textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
2211  if (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(CHECKBOX, TEXT_PADDING);
2212  }
2213 
2214  // Update control
2215  //--------------------------------------------------------------------
2216  if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
2217  {
2218  Vector2 mousePoint = GetMousePosition();
2219 
2220  Rectangle totalBounds = {
2221  (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT)? textBounds.x : bounds.x,
2222  bounds.y,
2223  bounds.width + textBounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING),
2224  bounds.height,
2225  };
2226 
2227  // Check checkbox state
2228  if (CheckCollisionPointRec(mousePoint, totalBounds))
2229  {
2230  if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
2231  else state = STATE_FOCUSED;
2232 
2233  if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
2234  {
2235  *checked = !(*checked);
2236  result = 1;
2237  }
2238  }
2239  }
2240  //--------------------------------------------------------------------
2241 
2242  // Draw control
2243  //--------------------------------------------------------------------
2244  GuiDrawRectangle(bounds, GuiGetStyle(CHECKBOX, BORDER_WIDTH), GetColor(GuiGetStyle(CHECKBOX, BORDER + (state*3))), BLANK);
2245 
2246  if (*checked)
2247  {
2248  Rectangle check = { bounds.x + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING),
2249  bounds.y + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING),
2250  bounds.width - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING)),
2251  bounds.height - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING)) };
2252  GuiDrawRectangle(check, 0, BLANK, GetColor(GuiGetStyle(CHECKBOX, TEXT + state*3)));
2253  }
2254 
2255  GuiDrawText(text, textBounds, (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
2256  //--------------------------------------------------------------------
2257 
2258  return result;
2259 }
2260 
2261 // Combo Box control
2262 int GuiComboBox(Rectangle bounds, const char *text, int *active)
2263 {
2264  int result = 0;
2265  GuiState state = guiState;
2266 
2267  int temp = 0;
2268  if (active == NULL) active = &temp;
2269 
2270  bounds.width -= (GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH) + GuiGetStyle(COMBOBOX, COMBO_BUTTON_SPACING));
2271 
2272  Rectangle selector = { (float)bounds.x + bounds.width + GuiGetStyle(COMBOBOX, COMBO_BUTTON_SPACING),
2273  (float)bounds.y, (float)GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH), (float)bounds.height };
2274 
2275  // Get substrings items from text (items pointers, lengths and count)
2276  int itemCount = 0;
2277  const char **items = GuiTextSplit(text, ';', &itemCount, NULL);
2278 
2279  if (*active < 0) *active = 0;
2280  else if (*active > (itemCount - 1)) *active = itemCount - 1;
2281 
2282  // Update control
2283  //--------------------------------------------------------------------
2284  if ((state != STATE_DISABLED) && !guiLocked && (itemCount > 1) && !guiControlExclusiveMode)
2285  {
2286  Vector2 mousePoint = GetMousePosition();
2287 
2288  if (CheckCollisionPointRec(mousePoint, bounds) ||
2289  CheckCollisionPointRec(mousePoint, selector))
2290  {
2291  if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
2292  {
2293  *active += 1;
2294  if (*active >= itemCount) *active = 0; // Cyclic combobox
2295  }
2296 
2297  if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
2298  else state = STATE_FOCUSED;
2299  }
2300  }
2301  //--------------------------------------------------------------------
2302 
2303  // Draw control
2304  //--------------------------------------------------------------------
2305  // Draw combo box main
2306  GuiDrawRectangle(bounds, GuiGetStyle(COMBOBOX, BORDER_WIDTH), GetColor(GuiGetStyle(COMBOBOX, BORDER + (state*3))), GetColor(GuiGetStyle(COMBOBOX, BASE + (state*3))));
2307  GuiDrawText(items[*active], GetTextBounds(COMBOBOX, bounds), GuiGetStyle(COMBOBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(COMBOBOX, TEXT + (state*3))));
2308 
2309  // Draw selector using a custom button
2310  // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values
2311  int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
2312  int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
2313  GuiSetStyle(BUTTON, BORDER_WIDTH, 1);
2314  GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
2315 
2316  GuiButton(selector, TextFormat("%i/%i", *active + 1, itemCount));
2317 
2318  GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign);
2319  GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
2320  //--------------------------------------------------------------------
2321 
2322  return result;
2323 }
2324 
2325 // Dropdown Box control
2326 // NOTE: Returns mouse click
2327 int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode)
2328 {
2329  int result = 0;
2330  GuiState state = guiState;
2331 
2332  int temp = 0;
2333  if (active == NULL) active = &temp;
2334 
2335  int itemSelected = *active;
2336  int itemFocused = -1;
2337 
2338  // Get substrings items from text (items pointers, lengths and count)
2339  int itemCount = 0;
2340  const char **items = GuiTextSplit(text, ';', &itemCount, NULL);
2341 
2342  Rectangle boundsOpen = bounds;
2343  boundsOpen.height = (itemCount + 1)*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING));
2344 
2345  Rectangle itemBounds = bounds;
2346 
2347  // Update control
2348  //--------------------------------------------------------------------
2349  if ((state != STATE_DISABLED) && (editMode || !guiLocked) && (itemCount > 1) && !guiControlExclusiveMode)
2350  {
2351  Vector2 mousePoint = GetMousePosition();
2352 
2353  if (editMode)
2354  {
2355  state = STATE_PRESSED;
2356 
2357  // Check if mouse has been pressed or released outside limits
2358  if (!CheckCollisionPointRec(mousePoint, boundsOpen))
2359  {
2360  if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) result = 1;
2361  }
2362 
2363  // Check if already selected item has been pressed again
2364  if (CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1;
2365 
2366  // Check focused and selected item
2367  for (int i = 0; i < itemCount; i++)
2368  {
2369  // Update item rectangle y position for next item
2370  itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING));
2371 
2372  if (CheckCollisionPointRec(mousePoint, itemBounds))
2373  {
2374  itemFocused = i;
2375  if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
2376  {
2377  itemSelected = i;
2378  result = 1; // Item selected
2379  }
2380  break;
2381  }
2382  }
2383 
2384  itemBounds = bounds;
2385  }
2386  else
2387  {
2388  if (CheckCollisionPointRec(mousePoint, bounds))
2389  {
2390  if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
2391  {
2392  result = 1;
2393  state = STATE_PRESSED;
2394  }
2395  else state = STATE_FOCUSED;
2396  }
2397  }
2398  }
2399  //--------------------------------------------------------------------
2400 
2401  // Draw control
2402  //--------------------------------------------------------------------
2403  if (editMode) GuiPanel(boundsOpen, NULL);
2404 
2405  GuiDrawRectangle(bounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER + state*3)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE + state*3)));
2406  GuiDrawText(items[itemSelected], GetTextBounds(DROPDOWNBOX, bounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + state*3)));
2407 
2408  if (editMode)
2409  {
2410  // Draw visible items
2411  for (int i = 0; i < itemCount; i++)
2412  {
2413  // Update item rectangle y position for next item
2414  itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING));
2415 
2416  if (i == itemSelected)
2417  {
2418  GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_PRESSED)));
2419  GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_PRESSED)));
2420  }
2421  else if (i == itemFocused)
2422  {
2423  GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_FOCUSED)));
2424  GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_FOCUSED)));
2425  }
2426  else GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_NORMAL)));
2427  }
2428  }
2429 
2430  if (!GuiGetStyle(DROPDOWNBOX, DROPDOWN_ARROW_HIDDEN))
2431  {
2432  // Draw arrows (using icon if available)
2433 #if defined(RAYGUI_NO_ICONS)
2434  GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 },
2435  TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))));
2436 #else
2437  GuiDrawText("#120#", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 },
2438  TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); // ICON_ARROW_DOWN_FILL
2439 #endif
2440  }
2441  //--------------------------------------------------------------------
2442 
2443  *active = itemSelected;
2444 
2445  // TODO: Use result to return more internal states: mouse-press out-of-bounds, mouse-press over selected-item...
2446  return result; // Mouse click: result = 1
2447 }
2448 
2449 // Text Box control
2450 // NOTE: Returns true on ENTER pressed (useful for data validation)
2451 int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
2452 {
2453  #if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)
2454  #define RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN 40 // Frames to wait for autocursor movement
2455  #endif
2456  #if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY)
2457  #define RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY 1 // Frames delay for autocursor movement
2458  #endif
2459 
2460  int result = 0;
2461  GuiState state = guiState;
2462 
2463  bool multiline = false; // TODO: Consider multiline text input
2464  int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE);
2465 
2466  Rectangle textBounds = GetTextBounds(TEXTBOX, bounds);
2467  int textLength = (int)strlen(text); // Get current text length
2468  int thisCursorIndex = textBoxCursorIndex;
2469  if (thisCursorIndex > textLength) thisCursorIndex = textLength;
2470  int textWidth = GetTextWidth(text) - GetTextWidth(text + thisCursorIndex);
2471  int textIndexOffset = 0; // Text index offset to start drawing in the box
2472 
2473  // Cursor rectangle
2474  // NOTE: Position X value should be updated
2475  Rectangle cursor = {
2476  textBounds.x + textWidth + GuiGetStyle(DEFAULT, TEXT_SPACING),
2477  textBounds.y + textBounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE),
2478  2,
2479  (float)GuiGetStyle(DEFAULT, TEXT_SIZE)*2
2480  };
2481 
2482  if (cursor.height >= bounds.height) cursor.height = bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2;
2483  if (cursor.y < (bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH))) cursor.y = bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH);
2484 
2485  // Mouse cursor rectangle
2486  // NOTE: Initialized outside of screen
2487  Rectangle mouseCursor = cursor;
2488  mouseCursor.x = -1;
2489  mouseCursor.width = 1;
2490 
2491  // Auto-cursor movement logic
2492  // NOTE: Cursor moves automatically when key down after some time
2493  if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_UP) || IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_BACKSPACE) || IsKeyDown(KEY_DELETE)) autoCursorCooldownCounter++;
2494  else
2495  {
2496  autoCursorCooldownCounter = 0; // GLOBAL: Cursor cooldown counter
2497  autoCursorDelayCounter = 0; // GLOBAL: Cursor delay counter
2498  }
2499 
2500  // Blink-cursor frame counter
2501  //if (!autoCursorMode) blinkCursorFrameCounter++;
2502  //else blinkCursorFrameCounter = 0;
2503 
2504  // Update control
2505  //--------------------------------------------------------------------
2506  // WARNING: Text editing is only supported under certain conditions:
2507  if ((state != STATE_DISABLED) && // Control not disabled
2508  !GuiGetStyle(TEXTBOX, TEXT_READONLY) && // TextBox not on read-only mode
2509  !guiLocked && // Gui not locked
2510  !guiControlExclusiveMode && // No gui slider on dragging
2511  (wrapMode == TEXT_WRAP_NONE)) // No wrap mode
2512  {
2513  Vector2 mousePosition = GetMousePosition();
2514 
2515  if (editMode)
2516  {
2517  state = STATE_PRESSED;
2518 
2519  if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength;
2520 
2521  // If text does not fit in the textbox and current cursor position is out of bounds,
2522  // we add an index offset to text for drawing only what requires depending on cursor
2523  while (textWidth >= textBounds.width)
2524  {
2525  int nextCodepointSize = 0;
2526  GetCodepointNext(text + textIndexOffset, &nextCodepointSize);
2527 
2528  textIndexOffset += nextCodepointSize;
2529 
2530  textWidth = GetTextWidth(text + textIndexOffset) - GetTextWidth(text + textBoxCursorIndex);
2531  }
2532 
2533  int codepoint = GetCharPressed(); // Get Unicode codepoint
2534  if (multiline && IsKeyPressed(KEY_ENTER)) codepoint = (int)'\n';
2535 
2536  // Encode codepoint as UTF-8
2537  int codepointSize = 0;
2538  const char *charEncoded = CodepointToUTF8(codepoint, &codepointSize);
2539 
2540  // Add codepoint to text, at current cursor position
2541  // NOTE: Make sure we do not overflow buffer size
2542  if (((multiline && (codepoint == (int)'\n')) || (codepoint >= 32)) && ((textLength + codepointSize) < textSize))
2543  {
2544  // Move forward data from cursor position
2545  for (int i = (textLength + codepointSize); i > textBoxCursorIndex; i--) text[i] = text[i - codepointSize];
2546 
2547  // Add new codepoint in current cursor position
2548  for (int i = 0; i < codepointSize; i++) text[textBoxCursorIndex + i] = charEncoded[i];
2549 
2550  textBoxCursorIndex += codepointSize;
2551  textLength += codepointSize;
2552 
2553  // Make sure text last character is EOL
2554  text[textLength] = '\0';
2555  }
2556 
2557  // Move cursor to start
2558  if ((textLength > 0) && IsKeyPressed(KEY_HOME)) textBoxCursorIndex = 0;
2559 
2560  // Move cursor to end
2561  if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_END)) textBoxCursorIndex = textLength;
2562 
2563  // Delete codepoint from text, after current cursor position
2564  if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(KEY_DELETE) && (autoCursorCooldownCounter >= RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN))))
2565  {
2566  autoCursorDelayCounter++;
2567 
2568  if (IsKeyPressed(KEY_DELETE) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames
2569  {
2570  int nextCodepointSize = 0;
2571  GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
2572 
2573  // Move backward text from cursor position
2574  for (int i = textBoxCursorIndex; i < textLength; i++) text[i] = text[i + nextCodepointSize];
2575 
2576  textLength -= codepointSize;
2577  if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength;
2578 
2579  // Make sure text last character is EOL
2580  text[textLength] = '\0';
2581  }
2582  }
2583 
2584  // Delete codepoint from text, before current cursor position
2585  if ((textLength > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(KEY_BACKSPACE) && (autoCursorCooldownCounter >= RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN))))
2586  {
2587  autoCursorDelayCounter++;
2588 
2589  if (IsKeyPressed(KEY_BACKSPACE) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames
2590  {
2591  int prevCodepointSize = 0;
2592  GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
2593 
2594  // Move backward text from cursor position
2595  for (int i = (textBoxCursorIndex - prevCodepointSize); i < textLength; i++) text[i] = text[i + prevCodepointSize];
2596 
2597  // TODO Check: >= cursor+codepointsize and <= length-codepointsize
2598 
2599  // Prevent cursor index from decrementing past 0
2600  if (textBoxCursorIndex > 0)
2601  {
2602  textBoxCursorIndex -= codepointSize;
2603  textLength -= codepointSize;
2604  }
2605 
2606  // Make sure text last character is EOL
2607  text[textLength] = '\0';
2608  }
2609  }
2610 
2611  // Move cursor position with keys
2612  if (IsKeyPressed(KEY_LEFT) || (IsKeyDown(KEY_LEFT) && (autoCursorCooldownCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)))
2613  {
2614  autoCursorDelayCounter++;
2615 
2616  if (IsKeyPressed(KEY_LEFT) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames
2617  {
2618  int prevCodepointSize = 0;
2619  GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
2620 
2621  if (textBoxCursorIndex >= prevCodepointSize) textBoxCursorIndex -= prevCodepointSize;
2622  }
2623  }
2624  else if (IsKeyPressed(KEY_RIGHT) || (IsKeyDown(KEY_RIGHT) && (autoCursorCooldownCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)))
2625  {
2626  autoCursorDelayCounter++;
2627 
2628  if (IsKeyPressed(KEY_RIGHT) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames
2629  {
2630  int nextCodepointSize = 0;
2631  GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
2632 
2633  if ((textBoxCursorIndex + nextCodepointSize) <= textLength) textBoxCursorIndex += nextCodepointSize;
2634  }
2635  }
2636 
2637  // Move cursor position with mouse
2638  if (CheckCollisionPointRec(mousePosition, textBounds)) // Mouse hover text
2639  {
2640  float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/(float)guiFont.baseSize;
2641  int codepointIndex = 0;
2642  float glyphWidth = 0.0f;
2643  float widthToMouseX = 0;
2644  int mouseCursorIndex = 0;
2645 
2646  for (int i = textIndexOffset; i < textLength; i++)
2647  {
2648  codepoint = GetCodepointNext(&text[i], &codepointSize);
2649  codepointIndex = GetGlyphIndex(guiFont, codepoint);
2650 
2651  if (guiFont.glyphs[codepointIndex].advanceX == 0) glyphWidth = ((float)guiFont.recs[codepointIndex].width*scaleFactor);
2652  else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor);
2653 
2654  if (mousePosition.x <= (textBounds.x + (widthToMouseX + glyphWidth/2)))
2655  {
2656  mouseCursor.x = textBounds.x + widthToMouseX;
2657  mouseCursorIndex = i;
2658  break;
2659  }
2660 
2661  widthToMouseX += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
2662  }
2663 
2664  // Check if mouse cursor is at the last position
2665  int textEndWidth = GetTextWidth(text + textIndexOffset);
2666  if (GetMousePosition().x >= (textBounds.x + textEndWidth - glyphWidth/2))
2667  {
2668  mouseCursor.x = textBounds.x + textEndWidth;
2669  mouseCursorIndex = textLength;
2670  }
2671 
2672  // Place cursor at required index on mouse click
2673  if ((mouseCursor.x >= 0) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
2674  {
2675  cursor.x = mouseCursor.x;
2676  textBoxCursorIndex = mouseCursorIndex;
2677  }
2678  }
2679  else mouseCursor.x = -1;
2680 
2681  // Recalculate cursor position.y depending on textBoxCursorIndex
2682  cursor.x = bounds.x + GuiGetStyle(TEXTBOX, TEXT_PADDING) + GetTextWidth(text + textIndexOffset) - GetTextWidth(text + textBoxCursorIndex) + GuiGetStyle(DEFAULT, TEXT_SPACING);
2683  //if (multiline) cursor.y = GetTextLines()
2684 
2685  // Finish text editing on ENTER or mouse click outside bounds
2686  if ((!multiline && IsKeyPressed(KEY_ENTER)) ||
2687  (!CheckCollisionPointRec(mousePosition, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)))
2688  {
2689  textBoxCursorIndex = 0; // GLOBAL: Reset the shared cursor index
2690  result = 1;
2691  }
2692  }
2693  else
2694  {
2695  if (CheckCollisionPointRec(mousePosition, bounds))
2696  {
2697  state = STATE_FOCUSED;
2698 
2699  if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
2700  {
2701  textBoxCursorIndex = textLength; // GLOBAL: Place cursor index to the end of current text
2702  result = 1;
2703  }
2704  }
2705  }
2706  }
2707  //--------------------------------------------------------------------
2708 
2709  // Draw control
2710  //--------------------------------------------------------------------
2711  if (state == STATE_PRESSED)
2712  {
2713  GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED)));
2714  }
2715  else if (state == STATE_DISABLED)
2716  {
2717  GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_DISABLED)));
2718  }
2719  else GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), BLANK);
2720 
2721  // Draw text considering index offset if required
2722  // NOTE: Text index offset depends on cursor position
2723  GuiDrawText(text + textIndexOffset, textBounds, GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))));
2724 
2725  // Draw cursor
2726  if (editMode && !GuiGetStyle(TEXTBOX, TEXT_READONLY))
2727  {
2728  //if (autoCursorMode || ((blinkCursorFrameCounter/40)%2 == 0))
2729  GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)));
2730 
2731  // Draw mouse position cursor (if required)
2732  if (mouseCursor.x >= 0) GuiDrawRectangle(mouseCursor, 0, BLANK, GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)));
2733  }
2734  else if (state == STATE_FOCUSED) GuiTooltip(bounds);
2735  //--------------------------------------------------------------------
2736 
2737  return result; // Mouse button pressed: result = 1
2738 }
2739 
2740 /*
2741 // Text Box control with multiple lines and word-wrap
2742 // NOTE: This text-box is readonly, no editing supported by default
2743 bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode)
2744 {
2745  bool pressed = false;
2746 
2747  GuiSetStyle(TEXTBOX, TEXT_READONLY, 1);
2748  GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_WORD); // WARNING: If wrap mode enabled, text editing is not supported
2749  GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_TOP);
2750 
2751  // TODO: Implement methods to calculate cursor position properly
2752  pressed = GuiTextBox(bounds, text, textSize, editMode);
2753 
2754  GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE);
2755  GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_NONE);
2756  GuiSetStyle(TEXTBOX, TEXT_READONLY, 0);
2757 
2758  return pressed;
2759 }
2760 */
2761 
2762 // Spinner control, returns selected value
2763 int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode)
2764 {
2765  int result = 1;
2766  GuiState state = guiState;
2767 
2768  int tempValue = *value;
2769 
2770  Rectangle spinner = { bounds.x + GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_SPACING), bounds.y,
2771  bounds.width - 2*(GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_SPACING)), bounds.height };
2772  Rectangle leftButtonBound = { (float)bounds.x, (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height };
2773  Rectangle rightButtonBound = { (float)bounds.x + bounds.width - GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height };
2774 
2775  Rectangle textBounds = { 0 };
2776  if (text != NULL)
2777  {
2778  textBounds.width = (float)GetTextWidth(text) + 2;
2779  textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
2780  textBounds.x = bounds.x + bounds.width + GuiGetStyle(SPINNER, TEXT_PADDING);
2781  textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
2782  if (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SPINNER, TEXT_PADDING);
2783  }
2784 
2785  // Update control
2786  //--------------------------------------------------------------------
2787  if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
2788  {
2789  Vector2 mousePoint = GetMousePosition();
2790 
2791  // Check spinner state
2792  if (CheckCollisionPointRec(mousePoint, bounds))
2793  {
2794  if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
2795  else state = STATE_FOCUSED;
2796  }
2797  }
2798 
2799 #if defined(RAYGUI_NO_ICONS)
2800  if (GuiButton(leftButtonBound, "<")) tempValue--;
2801  if (GuiButton(rightButtonBound, ">")) tempValue++;
2802 #else
2803  if (GuiButton(leftButtonBound, GuiIconText(ICON_ARROW_LEFT_FILL, NULL))) tempValue--;
2804  if (GuiButton(rightButtonBound, GuiIconText(ICON_ARROW_RIGHT_FILL, NULL))) tempValue++;
2805 #endif
2806 
2807  if (!editMode)
2808  {
2809  if (tempValue < minValue) tempValue = minValue;
2810  if (tempValue > maxValue) tempValue = maxValue;
2811  }
2812  //--------------------------------------------------------------------
2813 
2814  // Draw control
2815  //--------------------------------------------------------------------
2816  result = GuiValueBox(spinner, NULL, &tempValue, minValue, maxValue, editMode);
2817 
2818  // Draw value selector custom buttons
2819  // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values
2820  int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
2821  int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
2822  GuiSetStyle(BUTTON, BORDER_WIDTH, GuiGetStyle(SPINNER, BORDER_WIDTH));
2823  GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
2824 
2825  GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign);
2826  GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
2827 
2828  // Draw text label if provided
2829  GuiDrawText(text, textBounds, (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
2830  //--------------------------------------------------------------------
2831 
2832  *value = tempValue;
2833  return result;
2834 }
2835 
2836 // Value Box control, updates input text with numbers
2837 // NOTE: Requires static variables: frameCounter
2838 int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode)
2839 {
2840  #if !defined(RAYGUI_VALUEBOX_MAX_CHARS)
2841  #define RAYGUI_VALUEBOX_MAX_CHARS 32
2842  #endif
2843 
2844  int result = 0;
2845  GuiState state = guiState;
2846 
2847  char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0";
2848  sprintf(textValue, "%i", *value);
2849 
2850  Rectangle textBounds = { 0 };
2851  if (text != NULL)
2852  {
2853  textBounds.width = (float)GetTextWidth(text) + 2;
2854  textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
2855  textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING);
2856  textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
2857  if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING);
2858  }
2859 
2860  // Update control
2861  //--------------------------------------------------------------------
2862  if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
2863  {
2864  Vector2 mousePoint = GetMousePosition();
2865 
2866  bool valueHasChanged = false;
2867 
2868  if (editMode)
2869  {
2870  state = STATE_PRESSED;
2871 
2872  int keyCount = (int)strlen(textValue);
2873 
2874  // Only allow keys in range [48..57]
2875  if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS)
2876  {
2877  if (GetTextWidth(textValue) < bounds.width)
2878  {
2879  int key = GetCharPressed();
2880  if ((key >= 48) && (key <= 57))
2881  {
2882  textValue[keyCount] = (char)key;
2883  keyCount++;
2884  valueHasChanged = true;
2885  }
2886  }
2887  }
2888 
2889  // Delete text
2890  if (keyCount > 0)
2891  {
2892  if (IsKeyPressed(KEY_BACKSPACE))
2893  {
2894  keyCount--;
2895  textValue[keyCount] = '\0';
2896  valueHasChanged = true;
2897  }
2898  }
2899 
2900  if (valueHasChanged) *value = TextToInteger(textValue);
2901 
2902  // NOTE: We are not clamp values until user input finishes
2903  //if (*value > maxValue) *value = maxValue;
2904  //else if (*value < minValue) *value = minValue;
2905 
2906  if (IsKeyPressed(KEY_ENTER) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)))
2907  {
2908  if (*value > maxValue) *value = maxValue;
2909  else if (*value < minValue) *value = minValue;
2910 
2911  result = 1;
2912  }
2913  }
2914  else
2915  {
2916  if (*value > maxValue) *value = maxValue;
2917  else if (*value < minValue) *value = minValue;
2918 
2919  if (CheckCollisionPointRec(mousePoint, bounds))
2920  {
2921  state = STATE_FOCUSED;
2922  if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1;
2923  }
2924  }
2925  }
2926  //--------------------------------------------------------------------
2927 
2928  // Draw control
2929  //--------------------------------------------------------------------
2930  Color baseColor = BLANK;
2931  if (state == STATE_PRESSED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_PRESSED));
2932  else if (state == STATE_DISABLED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_DISABLED));
2933 
2934  GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), baseColor);
2935  GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3))));
2936 
2937  // Draw cursor
2938  if (editMode)
2939  {
2940  // NOTE: ValueBox internal text is always centered
2941  Rectangle cursor = { bounds.x + GetTextWidth(textValue)/2 + bounds.width/2 + 1, bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4, bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH) };
2942  GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED)));
2943  }
2944 
2945  // Draw text label if provided
2946  GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
2947  //--------------------------------------------------------------------
2948 
2949  return result;
2950 }
2951 
2952 // Floating point Value Box control, updates input val_str with numbers
2953 // NOTE: Requires static variables: frameCounter
2954 int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode)
2955 {
2956  #if !defined(RAYGUI_VALUEBOX_MAX_CHARS)
2957  #define RAYGUI_VALUEBOX_MAX_CHARS 32
2958  #endif
2959 
2960  int result = 0;
2961  GuiState state = guiState;
2962 
2963  //char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0";
2964  //sprintf(textValue, "%2.2f", *value);
2965 
2966  Rectangle textBounds = {0};
2967  if (text != NULL)
2968  {
2969  textBounds.width = (float)GetTextWidth(text) + 2;
2970  textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
2971  textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING);
2972  textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
2973  if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING);
2974  }
2975 
2976  // Update control
2977  //--------------------------------------------------------------------
2978  if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
2979  {
2980  Vector2 mousePoint = GetMousePosition();
2981 
2982  bool valueHasChanged = false;
2983 
2984  if (editMode)
2985  {
2986  state = STATE_PRESSED;
2987 
2988  int keyCount = (int)strlen(textValue);
2989 
2990  // Only allow keys in range [48..57]
2991  if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS)
2992  {
2993  if (GetTextWidth(textValue) < bounds.width)
2994  {
2995  int key = GetCharPressed();
2996  if (((key >= 48) && (key <= 57)) ||
2997  (key == '.') ||
2998  ((keyCount == 0) && (key == '+')) || // NOTE: Sign can only be in first position
2999  ((keyCount == 0) && (key == '-')))
3000  {
3001  textValue[keyCount] = (char)key;
3002  keyCount++;
3003 
3004  valueHasChanged = true;
3005  }
3006  }
3007  }
3008 
3009  // Pressed backspace
3010  if (IsKeyPressed(KEY_BACKSPACE))
3011  {
3012  if (keyCount > 0)
3013  {
3014  keyCount--;
3015  textValue[keyCount] = '\0';
3016  valueHasChanged = true;
3017  }
3018  }
3019 
3020  if (valueHasChanged) *value = TextToFloat(textValue);
3021 
3022  if (IsKeyPressed(KEY_ENTER) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) result = 1;
3023  }
3024  else
3025  {
3026  if (CheckCollisionPointRec(mousePoint, bounds))
3027  {
3028  state = STATE_FOCUSED;
3029  if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1;
3030  }
3031  }
3032  }
3033  //--------------------------------------------------------------------
3034 
3035  // Draw control
3036  //--------------------------------------------------------------------
3037  Color baseColor = BLANK;
3038  if (state == STATE_PRESSED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_PRESSED));
3039  else if (state == STATE_DISABLED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_DISABLED));
3040 
3041  GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), baseColor);
3042  GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3))));
3043 
3044  // Draw cursor
3045  if (editMode)
3046  {
3047  // NOTE: ValueBox internal text is always centered
3048  Rectangle cursor = {bounds.x + GetTextWidth(textValue)/2 + bounds.width/2 + 1,
3049  bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4,
3050  bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH)};
3051  GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED)));
3052  }
3053 
3054  // Draw text label if provided
3055  GuiDrawText(text, textBounds,
3056  (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT,
3057  GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
3058  //--------------------------------------------------------------------
3059 
3060  return result;
3061 }
3062 
3063 // Slider control with pro parameters
3064 // NOTE: Other GuiSlider*() controls use this one
3065 int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue, int sliderWidth)
3066 {
3067  int result = 0;
3068  GuiState state = guiState;
3069 
3070  float temp = (maxValue - minValue)/2.0f;
3071  if (value == NULL) value = &temp;
3072  float oldValue = *value;
3073 
3074  Rectangle slider = { bounds.x, bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING),
3075  0, bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) };
3076 
3077  // Update control
3078  //--------------------------------------------------------------------
3079  if ((state != STATE_DISABLED) && !guiLocked)
3080  {
3081  Vector2 mousePoint = GetMousePosition();
3082 
3083  if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
3084  {
3085  if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
3086  {
3087  if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec))
3088  {
3089  state = STATE_PRESSED;
3090  // Get equivalent value and slider position from mousePosition.x
3091  *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width-sliderWidth)) + minValue;
3092  }
3093  }
3094  else
3095  {
3096  guiControlExclusiveMode = false;
3097  guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
3098  }
3099  }
3100  else if (CheckCollisionPointRec(mousePoint, bounds))
3101  {
3102  if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
3103  {
3104  state = STATE_PRESSED;
3105  guiControlExclusiveMode = true;
3106  guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts
3107 
3108  if (!CheckCollisionPointRec(mousePoint, slider))
3109  {
3110  // Get equivalent value and slider position from mousePosition.x
3111  *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width-sliderWidth)) + minValue;
3112  }
3113  }
3114  else state = STATE_FOCUSED;
3115  }
3116 
3117  if (*value > maxValue) *value = maxValue;
3118  else if (*value < minValue) *value = minValue;
3119  }
3120 
3121  // Control value change check
3122  if (oldValue == *value) result = 0;
3123  else result = 1;
3124 
3125  // Slider bar limits check
3126  float sliderValue = (((*value - minValue)/(maxValue - minValue))*(bounds.width - sliderWidth - 2*GuiGetStyle(SLIDER, BORDER_WIDTH)));
3127  if (sliderWidth > 0) // Slider
3128  {
3129  slider.x += sliderValue;
3130  slider.width = (float)sliderWidth;
3131  if (slider.x <= (bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH))) slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH);
3132  else if ((slider.x + slider.width) >= (bounds.x + bounds.width)) slider.x = bounds.x + bounds.width - slider.width - GuiGetStyle(SLIDER, BORDER_WIDTH);
3133  }
3134  else if (sliderWidth == 0) // SliderBar
3135  {
3136  slider.x += GuiGetStyle(SLIDER, BORDER_WIDTH);
3137  slider.width = sliderValue;
3138  if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH);
3139  }
3140  //--------------------------------------------------------------------
3141 
3142  // Draw control
3143  //--------------------------------------------------------------------
3144  GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), GetColor(GuiGetStyle(SLIDER, BORDER + (state*3))), GetColor(GuiGetStyle(SLIDER, (state != STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)));
3145 
3146  // Draw slider internal bar (depends on state)
3147  if (state == STATE_NORMAL) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED)));
3148  else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_FOCUSED)));
3149  else if (state == STATE_PRESSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_PRESSED)));
3150 
3151  // Draw left/right text if provided
3152  if (textLeft != NULL)
3153  {
3154  Rectangle textBounds = { 0 };
3155  textBounds.width = (float)GetTextWidth(textLeft);
3156  textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
3157  textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SLIDER, TEXT_PADDING);
3158  textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
3159 
3160  GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))));
3161  }
3162 
3163  if (textRight != NULL)
3164  {
3165  Rectangle textBounds = { 0 };
3166  textBounds.width = (float)GetTextWidth(textRight);
3167  textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
3168  textBounds.x = bounds.x + bounds.width + GuiGetStyle(SLIDER, TEXT_PADDING);
3169  textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
3170 
3171  GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))));
3172  }
3173  //--------------------------------------------------------------------
3174 
3175  return result;
3176 }
3177 
3178 // Slider control extended, returns selected value and has text
3179 int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue)
3180 {
3181  return GuiSliderPro(bounds, textLeft, textRight, value, minValue, maxValue, GuiGetStyle(SLIDER, SLIDER_WIDTH));
3182 }
3183 
3184 // Slider Bar control extended, returns selected value
3185 int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue)
3186 {
3187  return GuiSliderPro(bounds, textLeft, textRight, value, minValue, maxValue, 0);
3188 }
3189 
3190 // Progress Bar control extended, shows current progress value
3191 int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue)
3192 {
3193  int result = 0;
3194  GuiState state = guiState;
3195 
3196  float temp = (maxValue - minValue)/2.0f;
3197  if (value == NULL) value = &temp;
3198 
3199  // Progress bar
3200  Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH),
3201  bounds.y + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) + GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING), 0,
3202  bounds.height - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - 2*GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING) };
3203 
3204  // Update control
3205  //--------------------------------------------------------------------
3206  if (*value > maxValue) *value = maxValue;
3207 
3208  // WARNING: Working with floats could lead to rounding issues
3209  if ((state != STATE_DISABLED)) progress.width = (float)(*value/(maxValue - minValue))*bounds.width - ((*value >= maxValue)? (float)(2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)) : 0.0f);
3210  //--------------------------------------------------------------------
3211 
3212  // Draw control
3213  //--------------------------------------------------------------------
3214  if (state == STATE_DISABLED)
3215  {
3216  GuiDrawRectangle(bounds, GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), GetColor(GuiGetStyle(PROGRESSBAR, BORDER + (state*3))), BLANK);
3217  }
3218  else
3219  {
3220  if (*value > minValue)
3221  {
3222  // Draw progress bar with colored border, more visual
3223  GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED)));
3224  GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height - 2 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED)));
3225  GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED)));
3226  }
3227  else GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
3228 
3229  if (*value >= maxValue) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + progress.width + 1, bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED)));
3230  else
3231  {
3232  // Draw borders not yet reached by value
3233  GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + 1, bounds.y, bounds.width - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
3234  GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + 1, bounds.y + bounds.height - 1, bounds.width - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
3235  GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y + 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height - 2 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
3236  }
3237 
3238  // Draw slider internal progress bar (depends on state)
3239  GuiDrawRectangle(progress, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BASE_COLOR_PRESSED)));
3240  }
3241 
3242  // Draw left/right text if provided
3243  if (textLeft != NULL)
3244  {
3245  Rectangle textBounds = { 0 };
3246  textBounds.width = (float)GetTextWidth(textLeft);
3247  textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
3248  textBounds.x = bounds.x - textBounds.width - GuiGetStyle(PROGRESSBAR, TEXT_PADDING);
3249  textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
3250 
3251  GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(PROGRESSBAR, TEXT + (state*3))));
3252  }
3253 
3254  if (textRight != NULL)
3255  {
3256  Rectangle textBounds = { 0 };
3257  textBounds.width = (float)GetTextWidth(textRight);
3258  textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
3259  textBounds.x = bounds.x + bounds.width + GuiGetStyle(PROGRESSBAR, TEXT_PADDING);
3260  textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
3261 
3262  GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(PROGRESSBAR, TEXT + (state*3))));
3263  }
3264  //--------------------------------------------------------------------
3265 
3266  return result;
3267 }
3268 
3269 // Status Bar control
3270 int GuiStatusBar(Rectangle bounds, const char *text)
3271 {
3272  int result = 0;
3273  GuiState state = guiState;
3274 
3275  // Draw control
3276  //--------------------------------------------------------------------
3277  GuiDrawRectangle(bounds, GuiGetStyle(STATUSBAR, BORDER_WIDTH), GetColor(GuiGetStyle(STATUSBAR, BORDER + (state*3))), GetColor(GuiGetStyle(STATUSBAR, BASE + (state*3))));
3278  GuiDrawText(text, GetTextBounds(STATUSBAR, bounds), GuiGetStyle(STATUSBAR, TEXT_ALIGNMENT), GetColor(GuiGetStyle(STATUSBAR, TEXT + (state*3))));
3279  //--------------------------------------------------------------------
3280 
3281  return result;
3282 }
3283 
3284 // Dummy rectangle control, intended for placeholding
3285 int GuiDummyRec(Rectangle bounds, const char *text)
3286 {
3287  int result = 0;
3288  GuiState state = guiState;
3289 
3290  // Update control
3291  //--------------------------------------------------------------------
3292  if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
3293  {
3294  Vector2 mousePoint = GetMousePosition();
3295 
3296  // Check button state
3297  if (CheckCollisionPointRec(mousePoint, bounds))
3298  {
3299  if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
3300  else state = STATE_FOCUSED;
3301  }
3302  }
3303  //--------------------------------------------------------------------
3304 
3305  // Draw control
3306  //--------------------------------------------------------------------
3307  GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state != STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)));
3308  GuiDrawText(text, GetTextBounds(DEFAULT, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(BUTTON, (state != STATE_DISABLED)? TEXT_COLOR_NORMAL : TEXT_COLOR_DISABLED)));
3309  //------------------------------------------------------------------
3310 
3311  return result;
3312 }
3313 
3314 // List View control
3315 int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active)
3316 {
3317  int result = 0;
3318  int itemCount = 0;
3319  const char **items = NULL;
3320 
3321  if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL);
3322 
3323  result = GuiListViewEx(bounds, items, itemCount, scrollIndex, active, NULL);
3324 
3325  return result;
3326 }
3327 
3328 // List View control with extended parameters
3329 int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollIndex, int *active, int *focus)
3330 {
3331  int result = 0;
3332  GuiState state = guiState;
3333 
3334  int itemFocused = (focus == NULL)? -1 : *focus;
3335  int itemSelected = (active == NULL)? -1 : *active;
3336 
3337  // Check if we need a scroll bar
3338  bool useScrollBar = false;
3339  if ((GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING))*count > bounds.height) useScrollBar = true;
3340 
3341  // Define base item rectangle [0]
3342  Rectangle itemBounds = { 0 };
3343  itemBounds.x = bounds.x + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING);
3344  itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) + GuiGetStyle(DEFAULT, BORDER_WIDTH);
3345  itemBounds.width = bounds.width - 2*GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) - GuiGetStyle(DEFAULT, BORDER_WIDTH);
3346  itemBounds.height = (float)GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT);
3347  if (useScrollBar) itemBounds.width -= GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH);
3348 
3349  // Get items on the list
3350  int visibleItems = (int)bounds.height/(GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING));
3351  if (visibleItems > count) visibleItems = count;
3352 
3353  int startIndex = (scrollIndex == NULL)? 0 : *scrollIndex;
3354  if ((startIndex < 0) || (startIndex > (count - visibleItems))) startIndex = 0;
3355  int endIndex = startIndex + visibleItems;
3356 
3357  // Update control
3358  //--------------------------------------------------------------------
3359  if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
3360  {
3361  Vector2 mousePoint = GetMousePosition();
3362 
3363  // Check mouse inside list view
3364  if (CheckCollisionPointRec(mousePoint, bounds))
3365  {
3366  state = STATE_FOCUSED;
3367 
3368  // Check focused and selected item
3369  for (int i = 0; i < visibleItems; i++)
3370  {
3371  if (CheckCollisionPointRec(mousePoint, itemBounds))
3372  {
3373  itemFocused = startIndex + i;
3374  if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
3375  {
3376  if (itemSelected == (startIndex + i)) itemSelected = -1;
3377  else itemSelected = startIndex + i;
3378  }
3379  break;
3380  }
3381 
3382  // Update item rectangle y position for next item
3383  itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING));
3384  }
3385 
3386  if (useScrollBar)
3387  {
3388  int wheelMove = (int)GetMouseWheelMove();
3389  startIndex -= wheelMove;
3390 
3391  if (startIndex < 0) startIndex = 0;
3392  else if (startIndex > (count - visibleItems)) startIndex = count - visibleItems;
3393 
3394  endIndex = startIndex + visibleItems;
3395  if (endIndex > count) endIndex = count;
3396  }
3397  }
3398  else itemFocused = -1;
3399 
3400  // Reset item rectangle y to [0]
3401  itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) + GuiGetStyle(DEFAULT, BORDER_WIDTH);
3402  }
3403  //--------------------------------------------------------------------
3404 
3405  // Draw control
3406  //--------------------------------------------------------------------
3407  GuiDrawRectangle(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background
3408 
3409  // Draw visible items
3410  for (int i = 0; ((i < visibleItems) && (text != NULL)); i++)
3411  {
3412  GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_NORMAL)), BLANK);
3413 
3414  if (state == STATE_DISABLED)
3415  {
3416  if ((startIndex + i) == itemSelected) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED)));
3417 
3418  GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED)));
3419  }
3420  else
3421  {
3422  if (((startIndex + i) == itemSelected) && (active != NULL))
3423  {
3424  // Draw item selected
3425  GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)));
3426  GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED)));
3427  }
3428  else if (((startIndex + i) == itemFocused)) // && (focus != NULL)) // NOTE: We want items focused, despite not returned!
3429  {
3430  // Draw item focused
3431  GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED)));
3432  GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED)));
3433  }
3434  else
3435  {
3436  // Draw item normal
3437  GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL)));
3438  }
3439  }
3440 
3441  // Update item rectangle y position for next item
3442  itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING));
3443  }
3444 
3445  if (useScrollBar)
3446  {
3447  Rectangle scrollBarBounds = {
3448  bounds.x + bounds.width - GuiGetStyle(LISTVIEW, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH),
3449  bounds.y + GuiGetStyle(LISTVIEW, BORDER_WIDTH), (float)GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH),
3450  bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH)
3451  };
3452 
3453  // Calculate percentage of visible items and apply same percentage to scrollbar
3454  float percentVisible = (float)(endIndex - startIndex)/count;
3455  float sliderSize = bounds.height*percentVisible;
3456 
3457  int prevSliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); // Save default slider size
3458  int prevScrollSpeed = GuiGetStyle(SCROLLBAR, SCROLL_SPEED); // Save default scroll speed
3459  GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)sliderSize); // Change slider size
3460  GuiSetStyle(SCROLLBAR, SCROLL_SPEED, count - visibleItems); // Change scroll speed
3461 
3462  startIndex = GuiScrollBar(scrollBarBounds, startIndex, 0, count - visibleItems);
3463 
3464  GuiSetStyle(SCROLLBAR, SCROLL_SPEED, prevScrollSpeed); // Reset scroll speed to default
3465  GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, prevSliderSize); // Reset slider size to default
3466  }
3467  //--------------------------------------------------------------------
3468 
3469  if (active != NULL) *active = itemSelected;
3470  if (focus != NULL) *focus = itemFocused;
3471  if (scrollIndex != NULL) *scrollIndex = startIndex;
3472 
3473  return result;
3474 }
3475 
3476 // Color Panel control - Color (RGBA) variant.
3477 int GuiColorPanel(Rectangle bounds, const char *text, Color *color)
3478 {
3479  int result = 0;
3480 
3481  Vector3 vcolor = { (float)color->r/255.0f, (float)color->g/255.0f, (float)color->b/255.0f };
3482  Vector3 hsv = ConvertRGBtoHSV(vcolor);
3483  Vector3 prevHsv = hsv; // workaround to see if GuiColorPanelHSV modifies the hsv.
3484 
3485  GuiColorPanelHSV(bounds, text, &hsv);
3486 
3487  // Check if the hsv was changed, only then change the color.
3488  // This is required, because the Color->HSV->Color conversion has precision errors.
3489  // Thus the assignment from HSV to Color should only be made, if the HSV has a new user-entered value.
3490  // Otherwise GuiColorPanel would often modify it's color without user input.
3491  // TODO: GuiColorPanelHSV could return 1 if the slider was dragged, to simplify this check.
3492  if (hsv.x != prevHsv.x || hsv.y != prevHsv.y || hsv.z != prevHsv.z)
3493  {
3494  Vector3 rgb = ConvertHSVtoRGB(hsv);
3495 
3496  // NOTE: Vector3ToColor() only available on raylib 1.8.1
3497  *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x),
3498  (unsigned char)(255.0f*rgb.y),
3499  (unsigned char)(255.0f*rgb.z),
3500  color->a };
3501  }
3502  return result;
3503 }
3504 
3505 // Color Bar Alpha control
3506 // NOTE: Returns alpha value normalized [0..1]
3507 int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha)
3508 {
3509  #if !defined(RAYGUI_COLORBARALPHA_CHECKED_SIZE)
3510  #define RAYGUI_COLORBARALPHA_CHECKED_SIZE 10
3511  #endif
3512 
3513  int result = 0;
3514  GuiState state = guiState;
3515  Rectangle selector = { (float)bounds.x + (*alpha)*bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.y - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT), (float)bounds.height + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2 };
3516 
3517  // Update control
3518  //--------------------------------------------------------------------
3519  if ((state != STATE_DISABLED) && !guiLocked)
3520  {
3521  Vector2 mousePoint = GetMousePosition();
3522 
3523  if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
3524  {
3525  if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
3526  {
3527  if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec))
3528  {
3529  state = STATE_PRESSED;
3530 
3531  *alpha = (mousePoint.x - bounds.x)/bounds.width;
3532  if (*alpha <= 0.0f) *alpha = 0.0f;
3533  if (*alpha >= 1.0f) *alpha = 1.0f;
3534  }
3535  }
3536  else
3537  {
3538  guiControlExclusiveMode = false;
3539  guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
3540  }
3541  }
3542  else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector))
3543  {
3544  if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
3545  {
3546  state = STATE_PRESSED;
3547  guiControlExclusiveMode = true;
3548  guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts
3549 
3550  *alpha = (mousePoint.x - bounds.x)/bounds.width;
3551  if (*alpha <= 0.0f) *alpha = 0.0f;
3552  if (*alpha >= 1.0f) *alpha = 1.0f;
3553  //selector.x = bounds.x + (int)(((alpha - 0)/(100 - 0))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))) - selector.width/2;
3554  }
3555  else state = STATE_FOCUSED;
3556  }
3557  }
3558  //--------------------------------------------------------------------
3559 
3560  // Draw control
3561  //--------------------------------------------------------------------
3562 
3563  // Draw alpha bar: checked background
3564  if (state != STATE_DISABLED)
3565  {
3566  int checksX = (int)bounds.width/RAYGUI_COLORBARALPHA_CHECKED_SIZE;
3567  int checksY = (int)bounds.height/RAYGUI_COLORBARALPHA_CHECKED_SIZE;
3568 
3569  for (int x = 0; x < checksX; x++)
3570  {
3571  for (int y = 0; y < checksY; y++)
3572  {
3573  Rectangle check = { bounds.x + x*RAYGUI_COLORBARALPHA_CHECKED_SIZE, bounds.y + y*RAYGUI_COLORBARALPHA_CHECKED_SIZE, RAYGUI_COLORBARALPHA_CHECKED_SIZE, RAYGUI_COLORBARALPHA_CHECKED_SIZE };
3574  GuiDrawRectangle(check, 0, BLANK, ((x + y)%2)? Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.4f) : Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.4f));
3575  }
3576  }
3577 
3578  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));
3579  }
3580  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));
3581 
3582  GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK);
3583 
3584  // Draw alpha bar: selector
3585  GuiDrawRectangle(selector, 0, BLANK, GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)));
3586  //--------------------------------------------------------------------
3587 
3588  return result;
3589 }
3590 
3591 // Color Bar Hue control
3592 // Returns hue value normalized [0..1]
3593 // NOTE: Other similar bars (for reference):
3594 // Color GuiColorBarSat() [WHITE->color]
3595 // Color GuiColorBarValue() [BLACK->color], HSV/HSL
3596 // float GuiColorBarLuminance() [BLACK->WHITE]
3597 int GuiColorBarHue(Rectangle bounds, const char *text, float *hue)
3598 {
3599  int result = 0;
3600  GuiState state = guiState;
3601  Rectangle selector = { (float)bounds.x - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)bounds.y + (*hue)/360.0f*bounds.height - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2, (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT) };
3602 
3603  // Update control
3604  //--------------------------------------------------------------------
3605  if ((state != STATE_DISABLED) && !guiLocked)
3606  {
3607  Vector2 mousePoint = GetMousePosition();
3608 
3609  if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
3610  {
3611  if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
3612  {
3613  if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec))
3614  {
3615  state = STATE_PRESSED;
3616 
3617  *hue = (mousePoint.y - bounds.y)*360/bounds.height;
3618  if (*hue <= 0.0f) *hue = 0.0f;
3619  if (*hue >= 359.0f) *hue = 359.0f;
3620  }
3621  }
3622  else
3623  {
3624  guiControlExclusiveMode = false;
3625  guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
3626  }
3627  }
3628  else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector))
3629  {
3630  if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
3631  {
3632  state = STATE_PRESSED;
3633  guiControlExclusiveMode = true;
3634  guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts
3635 
3636  *hue = (mousePoint.y - bounds.y)*360/bounds.height;
3637  if (*hue <= 0.0f) *hue = 0.0f;
3638  if (*hue >= 359.0f) *hue = 359.0f;
3639 
3640  }
3641  else state = STATE_FOCUSED;
3642 
3643  /*if (IsKeyDown(KEY_UP))
3644  {
3645  hue -= 2.0f;
3646  if (hue <= 0.0f) hue = 0.0f;
3647  }
3648  else if (IsKeyDown(KEY_DOWN))
3649  {
3650  hue += 2.0f;
3651  if (hue >= 360.0f) hue = 360.0f;
3652  }*/
3653  }
3654  }
3655  //--------------------------------------------------------------------
3656 
3657  // Draw control
3658  //--------------------------------------------------------------------
3659  if (state != STATE_DISABLED)
3660  {
3661  // Draw hue bar:color bars
3662  // TODO: Use directly DrawRectangleGradientEx(bounds, color1, color2, color2, color1);
3663  DrawRectangleGradientV((int)bounds.x, (int)(bounds.y), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha));
3664  DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + bounds.height/6), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha));
3665  DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 2*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha));
3666  DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 3*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha));
3667  DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 4*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha));
3668  DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 5*(bounds.height/6)), (int)bounds.width, (int)(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha));
3669  }
3670  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));
3671 
3672  GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK);
3673 
3674  // Draw hue bar: selector
3675  GuiDrawRectangle(selector, 0, BLANK, GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)));
3676  //--------------------------------------------------------------------
3677 
3678  return result;
3679 }
3680 
3681 // Color Picker control
3682 // NOTE: It's divided in multiple controls:
3683 // Color GuiColorPanel(Rectangle bounds, Color color)
3684 // float GuiColorBarAlpha(Rectangle bounds, float alpha)
3685 // float GuiColorBarHue(Rectangle bounds, float value)
3686 // NOTE: bounds define GuiColorPanel() size
3687 // NOTE: this picker converts RGB to HSV, which can cause the Hue control to jump. If you have this problem, consider using the HSV variant instead
3688 int GuiColorPicker(Rectangle bounds, const char *text, Color *color)
3689 {
3690  int result = 0;
3691 
3692  Color temp = { 200, 0, 0, 255 };
3693  if (color == NULL) color = &temp;
3694 
3695  GuiColorPanel(bounds, NULL, color);
3696 
3697  Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height };
3698  //Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) };
3699 
3700  // NOTE: this conversion can cause low hue-resolution, if the r, g and b value are very similar, which causes the hue bar to shift around when only the GuiColorPanel is used.
3701  Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ (*color).r/255.0f, (*color).g/255.0f, (*color).b/255.0f });
3702 
3703  GuiColorBarHue(boundsHue, NULL, &hsv.x);
3704 
3705  //color.a = (unsigned char)(GuiColorBarAlpha(boundsAlpha, (float)color.a/255.0f)*255.0f);
3706  Vector3 rgb = ConvertHSVtoRGB(hsv);
3707 
3708  *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 };
3709 
3710  return result;
3711 }
3712 
3713 // Color Picker control that avoids conversion to RGB and back to HSV on each call, thus avoiding jittering.
3714 // The user can call ConvertHSVtoRGB() to convert *colorHsv value to RGB.
3715 // NOTE: It's divided in multiple controls:
3716 // int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv)
3717 // int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha)
3718 // float GuiColorBarHue(Rectangle bounds, float value)
3719 // NOTE: bounds define GuiColorPanelHSV() size
3720 int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv)
3721 {
3722  int result = 0;
3723 
3724  Vector3 tempHsv = { 0 };
3725 
3726  if (colorHsv == NULL)
3727  {
3728  const Vector3 tempColor = { 200.0f/255.0f, 0.0f, 0.0f };
3729  tempHsv = ConvertRGBtoHSV(tempColor);
3730  colorHsv = &tempHsv;
3731  }
3732 
3733  GuiColorPanelHSV(bounds, NULL, colorHsv);
3734 
3735  const Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height };
3736 
3737  GuiColorBarHue(boundsHue, NULL, &colorHsv->x);
3738 
3739  return result;
3740 }
3741 
3742 // Color Panel control - HSV variant
3743 int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv)
3744 {
3745  int result = 0;
3746  GuiState state = guiState;
3747  Vector2 pickerSelector = { 0 };
3748 
3749  const Color colWhite = { 255, 255, 255, 255 };
3750  const Color colBlack = { 0, 0, 0, 255 };
3751 
3752  pickerSelector.x = bounds.x + (float)colorHsv->y*bounds.width; // HSV: Saturation
3753  pickerSelector.y = bounds.y + (1.0f - (float)colorHsv->z)*bounds.height; // HSV: Value
3754 
3755  Vector3 maxHue = { colorHsv->x, 1.0f, 1.0f };
3756  Vector3 rgbHue = ConvertHSVtoRGB(maxHue);
3757  Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x),
3758  (unsigned char)(255.0f*rgbHue.y),
3759  (unsigned char)(255.0f*rgbHue.z), 255 };
3760 
3761  // Update control
3762  //--------------------------------------------------------------------
3763  if ((state != STATE_DISABLED) && !guiLocked)
3764  {
3765  Vector2 mousePoint = GetMousePosition();
3766 
3767  if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
3768  {
3769  if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
3770  {
3771  if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec))
3772  {
3773  pickerSelector = mousePoint;
3774 
3775  if (pickerSelector.x < bounds.x) pickerSelector.x = bounds.x;
3776  if (pickerSelector.x > bounds.x + bounds.width) pickerSelector.x = bounds.x + bounds.width;
3777  if (pickerSelector.y < bounds.y) pickerSelector.y = bounds.y;
3778  if (pickerSelector.y > bounds.y + bounds.height) pickerSelector.y = bounds.y + bounds.height;
3779 
3780  // Calculate color from picker
3781  Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y };
3782 
3783  colorPick.x /= (float)bounds.width; // Get normalized value on x
3784  colorPick.y /= (float)bounds.height; // Get normalized value on y
3785 
3786  colorHsv->y = colorPick.x;
3787  colorHsv->z = 1.0f - colorPick.y;
3788 
3789  }
3790  }
3791  else
3792  {
3793  guiControlExclusiveMode = false;
3794  guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
3795  }
3796  }
3797  else if (CheckCollisionPointRec(mousePoint, bounds))
3798  {
3799  if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
3800  {
3801  state = STATE_PRESSED;
3802  guiControlExclusiveMode = true;
3803  guiControlExclusiveRec = bounds;
3804  pickerSelector = mousePoint;
3805 
3806  // Calculate color from picker
3807  Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y };
3808 
3809  colorPick.x /= (float)bounds.width; // Get normalized value on x
3810  colorPick.y /= (float)bounds.height; // Get normalized value on y
3811 
3812  colorHsv->y = colorPick.x;
3813  colorHsv->z = 1.0f - colorPick.y;
3814  }
3815  else state = STATE_FOCUSED;
3816  }
3817  }
3818  //--------------------------------------------------------------------
3819 
3820  // Draw control
3821  //--------------------------------------------------------------------
3822  if (state != STATE_DISABLED)
3823  {
3824  DrawRectangleGradientEx(bounds, Fade(colWhite, guiAlpha), Fade(colWhite, guiAlpha), Fade(maxHueCol, guiAlpha), Fade(maxHueCol, guiAlpha));
3825  DrawRectangleGradientEx(bounds, Fade(colBlack, 0), Fade(colBlack, guiAlpha), Fade(colBlack, guiAlpha), Fade(colBlack, 0));
3826 
3827  // Draw color picker: selector
3828  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) };
3829  GuiDrawRectangle(selector, 0, BLANK, colWhite);
3830  }
3831  else
3832  {
3833  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));
3834  }
3835 
3836  GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK);
3837  //--------------------------------------------------------------------
3838 
3839  return result;
3840 }
3841 
3842 // Message Box control
3843 int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons)
3844 {
3845  #if !defined(RAYGUI_MESSAGEBOX_BUTTON_HEIGHT)
3846  #define RAYGUI_MESSAGEBOX_BUTTON_HEIGHT 24
3847  #endif
3848  #if !defined(RAYGUI_MESSAGEBOX_BUTTON_PADDING)
3849  #define RAYGUI_MESSAGEBOX_BUTTON_PADDING 12
3850  #endif
3851 
3852  int result = -1; // Returns clicked button from buttons list, 0 refers to closed window button
3853 
3854  int buttonCount = 0;
3855  const char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL);
3856  Rectangle buttonBounds = { 0 };
3857  buttonBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING;
3858  buttonBounds.y = bounds.y + bounds.height - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT - RAYGUI_MESSAGEBOX_BUTTON_PADDING;
3859  buttonBounds.width = (bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount;
3860  buttonBounds.height = RAYGUI_MESSAGEBOX_BUTTON_HEIGHT;
3861 
3862  int textWidth = GetTextWidth(message) + 2;
3863 
3864  Rectangle textBounds = { 0 };
3865  textBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING;
3866  textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + RAYGUI_MESSAGEBOX_BUTTON_PADDING;
3867  textBounds.width = bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*2;
3868  textBounds.height = bounds.height - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 3*RAYGUI_MESSAGEBOX_BUTTON_PADDING - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT;
3869 
3870  // Draw control
3871  //--------------------------------------------------------------------
3872  if (GuiWindowBox(bounds, title)) result = 0;
3873 
3874  int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT);
3875  GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
3876  GuiLabel(textBounds, message);
3877  GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment);
3878 
3879  prevTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
3880  GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
3881 
3882  for (int i = 0; i < buttonCount; i++)
3883  {
3884  if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1;
3885  buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING);
3886  }
3887 
3888  GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevTextAlignment);
3889  //--------------------------------------------------------------------
3890 
3891  return result;
3892 }
3893 
3894 // Text Input Box control, ask for text
3895 int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive)
3896 {
3897  #if !defined(RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT)
3898  #define RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT 24
3899  #endif
3900  #if !defined(RAYGUI_TEXTINPUTBOX_BUTTON_PADDING)
3901  #define RAYGUI_TEXTINPUTBOX_BUTTON_PADDING 12
3902  #endif
3903  #if !defined(RAYGUI_TEXTINPUTBOX_HEIGHT)
3904  #define RAYGUI_TEXTINPUTBOX_HEIGHT 26
3905  #endif
3906 
3907  // Used to enable text edit mode
3908  // WARNING: No more than one GuiTextInputBox() should be open at the same time
3909  static bool textEditMode = false;
3910 
3911  int result = -1;
3912 
3913  int buttonCount = 0;
3914  const char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL);
3915  Rectangle buttonBounds = { 0 };
3916  buttonBounds.x = bounds.x + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING;
3917  buttonBounds.y = bounds.y + bounds.height - RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING;
3918  buttonBounds.width = (bounds.width - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount;
3919  buttonBounds.height = RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT;
3920 
3921  int messageInputHeight = (int)bounds.height - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT - 2*RAYGUI_TEXTINPUTBOX_BUTTON_PADDING;
3922 
3923  Rectangle textBounds = { 0 };
3924  if (message != NULL)
3925  {
3926  int textSize = GetTextWidth(message) + 2;
3927 
3928  textBounds.x = bounds.x + bounds.width/2 - textSize/2;
3929  textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + messageInputHeight/4 - (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
3930  textBounds.width = (float)textSize;
3931  textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
3932  }
3933 
3934  Rectangle textBoxBounds = { 0 };
3935  textBoxBounds.x = bounds.x + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING;
3936  textBoxBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - RAYGUI_TEXTINPUTBOX_HEIGHT/2;
3937  if (message == NULL) textBoxBounds.y = bounds.y + 24 + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING;
3938  else textBoxBounds.y += (messageInputHeight/2 + messageInputHeight/4);
3939  textBoxBounds.width = bounds.width - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING*2;
3940  textBoxBounds.height = RAYGUI_TEXTINPUTBOX_HEIGHT;
3941 
3942  // Draw control
3943  //--------------------------------------------------------------------
3944  if (GuiWindowBox(bounds, title)) result = 0;
3945 
3946  // Draw message if available
3947  if (message != NULL)
3948  {
3949  int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT);
3950  GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
3951  GuiLabel(textBounds, message);
3952  GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment);
3953  }
3954 
3955  if (secretViewActive != NULL)
3956  {
3957  static char stars[] = "****************";
3958  if (GuiTextBox(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x, textBoxBounds.y, textBoxBounds.width - 4 - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.height },
3959  ((*secretViewActive == 1) || textEditMode)? text : stars, textMaxSize, textEditMode)) textEditMode = !textEditMode;
3960 
3961  GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, (*secretViewActive == 1)? "#44#" : "#45#", secretViewActive);
3962  }
3963  else
3964  {
3965  if (GuiTextBox(textBoxBounds, text, textMaxSize, textEditMode)) textEditMode = !textEditMode;
3966  }
3967 
3968  int prevBtnTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
3969  GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
3970 
3971  for (int i = 0; i < buttonCount; i++)
3972  {
3973  if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1;
3974  buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING);
3975  }
3976 
3977  if (result >= 0) textEditMode = false;
3978 
3979  GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevBtnTextAlignment);
3980  //--------------------------------------------------------------------
3981 
3982  return result; // Result is the pressed button index
3983 }
3984 
3985 // Grid control
3986 // NOTE: Returns grid mouse-hover selected cell
3987 // About drawing lines at subpixel spacing, simple put, not easy solution:
3988 // https://stackoverflow.com/questions/4435450/2d-opengl-drawing-lines-that-dont-exactly-fit-pixel-raster
3989 int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vector2 *mouseCell)
3990 {
3991  // Grid lines alpha amount
3992  #if !defined(RAYGUI_GRID_ALPHA)
3993  #define RAYGUI_GRID_ALPHA 0.15f
3994  #endif
3995 
3996  int result = 0;
3997  GuiState state = guiState;
3998 
3999  Vector2 mousePoint = GetMousePosition();
4000  Vector2 currentMouseCell = { -1, -1 };
4001 
4002  float spaceWidth = spacing/(float)subdivs;
4003  int linesV = (int)(bounds.width/spaceWidth) + 1;
4004  int linesH = (int)(bounds.height/spaceWidth) + 1;
4005 
4006  int color = GuiGetStyle(DEFAULT, LINE_COLOR);
4007 
4008  // Update control
4009  //--------------------------------------------------------------------
4010  if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
4011  {
4012  if (CheckCollisionPointRec(mousePoint, bounds))
4013  {
4014  // NOTE: Cell values must be the upper left of the cell the mouse is in
4015  currentMouseCell.x = floorf((mousePoint.x - bounds.x)/spacing);
4016  currentMouseCell.y = floorf((mousePoint.y - bounds.y)/spacing);
4017  }
4018  }
4019  //--------------------------------------------------------------------
4020 
4021  // Draw control
4022  //--------------------------------------------------------------------
4023  if (state == STATE_DISABLED) color = GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED);
4024 
4025  if (subdivs > 0)
4026  {
4027  // Draw vertical grid lines
4028  for (int i = 0; i < linesV; i++)
4029  {
4030  Rectangle lineV = { bounds.x + spacing*i/subdivs, bounds.y, 1, bounds.height + 1 };
4031  GuiDrawRectangle(lineV, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(color), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(color), RAYGUI_GRID_ALPHA));
4032  }
4033 
4034  // Draw horizontal grid lines
4035  for (int i = 0; i < linesH; i++)
4036  {
4037  Rectangle lineH = { bounds.x, bounds.y + spacing*i/subdivs, bounds.width + 1, 1 };
4038  GuiDrawRectangle(lineH, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(color), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(color), RAYGUI_GRID_ALPHA));
4039  }
4040  }
4041 
4042  if (mouseCell != NULL) *mouseCell = currentMouseCell;
4043  return result;
4044 }
4045 
4046 //----------------------------------------------------------------------------------
4047 // Tooltip management functions
4048 // NOTE: Tooltips requires some global variables: tooltipPtr
4049 //----------------------------------------------------------------------------------
4050 // Enable gui tooltips (global state)
4051 void GuiEnableTooltip(void) { guiTooltip = true; }
4052 
4053 // Disable gui tooltips (global state)
4054 void GuiDisableTooltip(void) { guiTooltip = false; }
4055 
4056 // Set tooltip string
4057 void GuiSetTooltip(const char *tooltip) { guiTooltipPtr = tooltip; }
4058 
4059 //----------------------------------------------------------------------------------
4060 // Styles loading functions
4061 //----------------------------------------------------------------------------------
4062 
4063 // Load raygui style file (.rgs)
4064 // NOTE: By default a binary file is expected, that file could contain a custom font,
4065 // in that case, custom font image atlas is GRAY+ALPHA and pixel data can be compressed (DEFLATE)
4066 void GuiLoadStyle(const char *fileName)
4067 {
4068  #define MAX_LINE_BUFFER_SIZE 256
4069 
4070  bool tryBinary = false;
4071  if (!guiStyleLoaded) GuiLoadStyleDefault();
4072 
4073  // Try reading the files as text file first
4074  FILE *rgsFile = fopen(fileName, "rt");
4075 
4076  if (rgsFile != NULL)
4077  {
4078  char buffer[MAX_LINE_BUFFER_SIZE] = { 0 };
4079  fgets(buffer, MAX_LINE_BUFFER_SIZE, rgsFile);
4080 
4081  if (buffer[0] == '#')
4082  {
4083  int controlId = 0;
4084  int propertyId = 0;
4085  unsigned int propertyValue = 0;
4086 
4087  while (!feof(rgsFile))
4088  {
4089  switch (buffer[0])
4090  {
4091  case 'p':
4092  {
4093  // Style property: p <control_id> <property_id> <property_value> <property_name>
4094 
4095  sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue);
4096  GuiSetStyle(controlId, propertyId, (int)propertyValue);
4097 
4098  } break;
4099  case 'f':
4100  {
4101  // Style font: f <gen_font_size> <charmap_file> <font_file>
4102 
4103  int fontSize = 0;
4104  char charmapFileName[256] = { 0 };
4105  char fontFileName[256] = { 0 };
4106  sscanf(buffer, "f %d %s %[^\r\n]s", &fontSize, charmapFileName, fontFileName);
4107 
4108  Font font = { 0 };
4109  int *codepoints = NULL;
4110  int codepointCount = 0;
4111 
4112  if (charmapFileName[0] != '0')
4113  {
4114  // Load text data from file
4115  // NOTE: Expected an UTF-8 array of codepoints, no separation
4116  char *textData = LoadFileText(TextFormat("%s/%s", GetDirectoryPath(fileName), charmapFileName));
4117  codepoints = LoadCodepoints(textData, &codepointCount);
4118  UnloadFileText(textData);
4119  }
4120 
4121  if (fontFileName[0] != '\0')
4122  {
4123  // In case a font is already loaded and it is not default internal font, unload it
4124  if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture);
4125 
4126  if (codepointCount > 0) font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, codepoints, codepointCount);
4127  else font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, NULL, 0); // Default to 95 standard codepoints
4128  }
4129 
4130  // If font texture not properly loaded, revert to default font and size/spacing
4131  if (font.texture.id == 0)
4132  {
4133  font = GetFontDefault();
4134  GuiSetStyle(DEFAULT, TEXT_SIZE, 10);
4135  GuiSetStyle(DEFAULT, TEXT_SPACING, 1);
4136  }
4137 
4138  UnloadCodepoints(codepoints);
4139 
4140  if ((font.texture.id > 0) && (font.glyphCount > 0)) GuiSetFont(font);
4141 
4142  } break;
4143  default: break;
4144  }
4145 
4146  fgets(buffer, MAX_LINE_BUFFER_SIZE, rgsFile);
4147  }
4148  }
4149  else tryBinary = true;
4150 
4151  fclose(rgsFile);
4152  }
4153 
4154  if (tryBinary)
4155  {
4156  rgsFile = fopen(fileName, "rb");
4157 
4158  if (rgsFile != NULL)
4159  {
4160  fseek(rgsFile, 0, SEEK_END);
4161  int fileDataSize = ftell(rgsFile);
4162  fseek(rgsFile, 0, SEEK_SET);
4163 
4164  if (fileDataSize > 0)
4165  {
4166  unsigned char *fileData = (unsigned char *)RAYGUI_MALLOC(fileDataSize*sizeof(unsigned char));
4167  fread(fileData, sizeof(unsigned char), fileDataSize, rgsFile);
4168 
4169  GuiLoadStyleFromMemory(fileData, fileDataSize);
4170 
4171  RAYGUI_FREE(fileData);
4172  }
4173 
4174  fclose(rgsFile);
4175  }
4176  }
4177 }
4178 
4179 // Load style default over global style
4180 void GuiLoadStyleDefault(void)
4181 {
4182  // We set this variable first to avoid cyclic function calls
4183  // when calling GuiSetStyle() and GuiGetStyle()
4184  guiStyleLoaded = true;
4185 
4186  // Initialize default LIGHT style property values
4187  // WARNING: Default value are applied to all controls on set but
4188  // they can be overwritten later on for every custom control
4189  GuiSetStyle(DEFAULT, BORDER_COLOR_NORMAL, 0x838383ff);
4190  GuiSetStyle(DEFAULT, BASE_COLOR_NORMAL, 0xc9c9c9ff);
4191  GuiSetStyle(DEFAULT, TEXT_COLOR_NORMAL, 0x686868ff);
4192  GuiSetStyle(DEFAULT, BORDER_COLOR_FOCUSED, 0x5bb2d9ff);
4193  GuiSetStyle(DEFAULT, BASE_COLOR_FOCUSED, 0xc9effeff);
4194  GuiSetStyle(DEFAULT, TEXT_COLOR_FOCUSED, 0x6c9bbcff);
4195  GuiSetStyle(DEFAULT, BORDER_COLOR_PRESSED, 0x0492c7ff);
4196  GuiSetStyle(DEFAULT, BASE_COLOR_PRESSED, 0x97e8ffff);
4197  GuiSetStyle(DEFAULT, TEXT_COLOR_PRESSED, 0x368bafff);
4198  GuiSetStyle(DEFAULT, BORDER_COLOR_DISABLED, 0xb5c1c2ff);
4199  GuiSetStyle(DEFAULT, BASE_COLOR_DISABLED, 0xe6e9e9ff);
4200  GuiSetStyle(DEFAULT, TEXT_COLOR_DISABLED, 0xaeb7b8ff);
4201  GuiSetStyle(DEFAULT, BORDER_WIDTH, 1);
4202  GuiSetStyle(DEFAULT, TEXT_PADDING, 0);
4203  GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
4204 
4205  // Initialize default extended property values
4206  // NOTE: By default, extended property values are initialized to 0
4207  GuiSetStyle(DEFAULT, TEXT_SIZE, 10); // DEFAULT, shared by all controls
4208  GuiSetStyle(DEFAULT, TEXT_SPACING, 1); // DEFAULT, shared by all controls
4209  GuiSetStyle(DEFAULT, LINE_COLOR, 0x90abb5ff); // DEFAULT specific property
4210  GuiSetStyle(DEFAULT, BACKGROUND_COLOR, 0xf5f5f5ff); // DEFAULT specific property
4211  GuiSetStyle(DEFAULT, TEXT_LINE_SPACING, 15); // DEFAULT, 15 pixels between lines
4212  GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); // DEFAULT, text aligned vertically to middle of text-bounds
4213 
4214  // Initialize control-specific property values
4215  // NOTE: Those properties are in default list but require specific values by control type
4216  GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
4217  GuiSetStyle(BUTTON, BORDER_WIDTH, 2);
4218  GuiSetStyle(SLIDER, TEXT_PADDING, 4);
4219  GuiSetStyle(PROGRESSBAR, TEXT_PADDING, 4);
4220  GuiSetStyle(CHECKBOX, TEXT_PADDING, 4);
4221  GuiSetStyle(CHECKBOX, TEXT_ALIGNMENT, TEXT_ALIGN_RIGHT);
4222  GuiSetStyle(DROPDOWNBOX, TEXT_PADDING, 0);
4223  GuiSetStyle(DROPDOWNBOX, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
4224  GuiSetStyle(TEXTBOX, TEXT_PADDING, 4);
4225  GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
4226  GuiSetStyle(VALUEBOX, TEXT_PADDING, 0);
4227  GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
4228  GuiSetStyle(SPINNER, TEXT_PADDING, 0);
4229  GuiSetStyle(SPINNER, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
4230  GuiSetStyle(STATUSBAR, TEXT_PADDING, 8);
4231  GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
4232 
4233  // Initialize extended property values
4234  // NOTE: By default, extended property values are initialized to 0
4235  GuiSetStyle(TOGGLE, GROUP_PADDING, 2);
4236  GuiSetStyle(SLIDER, SLIDER_WIDTH, 16);
4237  GuiSetStyle(SLIDER, SLIDER_PADDING, 1);
4238  GuiSetStyle(PROGRESSBAR, PROGRESS_PADDING, 1);
4239  GuiSetStyle(CHECKBOX, CHECK_PADDING, 1);
4240  GuiSetStyle(COMBOBOX, COMBO_BUTTON_WIDTH, 32);
4241  GuiSetStyle(COMBOBOX, COMBO_BUTTON_SPACING, 2);
4242  GuiSetStyle(DROPDOWNBOX, ARROW_PADDING, 16);
4243  GuiSetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING, 2);
4244  GuiSetStyle(SPINNER, SPIN_BUTTON_WIDTH, 24);
4245  GuiSetStyle(SPINNER, SPIN_BUTTON_SPACING, 2);
4246  GuiSetStyle(SCROLLBAR, BORDER_WIDTH, 0);
4247  GuiSetStyle(SCROLLBAR, ARROWS_VISIBLE, 0);
4248  GuiSetStyle(SCROLLBAR, ARROWS_SIZE, 6);
4249  GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING, 0);
4250  GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, 16);
4251  GuiSetStyle(SCROLLBAR, SCROLL_PADDING, 0);
4252  GuiSetStyle(SCROLLBAR, SCROLL_SPEED, 12);
4253  GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, 28);
4254  GuiSetStyle(LISTVIEW, LIST_ITEMS_SPACING, 2);
4255  GuiSetStyle(LISTVIEW, SCROLLBAR_WIDTH, 12);
4256  GuiSetStyle(LISTVIEW, SCROLLBAR_SIDE, SCROLLBAR_RIGHT_SIDE);
4257  GuiSetStyle(COLORPICKER, COLOR_SELECTOR_SIZE, 8);
4258  GuiSetStyle(COLORPICKER, HUEBAR_WIDTH, 16);
4259  GuiSetStyle(COLORPICKER, HUEBAR_PADDING, 8);
4260  GuiSetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT, 8);
4261  GuiSetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW, 2);
4262 
4263  if (guiFont.texture.id != GetFontDefault().texture.id)
4264  {
4265  // Unload previous font texture
4266  UnloadTexture(guiFont.texture);
4267  RL_FREE(guiFont.recs);
4268  RL_FREE(guiFont.glyphs);
4269  guiFont.recs = NULL;
4270  guiFont.glyphs = NULL;
4271 
4272  // Setup default raylib font
4273  guiFont = GetFontDefault();
4274 
4275  // NOTE: Default raylib font character 95 is a white square
4276  Rectangle whiteChar = guiFont.recs[95];
4277 
4278  // NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering
4279  SetShapesTexture(guiFont.texture, RAYGUI_CLITERAL(Rectangle){ whiteChar.x + 1, whiteChar.y + 1, whiteChar.width - 2, whiteChar.height - 2 });
4280  }
4281 }
4282 
4283 // Get text with icon id prepended
4284 // NOTE: Useful to add icons by name id (enum) instead of
4285 // a number that can change between ricon versions
4286 const char *GuiIconText(int iconId, const char *text)
4287 {
4288 #if defined(RAYGUI_NO_ICONS)
4289  return NULL;
4290 #else
4291  static char buffer[1024] = { 0 };
4292  static char iconBuffer[16] = { 0 };
4293 
4294  if (text != NULL)
4295  {
4296  memset(buffer, 0, 1024);
4297  sprintf(buffer, "#%03i#", iconId);
4298 
4299  for (int i = 5; i < 1024; i++)
4300  {
4301  buffer[i] = text[i - 5];
4302  if (text[i - 5] == '\0') break;
4303  }
4304 
4305  return buffer;
4306  }
4307  else
4308  {
4309  sprintf(iconBuffer, "#%03i#", iconId);
4310 
4311  return iconBuffer;
4312  }
4313 #endif
4314 }
4315 
4316 #if !defined(RAYGUI_NO_ICONS)
4317 // Get full icons data pointer
4318 unsigned int *GuiGetIcons(void) { return guiIconsPtr; }
4319 
4320 // Load raygui icons file (.rgi)
4321 // NOTE: In case nameIds are required, they can be requested with loadIconsName,
4322 // they are returned as a guiIconsName[iconCount][RAYGUI_ICON_MAX_NAME_LENGTH],
4323 // WARNING: guiIconsName[]][] memory should be manually freed!
4324 char **GuiLoadIcons(const char *fileName, bool loadIconsName)
4325 {
4326  // Style File Structure (.rgi)
4327  // ------------------------------------------------------
4328  // Offset | Size | Type | Description
4329  // ------------------------------------------------------
4330  // 0 | 4 | char | Signature: "rGI "
4331  // 4 | 2 | short | Version: 100
4332  // 6 | 2 | short | reserved
4333 
4334  // 8 | 2 | short | Num icons (N)
4335  // 10 | 2 | short | Icons size (Options: 16, 32, 64) (S)
4336 
4337  // Icons name id (32 bytes per name id)
4338  // foreach (icon)
4339  // {
4340  // 12+32*i | 32 | char | Icon NameId
4341  // }
4342 
4343  // Icons data: One bit per pixel, stored as unsigned int array (depends on icon size)
4344  // S*S pixels/32bit per unsigned int = K unsigned int per icon
4345  // foreach (icon)
4346  // {
4347  // ... | K | unsigned int | Icon Data
4348  // }
4349 
4350  FILE *rgiFile = fopen(fileName, "rb");
4351 
4352  char **guiIconsName = NULL;
4353 
4354  if (rgiFile != NULL)
4355  {
4356  char signature[5] = { 0 };
4357  short version = 0;
4358  short reserved = 0;
4359  short iconCount = 0;
4360  short iconSize = 0;
4361 
4362  fread(signature, 1, 4, rgiFile);
4363  fread(&version, sizeof(short), 1, rgiFile);
4364  fread(&reserved, sizeof(short), 1, rgiFile);
4365  fread(&iconCount, sizeof(short), 1, rgiFile);
4366  fread(&iconSize, sizeof(short), 1, rgiFile);
4367 
4368  if ((signature[0] == 'r') &&
4369  (signature[1] == 'G') &&
4370  (signature[2] == 'I') &&
4371  (signature[3] == ' '))
4372  {
4373  if (loadIconsName)
4374  {
4375  guiIconsName = (char **)RAYGUI_MALLOC(iconCount*sizeof(char **));
4376  for (int i = 0; i < iconCount; i++)
4377  {
4378  guiIconsName[i] = (char *)RAYGUI_MALLOC(RAYGUI_ICON_MAX_NAME_LENGTH);
4379  fread(guiIconsName[i], 1, RAYGUI_ICON_MAX_NAME_LENGTH, rgiFile);
4380  }
4381  }
4382  else fseek(rgiFile, iconCount*RAYGUI_ICON_MAX_NAME_LENGTH, SEEK_CUR);
4383 
4384  // Read icons data directly over internal icons array
4385  fread(guiIconsPtr, sizeof(unsigned int), iconCount*(iconSize*iconSize/32), rgiFile);
4386  }
4387 
4388  fclose(rgiFile);
4389  }
4390 
4391  return guiIconsName;
4392 }
4393 
4394 // Draw selected icon using rectangles pixel-by-pixel
4395 void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color)
4396 {
4397  #define BIT_CHECK(a,b) ((a) & (1u<<(b)))
4398 
4399  for (int i = 0, y = 0; i < RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32; i++)
4400  {
4401  for (int k = 0; k < 32; k++)
4402  {
4403  if (BIT_CHECK(guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i], k))
4404  {
4405  #if !defined(RAYGUI_STANDALONE)
4406  GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize, (float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color);
4407  #endif
4408  }
4409 
4410  if ((k == 15) || (k == 31)) y++;
4411  }
4412  }
4413 }
4414 
4415 // Set icon drawing size
4416 void GuiSetIconScale(int scale)
4417 {
4418  if (scale >= 1) guiIconScale = scale;
4419 }
4420 
4421 #endif // !RAYGUI_NO_ICONS
4422 
4423 //----------------------------------------------------------------------------------
4424 // Module specific Functions Definition
4425 //----------------------------------------------------------------------------------
4426 
4427 // Load style from memory
4428 // WARNING: Binary files only
4429 static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
4430 {
4431  unsigned char *fileDataPtr = (unsigned char *)fileData;
4432 
4433  char signature[5] = { 0 };
4434  short version = 0;
4435  short reserved = 0;
4436  int propertyCount = 0;
4437 
4438  memcpy(signature, fileDataPtr, 4);
4439  memcpy(&version, fileDataPtr + 4, sizeof(short));
4440  memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short));
4441  memcpy(&propertyCount, fileDataPtr + 4 + 2 + 2, sizeof(int));
4442  fileDataPtr += 12;
4443 
4444  if ((signature[0] == 'r') &&
4445  (signature[1] == 'G') &&
4446  (signature[2] == 'S') &&
4447  (signature[3] == ' '))
4448  {
4449  short controlId = 0;
4450  short propertyId = 0;
4451  unsigned int propertyValue = 0;
4452 
4453  for (int i = 0; i < propertyCount; i++)
4454  {
4455  memcpy(&controlId, fileDataPtr, sizeof(short));
4456  memcpy(&propertyId, fileDataPtr + 2, sizeof(short));
4457  memcpy(&propertyValue, fileDataPtr + 2 + 2, sizeof(unsigned int));
4458  fileDataPtr += 8;
4459 
4460  if (controlId == 0) // DEFAULT control
4461  {
4462  // If a DEFAULT property is loaded, it is propagated to all controls
4463  // NOTE: All DEFAULT properties should be defined first in the file
4464  GuiSetStyle(0, (int)propertyId, propertyValue);
4465 
4466  if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int i = 1; i < RAYGUI_MAX_CONTROLS; i++) GuiSetStyle(i, (int)propertyId, propertyValue);
4467  }
4468  else GuiSetStyle((int)controlId, (int)propertyId, propertyValue);
4469  }
4470 
4471  // Font loading is highly dependant on raylib API to load font data and image
4472 
4473 #if !defined(RAYGUI_STANDALONE)
4474  // Load custom font if available
4475  int fontDataSize = 0;
4476  memcpy(&fontDataSize, fileDataPtr, sizeof(int));
4477  fileDataPtr += 4;
4478 
4479  if (fontDataSize > 0)
4480  {
4481  Font font = { 0 };
4482  int fontType = 0; // 0-Normal, 1-SDF
4483 
4484  memcpy(&font.baseSize, fileDataPtr, sizeof(int));
4485  memcpy(&font.glyphCount, fileDataPtr + 4, sizeof(int));
4486  memcpy(&fontType, fileDataPtr + 4 + 4, sizeof(int));
4487  fileDataPtr += 12;
4488 
4489  // Load font white rectangle
4490  Rectangle fontWhiteRec = { 0 };
4491  memcpy(&fontWhiteRec, fileDataPtr, sizeof(Rectangle));
4492  fileDataPtr += 16;
4493 
4494  // Load font image parameters
4495  int fontImageUncompSize = 0;
4496  int fontImageCompSize = 0;
4497  memcpy(&fontImageUncompSize, fileDataPtr, sizeof(int));
4498  memcpy(&fontImageCompSize, fileDataPtr + 4, sizeof(int));
4499  fileDataPtr += 8;
4500 
4501  Image imFont = { 0 };
4502  imFont.mipmaps = 1;
4503  memcpy(&imFont.width, fileDataPtr, sizeof(int));
4504  memcpy(&imFont.height, fileDataPtr + 4, sizeof(int));
4505  memcpy(&imFont.format, fileDataPtr + 4 + 4, sizeof(int));
4506  fileDataPtr += 12;
4507 
4508  if ((fontImageCompSize > 0) && (fontImageCompSize != fontImageUncompSize))
4509  {
4510  // Compressed font atlas image data (DEFLATE), it requires DecompressData()
4511  int dataUncompSize = 0;
4512  unsigned char *compData = (unsigned char *)RAYGUI_MALLOC(fontImageCompSize);
4513  memcpy(compData, fileDataPtr, fontImageCompSize);
4514  fileDataPtr += fontImageCompSize;
4515 
4516  imFont.data = DecompressData(compData, fontImageCompSize, &dataUncompSize);
4517 
4518  // Security check, dataUncompSize must match the provided fontImageUncompSize
4519  if (dataUncompSize != fontImageUncompSize) RAYGUI_LOG("WARNING: Uncompressed font atlas image data could be corrupted");
4520 
4521  RAYGUI_FREE(compData);
4522  }
4523  else
4524  {
4525  // Font atlas image data is not compressed
4526  imFont.data = (unsigned char *)RAYGUI_MALLOC(fontImageUncompSize);
4527  memcpy(imFont.data, fileDataPtr, fontImageUncompSize);
4528  fileDataPtr += fontImageUncompSize;
4529  }
4530 
4531  if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture);
4532  font.texture = LoadTextureFromImage(imFont);
4533 
4534  RAYGUI_FREE(imFont.data);
4535 
4536  // Validate font atlas texture was loaded correctly
4537  if (font.texture.id != 0)
4538  {
4539  // Load font recs data
4540  int recsDataSize = font.glyphCount*sizeof(Rectangle);
4541  int recsDataCompressedSize = 0;
4542 
4543  // WARNING: Version 400 adds the compression size parameter
4544  if (version >= 400)
4545  {
4546  // RGS files version 400 support compressed recs data
4547  memcpy(&recsDataCompressedSize, fileDataPtr, sizeof(int));
4548  fileDataPtr += sizeof(int);
4549  }
4550 
4551  if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize))
4552  {
4553  // Recs data is compressed, uncompress it
4554  unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_MALLOC(recsDataCompressedSize);
4555 
4556  memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize);
4557  fileDataPtr += recsDataCompressedSize;
4558 
4559  int recsDataUncompSize = 0;
4560  font.recs = (Rectangle *)DecompressData(recsDataCompressed, recsDataCompressedSize, &recsDataUncompSize);
4561 
4562  // Security check, data uncompressed size must match the expected original data size
4563  if (recsDataUncompSize != recsDataSize) RAYGUI_LOG("WARNING: Uncompressed font recs data could be corrupted");
4564 
4565  RAYGUI_FREE(recsDataCompressed);
4566  }
4567  else
4568  {
4569  // Recs data is uncompressed
4570  font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
4571  for (int i = 0; i < font.glyphCount; i++)
4572  {
4573  memcpy(&font.recs[i], fileDataPtr, sizeof(Rectangle));
4574  fileDataPtr += sizeof(Rectangle);
4575  }
4576  }
4577 
4578  // Load font glyphs info data
4579  int glyphsDataSize = font.glyphCount*16; // 16 bytes data per glyph
4580  int glyphsDataCompressedSize = 0;
4581 
4582  // WARNING: Version 400 adds the compression size parameter
4583  if (version >= 400)
4584  {
4585  // RGS files version 400 support compressed glyphs data
4586  memcpy(&glyphsDataCompressedSize, fileDataPtr, sizeof(int));
4587  fileDataPtr += sizeof(int);
4588  }
4589 
4590  // Allocate required glyphs space to fill with data
4591  font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
4592 
4593  if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize))
4594  {
4595  // Glyphs data is compressed, uncompress it
4596  unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_MALLOC(glyphsDataCompressedSize);
4597 
4598  memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize);
4599  fileDataPtr += glyphsDataCompressedSize;
4600 
4601  int glyphsDataUncompSize = 0;
4602  unsigned char *glyphsDataUncomp = DecompressData(glypsDataCompressed, glyphsDataCompressedSize, &glyphsDataUncompSize);
4603 
4604  // Security check, data uncompressed size must match the expected original data size
4605  if (glyphsDataUncompSize != glyphsDataSize) RAYGUI_LOG("WARNING: Uncompressed font glyphs data could be corrupted");
4606 
4607  unsigned char *glyphsDataUncompPtr = glyphsDataUncomp;
4608 
4609  for (int i = 0; i < font.glyphCount; i++)
4610  {
4611  memcpy(&font.glyphs[i].value, glyphsDataUncompPtr, sizeof(int));
4612  memcpy(&font.glyphs[i].offsetX, glyphsDataUncompPtr + 4, sizeof(int));
4613  memcpy(&font.glyphs[i].offsetY, glyphsDataUncompPtr + 8, sizeof(int));
4614  memcpy(&font.glyphs[i].advanceX, glyphsDataUncompPtr + 12, sizeof(int));
4615  glyphsDataUncompPtr += 16;
4616  }
4617 
4618  RAYGUI_FREE(glypsDataCompressed);
4619  RAYGUI_FREE(glyphsDataUncomp);
4620  }
4621  else
4622  {
4623  // Glyphs data is uncompressed
4624  for (int i = 0; i < font.glyphCount; i++)
4625  {
4626  memcpy(&font.glyphs[i].value, fileDataPtr, sizeof(int));
4627  memcpy(&font.glyphs[i].offsetX, fileDataPtr + 4, sizeof(int));
4628  memcpy(&font.glyphs[i].offsetY, fileDataPtr + 8, sizeof(int));
4629  memcpy(&font.glyphs[i].advanceX, fileDataPtr + 12, sizeof(int));
4630  fileDataPtr += 16;
4631  }
4632  }
4633  }
4634  else font = GetFontDefault(); // Fallback in case of errors loading font atlas texture
4635 
4636  GuiSetFont(font);
4637 
4638  // Set font texture source rectangle to be used as white texture to draw shapes
4639  // NOTE: It makes possible to draw shapes and text (full UI) in a single draw call
4640  if ((fontWhiteRec.x > 0) &&
4641  (fontWhiteRec.y > 0) &&
4642  (fontWhiteRec.width > 0) &&
4643  (fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec);
4644  }
4645 #endif
4646  }
4647 }
4648 
4649 // Gui get text width considering icon
4650 static int GetTextWidth(const char *text)
4651 {
4652  #if !defined(ICON_TEXT_PADDING)
4653  #define ICON_TEXT_PADDING 4
4654  #endif
4655 
4656  Vector2 textSize = { 0 };
4657  int textIconOffset = 0;
4658 
4659  if ((text != NULL) && (text[0] != '\0'))
4660  {
4661  if (text[0] == '#')
4662  {
4663  for (int i = 1; (i < 5) && (text[i] != '\0'); i++)
4664  {
4665  if (text[i] == '#')
4666  {
4667  textIconOffset = i;
4668  break;
4669  }
4670  }
4671  }
4672 
4673  text += textIconOffset;
4674 
4675  // Make sure guiFont is set, GuiGetStyle() initializes it lazynessly
4676  float fontSize = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
4677 
4678  // Custom MeasureText() implementation
4679  if ((guiFont.texture.id > 0) && (text != NULL))
4680  {
4681  // Get size in bytes of text, considering end of line and line break
4682  int size = 0;
4683  for (int i = 0; i < MAX_LINE_BUFFER_SIZE; i++)
4684  {
4685  if ((text[i] != '\0') && (text[i] != '\n')) size++;
4686  else break;
4687  }
4688 
4689  float scaleFactor = fontSize/(float)guiFont.baseSize;
4690  textSize.y = (float)guiFont.baseSize*scaleFactor;
4691  float glyphWidth = 0.0f;
4692 
4693  for (int i = 0, codepointSize = 0; i < size; i += codepointSize)
4694  {
4695  int codepoint = GetCodepointNext(&text[i], &codepointSize);
4696  int codepointIndex = GetGlyphIndex(guiFont, codepoint);
4697 
4698  if (guiFont.glyphs[codepointIndex].advanceX == 0) glyphWidth = ((float)guiFont.recs[codepointIndex].width*scaleFactor);
4699  else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor);
4700 
4701  textSize.x += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
4702  }
4703  }
4704 
4705  if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + ICON_TEXT_PADDING);
4706  }
4707 
4708  return (int)textSize.x;
4709 }
4710 
4711 // Get text bounds considering control bounds
4712 static Rectangle GetTextBounds(int control, Rectangle bounds)
4713 {
4714  Rectangle textBounds = bounds;
4715 
4716  textBounds.x = bounds.x + GuiGetStyle(control, BORDER_WIDTH);
4717  textBounds.y = bounds.y + GuiGetStyle(control, BORDER_WIDTH) + GuiGetStyle(control, TEXT_PADDING);
4718  textBounds.width = bounds.width - 2*GuiGetStyle(control, BORDER_WIDTH) - 2*GuiGetStyle(control, TEXT_PADDING);
4719  textBounds.height = bounds.height - 2*GuiGetStyle(control, BORDER_WIDTH) - 2*GuiGetStyle(control, TEXT_PADDING); // NOTE: Text is processed line per line!
4720 
4721  // Depending on control, TEXT_PADDING and TEXT_ALIGNMENT properties could affect the text-bounds
4722  switch (control)
4723  {
4724  case COMBOBOX:
4725  case DROPDOWNBOX:
4726  case LISTVIEW:
4727  // TODO: Special cases (no label): COMBOBOX, DROPDOWNBOX, LISTVIEW
4728  case SLIDER:
4729  case CHECKBOX:
4730  case VALUEBOX:
4731  case SPINNER:
4732  // TODO: More special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER
4733  default:
4734  {
4735  // TODO: WARNING: TEXT_ALIGNMENT is already considered in GuiDrawText()
4736  if (GuiGetStyle(control, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT) textBounds.x -= GuiGetStyle(control, TEXT_PADDING);
4737  else textBounds.x += GuiGetStyle(control, TEXT_PADDING);
4738  }
4739  break;
4740  }
4741 
4742  return textBounds;
4743 }
4744 
4745 // Get text icon if provided and move text cursor
4746 // NOTE: We support up to 999 values for iconId
4747 static const char *GetTextIcon(const char *text, int *iconId)
4748 {
4749 #if !defined(RAYGUI_NO_ICONS)
4750  *iconId = -1;
4751  if (text[0] == '#') // Maybe we have an icon!
4752  {
4753  char iconValue[4] = { 0 }; // Maximum length for icon value: 3 digits + '\0'
4754 
4755  int pos = 1;
4756  while ((pos < 4) && (text[pos] >= '0') && (text[pos] <= '9'))
4757  {
4758  iconValue[pos - 1] = text[pos];
4759  pos++;
4760  }
4761 
4762  if (text[pos] == '#')
4763  {
4764  *iconId = TextToInteger(iconValue);
4765 
4766  // Move text pointer after icon
4767  // WARNING: If only icon provided, it could point to EOL character: '\0'
4768  if (*iconId >= 0) text += (pos + 1);
4769  }
4770  }
4771 #endif
4772 
4773  return text;
4774 }
4775 
4776 // Get text divided into lines (by line-breaks '\n')
4777 const char **GetTextLines(const char *text, int *count)
4778 {
4779  #define RAYGUI_MAX_TEXT_LINES 128
4780 
4781  static const char *lines[RAYGUI_MAX_TEXT_LINES] = { 0 };
4782  for (int i = 0; i < RAYGUI_MAX_TEXT_LINES; i++) lines[i] = NULL; // Init NULL pointers to substrings
4783 
4784  int textSize = (int)strlen(text);
4785 
4786  lines[0] = text;
4787  int len = 0;
4788  *count = 1;
4789  //int lineSize = 0; // Stores current line size, not returned
4790 
4791  for (int i = 0, k = 0; (i < textSize) && (*count < RAYGUI_MAX_TEXT_LINES); i++)
4792  {
4793  if (text[i] == '\n')
4794  {
4795  //lineSize = len;
4796  k++;
4797  lines[k] = &text[i + 1]; // WARNING: next value is valid?
4798  len = 0;
4799  *count += 1;
4800  }
4801  else len++;
4802  }
4803 
4804  //lines[*count - 1].size = len;
4805 
4806  return lines;
4807 }
4808 
4809 // Get text width to next space for provided string
4810 static float GetNextSpaceWidth(const char *text, int *nextSpaceIndex)
4811 {
4812  float width = 0;
4813  int codepointByteCount = 0;
4814  int codepoint = 0;
4815  int index = 0;
4816  float glyphWidth = 0;
4817  float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize;
4818 
4819  for (int i = 0; text[i] != '\0'; i++)
4820  {
4821  if (text[i] != ' ')
4822  {
4823  codepoint = GetCodepoint(&text[i], &codepointByteCount);
4824  index = GetGlyphIndex(guiFont, codepoint);
4825  glyphWidth = (guiFont.glyphs[index].advanceX == 0)? guiFont.recs[index].width*scaleFactor : guiFont.glyphs[index].advanceX*scaleFactor;
4826  width += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
4827  }
4828  else
4829  {
4830  *nextSpaceIndex = i;
4831  break;
4832  }
4833  }
4834 
4835  return width;
4836 }
4837 
4838 // Gui draw text using default font
4839 static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint)
4840 {
4841  #define TEXT_VALIGN_PIXEL_OFFSET(h) ((int)h%2) // Vertical alignment for pixel perfect
4842 
4843  #if !defined(ICON_TEXT_PADDING)
4844  #define ICON_TEXT_PADDING 4
4845  #endif
4846 
4847  if ((text == NULL) || (text[0] == '\0')) return; // Security check
4848 
4849  // PROCEDURE:
4850  // - Text is processed line per line
4851  // - For every line, horizontal alignment is defined
4852  // - For all text, vertical alignment is defined (multiline text only)
4853  // - For every line, wordwrap mode is checked (useful for GuitextBox(), read-only)
4854 
4855  // Get text lines (using '\n' as delimiter) to be processed individually
4856  // WARNING: We can't use GuiTextSplit() function because it can be already used
4857  // before the GuiDrawText() call and its buffer is static, it would be overriden :(
4858  int lineCount = 0;
4859  const char **lines = GetTextLines(text, &lineCount);
4860 
4861  // Text style variables
4862  //int alignment = GuiGetStyle(DEFAULT, TEXT_ALIGNMENT);
4863  int alignmentVertical = GuiGetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL);
4864  int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); // Wrap-mode only available in read-only mode, no for text editing
4865 
4866  // TODO: WARNING: This totalHeight is not valid for vertical alignment in case of word-wrap
4867  float totalHeight = (float)(lineCount*GuiGetStyle(DEFAULT, TEXT_SIZE) + (lineCount - 1)*GuiGetStyle(DEFAULT, TEXT_SIZE)/2);
4868  float posOffsetY = 0.0f;
4869 
4870  for (int i = 0; i < lineCount; i++)
4871  {
4872  int iconId = 0;
4873  lines[i] = GetTextIcon(lines[i], &iconId); // Check text for icon and move cursor
4874 
4875  // Get text position depending on alignment and iconId
4876  //---------------------------------------------------------------------------------
4877  Vector2 textBoundsPosition = { textBounds.x, textBounds.y };
4878  float textBoundsWidthOffset = 0.0f;
4879 
4880  // NOTE: We get text size after icon has been processed
4881  // WARNING: GetTextWidth() also processes text icon to get width! -> Really needed?
4882  int textSizeX = GetTextWidth(lines[i]);
4883 
4884  // If text requires an icon, add size to measure
4885  if (iconId >= 0)
4886  {
4887  textSizeX += RAYGUI_ICON_SIZE*guiIconScale;
4888 
4889  // WARNING: If only icon provided, text could be pointing to EOF character: '\0'
4890 #if !defined(RAYGUI_NO_ICONS)
4891  if ((lines[i] != NULL) && (lines[i][0] != '\0')) textSizeX += ICON_TEXT_PADDING;
4892 #endif
4893  }
4894 
4895  // Check guiTextAlign global variables
4896  switch (alignment)
4897  {
4898  case TEXT_ALIGN_LEFT: textBoundsPosition.x = textBounds.x; break;
4899  case TEXT_ALIGN_CENTER: textBoundsPosition.x = textBounds.x + textBounds.width/2 - textSizeX/2; break;
4900  case TEXT_ALIGN_RIGHT: textBoundsPosition.x = textBounds.x + textBounds.width - textSizeX; break;
4901  default: break;
4902  }
4903 
4904  if (textSizeX > textBounds.width && (lines[i] != NULL) && (lines[i][0] != '\0')) textBoundsPosition.x = textBounds.x;
4905 
4906  switch (alignmentVertical)
4907  {
4908  // Only valid in case of wordWrap = 0;
4909  case TEXT_ALIGN_TOP: textBoundsPosition.y = textBounds.y + posOffsetY; break;
4910  case TEXT_ALIGN_MIDDLE: textBoundsPosition.y = textBounds.y + posOffsetY + textBounds.height/2 - totalHeight/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height); break;
4911  case TEXT_ALIGN_BOTTOM: textBoundsPosition.y = textBounds.y + posOffsetY + textBounds.height - totalHeight + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height); break;
4912  default: break;
4913  }
4914 
4915  // NOTE: Make sure we get pixel-perfect coordinates,
4916  // In case of decimals we got weird text positioning
4917  textBoundsPosition.x = (float)((int)textBoundsPosition.x);
4918  textBoundsPosition.y = (float)((int)textBoundsPosition.y);
4919  //---------------------------------------------------------------------------------
4920 
4921  // Draw text (with icon if available)
4922  //---------------------------------------------------------------------------------
4923 #if !defined(RAYGUI_NO_ICONS)
4924  if (iconId >= 0)
4925  {
4926  // NOTE: We consider icon height, probably different than text size
4927  GuiDrawIcon(iconId, (int)textBoundsPosition.x, (int)(textBounds.y + textBounds.height/2 - RAYGUI_ICON_SIZE*guiIconScale/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height)), guiIconScale, tint);
4928  textBoundsPosition.x += (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING);
4929  textBoundsWidthOffset = (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING);
4930  }
4931 #endif
4932  // Get size in bytes of text,
4933  // considering end of line and line break
4934  int lineSize = 0;
4935  for (int c = 0; (lines[i][c] != '\0') && (lines[i][c] != '\n') && (lines[i][c] != '\r'); c++, lineSize++){ }
4936  float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize;
4937 
4938  int lastSpaceIndex = 0;
4939  bool tempWrapCharMode = false;
4940 
4941  int textOffsetY = 0;
4942  float textOffsetX = 0.0f;
4943  float glyphWidth = 0;
4944 
4945  int ellipsisWidth = GetTextWidth("...");
4946  bool overflowReached = false;
4947  for (int c = 0, codepointSize = 0; c < lineSize; c += codepointSize)
4948  {
4949  int codepoint = GetCodepointNext(&lines[i][c], &codepointSize);
4950  int index = GetGlyphIndex(guiFont, codepoint);
4951 
4952  // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
4953  // but we need to draw all of the bad bytes using the '?' symbol moving one byte
4954  if (codepoint == 0x3f) codepointSize = 1; // TODO: Review not recognized codepoints size
4955 
4956  // Get glyph width to check if it goes out of bounds
4957  if (guiFont.glyphs[index].advanceX == 0) glyphWidth = ((float)guiFont.recs[index].width*scaleFactor);
4958  else glyphWidth = (float)guiFont.glyphs[index].advanceX*scaleFactor;
4959 
4960  // Wrap mode text measuring, to validate if
4961  // it can be drawn or a new line is required
4962  if (wrapMode == TEXT_WRAP_CHAR)
4963  {
4964  // Jump to next line if current character reach end of the box limits
4965  if ((textOffsetX + glyphWidth) > textBounds.width - textBoundsWidthOffset)
4966  {
4967  textOffsetX = 0.0f;
4968  textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING);
4969 
4970  if (tempWrapCharMode) // Wrap at char level when too long words
4971  {
4972  wrapMode = TEXT_WRAP_WORD;
4973  tempWrapCharMode = false;
4974  }
4975  }
4976  }
4977  else if (wrapMode == TEXT_WRAP_WORD)
4978  {
4979  if (codepoint == 32) lastSpaceIndex = c;
4980 
4981  // Get width to next space in line
4982  int nextSpaceIndex = 0;
4983  float nextSpaceWidth = GetNextSpaceWidth(lines[i] + c, &nextSpaceIndex);
4984 
4985  int nextSpaceIndex2 = 0;
4986  float nextWordSize = GetNextSpaceWidth(lines[i] + lastSpaceIndex + 1, &nextSpaceIndex2);
4987 
4988  if (nextWordSize > textBounds.width - textBoundsWidthOffset)
4989  {
4990  // Considering the case the next word is longer than bounds
4991  tempWrapCharMode = true;
4992  wrapMode = TEXT_WRAP_CHAR;
4993  }
4994  else if ((textOffsetX + nextSpaceWidth) > textBounds.width - textBoundsWidthOffset)
4995  {
4996  textOffsetX = 0.0f;
4997  textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING);
4998  }
4999  }
5000 
5001  if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint
5002  else
5003  {
5004  // TODO: There are multiple types of spaces in Unicode,
5005  // maybe it's a good idea to add support for more: http://jkorpela.fi/chars/spaces.html
5006  if ((codepoint != ' ') && (codepoint != '\t')) // Do not draw codepoints with no glyph
5007  {
5008  if (wrapMode == TEXT_WRAP_NONE)
5009  {
5010  // Draw only required text glyphs fitting the textBounds.width
5011  if (textSizeX > textBounds.width)
5012  {
5013  if (textOffsetX <= (textBounds.width - glyphWidth - textBoundsWidthOffset - ellipsisWidth))
5014  {
5015  DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha));
5016  }
5017  else if (!overflowReached)
5018  {
5019  overflowReached = true;
5020 
5021  for (int j = 0; j < ellipsisWidth; j += ellipsisWidth/3)
5022  {
5023  DrawTextCodepoint(guiFont, '.', RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX + j, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha));
5024  }
5025  }
5026  }
5027  else
5028  {
5029  DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha));
5030  }
5031  }
5032  else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD))
5033  {
5034  // Draw only glyphs inside the bounds
5035  if ((textBoundsPosition.y + textOffsetY) <= (textBounds.y + textBounds.height - GuiGetStyle(DEFAULT, TEXT_SIZE)))
5036  {
5037  DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha));
5038  }
5039  }
5040  }
5041 
5042  if (guiFont.glyphs[index].advanceX == 0) textOffsetX += ((float)guiFont.recs[index].width*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
5043  else textOffsetX += ((float)guiFont.glyphs[index].advanceX*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
5044  }
5045  }
5046 
5047  if (wrapMode == TEXT_WRAP_NONE) posOffsetY += (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING);
5048  else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) posOffsetY += (textOffsetY + (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING));
5049  //---------------------------------------------------------------------------------
5050  }
5051 
5052 #if defined(RAYGUI_DEBUG_TEXT_BOUNDS)
5053  GuiDrawRectangle(textBounds, 0, WHITE, Fade(BLUE, 0.4f));
5054 #endif
5055 }
5056 
5057 // Gui draw rectangle using default raygui plain style with borders
5058 static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color)
5059 {
5060  if (color.a > 0)
5061  {
5062  // Draw rectangle filled with color
5063  DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, GuiFade(color, guiAlpha));
5064  }
5065 
5066  if (borderWidth > 0)
5067  {
5068  // Draw rectangle border lines with color
5069  DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, borderWidth, GuiFade(borderColor, guiAlpha));
5070  DrawRectangle((int)rec.x, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, GuiFade(borderColor, guiAlpha));
5071  DrawRectangle((int)rec.x + (int)rec.width - borderWidth, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, GuiFade(borderColor, guiAlpha));
5072  DrawRectangle((int)rec.x, (int)rec.y + (int)rec.height - borderWidth, (int)rec.width, borderWidth, GuiFade(borderColor, guiAlpha));
5073  }
5074 
5075 #if defined(RAYGUI_DEBUG_RECS_BOUNDS)
5076  DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, Fade(RED, 0.4f));
5077 #endif
5078 }
5079 
5080 // Draw tooltip using control bounds
5081 static void GuiTooltip(Rectangle controlRec)
5082 {
5083  if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiControlExclusiveMode)
5084  {
5085  Vector2 textSize = MeasureTextEx(GuiGetFont(), guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
5086 
5087  if ((controlRec.x + textSize.x + 16) > GetScreenWidth()) controlRec.x -= (textSize.x + 16 - controlRec.width);
5088 
5089  GuiPanel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.f }, NULL);
5090 
5091  int textPadding = GuiGetStyle(LABEL, TEXT_PADDING);
5092  int textAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT);
5093  GuiSetStyle(LABEL, TEXT_PADDING, 0);
5094  GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
5095  GuiLabel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.f }, guiTooltipPtr);
5096  GuiSetStyle(LABEL, TEXT_ALIGNMENT, textAlignment);
5097  GuiSetStyle(LABEL, TEXT_PADDING, textPadding);
5098  }
5099 }
5100 
5101 // Split controls text into multiple strings
5102 // Also check for multiple columns (required by GuiToggleGroup())
5103 static const char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow)
5104 {
5105  // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
5106  // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
5107  // all used memory is static... it has some limitations:
5108  // 1. Maximum number of possible split strings is set by RAYGUI_TEXTSPLIT_MAX_ITEMS
5109  // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE
5110  // NOTE: Those definitions could be externally provided if required
5111 
5112  // TODO: HACK: GuiTextSplit() - Review how textRows are returned to user
5113  // textRow is an externally provided array of integers that stores row number for every splitted string
5114 
5115  #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS)
5116  #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128
5117  #endif
5118  #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE)
5119  #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024
5120  #endif
5121 
5122  static const char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL }; // String pointers array (points to buffer data)
5123  static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; // Buffer data (text input copy with '\0' added)
5124  memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE);
5125 
5126  result[0] = buffer;
5127  int counter = 1;
5128 
5129  if (textRow != NULL) textRow[0] = 0;
5130 
5131  // Count how many substrings we have on text and point to every one
5132  for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++)
5133  {
5134  buffer[i] = text[i];
5135  if (buffer[i] == '\0') break;
5136  else if ((buffer[i] == delimiter) || (buffer[i] == '\n'))
5137  {
5138  result[counter] = buffer + i + 1;
5139 
5140  if (textRow != NULL)
5141  {
5142  if (buffer[i] == '\n') textRow[counter] = textRow[counter - 1] + 1;
5143  else textRow[counter] = textRow[counter - 1];
5144  }
5145 
5146  buffer[i] = '\0'; // Set an end of string at this point
5147 
5148  counter++;
5149  if (counter > RAYGUI_TEXTSPLIT_MAX_ITEMS) break;
5150  }
5151  }
5152 
5153  *count = counter;
5154 
5155  return result;
5156 }
5157 
5158 // Convert color data from RGB to HSV
5159 // NOTE: Color data should be passed normalized
5160 static Vector3 ConvertRGBtoHSV(Vector3 rgb)
5161 {
5162  Vector3 hsv = { 0 };
5163  float min = 0.0f;
5164  float max = 0.0f;
5165  float delta = 0.0f;
5166 
5167  min = (rgb.x < rgb.y)? rgb.x : rgb.y;
5168  min = (min < rgb.z)? min : rgb.z;
5169 
5170  max = (rgb.x > rgb.y)? rgb.x : rgb.y;
5171  max = (max > rgb.z)? max : rgb.z;
5172 
5173  hsv.z = max; // Value
5174  delta = max - min;
5175 
5176  if (delta < 0.00001f)
5177  {
5178  hsv.y = 0.0f;
5179  hsv.x = 0.0f; // Undefined, maybe NAN?
5180  return hsv;
5181  }
5182 
5183  if (max > 0.0f)
5184  {
5185  // NOTE: If max is 0, this divide would cause a crash
5186  hsv.y = (delta/max); // Saturation
5187  }
5188  else
5189  {
5190  // NOTE: If max is 0, then r = g = b = 0, s = 0, h is undefined
5191  hsv.y = 0.0f;
5192  hsv.x = 0.0f; // Undefined, maybe NAN?
5193  return hsv;
5194  }
5195 
5196  // NOTE: Comparing float values could not work properly
5197  if (rgb.x >= max) hsv.x = (rgb.y - rgb.z)/delta; // Between yellow & magenta
5198  else
5199  {
5200  if (rgb.y >= max) hsv.x = 2.0f + (rgb.z - rgb.x)/delta; // Between cyan & yellow
5201  else hsv.x = 4.0f + (rgb.x - rgb.y)/delta; // Between magenta & cyan
5202  }
5203 
5204  hsv.x *= 60.0f; // Convert to degrees
5205 
5206  if (hsv.x < 0.0f) hsv.x += 360.0f;
5207 
5208  return hsv;
5209 }
5210 
5211 // Convert color data from HSV to RGB
5212 // NOTE: Color data should be passed normalized
5213 static Vector3 ConvertHSVtoRGB(Vector3 hsv)
5214 {
5215  Vector3 rgb = { 0 };
5216  float hh = 0.0f, p = 0.0f, q = 0.0f, t = 0.0f, ff = 0.0f;
5217  long i = 0;
5218 
5219  // NOTE: Comparing float values could not work properly
5220  if (hsv.y <= 0.0f)
5221  {
5222  rgb.x = hsv.z;
5223  rgb.y = hsv.z;
5224  rgb.z = hsv.z;
5225  return rgb;
5226  }
5227 
5228  hh = hsv.x;
5229  if (hh >= 360.0f) hh = 0.0f;
5230  hh /= 60.0f;
5231 
5232  i = (long)hh;
5233  ff = hh - i;
5234  p = hsv.z*(1.0f - hsv.y);
5235  q = hsv.z*(1.0f - (hsv.y*ff));
5236  t = hsv.z*(1.0f - (hsv.y*(1.0f - ff)));
5237 
5238  switch (i)
5239  {
5240  case 0:
5241  {
5242  rgb.x = hsv.z;
5243  rgb.y = t;
5244  rgb.z = p;
5245  } break;
5246  case 1:
5247  {
5248  rgb.x = q;
5249  rgb.y = hsv.z;
5250  rgb.z = p;
5251  } break;
5252  case 2:
5253  {
5254  rgb.x = p;
5255  rgb.y = hsv.z;
5256  rgb.z = t;
5257  } break;
5258  case 3:
5259  {
5260  rgb.x = p;
5261  rgb.y = q;
5262  rgb.z = hsv.z;
5263  } break;
5264  case 4:
5265  {
5266  rgb.x = t;
5267  rgb.y = p;
5268  rgb.z = hsv.z;
5269  } break;
5270  case 5:
5271  default:
5272  {
5273  rgb.x = hsv.z;
5274  rgb.y = p;
5275  rgb.z = q;
5276  } break;
5277  }
5278 
5279  return rgb;
5280 }
5281 
5282 // Scroll bar control (used by GuiScrollPanel())
5283 static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue)
5284 {
5285  GuiState state = guiState;
5286 
5287  // Is the scrollbar horizontal or vertical?
5288  bool isVertical = (bounds.width > bounds.height)? false : true;
5289 
5290  // The size (width or height depending on scrollbar type) of the spinner buttons
5291  const int spinnerSize = GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)?
5292  (isVertical? (int)bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) :
5293  (int)bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0;
5294 
5295  // Arrow buttons [<] [>] [∧] [∨]
5296  Rectangle arrowUpLeft = { 0 };
5297  Rectangle arrowDownRight = { 0 };
5298 
5299  // Actual area of the scrollbar excluding the arrow buttons
5300  Rectangle scrollbar = { 0 };
5301 
5302  // Slider bar that moves --[///]-----
5303  Rectangle slider = { 0 };
5304 
5305  // Normalize value
5306  if (value > maxValue) value = maxValue;
5307  if (value < minValue) value = minValue;
5308 
5309  int valueRange = maxValue - minValue;
5310  if (valueRange <= 0) valueRange = 1;
5311 
5312  int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE);
5313  if (sliderSize < 1) sliderSize = 1; // TODO: Consider a minimum slider size
5314 
5315  // Calculate rectangles for all of the components
5316  arrowUpLeft = RAYGUI_CLITERAL(Rectangle){
5317  (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH),
5318  (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH),
5319  (float)spinnerSize, (float)spinnerSize };
5320 
5321  if (isVertical)
5322  {
5323  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 };
5324  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) };
5325 
5326  // Make sure the slider won't get outside of the scrollbar
5327  sliderSize = (sliderSize >= scrollbar.height)? ((int)scrollbar.height - 2) : sliderSize;
5328  slider = RAYGUI_CLITERAL(Rectangle){
5329  bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING),
5330  scrollbar.y + (int)(((float)(value - minValue)/valueRange)*(scrollbar.height - sliderSize)),
5331  bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)),
5332  (float)sliderSize };
5333  }
5334  else // horizontal
5335  {
5336  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 };
5337  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)) };
5338 
5339  // Make sure the slider won't get outside of the scrollbar
5340  sliderSize = (sliderSize >= scrollbar.width)? ((int)scrollbar.width - 2) : sliderSize;
5341  slider = RAYGUI_CLITERAL(Rectangle){
5342  scrollbar.x + (int)(((float)(value - minValue)/valueRange)*(scrollbar.width - sliderSize)),
5343  bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING),
5344  (float)sliderSize,
5345  bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)) };
5346  }
5347 
5348  // Update control
5349  //--------------------------------------------------------------------
5350  if ((state != STATE_DISABLED) && !guiLocked)
5351  {
5352  Vector2 mousePoint = GetMousePosition();
5353 
5354  if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
5355  {
5356  if (IsMouseButtonDown(MOUSE_LEFT_BUTTON) &&
5357  !CheckCollisionPointRec(mousePoint, arrowUpLeft) &&
5358  !CheckCollisionPointRec(mousePoint, arrowDownRight))
5359  {
5360  if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec))
5361  {
5362  state = STATE_PRESSED;
5363 
5364  if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue);
5365  else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue);
5366  }
5367  }
5368  else
5369  {
5370  guiControlExclusiveMode = false;
5371  guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
5372  }
5373  }
5374  else if (CheckCollisionPointRec(mousePoint, bounds))
5375  {
5376  state = STATE_FOCUSED;
5377 
5378  // Handle mouse wheel
5379  int wheel = (int)GetMouseWheelMove();
5380  if (wheel != 0) value += wheel;
5381 
5382  // Handle mouse button down
5383  if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
5384  {
5385  guiControlExclusiveMode = true;
5386  guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts
5387 
5388  // Check arrows click
5389  if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
5390  else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
5391  else if (!CheckCollisionPointRec(mousePoint, slider))
5392  {
5393  // If click on scrollbar position but not on slider, place slider directly on that position
5394  if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue);
5395  else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue);
5396  }
5397 
5398  state = STATE_PRESSED;
5399  }
5400 
5401  // Keyboard control on mouse hover scrollbar
5402  /*
5403  if (isVertical)
5404  {
5405  if (IsKeyDown(KEY_DOWN)) value += 5;
5406  else if (IsKeyDown(KEY_UP)) value -= 5;
5407  }
5408  else
5409  {
5410  if (IsKeyDown(KEY_RIGHT)) value += 5;
5411  else if (IsKeyDown(KEY_LEFT)) value -= 5;
5412  }
5413  */
5414  }
5415 
5416  // Normalize value
5417  if (value > maxValue) value = maxValue;
5418  if (value < minValue) value = minValue;
5419  }
5420  //--------------------------------------------------------------------
5421 
5422  // Draw control
5423  //--------------------------------------------------------------------
5424  GuiDrawRectangle(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED))); // Draw the background
5425 
5426  GuiDrawRectangle(scrollbar, 0, BLANK, GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL))); // Draw the scrollbar active area background
5427  GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BORDER + state*3))); // Draw the slider bar
5428 
5429  // Draw arrows (using icon if available)
5430  if (GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE))
5431  {
5432 #if defined(RAYGUI_NO_ICONS)
5433  GuiDrawText(isVertical? "^" : "<",
5434  RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height },
5435  TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))));
5436  GuiDrawText(isVertical? "v" : ">",
5437  RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height },
5438  TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))));
5439 #else
5440  GuiDrawText(isVertical? "#121#" : "#118#",
5441  RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height },
5442  TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_UP_FILL / ICON_ARROW_LEFT_FILL
5443  GuiDrawText(isVertical? "#120#" : "#119#",
5444  RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height },
5445  TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_DOWN_FILL / ICON_ARROW_RIGHT_FILL
5446 #endif
5447  }
5448  //--------------------------------------------------------------------
5449 
5450  return value;
5451 }
5452 
5453 // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
5454 // WARNING: It multiplies current alpha by alpha scale factor
5455 static Color GuiFade(Color color, float alpha)
5456 {
5457  if (alpha < 0.0f) alpha = 0.0f;
5458  else if (alpha > 1.0f) alpha = 1.0f;
5459 
5460  Color result = { color.r, color.g, color.b, (unsigned char)(color.a*alpha) };
5461 
5462  return result;
5463 }
5464 
5465 #if defined(RAYGUI_STANDALONE)
5466 // Returns a Color struct from hexadecimal value
5467 static Color GetColor(int hexValue)
5468 {
5469  Color color;
5470 
5471  color.r = (unsigned char)(hexValue >> 24) & 0xFF;
5472  color.g = (unsigned char)(hexValue >> 16) & 0xFF;
5473  color.b = (unsigned char)(hexValue >> 8) & 0xFF;
5474  color.a = (unsigned char)hexValue & 0xFF;
5475 
5476  return color;
5477 }
5478 
5479 // Returns hexadecimal value for a Color
5480 static int ColorToInt(Color color)
5481 {
5482  return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a);
5483 }
5484 
5485 // Check if point is inside rectangle
5486 static bool CheckCollisionPointRec(Vector2 point, Rectangle rec)
5487 {
5488  bool collision = false;
5489 
5490  if ((point.x >= rec.x) && (point.x <= (rec.x + rec.width)) &&
5491  (point.y >= rec.y) && (point.y <= (rec.y + rec.height))) collision = true;
5492 
5493  return collision;
5494 }
5495 
5496 // Formatting of text with variables to 'embed'
5497 static const char *TextFormat(const char *text, ...)
5498 {
5499  #if !defined(RAYGUI_TEXTFORMAT_MAX_SIZE)
5500  #define RAYGUI_TEXTFORMAT_MAX_SIZE 256
5501  #endif
5502 
5503  static char buffer[RAYGUI_TEXTFORMAT_MAX_SIZE];
5504 
5505  va_list args;
5506  va_start(args, text);
5507  vsprintf(buffer, text, args);
5508  va_end(args);
5509 
5510  return buffer;
5511 }
5512 
5513 // Draw rectangle with vertical gradient fill color
5514 // NOTE: This function is only used by GuiColorPicker()
5515 static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2)
5516 {
5517  Rectangle bounds = { (float)posX, (float)posY, (float)width, (float)height };
5518  DrawRectangleGradientEx(bounds, color1, color2, color2, color1);
5519 }
5520 
5521 // Split string into multiple strings
5522 const char **TextSplit(const char *text, char delimiter, int *count)
5523 {
5524  // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
5525  // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
5526  // all used memory is static... it has some limitations:
5527  // 1. Maximum number of possible split strings is set by RAYGUI_TEXTSPLIT_MAX_ITEMS
5528  // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE
5529 
5530  #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS)
5531  #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128
5532  #endif
5533  #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE)
5534  #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024
5535  #endif
5536 
5537  static const char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL };
5538  static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 };
5539  memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE);
5540 
5541  result[0] = buffer;
5542  int counter = 0;
5543 
5544  if (text != NULL)
5545  {
5546  counter = 1;
5547 
5548  // Count how many substrings we have on text and point to every one
5549  for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++)
5550  {
5551  buffer[i] = text[i];
5552  if (buffer[i] == '\0') break;
5553  else if (buffer[i] == delimiter)
5554  {
5555  buffer[i] = '\0'; // Set an end of string at this point
5556  result[counter] = buffer + i + 1;
5557  counter++;
5558 
5559  if (counter == RAYGUI_TEXTSPLIT_MAX_ITEMS) break;
5560  }
5561  }
5562  }
5563 
5564  *count = counter;
5565  return result;
5566 }
5567 
5568 // Get integer value from text
5569 // NOTE: This function replaces atoi() [stdlib.h]
5570 static int TextToInteger(const char *text)
5571 {
5572  int value = 0;
5573  int sign = 1;
5574 
5575  if ((text[0] == '+') || (text[0] == '-'))
5576  {
5577  if (text[0] == '-') sign = -1;
5578  text++;
5579  }
5580 
5581  for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); ++i) value = value*10 + (int)(text[i] - '0');
5582 
5583  return value*sign;
5584 }
5585 
5586 // Get float value from text
5587 // NOTE: This function replaces atof() [stdlib.h]
5588 // WARNING: Only '.' character is understood as decimal point
5589 static float TextToFloat(const char *text)
5590 {
5591  float value = 0.0f;
5592  float sign = 1.0f;
5593 
5594  if ((text[0] == '+') || (text[0] == '-'))
5595  {
5596  if (text[0] == '-') sign = -1.0f;
5597  text++;
5598  }
5599 
5600  int i = 0;
5601  for (; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10.0f + (float)(text[i] - '0');
5602 
5603  if (text[i++] != '.') value *= sign;
5604  else
5605  {
5606  float divisor = 10.0f;
5607  for (; ((text[i] >= '0') && (text[i] <= '9')); i++)
5608  {
5609  value += ((float)(text[i] - '0'))/divisor;
5610  divisor = divisor*10.0f;
5611  }
5612  }
5613 
5614  return value;
5615 }
5616 
5617 // Encode codepoint into UTF-8 text (char array size returned as parameter)
5618 static const char *CodepointToUTF8(int codepoint, int *byteSize)
5619 {
5620  static char utf8[6] = { 0 };
5621  int size = 0;
5622 
5623  if (codepoint <= 0x7f)
5624  {
5625  utf8[0] = (char)codepoint;
5626  size = 1;
5627  }
5628  else if (codepoint <= 0x7ff)
5629  {
5630  utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0);
5631  utf8[1] = (char)((codepoint & 0x3f) | 0x80);
5632  size = 2;
5633  }
5634  else if (codepoint <= 0xffff)
5635  {
5636  utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0);
5637  utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
5638  utf8[2] = (char)((codepoint & 0x3f) | 0x80);
5639  size = 3;
5640  }
5641  else if (codepoint <= 0x10ffff)
5642  {
5643  utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0);
5644  utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80);
5645  utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
5646  utf8[3] = (char)((codepoint & 0x3f) | 0x80);
5647  size = 4;
5648  }
5649 
5650  *byteSize = size;
5651 
5652  return utf8;
5653 }
5654 
5655 // Get next codepoint in a UTF-8 encoded text, scanning until '\0' is found
5656 // When a invalid UTF-8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned
5657 // Total number of bytes processed are returned as a parameter
5658 // NOTE: the standard says U+FFFD should be returned in case of errors
5659 // but that character is not supported by the default font in raylib
5660 static int GetCodepointNext(const char *text, int *codepointSize)
5661 {
5662  const char *ptr = text;
5663  int codepoint = 0x3f; // Codepoint (defaults to '?')
5664  *codepointSize = 1;
5665 
5666  // Get current codepoint and bytes processed
5667  if (0xf0 == (0xf8 & ptr[0]))
5668  {
5669  // 4 byte UTF-8 codepoint
5670  if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80) || ((ptr[3] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks
5671  codepoint = ((0x07 & ptr[0]) << 18) | ((0x3f & ptr[1]) << 12) | ((0x3f & ptr[2]) << 6) | (0x3f & ptr[3]);
5672  *codepointSize = 4;
5673  }
5674  else if (0xe0 == (0xf0 & ptr[0]))
5675  {
5676  // 3 byte UTF-8 codepoint */
5677  if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks
5678  codepoint = ((0x0f & ptr[0]) << 12) | ((0x3f & ptr[1]) << 6) | (0x3f & ptr[2]);
5679  *codepointSize = 3;
5680  }
5681  else if (0xc0 == (0xe0 & ptr[0]))
5682  {
5683  // 2 byte UTF-8 codepoint
5684  if ((ptr[1] & 0xC0) ^ 0x80) { return codepoint; } //10xxxxxx checks
5685  codepoint = ((0x1f & ptr[0]) << 6) | (0x3f & ptr[1]);
5686  *codepointSize = 2;
5687  }
5688  else if (0x00 == (0x80 & ptr[0]))
5689  {
5690  // 1 byte UTF-8 codepoint
5691  codepoint = ptr[0];
5692  *codepointSize = 1;
5693  }
5694 
5695  return codepoint;
5696 }
5697 #endif // RAYGUI_STANDALONE
5698 
5699 #endif // RAYGUI_IMPLEMENTATION
Definition: rlgl_standalone.c:79
Definition: raylib.h:257
Definition: raylib.h:209
Definition: raylib.h:310
Definition: raylib.h:249
Definition: raylib.h:301
Definition: raylib.h:215
Definition: raygui.h:449
Definition: raylib.h:266