comparison third_party/raylib/include/raygui.h @ 54:b3e82d22f961

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