raygui.h 146 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306
  1. /*******************************************************************************************
  2. *
  3. * raygui v2.0-dev - A simple and easy-to-use immedite-mode-gui library
  4. *
  5. * DESCRIPTION:
  6. *
  7. * raygui is a tools-dev-focused immediate-mode-gui library based on raylib but also possible
  8. * to be used as a standalone library, as long as input and drawing functions are provided.
  9. *
  10. * Basic controls provided:
  11. *
  12. * - WindowBox
  13. * - GroupBox
  14. * - Line
  15. * - Panel
  16. * - Label
  17. * - Button
  18. * - LabelButton --> Label
  19. * - ImageButton --> Button
  20. * - ImageButtonEx --> Button
  21. * - Toggle
  22. * - ToggleGroup --> Toggle
  23. * - CheckBox
  24. * - ComboBox
  25. * - DropdownBox
  26. * - TextBox
  27. * - TextBoxMulti
  28. * - ValueBox --> TextBox
  29. * - Spinner --> Button, ValueBox
  30. * - Slider
  31. * - SliderBar --> Slider
  32. * - ProgressBar
  33. * - StatusBar
  34. * - ScrollPanel
  35. * - ListView --> ListElement
  36. * - ColorPicker --> ColorPanel, ColorBarHue
  37. * - MessageBox
  38. * - DummyRec
  39. * - ScrollBar
  40. * - Grid
  41. *
  42. * It also provides a set of functions for styling the controls based on its properties (size, color).
  43. *
  44. * CONFIGURATION:
  45. *
  46. * #define RAYGUI_IMPLEMENTATION
  47. * Generates the implementation of the library into the included file.
  48. * If not defined, the library is in header only mode and can be included in other headers
  49. * or source files without problems. But only ONE file should hold the implementation.
  50. *
  51. * #define RAYGUI_STATIC (defined by default)
  52. * The generated implementation will stay private inside implementation file and all
  53. * internal symbols and functions will only be visible inside that file.
  54. *
  55. * #define RAYGUI_STANDALONE
  56. * Avoid raylib.h header inclusion in this file. Data types defined on raylib are defined
  57. * internally in the library and input management and drawing functions must be provided by
  58. * the user (check library implementation for further details).
  59. *
  60. * #define RAYGUI_RICONS_SUPPORT
  61. * Includes ricons.h header defining a set of 128 icons (binary format) to be used on
  62. * multiple controls and following raygui styles
  63. *
  64. * VERSIONS HISTORY:
  65. * 2.0 (xx-Dec-2018) Complete review of new controls, redesigned style system
  66. * 1.9 (01-May-2018) Lot of rework and redesign! Lots of new controls!
  67. * 1.5 (21-Jun-2017) Working in an improved styles system
  68. * 1.4 (15-Jun-2017) Rewritten all GUI functions (removed useless ones)
  69. * 1.3 (12-Jun-2017) Redesigned styles system
  70. * 1.1 (01-Jun-2017) Complete review of the library
  71. * 1.0 (07-Jun-2016) Converted to header-only by Ramon Santamaria.
  72. * 0.9 (07-Mar-2016) Reviewed and tested by Albert Martos, Ian Eito, Sergio Martinez and Ramon Santamaria.
  73. * 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria.
  74. *
  75. * CONTRIBUTORS:
  76. * Ramon Santamaria: Supervision, review, redesign, update and maintenance...
  77. * Sergio Martinez: Review, testing (2015) and redesign of multiple controls (2018)
  78. * Adria Arranz: Testing and Implementation of additional controls (2018)
  79. * Jordi Jorba: Testing and Implementation of additional controls (2018)
  80. * Albert Martos: Review and testing of the library (2015)
  81. * Ian Eito: Review and testing of the library (2015)
  82. * Kevin Gato: Initial implementation of basic components (2014)
  83. * Daniel Nicolas: Initial implementation of basic components (2014)
  84. *
  85. *
  86. * LICENSE: zlib/libpng
  87. *
  88. * Copyright (c) 2014-2018 Ramon Santamaria (@raysan5)
  89. *
  90. * This software is provided "as-is", without any express or implied warranty. In no event
  91. * will the authors be held liable for any damages arising from the use of this software.
  92. *
  93. * Permission is granted to anyone to use this software for any purpose, including commercial
  94. * applications, and to alter it and redistribute it freely, subject to the following restrictions:
  95. *
  96. * 1. The origin of this software must not be misrepresented; you must not claim that you
  97. * wrote the original software. If you use this software in a product, an acknowledgment
  98. * in the product documentation would be appreciated but is not required.
  99. *
  100. * 2. Altered source versions must be plainly marked as such, and must not be misrepresented
  101. * as being the original software.
  102. *
  103. * 3. This notice may not be removed or altered from any source distribution.
  104. *
  105. **********************************************************************************************/
  106. #ifndef RAYGUI_H
  107. #define RAYGUI_H
  108. #define RAYGUI_VERSION "2.0-dev"
  109. #if !defined(RAYGUI_STANDALONE)
  110. #include "raylib.h"
  111. #endif
  112. #if defined(RAYGUI_IMPLEMENTATION)
  113. #if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED)
  114. #define RAYGUIDEF __declspec(dllexport) extern // We are building raygui as a Win32 shared library (.dll).
  115. #elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED)
  116. #define RAYGUIDEF __declspec(dllimport) // We are using raygui as a Win32 shared library (.dll)
  117. #else
  118. #ifdef __cplusplus
  119. #define RAYGUIDEF extern "C" // Functions visible from other files (no name mangling of functions in C++)
  120. #else
  121. #define RAYGUIDEF extern // Functions visible from other files
  122. #endif
  123. #endif
  124. #elif defined(RAYGUI_STATIC)
  125. #define RAYGUIDEF static // Functions just visible to module including this file
  126. #endif
  127. #include <stdlib.h> // Required for: atoi()
  128. //----------------------------------------------------------------------------------
  129. // Defines and Macros
  130. //----------------------------------------------------------------------------------
  131. #define VALIGN_OFFSET(h) ((int)h%2) // Vertical alignment for pixel perfect
  132. #define TEXTEDIT_CURSOR_BLINK_FRAMES 20 // Text edit controls cursor blink timming
  133. #define NUM_CONTROLS 13 // Number of standard controls
  134. #define NUM_PROPS_DEFAULT 16 // Number of standard properties
  135. #define NUM_PROPS_EXTENDED 8 // Number of extended properties
  136. //----------------------------------------------------------------------------------
  137. // Types and Structures Definition
  138. // NOTE: Some types are required for RAYGUI_STANDALONE usage
  139. //----------------------------------------------------------------------------------
  140. #if defined(RAYGUI_STANDALONE)
  141. #ifndef __cplusplus
  142. // Boolean type
  143. #ifndef true
  144. typedef enum { false, true } bool;
  145. #endif
  146. #endif
  147. // Vector2 type
  148. typedef struct Vector2 {
  149. float x;
  150. float y;
  151. } Vector2;
  152. // Vector3 type
  153. typedef struct Vector3 {
  154. float x;
  155. float y;
  156. float z;
  157. } Vector3;
  158. // Color type, RGBA (32bit)
  159. typedef struct Color {
  160. unsigned char r;
  161. unsigned char g;
  162. unsigned char b;
  163. unsigned char a;
  164. } Color;
  165. // Rectangle type
  166. typedef struct Rectangle {
  167. int x;
  168. int y;
  169. int width;
  170. int height;
  171. } Rectangle;
  172. // Texture2D type
  173. typedef struct Texture2D { } Texture2D;
  174. // Font type
  175. typedef struct Font { } Font;
  176. #endif
  177. // Gui global state enum
  178. typedef enum {
  179. GUI_STATE_NORMAL = 0,
  180. GUI_STATE_FOCUSED,
  181. GUI_STATE_PRESSED,
  182. GUI_STATE_DISABLED,
  183. } GuiControlState;
  184. // Gui global text alignment
  185. typedef enum {
  186. GUI_TEXT_ALIGN_LEFT = 0,
  187. GUI_TEXT_ALIGN_CENTER,
  188. GUI_TEXT_ALIGN_RIGHT,
  189. } GuiTextAlignment;
  190. // Gui standard controls
  191. typedef enum {
  192. DEFAULT = 0,
  193. LABEL, // LABELBUTTON
  194. BUTTON, // IMAGEBUTTON
  195. TOGGLE, // TOGGLEGROUP
  196. SLIDER, // SLIDERBAR
  197. PROGRESSBAR,
  198. CHECKBOX,
  199. COMBOBOX,
  200. DROPDOWNBOX,
  201. TEXTBOX, // VALUEBOX, SPINNER, TEXTBOXMULTI -> TODO: Probably they should not be dependant on TEXTBOX style!
  202. LISTVIEW,
  203. COLORPICKER,
  204. SCROLLBAR
  205. } GuiControlStandard;
  206. // Gui default properties for every control
  207. typedef enum {
  208. BORDER_COLOR_NORMAL = 0,
  209. BASE_COLOR_NORMAL,
  210. TEXT_COLOR_NORMAL,
  211. BORDER_COLOR_FOCUSED,
  212. BASE_COLOR_FOCUSED,
  213. TEXT_COLOR_FOCUSED,
  214. BORDER_COLOR_PRESSED,
  215. BASE_COLOR_PRESSED,
  216. TEXT_COLOR_PRESSED,
  217. BORDER_COLOR_DISABLED,
  218. BASE_COLOR_DISABLED,
  219. TEXT_COLOR_DISABLED,
  220. BORDER_WIDTH,
  221. INNER_PADDING,
  222. TEXT_ALIGNMENT,
  223. RESERVED02
  224. } GuiControlProperty;
  225. // Gui extended properties depending on control type
  226. // NOTE: We reserve a fixed size of additional properties per control (8)
  227. // Default properties
  228. typedef enum {
  229. TEXT_SIZE = 16,
  230. TEXT_SPACING,
  231. LINE_COLOR,
  232. //LINE_THICK,
  233. BACKGROUND_COLOR,
  234. } GuiDefaultProperty;
  235. // Label
  236. //typedef enum { } GuiLabelProperty;
  237. // Button
  238. //typedef enum { } GuiButtonProperty;
  239. // Toggle / ToggleGroup
  240. typedef enum {
  241. GROUP_PADDING = 16,
  242. } GuiToggleProperty;
  243. // Slider / SliderBar
  244. typedef enum {
  245. SLIDER_WIDTH = 16,
  246. TEXT_PADDING
  247. } GuiSliderProperty;
  248. // ProgressBar
  249. //typedef enum { } GuiProgressBarProperty;
  250. // TextBox / TextBoxMulti / ValueBox / Spinner
  251. typedef enum {
  252. MULTILINE_PADDING = 16,
  253. SPINNER_BUTTON_WIDTH,
  254. SPINNER_BUTTON_PADDING,
  255. SPINNER_BUTTON_BORDER_WIDTH
  256. } GuiTextBoxProperty;
  257. // CheckBox
  258. typedef enum {
  259. CHECK_TEXT_PADDING = 16
  260. } GuiCheckBoxProperty;
  261. // ComboBox
  262. typedef enum {
  263. SELECTOR_WIDTH = 16,
  264. SELECTOR_PADDING
  265. } GuiComboBoxProperty;
  266. // DropdownBox
  267. typedef enum {
  268. ARROW_RIGHT_PADDING = 16,
  269. } GuiDropdownBoxProperty;
  270. // ColorPicker
  271. typedef enum {
  272. COLOR_SELECTOR_SIZE = 16,
  273. BAR_WIDTH, // Lateral bar width
  274. BAR_PADDING, // Lateral bar separation from panel
  275. BAR_SELECTOR_HEIGHT, // Lateral bar selector height
  276. BAR_SELECTOR_PADDING // Lateral bar selector outer padding
  277. } GuiColorPickerProperty;
  278. // ListView
  279. typedef enum {
  280. ELEMENTS_HEIGHT = 16,
  281. ELEMENTS_PADDING,
  282. SCROLLBAR_WIDTH,
  283. SCROLLBAR_SIDE, // This property defines vertical scrollbar side (SCROLLBAR_LEFT_SIDE or SCROLLBAR_RIGHT_SIDE)
  284. } GuiListViewProperty;
  285. // ScrollBar
  286. typedef enum {
  287. ARROWS_SIZE = 16,
  288. SLIDER_PADDING,
  289. SLIDER_SIZE,
  290. SCROLL_SPEED,
  291. SHOW_SPINNER_BUTTONS
  292. } GuiScrollBarProperty;
  293. // ScrollBar side
  294. typedef enum {
  295. SCROLLBAR_LEFT_SIDE = 0,
  296. SCROLLBAR_RIGHT_SIDE
  297. } GuiScrollBarSide;
  298. //----------------------------------------------------------------------------------
  299. // Global Variables Definition
  300. //----------------------------------------------------------------------------------
  301. // ...
  302. //----------------------------------------------------------------------------------
  303. // Module Functions Declaration
  304. //----------------------------------------------------------------------------------
  305. // Global gui modification functions
  306. RAYGUIDEF void GuiEnable(void); // Enable gui controls (global state)
  307. RAYGUIDEF void GuiDisable(void); // Disable gui controls (global state)
  308. RAYGUIDEF void GuiLock(void); // Lock gui controls (global state)
  309. RAYGUIDEF void GuiUnlock(void); // Unlock gui controls (global state)
  310. RAYGUIDEF void GuiState(int state); // Set gui state (global state)
  311. RAYGUIDEF void GuiFont(Font font); // Set gui custom font (global state)
  312. RAYGUIDEF void GuiFade(float alpha); // Set gui controls alpha (global state), alpha goes from 0.0f to 1.0f
  313. // Style set/get functions
  314. RAYGUIDEF void GuiSetStyle(int control, int property, int value); // Set one style property
  315. RAYGUIDEF int GuiGetStyle(int control, int property); // Get one style property
  316. // Container/separator controls, useful for controls organization
  317. RAYGUIDEF bool GuiWindowBox(Rectangle bounds, const char *text); // Window Box control, shows a window that can be closed
  318. RAYGUIDEF void GuiGroupBox(Rectangle bounds, const char *text); // Group Box control with title name
  319. RAYGUIDEF void GuiLine(Rectangle bounds, const char *text); // Line separator control, could contain text
  320. RAYGUIDEF void GuiPanel(Rectangle bounds); // Panel control, useful to group controls
  321. RAYGUIDEF Rectangle GuiScrollPanel(Rectangle bounds, Rectangle content, Vector2 *scroll); // Scroll Panel control
  322. // Basic controls set
  323. RAYGUIDEF void GuiLabel(Rectangle bounds, const char *text); // Label control, shows text
  324. RAYGUIDEF bool GuiButton(Rectangle bounds, const char *text); // Button control, returns true when clicked
  325. RAYGUIDEF bool GuiLabelButton(Rectangle bounds, const char *text); // Label button control, show true when clicked
  326. RAYGUIDEF bool GuiImageButton(Rectangle bounds, Texture2D texture); // Image button control, returns true when clicked
  327. RAYGUIDEF bool GuiImageButtonEx(Rectangle bounds, Texture2D texture, Rectangle texSource, const char *text); // Image button extended control, returns true when clicked
  328. RAYGUIDEF bool GuiToggle(Rectangle bounds, const char *text, bool active); // Toggle Button control, returns true when active
  329. RAYGUIDEF int GuiToggleGroup(Rectangle bounds, const char *text, int active); // Toggle Group control, returns active toggle index
  330. RAYGUIDEF bool GuiCheckBox(Rectangle bounds, const char *text, bool checked); // Check Box control, returns true when active
  331. RAYGUIDEF int GuiComboBox(Rectangle bounds, const char *text, int active); // Combo Box control, returns selected item index
  332. RAYGUIDEF bool GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode); // Dropdown Box control, returns selected item
  333. RAYGUIDEF bool GuiSpinner(Rectangle bounds, int *value, int minValue, int maxValue, bool editMode); // Spinner control, returns selected value
  334. RAYGUIDEF bool GuiValueBox(Rectangle bounds, int *value, int minValue, int maxValue, bool editMode); // Value Box control, updates input text with numbers
  335. RAYGUIDEF bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode); // Text Box control, updates input text
  336. RAYGUIDEF bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode); // Text Box control with multiple lines
  337. RAYGUIDEF float GuiSlider(Rectangle bounds, const char *text, float value, float minValue, float maxValue, bool showValue); // Slider control, returns selected value
  338. RAYGUIDEF float GuiSliderBar(Rectangle bounds, const char *text, float value, float minValue, float maxValue, bool showValue); // Slider Bar control, returns selected value
  339. RAYGUIDEF float GuiProgressBar(Rectangle bounds, const char *text, float value, float minValue, float maxValue, bool showValue); // Progress Bar control, shows current progress value
  340. RAYGUIDEF void GuiStatusBar(Rectangle bounds, const char *text); // Status Bar control, shows info text
  341. RAYGUIDEF void GuiDummyRec(Rectangle bounds, const char *text); // Dummy control for placeholders
  342. RAYGUIDEF int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll Bar control
  343. // Advance controls set
  344. RAYGUIDEF bool GuiListView(Rectangle bounds, const char *text, int *active, int *scrollIndex, bool editMode); // List View control, returns selected list element index
  345. RAYGUIDEF bool GuiListViewEx(Rectangle bounds, const char **text, int count, int *enabled, int *active, int *focus, int *scrollIndex, bool editMode); // List View with extended parameters
  346. RAYGUIDEF int GuiMessageBox(Rectangle bounds, const char *windowTitle, const char *message, const char *buttons); // Message Box control, displays a message
  347. RAYGUIDEF Color GuiColorPicker(Rectangle bounds, Color color); // Color Picker control
  348. RAYGUIDEF Vector2 GuiGrid(Rectangle bounds, float spacing, int subdivs); // Grid
  349. // Styles loading functions
  350. RAYGUIDEF void GuiLoadStyle(const char *fileName); // Load style file (.rgs)
  351. RAYGUIDEF void GuiLoadStyleProps(const int *props, int count); // Load style properties from array
  352. RAYGUIDEF void GuiLoadStyleDefault(void); // Load style default over global style
  353. RAYGUIDEF void GuiUpdateStyleComplete(void); // Updates full style properties set with default values
  354. /*
  355. typedef GuiStyle (unsigned int *)
  356. RAYGUIDEF GuiStyle LoadGuiStyle(const char *fileName); // Load style from file (.rgs)
  357. RAYGUIDEF void UnloadGuiStyle(GuiStyle style); // Unload style
  358. */
  359. RAYGUIDEF const char *GuiIconText(int iconId, const char *text); // Get text with icon id prepended
  360. #endif // RAYGUI_H
  361. /***********************************************************************************
  362. *
  363. * RAYGUI IMPLEMENTATION
  364. *
  365. ************************************************************************************/
  366. #if defined(RAYGUI_IMPLEMENTATION)
  367. #if defined(RAYGUI_RICONS_SUPPORT)
  368. #if defined(RAYGUI_STANDALONE)
  369. #define RICONS_STANDALONE
  370. #endif
  371. #define RICONS_IMPLEMENTATION
  372. #include "ricons.h" // Required for: raygui icons
  373. #endif
  374. #include <stdio.h> // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), vsprintf()
  375. #include <string.h> // Required for: strlen() on GuiTextBox()
  376. #if defined(RAYGUI_STANDALONE)
  377. #include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end()
  378. #endif
  379. //----------------------------------------------------------------------------------
  380. // Defines and Macros
  381. //----------------------------------------------------------------------------------
  382. //...
  383. //----------------------------------------------------------------------------------
  384. // Types and Structures Definition
  385. //----------------------------------------------------------------------------------
  386. // Gui control property style element
  387. typedef enum { BORDER = 0, BASE, TEXT, OTHER } GuiPropertyElement;
  388. //----------------------------------------------------------------------------------
  389. // Global Variables Definition
  390. //----------------------------------------------------------------------------------
  391. static GuiControlState guiState = GUI_STATE_NORMAL;
  392. static Font guiFont = { 0 }; // NOTE: Highly coupled to raylib
  393. static bool guiLocked = false;
  394. static float guiAlpha = 1.0f;
  395. // Global gui style array (allocated on heap by default)
  396. // NOTE: In raygui we manage a single int array with all the possible style properties.
  397. // When a new style is loaded, it loads over the global style... but default gui style
  398. // could always be recovered with GuiLoadStyleDefault()
  399. static unsigned int guiStyle[NUM_CONTROLS*(NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED)] = { 0 };
  400. static bool guiStyleLoaded = false;
  401. //----------------------------------------------------------------------------------
  402. // Standalone Mode Functions Declaration
  403. //
  404. // NOTE: raygui depend on some raylib input and drawing functions
  405. // To use raygui as standalone library, below functions must be defined by the user
  406. //----------------------------------------------------------------------------------
  407. #if defined(RAYGUI_STANDALONE)
  408. #define KEY_RIGHT 262
  409. #define KEY_LEFT 263
  410. #define KEY_DOWN 264
  411. #define KEY_UP 265
  412. #define KEY_BACKSPACE 259
  413. #define KEY_ENTER 257
  414. #define MOUSE_LEFT_BUTTON 0
  415. #ifdef __cplusplus
  416. #define CLITERAL
  417. #else
  418. #define CLITERAL (Color)
  419. #endif
  420. #define WHITE CLITERAL{ 255, 255, 255, 255 } // White
  421. #define BLACK CLITERAL{ 0, 0, 0, 255 } // Black
  422. #define RAYWHITE CLITERAL{ 245, 245, 245, 255 } // My own White (raylib logo)
  423. #define GRAY CLITERAL{ 130, 130, 130, 255 } // Gray -- GuiColorBarAlpha()
  424. // raylib functions are already implemented in raygui
  425. //-------------------------------------------------------------------------------
  426. static Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value
  427. static int ColorToInt(Color color); // Returns hexadecimal value for a Color
  428. static Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
  429. static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle
  430. static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed'
  431. //-------------------------------------------------------------------------------
  432. // Input required functions
  433. //-------------------------------------------------------------------------------
  434. static Vector2 GetMousePosition(void) { return (Vector2){ 0, 0 }; }
  435. static int GetMouseWheelMove(void) { return 0; }
  436. static bool IsMouseButtonDown(int button) { return false; }
  437. static bool IsMouseButtonPressed(int button) { return false; }
  438. static bool IsMouseButtonReleased(int button) { return false; }
  439. static bool IsKeyDown(int key) { return false; }
  440. static bool IsKeyPressed(int key) { return false; }
  441. static int GetKeyPressed(void) { return 0; } // -- GuiTextBox()
  442. //-------------------------------------------------------------------------------
  443. // Drawing required functions
  444. //-------------------------------------------------------------------------------
  445. static void DrawRectangle(int x, int y, int width, int height, Color color) { /* TODO */ }
  446. static void DrawRectangleRec(Rectangle rec, Color color) { DrawRectangle(rec.x, rec.y, rec.width, rec.height, color); }
  447. static void DrawRectangleLinesEx(Rectangle rec, int lineThick, Color color) { /* TODO */ }
  448. static void DrawRectangleLines(int x, int y, int width, int height, Color color) { /* TODO */ } // -- GuiColorPicker()
  449. static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2); // -- GuiColorPicker()
  450. static void DrawRectangleGradientH(int posX, int posY, int width, int height, Color color1, Color color2); // -- GuiColorPicker()
  451. static void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // -- GuiColorPicker()
  452. static void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color) { /* TODO */ } // -- GuiDropdownBox()
  453. static void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color) { /* TODO */ } // -- GuiScrollBar()
  454. static void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint) { } // -- GuiImageButtonEx()
  455. //-------------------------------------------------------------------------------
  456. // Text required functions
  457. //-------------------------------------------------------------------------------
  458. static Font GetFontDefault(void); // -- GetTextWidth()
  459. static Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing) { return (Vector2){ 0.0f }; } // Measure text size depending on font
  460. static void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint) { } // Draw text using font and additional parameters
  461. //-------------------------------------------------------------------------------
  462. #endif // RAYGUI_STANDALONE
  463. //----------------------------------------------------------------------------------
  464. // Module specific Functions Declaration
  465. //----------------------------------------------------------------------------------
  466. // List Element control, returns element state
  467. static bool GuiListElement(Rectangle bounds, const char *text, bool active, bool editMode);
  468. static Vector3 ConvertHSVtoRGB(Vector3 hsv); // Convert color data from HSV to RGB
  469. static Vector3 ConvertRGBtoHSV(Vector3 rgb); // Convert color data from RGB to HSV
  470. // Gui get text width using default font
  471. static int GetTextWidth(const char *text) // TODO: GetTextSize()
  472. {
  473. Vector2 size = { 0 };
  474. if (guiFont.texture.id == 0) guiFont = GetFontDefault();
  475. if ((text != NULL) && (text[0] != '\0')) size = MeasureTextEx(guiFont, text, GuiGetStyle(DEFAULT, TEXT_SIZE), GuiGetStyle(DEFAULT, TEXT_SPACING));
  476. // TODO: Consider text icon width here???
  477. return (int)size.x;
  478. }
  479. // Get text bounds considering control bounds
  480. static Rectangle GetTextBounds(int control, Rectangle bounds)
  481. {
  482. Rectangle textBounds = { 0 };
  483. textBounds.x = bounds.x + GuiGetStyle(control, BORDER_WIDTH) + GuiGetStyle(control, INNER_PADDING);
  484. textBounds.y = bounds.y + GuiGetStyle(control, BORDER_WIDTH) + GuiGetStyle(control, INNER_PADDING);
  485. textBounds.width = bounds.width - 2*(GuiGetStyle(control, BORDER_WIDTH) + GuiGetStyle(control, INNER_PADDING));
  486. textBounds.height = bounds.height - 2*(GuiGetStyle(control, BORDER_WIDTH) + GuiGetStyle(control, INNER_PADDING));
  487. switch (control)
  488. {
  489. case COMBOBOX: bounds.width -= (GuiGetStyle(control, SELECTOR_WIDTH) + GuiGetStyle(control, SELECTOR_PADDING)); break;
  490. case CHECKBOX: bounds.x += (bounds.width + GuiGetStyle(control, CHECK_TEXT_PADDING)); break;
  491. default: break;
  492. }
  493. // TODO: Special cases: COMBOBOX, DROPDOWNBOX, SPINNER, LISTVIEW (scrollbar?)
  494. // More special cases: CHECKBOX, SLIDER
  495. return textBounds;
  496. }
  497. // Get text icon if provided and move text cursor
  498. static const char *GetTextIcon(const char *text, int *iconId)
  499. {
  500. #if defined(RAYGUI_RICONS_SUPPORT)
  501. if (text[0] == '#') // Maybe we have an icon!
  502. {
  503. char iconValue[4] = { 0 };
  504. int i = 1;
  505. for (i = 1; i < 4; i++)
  506. {
  507. if ((text[i] != '#') && (text[i] != '\0')) iconValue[i - 1] = text[i];
  508. else break;
  509. }
  510. iconValue[3] = '\0';
  511. *iconId = atoi(iconValue);
  512. // Move text pointer after icon
  513. // WARNING: If only icon provided, it could point to EOL character!
  514. if (*iconId > 0) text += (i + 1);
  515. }
  516. #endif
  517. return text;
  518. }
  519. // Gui draw text using default font
  520. static void GuiDrawText(const char *text, Rectangle bounds, int alignment, Color tint)
  521. {
  522. if (guiFont.texture.id == 0) guiFont = GetFontDefault();
  523. if ((text != NULL) && (text[0] != '\0'))
  524. {
  525. int iconId = 0;
  526. text = GetTextIcon(text, &iconId); // Check text for icon and move cursor
  527. // Get text position depending on alignment and iconId
  528. //---------------------------------------------------------------------------------
  529. #define ICON_TEXT_PADDING 4
  530. Vector2 position = { bounds.x, bounds.y };
  531. // NOTE: We get text size after icon been processed
  532. int textWidth = GetTextWidth(text);
  533. int textHeight = GuiGetStyle(DEFAULT, TEXT_SIZE);
  534. #if defined(RAYGUI_RICONS_SUPPORT)
  535. if (iconId > 0)
  536. {
  537. textWidth += RICONS_SIZE;
  538. // WARNING: If only icon provided, text could be pointing to eof character!
  539. if ((text != NULL) && (text[0] != '\0')) textWidth += ICON_TEXT_PADDING;
  540. }
  541. #endif
  542. // Check guiTextAlign global variables
  543. switch (alignment)
  544. {
  545. case GUI_TEXT_ALIGN_LEFT:
  546. {
  547. position.x = bounds.x;
  548. position.y = bounds.y + bounds.height/2 - textHeight/2 + VALIGN_OFFSET(bounds.height);
  549. } break;
  550. case GUI_TEXT_ALIGN_CENTER:
  551. {
  552. position.x = bounds.x + bounds.width/2 - textWidth/2;
  553. position.y = bounds.y + bounds.height/2 - textHeight/2 + VALIGN_OFFSET(bounds.height);
  554. } break;
  555. case GUI_TEXT_ALIGN_RIGHT:
  556. {
  557. position.x = bounds.x + bounds.width - textWidth;
  558. position.y = bounds.y + bounds.height/2 - textHeight/2 + VALIGN_OFFSET(bounds.height);
  559. } break;
  560. default: break;
  561. }
  562. //---------------------------------------------------------------------------------
  563. // Draw text (with icon if available)
  564. //---------------------------------------------------------------------------------
  565. #if defined(RAYGUI_RICONS_SUPPORT)
  566. #define ICON_TEXT_PADDING 4
  567. if (iconId > 0)
  568. {
  569. // NOTE: We consider icon height, probably different than text size
  570. DrawIcon(iconId, (Vector2){ position.x, bounds.y + bounds.height/2 - RICONS_SIZE/2 + VALIGN_OFFSET(bounds.height) }, 1, tint);
  571. position.x += (RICONS_SIZE + ICON_TEXT_PADDING);
  572. }
  573. #endif
  574. DrawTextEx(guiFont, text, position, GuiGetStyle(DEFAULT, TEXT_SIZE), GuiGetStyle(DEFAULT, TEXT_SPACING), tint);
  575. //---------------------------------------------------------------------------------
  576. }
  577. }
  578. // Split controls text into multiple strings
  579. // Also check for multiple columns (required by GuiToggleGroup())
  580. static const char **GuiTextSplit(const char *text, int *count, int *textRow);
  581. //----------------------------------------------------------------------------------
  582. // Module Functions Definition
  583. //----------------------------------------------------------------------------------
  584. // Enable gui global state
  585. RAYGUIDEF void GuiEnable(void) { guiState = GUI_STATE_NORMAL; }
  586. // Disable gui global state
  587. RAYGUIDEF void GuiDisable(void) { guiState = GUI_STATE_DISABLED; }
  588. // Lock gui global state
  589. RAYGUIDEF void GuiLock(void) { guiLocked = true; }
  590. // Unlock gui global state
  591. RAYGUIDEF void GuiUnlock(void) { guiLocked = false; }
  592. // Set gui state (global state)
  593. RAYGUIDEF void GuiState(int state) { guiState = (GuiControlState)state; }
  594. // Define custom gui font
  595. RAYGUIDEF void GuiFont(Font font)
  596. {
  597. if (font.texture.id > 0)
  598. {
  599. guiFont = font;
  600. GuiSetStyle(DEFAULT, TEXT_SIZE, font.baseSize);
  601. // Populate all controls with new font size
  602. for (int i = 1; i < NUM_CONTROLS; i++) GuiSetStyle(i, TEXT_SIZE, GuiGetStyle(DEFAULT, TEXT_SIZE));
  603. // NOTE: Loaded font spacing must be set manually
  604. //GuiSetStyle(DEFAULT, TEXT_SPACING, 1);
  605. }
  606. }
  607. // Set gui controls alpha global state
  608. RAYGUIDEF void GuiFade(float alpha)
  609. {
  610. if (alpha < 0.0f) alpha = 0.0f;
  611. else if (alpha > 1.0f) alpha = 1.0f;
  612. guiAlpha = alpha;
  613. }
  614. // Set control style property value
  615. RAYGUIDEF void GuiSetStyle(int control, int property, int value)
  616. {
  617. if (!guiStyleLoaded) GuiLoadStyleDefault();
  618. guiStyle[control*(NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED) + property] = value;
  619. }
  620. // Get control style property value
  621. RAYGUIDEF int GuiGetStyle(int control, int property)
  622. {
  623. if (!guiStyleLoaded) GuiLoadStyleDefault();
  624. return guiStyle[control*(NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED) + property];
  625. }
  626. // Window Box control
  627. RAYGUIDEF bool GuiWindowBox(Rectangle bounds, const char *text)
  628. {
  629. #define WINDOW_CLOSE_BUTTON_PADDING 2
  630. #define WINDOW_STATUSBAR_HEIGHT 24
  631. GuiControlState state = guiState;
  632. bool clicked = false;
  633. Rectangle statusBar = { bounds.x, bounds.y, bounds.width, WINDOW_STATUSBAR_HEIGHT };
  634. if (bounds.height < WINDOW_STATUSBAR_HEIGHT*2) bounds.height = WINDOW_STATUSBAR_HEIGHT*2;
  635. Rectangle buttonRec = { statusBar.x + statusBar.width - GuiGetStyle(DEFAULT, BORDER_WIDTH) - WINDOW_CLOSE_BUTTON_PADDING - 20,
  636. statusBar.y + GuiGetStyle(DEFAULT, BORDER_WIDTH) + WINDOW_CLOSE_BUTTON_PADDING, 18, 18 };
  637. // Update control
  638. //--------------------------------------------------------------------
  639. // NOTE: Logic is directly managed by button
  640. //--------------------------------------------------------------------
  641. // Draw control
  642. //--------------------------------------------------------------------
  643. // Draw window base
  644. DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(DEFAULT, BORDER + (state*3))), guiAlpha));
  645. DrawRectangleRec((Rectangle){ bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH),
  646. bounds.width - GuiGetStyle(DEFAULT, BORDER_WIDTH)*2, bounds.height - GuiGetStyle(DEFAULT, BORDER_WIDTH)*2 },
  647. Fade(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)), guiAlpha));
  648. // Draw window header as status bar
  649. int defaultPadding = GuiGetStyle(DEFAULT, INNER_PADDING);
  650. int defaultTextAlign = GuiGetStyle(DEFAULT, TEXT_ALIGNMENT);
  651. GuiSetStyle(DEFAULT, INNER_PADDING, 8);
  652. GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT);
  653. GuiStatusBar(statusBar, text);
  654. GuiSetStyle(DEFAULT, INNER_PADDING, defaultPadding);
  655. GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, defaultTextAlign);
  656. // Draw window close button
  657. int buttonBorder = GuiGetStyle(BUTTON, BORDER_WIDTH);
  658. int buttonTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
  659. GuiSetStyle(BUTTON, BORDER_WIDTH, 1);
  660. GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
  661. #if defined(RAYGUI_RICONS_SUPPORT)
  662. clicked = GuiButton(buttonRec, GuiIconText(RICON_CROSS_SMALL, NULL));
  663. #else
  664. clicked = GuiButton(buttonRec, "x");
  665. #endif
  666. GuiSetStyle(BUTTON, BORDER_WIDTH, buttonBorder);
  667. GuiSetStyle(BUTTON, TEXT_ALIGNMENT, buttonTextAlignment);
  668. //--------------------------------------------------------------------
  669. return clicked;
  670. }
  671. // Group Box control with title name
  672. RAYGUIDEF void GuiGroupBox(Rectangle bounds, const char *text)
  673. {
  674. #define GROUPBOX_LINE_THICK 1
  675. #define GROUPBOX_TEXT_PADDING 10
  676. #define GROUPBOX_PADDING 2
  677. GuiControlState state = guiState;
  678. // Draw control
  679. //--------------------------------------------------------------------
  680. DrawRectangle(bounds.x, bounds.y, GROUPBOX_LINE_THICK, bounds.height, Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)), guiAlpha));
  681. DrawRectangle(bounds.x, bounds.y + bounds.height - 1, bounds.width, GROUPBOX_LINE_THICK, Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)), guiAlpha));
  682. DrawRectangle(bounds.x + bounds.width - 1, bounds.y, GROUPBOX_LINE_THICK, bounds.height, Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)), guiAlpha));
  683. GuiLine((Rectangle){ bounds.x, bounds.y, bounds.width, 1 }, text);
  684. //--------------------------------------------------------------------
  685. }
  686. // Line control
  687. RAYGUIDEF void GuiLine(Rectangle bounds, const char *text)
  688. {
  689. #define LINE_THICK 1
  690. #define LINE_TEXT_PADDING 10
  691. #define LINE_TEXT_SPACING 2
  692. GuiControlState state = guiState;
  693. Color color = Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)), guiAlpha);
  694. // Draw control
  695. //--------------------------------------------------------------------
  696. if (text == NULL) DrawRectangle(bounds.x, bounds.y + bounds.height/2, bounds.width, 1, color);
  697. else
  698. {
  699. Rectangle textBounds = { 0 };
  700. textBounds.width = GetTextWidth(text) + 2*LINE_TEXT_SPACING; // TODO: Consider text icon
  701. textBounds.height = GuiGetStyle(DEFAULT, TEXT_SIZE);
  702. textBounds.x = bounds.x + LINE_TEXT_PADDING + LINE_TEXT_SPACING;
  703. textBounds.y = bounds.y - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
  704. // Draw line with embedded text label: "--- text --------------"
  705. DrawRectangle(bounds.x, bounds.y, LINE_TEXT_PADDING, 1, color);
  706. GuiLabel(textBounds, text);
  707. DrawRectangle(bounds.x + textBounds.width + LINE_TEXT_PADDING + 2*LINE_TEXT_SPACING, bounds.y, bounds.width - (textBounds.width + LINE_TEXT_PADDING + 2*LINE_TEXT_SPACING), 1, color);
  708. }
  709. //--------------------------------------------------------------------
  710. }
  711. // Panel control
  712. RAYGUIDEF void GuiPanel(Rectangle bounds)
  713. {
  714. #define PANEL_BORDER_WIDTH 1
  715. GuiControlState state = guiState;
  716. // Draw control
  717. //--------------------------------------------------------------------
  718. DrawRectangleRec(bounds, Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BASE_COLOR_DISABLED : BACKGROUND_COLOR)), guiAlpha));
  719. DrawRectangleLinesEx(bounds, PANEL_BORDER_WIDTH, Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BORDER_COLOR_DISABLED: LINE_COLOR)), guiAlpha));
  720. //--------------------------------------------------------------------
  721. }
  722. // Scroll Panel control
  723. RAYGUIDEF Rectangle GuiScrollPanel(Rectangle bounds, Rectangle content, Vector2 *scroll)
  724. {
  725. GuiControlState state = guiState;
  726. Vector2 scrollPos = { 0.0f, 0.0f };
  727. if (scroll != NULL) scrollPos = *scroll;
  728. bool hasHorizontalScrollBar = (content.width > bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false;
  729. bool hasVerticalScrollBar = (content.height > bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false;
  730. // Recheck to account for the other scrollbar being visible
  731. if (!hasHorizontalScrollBar) hasHorizontalScrollBar = (hasVerticalScrollBar && (content.width > (bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false;
  732. if (!hasVerticalScrollBar) hasVerticalScrollBar = (hasHorizontalScrollBar && (content.height > (bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false;
  733. const int horizontalScrollBarWidth = hasHorizontalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0;
  734. const int verticalScrollBarWidth = hasVerticalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0;
  735. const Rectangle horizontalScrollBar = { ((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? bounds.x + verticalScrollBarWidth : bounds.x) + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + bounds.height - horizontalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - verticalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH), horizontalScrollBarWidth };
  736. const Rectangle verticalScrollBar = { ((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH) : bounds.x + bounds.width - verticalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH)), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), verticalScrollBarWidth, bounds.height - horizontalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) };
  737. // Calculate view area (area without the scrollbars)
  738. Rectangle view = (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)?
  739. (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 } :
  740. (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 };
  741. // Clip view area to the actual content size
  742. if (view.width > content.width) view.width = content.width;
  743. if (view.height > content.height) view.height = content.height;
  744. // TODO: Review!
  745. const int horizontalMin = hasHorizontalScrollBar? ((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? -verticalScrollBarWidth : 0) - GuiGetStyle(DEFAULT, BORDER_WIDTH) : ((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? -verticalScrollBarWidth : 0) - GuiGetStyle(DEFAULT, BORDER_WIDTH);
  746. const int horizontalMax = hasHorizontalScrollBar? content.width - bounds.width + verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH) - ((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? verticalScrollBarWidth : 0) : -GuiGetStyle(DEFAULT, BORDER_WIDTH);
  747. const int verticalMin = hasVerticalScrollBar? -GuiGetStyle(DEFAULT, BORDER_WIDTH) : -GuiGetStyle(DEFAULT, BORDER_WIDTH);
  748. const int verticalMax = hasVerticalScrollBar? content.height - bounds.height + horizontalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH) : -GuiGetStyle(DEFAULT, BORDER_WIDTH);
  749. // Update control
  750. //--------------------------------------------------------------------
  751. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  752. {
  753. Vector2 mousePoint = GetMousePosition();
  754. // Check button state
  755. if (CheckCollisionPointRec(mousePoint, bounds))
  756. {
  757. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
  758. else state = GUI_STATE_FOCUSED;
  759. if (hasHorizontalScrollBar)
  760. {
  761. if (IsKeyDown(KEY_RIGHT)) scrollPos.x -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
  762. if (IsKeyDown(KEY_LEFT)) scrollPos.x += GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
  763. }
  764. if (hasVerticalScrollBar)
  765. {
  766. if (IsKeyDown(KEY_DOWN)) scrollPos.y -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
  767. if (IsKeyDown(KEY_UP)) scrollPos.y += GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
  768. }
  769. scrollPos.y += GetMouseWheelMove()*20;
  770. }
  771. }
  772. // Normalize scroll values
  773. if (scrollPos.x > -horizontalMin) scrollPos.x = -horizontalMin;
  774. if (scrollPos.x < -horizontalMax) scrollPos.x = -horizontalMax;
  775. if (scrollPos.y > -verticalMin) scrollPos.y = -verticalMin;
  776. if (scrollPos.y < -verticalMax) scrollPos.y = -verticalMax;
  777. //--------------------------------------------------------------------
  778. // Draw control
  779. //--------------------------------------------------------------------
  780. DrawRectangleRec(bounds, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background
  781. // Save size of the scrollbar slider
  782. const int slider = GuiGetStyle(SCROLLBAR, SLIDER_SIZE);
  783. // Draw horizontal scrollbar if visible
  784. if (hasHorizontalScrollBar)
  785. {
  786. // Change scrollbar slider size to show the diff in size between the content width and the widget width
  787. GuiSetStyle(SCROLLBAR, SLIDER_SIZE, ((bounds.width - 2 * GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth)/content.width)*(bounds.width - 2 * GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth));
  788. scrollPos.x = -GuiScrollBar(horizontalScrollBar, -scrollPos.x, horizontalMin, horizontalMax);
  789. }
  790. // Draw vertical scrollbar if visible
  791. if (hasVerticalScrollBar)
  792. {
  793. // Change scrollbar slider size to show the diff in size between the content height and the widget height
  794. GuiSetStyle(SCROLLBAR, SLIDER_SIZE, ((bounds.height - 2 * GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth)/content.height)* (bounds.height - 2 * GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth));
  795. scrollPos.y = -GuiScrollBar(verticalScrollBar, -scrollPos.y, verticalMin, verticalMax);
  796. }
  797. // Draw detail corner rectangle if both scroll bars are visible
  798. if (hasHorizontalScrollBar && hasVerticalScrollBar)
  799. {
  800. // TODO: Consider scroll bars side
  801. DrawRectangle(horizontalScrollBar.x + horizontalScrollBar.width + 2,
  802. verticalScrollBar.y + verticalScrollBar.height + 2,
  803. horizontalScrollBarWidth - 4, verticalScrollBarWidth - 4,
  804. Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT + (state*3))), guiAlpha));
  805. }
  806. // Set scrollbar slider size back to the way it was before
  807. GuiSetStyle(SCROLLBAR, SLIDER_SIZE, slider);
  808. // Draw scrollbar lines depending on current state
  809. DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER + (state*3))), guiAlpha));
  810. //--------------------------------------------------------------------
  811. if (scroll != NULL) *scroll = scrollPos;
  812. return view;
  813. }
  814. // Label control
  815. RAYGUIDEF void GuiLabel(Rectangle bounds, const char *text)
  816. {
  817. GuiControlState state = guiState;
  818. // Update control
  819. //--------------------------------------------------------------------
  820. // ...
  821. //--------------------------------------------------------------------
  822. // Draw control
  823. //--------------------------------------------------------------------
  824. GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LABEL, (state == GUI_STATE_DISABLED)? TEXT_COLOR_DISABLED : TEXT_COLOR_NORMAL)), guiAlpha));
  825. //--------------------------------------------------------------------
  826. }
  827. // Button control, returns true when clicked
  828. RAYGUIDEF bool GuiButton(Rectangle bounds, const char *text)
  829. {
  830. GuiControlState state = guiState;
  831. bool pressed = false;
  832. // Update control
  833. //--------------------------------------------------------------------
  834. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  835. {
  836. Vector2 mousePoint = GetMousePosition();
  837. // Check button state
  838. if (CheckCollisionPointRec(mousePoint, bounds))
  839. {
  840. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
  841. else state = GUI_STATE_FOCUSED;
  842. if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true;
  843. }
  844. }
  845. //--------------------------------------------------------------------
  846. // Draw control
  847. //--------------------------------------------------------------------
  848. DrawRectangleLinesEx(bounds, GuiGetStyle(BUTTON, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(BUTTON, BORDER + (state*3))), guiAlpha));
  849. DrawRectangle(bounds.x + GuiGetStyle(BUTTON, BORDER_WIDTH), bounds.y + GuiGetStyle(BUTTON, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(BUTTON, BORDER_WIDTH), bounds.height - 2*GuiGetStyle(BUTTON, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(BUTTON, BASE + (state*3))), guiAlpha));
  850. GuiDrawText(text, GetTextBounds(BUTTON, bounds), GuiGetStyle(BUTTON, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(BUTTON, TEXT + (state*3))), guiAlpha));
  851. //------------------------------------------------------------------
  852. return pressed;
  853. }
  854. // Label button control
  855. RAYGUIDEF bool GuiLabelButton(Rectangle bounds, const char *text)
  856. {
  857. GuiControlState state = guiState;
  858. bool pressed = false;
  859. // Update control
  860. //--------------------------------------------------------------------
  861. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  862. {
  863. Vector2 mousePoint = GetMousePosition();
  864. // Check checkbox state
  865. if (CheckCollisionPointRec(mousePoint, bounds))
  866. {
  867. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
  868. else state = GUI_STATE_FOCUSED;
  869. if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true;
  870. }
  871. }
  872. //--------------------------------------------------------------------
  873. // Draw control
  874. //--------------------------------------------------------------------
  875. GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha));
  876. //--------------------------------------------------------------------
  877. return pressed;
  878. }
  879. // Image button control, returns true when clicked
  880. RAYGUIDEF bool GuiImageButton(Rectangle bounds, Texture2D texture)
  881. {
  882. return GuiImageButtonEx(bounds, texture, (Rectangle){ 0, 0, texture.width, texture.height }, NULL);
  883. }
  884. // Image button control, returns true when clicked
  885. RAYGUIDEF bool GuiImageButtonEx(Rectangle bounds, Texture2D texture, Rectangle texSource, const char *text)
  886. {
  887. GuiControlState state = guiState;
  888. bool clicked = false;
  889. // Update control
  890. //--------------------------------------------------------------------
  891. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  892. {
  893. Vector2 mousePoint = GetMousePosition();
  894. // Check button state
  895. if (CheckCollisionPointRec(mousePoint, bounds))
  896. {
  897. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
  898. else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) clicked = true;
  899. else state = GUI_STATE_FOCUSED;
  900. }
  901. }
  902. //--------------------------------------------------------------------
  903. // Draw control
  904. //--------------------------------------------------------------------
  905. DrawRectangleLinesEx(bounds, GuiGetStyle(BUTTON, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(BUTTON, BORDER + (state*3))), guiAlpha));
  906. DrawRectangle(bounds.x + GuiGetStyle(BUTTON, BORDER_WIDTH), bounds.y + GuiGetStyle(BUTTON, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(BUTTON, BORDER_WIDTH), bounds.height - 2*GuiGetStyle(BUTTON, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(BUTTON, BASE + (state*3))), guiAlpha));
  907. if (text != NULL) GuiDrawText(text, GetTextBounds(BUTTON, bounds), GuiGetStyle(BUTTON, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(BUTTON, TEXT + (state*3))), guiAlpha));
  908. if (texture.id > 0) DrawTextureRec(texture, texSource, (Vector2){ bounds.x + bounds.width/2 - (texSource.width + GuiGetStyle(BUTTON, INNER_PADDING)/2)/2, bounds.y + bounds.height/2 - texSource.height/2 }, Fade(GetColor(GuiGetStyle(BUTTON, TEXT + (state*3))), guiAlpha));
  909. //------------------------------------------------------------------
  910. return clicked;
  911. }
  912. // Toggle Button control, returns true when active
  913. RAYGUIDEF bool GuiToggle(Rectangle bounds, const char *text, bool active)
  914. {
  915. GuiControlState state = guiState;
  916. // Update control
  917. //--------------------------------------------------------------------
  918. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  919. {
  920. Vector2 mousePoint = GetMousePosition();
  921. // Check toggle button state
  922. if (CheckCollisionPointRec(mousePoint, bounds))
  923. {
  924. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
  925. else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
  926. {
  927. state = GUI_STATE_NORMAL;
  928. active = !active;
  929. }
  930. else state = GUI_STATE_FOCUSED;
  931. }
  932. }
  933. //--------------------------------------------------------------------
  934. // Draw control
  935. //--------------------------------------------------------------------
  936. if (state == GUI_STATE_NORMAL)
  937. {
  938. DrawRectangleLinesEx(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TOGGLE, (active? BORDER_COLOR_PRESSED : (BORDER + state*3)))), guiAlpha));
  939. DrawRectangle(bounds.x + GuiGetStyle(TOGGLE, BORDER_WIDTH), bounds.y + GuiGetStyle(TOGGLE, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(TOGGLE, BORDER_WIDTH), bounds.height - 2*GuiGetStyle(TOGGLE, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TOGGLE, (active? BASE_COLOR_PRESSED : (BASE + state*3)))), guiAlpha));
  940. GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TOGGLE, (active? TEXT_COLOR_PRESSED : (TEXT + state*3)))), guiAlpha));
  941. }
  942. else
  943. {
  944. DrawRectangleLinesEx(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TOGGLE, BORDER + state*3)), guiAlpha));
  945. DrawRectangle(bounds.x + GuiGetStyle(TOGGLE, BORDER_WIDTH), bounds.y + GuiGetStyle(TOGGLE, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(TOGGLE, BORDER_WIDTH), bounds.height - 2*GuiGetStyle(TOGGLE, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TOGGLE, BASE + state*3)), guiAlpha));
  946. GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TOGGLE, TEXT + state*3)), guiAlpha));
  947. }
  948. //--------------------------------------------------------------------
  949. return active;
  950. }
  951. // Toggle Group control, returns toggled button index
  952. RAYGUIDEF int GuiToggleGroup(Rectangle bounds, const char *text, int active)
  953. {
  954. float initBoundsX = bounds.x;
  955. // Get substrings elements from text (elements pointers)
  956. int rows[64] = { 0 };
  957. int elementsCount = 0;
  958. const char **elementsPtrs = GuiTextSplit(text, &elementsCount, rows);
  959. int prevRow = rows[0];
  960. for (int i = 0; i < elementsCount; i++)
  961. {
  962. if (prevRow != rows[i])
  963. {
  964. bounds.x = initBoundsX;
  965. bounds.y += (bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING));
  966. prevRow = rows[i];
  967. }
  968. if (i == active) GuiToggle(bounds, elementsPtrs[i], true);
  969. else if (GuiToggle(bounds, elementsPtrs[i], false) == true) active = i;
  970. bounds.x += (bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING));
  971. }
  972. return active;
  973. }
  974. // Check Box control, returns true when active
  975. RAYGUIDEF bool GuiCheckBox(Rectangle bounds, const char *text, bool checked)
  976. {
  977. GuiControlState state = guiState;
  978. Rectangle textBounds = { 0 };
  979. textBounds.x = bounds.x + bounds.width + GuiGetStyle(CHECKBOX, CHECK_TEXT_PADDING);
  980. textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
  981. textBounds.width = GetTextWidth(text); // TODO: Consider text icon
  982. textBounds.height = GuiGetStyle(DEFAULT, TEXT_SIZE);
  983. // Update control
  984. //--------------------------------------------------------------------
  985. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  986. {
  987. Vector2 mousePoint = GetMousePosition();
  988. // Check checkbox state
  989. if (CheckCollisionPointRec(mousePoint, (Rectangle){ bounds.x, bounds.y, bounds.width + textBounds.width + GuiGetStyle(CHECKBOX, CHECK_TEXT_PADDING), bounds.height }))
  990. {
  991. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
  992. else state = GUI_STATE_FOCUSED;
  993. if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) checked = !checked;
  994. }
  995. }
  996. //--------------------------------------------------------------------
  997. // Draw control
  998. //--------------------------------------------------------------------
  999. DrawRectangleLinesEx(bounds, GuiGetStyle(CHECKBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(CHECKBOX, BORDER + (state*3))), guiAlpha));
  1000. if (checked) DrawRectangle(bounds.x + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, INNER_PADDING),
  1001. bounds.y + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, INNER_PADDING),
  1002. bounds.width - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, INNER_PADDING)),
  1003. bounds.height - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, INNER_PADDING)),
  1004. Fade(GetColor(GuiGetStyle(CHECKBOX, TEXT + state*3)), guiAlpha));
  1005. // NOTE: Forced left text alignment
  1006. GuiDrawText(text, textBounds, GUI_TEXT_ALIGN_LEFT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha));
  1007. //--------------------------------------------------------------------
  1008. return checked;
  1009. }
  1010. // Combo Box control, returns selected item index
  1011. RAYGUIDEF int GuiComboBox(Rectangle bounds, const char *text, int active)
  1012. {
  1013. GuiControlState state = guiState;
  1014. bounds.width -= (GuiGetStyle(COMBOBOX, SELECTOR_WIDTH) + GuiGetStyle(COMBOBOX, SELECTOR_PADDING));
  1015. Rectangle selector = { bounds.x + bounds.width + GuiGetStyle(COMBOBOX, SELECTOR_PADDING),
  1016. bounds.y, GuiGetStyle(COMBOBOX, SELECTOR_WIDTH), bounds.height };
  1017. // Get substrings elements from text (elements pointers, lengths and count)
  1018. int elementsCount = 0;
  1019. const char **elementsPtrs = GuiTextSplit(text, &elementsCount, NULL);
  1020. if (active < 0) active = 0;
  1021. else if (active > elementsCount - 1) active = elementsCount - 1;
  1022. // Update control
  1023. //--------------------------------------------------------------------
  1024. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  1025. {
  1026. Vector2 mousePoint = GetMousePosition();
  1027. if (CheckCollisionPointRec(mousePoint, bounds) ||
  1028. CheckCollisionPointRec(mousePoint, selector))
  1029. {
  1030. if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
  1031. {
  1032. active += 1;
  1033. if (active >= elementsCount) active = 0;
  1034. }
  1035. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
  1036. else state = GUI_STATE_FOCUSED;
  1037. }
  1038. }
  1039. //--------------------------------------------------------------------
  1040. // Draw control
  1041. //--------------------------------------------------------------------
  1042. // Draw combo box main
  1043. DrawRectangleLinesEx(bounds, GuiGetStyle(COMBOBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(COMBOBOX, BORDER + (state*3))), guiAlpha));
  1044. DrawRectangle(bounds.x + GuiGetStyle(COMBOBOX, BORDER_WIDTH), bounds.y + GuiGetStyle(COMBOBOX, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(COMBOBOX, BORDER_WIDTH), bounds.height - 2*GuiGetStyle(COMBOBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(COMBOBOX, BASE + (state*3))), guiAlpha));
  1045. GuiDrawText(elementsPtrs[active], GetTextBounds(COMBOBOX, bounds), GuiGetStyle(COMBOBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(COMBOBOX, TEXT + (state*3))), guiAlpha));
  1046. // Draw selector using a custom button
  1047. // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values
  1048. GuiSetStyle(BUTTON, BORDER_WIDTH, 1);
  1049. int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
  1050. GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
  1051. GuiButton(selector, TextFormat("%i/%i", active + 1, elementsCount));
  1052. GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign);
  1053. GuiSetStyle(BUTTON, BORDER_WIDTH, 2);
  1054. //--------------------------------------------------------------------
  1055. return active;
  1056. }
  1057. // Dropdown Box control, returns selected item
  1058. RAYGUIDEF bool GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode)
  1059. {
  1060. GuiControlState state = guiState;
  1061. // Get substrings elements from text (elements pointers, lengths and count)
  1062. int elementsCount = 0;
  1063. const char **elementsPtrs = GuiTextSplit(text, &elementsCount, NULL);
  1064. bool pressed = false;
  1065. int auxActive = *active;
  1066. Rectangle closeBounds = bounds;
  1067. Rectangle openBounds = bounds;
  1068. openBounds.height *= (elementsCount + 1);
  1069. // Update control
  1070. //--------------------------------------------------------------------
  1071. if (guiLocked && editMode) guiLocked = false;
  1072. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  1073. {
  1074. Vector2 mousePoint = GetMousePosition();
  1075. if (editMode) state = GUI_STATE_PRESSED;
  1076. if (!editMode)
  1077. {
  1078. if (CheckCollisionPointRec(mousePoint, closeBounds))
  1079. {
  1080. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
  1081. if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
  1082. else state = GUI_STATE_FOCUSED;
  1083. }
  1084. }
  1085. else
  1086. {
  1087. if (CheckCollisionPointRec(mousePoint, closeBounds))
  1088. {
  1089. if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
  1090. }
  1091. else if (!CheckCollisionPointRec(mousePoint, openBounds))
  1092. {
  1093. if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true;
  1094. }
  1095. }
  1096. }
  1097. //--------------------------------------------------------------------
  1098. // Draw control
  1099. //--------------------------------------------------------------------
  1100. // TODO: Review this ugly hack... DROPDOWNBOX depends on GiListElement() that uses DEFAULT_TEXT_ALIGNMENT
  1101. int tempTextAlign = GuiGetStyle(DEFAULT, TEXT_ALIGNMENT);
  1102. GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT));
  1103. switch (state)
  1104. {
  1105. case GUI_STATE_NORMAL:
  1106. {
  1107. DrawRectangle(bounds.x, bounds.y, bounds.width, bounds.height, Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_NORMAL)), guiAlpha));
  1108. DrawRectangleLinesEx(bounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_NORMAL)), guiAlpha));
  1109. GuiListElement((Rectangle){ bounds.x, bounds.y, bounds.width, bounds.height }, elementsPtrs[auxActive], false, false);
  1110. } break;
  1111. case GUI_STATE_FOCUSED:
  1112. {
  1113. GuiListElement((Rectangle){ bounds.x, bounds.y, bounds.width, bounds.height }, elementsPtrs[auxActive], false, editMode);
  1114. } break;
  1115. case GUI_STATE_PRESSED:
  1116. {
  1117. if (!editMode) GuiListElement((Rectangle){ bounds.x, bounds.y, bounds.width, bounds.height }, elementsPtrs[auxActive], true, true);
  1118. if (editMode)
  1119. {
  1120. GuiPanel(openBounds);
  1121. GuiListElement((Rectangle){ bounds.x, bounds.y, bounds.width, bounds.height }, elementsPtrs[auxActive], true, true);
  1122. for (int i = 0; i < elementsCount; i++)
  1123. {
  1124. if (i == auxActive && editMode)
  1125. {
  1126. if (GuiListElement((Rectangle){ bounds.x, bounds.y + bounds.height*(i + 1) + GuiGetStyle(DROPDOWNBOX, INNER_PADDING),
  1127. bounds.width, bounds.height - GuiGetStyle(DROPDOWNBOX, INNER_PADDING) },
  1128. elementsPtrs[i], true, true) == false) pressed = true;
  1129. }
  1130. else
  1131. {
  1132. if (GuiListElement((Rectangle){ bounds.x, bounds.y + bounds.height*(i+1) + GuiGetStyle(DROPDOWNBOX, INNER_PADDING),
  1133. bounds.width, bounds.height - GuiGetStyle(DROPDOWNBOX, INNER_PADDING) },
  1134. elementsPtrs[i], false, true))
  1135. {
  1136. auxActive = i;
  1137. pressed = true;
  1138. }
  1139. }
  1140. }
  1141. }
  1142. } break;
  1143. case GUI_STATE_DISABLED:
  1144. {
  1145. DrawRectangle(bounds.x, bounds.y, bounds.width, bounds.height, Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_DISABLED)), guiAlpha));
  1146. DrawRectangleLinesEx(bounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_DISABLED)), guiAlpha));
  1147. GuiListElement((Rectangle){ bounds.x, bounds.y, bounds.width, bounds.height }, elementsPtrs[auxActive], false, false);
  1148. } break;
  1149. default: break;
  1150. }
  1151. GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, tempTextAlign);
  1152. DrawTriangle((Vector2){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_RIGHT_PADDING), bounds.y + bounds.height/2 - 2 },
  1153. (Vector2){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_RIGHT_PADDING) + 5, bounds.y + bounds.height/2 - 2 + 5 },
  1154. (Vector2){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_RIGHT_PADDING) + 10, bounds.y + bounds.height/2 - 2 },
  1155. Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))), guiAlpha));
  1156. //--------------------------------------------------------------------
  1157. *active = auxActive;
  1158. return pressed;
  1159. }
  1160. // Spinner control, returns selected value
  1161. // NOTE: Requires static variables: framesCounter, valueSpeed - ERROR!
  1162. RAYGUIDEF bool GuiSpinner(Rectangle bounds, int *value, int minValue, int maxValue, bool editMode)
  1163. {
  1164. bool pressed = false;
  1165. int tempValue = *value;
  1166. Rectangle spinner = { bounds.x + GuiGetStyle(TEXTBOX, SPINNER_BUTTON_WIDTH) + GuiGetStyle(TEXTBOX, SPINNER_BUTTON_PADDING), bounds.y,
  1167. bounds.width - 2*(GuiGetStyle(TEXTBOX, SPINNER_BUTTON_WIDTH) + GuiGetStyle(TEXTBOX, SPINNER_BUTTON_PADDING)), bounds.height };
  1168. Rectangle leftButtonBound = { bounds.x, bounds.y, GuiGetStyle(TEXTBOX, SPINNER_BUTTON_WIDTH), bounds.height };
  1169. Rectangle rightButtonBound = { bounds.x + bounds.width - GuiGetStyle(TEXTBOX, SPINNER_BUTTON_WIDTH), bounds.y, GuiGetStyle(TEXTBOX, SPINNER_BUTTON_WIDTH), bounds.height };
  1170. // Update control
  1171. //--------------------------------------------------------------------
  1172. if (!editMode)
  1173. {
  1174. if (tempValue < minValue) tempValue = minValue;
  1175. if (tempValue > maxValue) tempValue = maxValue;
  1176. }
  1177. //--------------------------------------------------------------------
  1178. // Draw control
  1179. //--------------------------------------------------------------------
  1180. pressed = GuiValueBox(spinner, &tempValue, minValue, maxValue, editMode);
  1181. // Draw value selector custom buttons
  1182. // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values
  1183. int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
  1184. GuiSetStyle(BUTTON, BORDER_WIDTH, GuiGetStyle(TEXTBOX, SPINNER_BUTTON_BORDER_WIDTH));
  1185. int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
  1186. GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
  1187. #if defined(RAYGUI_RICONS_SUPPORT)
  1188. if (GuiButton(leftButtonBound, GuiIconText(RICON_ARROW_LEFT_FILL, NULL))) tempValue--;
  1189. if (GuiButton(rightButtonBound, GuiIconText(RICON_ARROW_RIGHT_FILL, NULL))) tempValue++;
  1190. #else
  1191. if (GuiButton(leftButtonBound, "<")) tempValue--;
  1192. if (GuiButton(rightButtonBound, ">")) tempValue++;
  1193. #endif
  1194. GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign);
  1195. GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
  1196. //--------------------------------------------------------------------
  1197. *value = tempValue;
  1198. return pressed;
  1199. }
  1200. // Value Box control, updates input text with numbers
  1201. // NOTE: Requires static variables: framesCounter
  1202. RAYGUIDEF bool GuiValueBox(Rectangle bounds, int *value, int minValue, int maxValue, bool editMode)
  1203. {
  1204. #define VALUEBOX_MAX_CHARS 32
  1205. static int framesCounter = 0; // Required for blinking cursor
  1206. GuiControlState state = guiState;
  1207. bool pressed = false;
  1208. char text[VALUEBOX_MAX_CHARS + 1] = "\0";
  1209. sprintf(text, "%i", *value);
  1210. // Update control
  1211. //--------------------------------------------------------------------
  1212. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  1213. {
  1214. Vector2 mousePoint = GetMousePosition();
  1215. bool valueHasChanged = false;
  1216. if (editMode)
  1217. {
  1218. state = GUI_STATE_PRESSED;
  1219. framesCounter++;
  1220. int keyCount = strlen(text);
  1221. // Only allow keys in range [48..57]
  1222. if (keyCount < VALUEBOX_MAX_CHARS)
  1223. {
  1224. int maxWidth = (bounds.width - (GuiGetStyle(DEFAULT, INNER_PADDING)*2));
  1225. if (GetTextWidth(text) < maxWidth)
  1226. {
  1227. int key = GetKeyPressed();
  1228. if ((key >= 48) && (key <= 57))
  1229. {
  1230. text[keyCount] = (char)key;
  1231. keyCount++;
  1232. valueHasChanged = true;
  1233. }
  1234. }
  1235. }
  1236. // Delete text
  1237. if (keyCount > 0)
  1238. {
  1239. if (IsKeyPressed(KEY_BACKSPACE))
  1240. {
  1241. keyCount--;
  1242. text[keyCount] = '\0';
  1243. framesCounter = 0;
  1244. if (keyCount < 0) keyCount = 0;
  1245. valueHasChanged = true;
  1246. }
  1247. else if (IsKeyDown(KEY_BACKSPACE))
  1248. {
  1249. if ((framesCounter > TEXTEDIT_CURSOR_BLINK_FRAMES) && (framesCounter%2) == 0) keyCount--;
  1250. text[keyCount] = '\0';
  1251. if (keyCount < 0) keyCount = 0;
  1252. valueHasChanged = true;
  1253. }
  1254. }
  1255. if (valueHasChanged) *value = atoi(text);
  1256. }
  1257. else
  1258. {
  1259. if (*value > maxValue) *value = maxValue;
  1260. else if (*value < minValue) *value = minValue;
  1261. }
  1262. if (!editMode)
  1263. {
  1264. if (CheckCollisionPointRec(mousePoint, bounds))
  1265. {
  1266. state = GUI_STATE_FOCUSED;
  1267. if (IsMouseButtonPressed(0)) pressed = true;
  1268. }
  1269. }
  1270. else
  1271. {
  1272. if (IsKeyPressed(KEY_ENTER) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(0))) pressed = true;
  1273. }
  1274. if (pressed) framesCounter = 0;
  1275. }
  1276. //--------------------------------------------------------------------
  1277. // Draw control
  1278. //--------------------------------------------------------------------
  1279. DrawRectangleLinesEx(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha));
  1280. if (state == GUI_STATE_PRESSED)
  1281. {
  1282. DrawRectangle(bounds.x + GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.height - 2*GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_FOCUSED)), guiAlpha));
  1283. if (editMode && ((framesCounter/20)%2 == 0)) DrawRectangle(bounds.x + GetTextWidth(text)/2 + bounds.width/2 + 2, bounds.y + GuiGetStyle(TEXTBOX, INNER_PADDING), 1, bounds.height - GuiGetStyle(TEXTBOX, INNER_PADDING)*2, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_FOCUSED)), guiAlpha));
  1284. }
  1285. else if (state == GUI_STATE_DISABLED)
  1286. {
  1287. DrawRectangle(bounds.x + GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.height - 2*GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_DISABLED)), guiAlpha));
  1288. }
  1289. GuiDrawText(text, GetTextBounds(TEXTBOX, bounds), GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha));
  1290. //--------------------------------------------------------------------
  1291. return pressed;
  1292. }
  1293. // Text Box control, updates input text
  1294. // NOTE 1: Requires static variables: framesCounter
  1295. // NOTE 2: Returns if KEY_ENTER pressed (useful for data validation)
  1296. RAYGUIDEF bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
  1297. {
  1298. static int framesCounter = 0; // Required for blinking cursor
  1299. GuiControlState state = guiState;
  1300. bool pressed = false;
  1301. // Update control
  1302. //--------------------------------------------------------------------
  1303. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  1304. {
  1305. Vector2 mousePoint = GetMousePosition();
  1306. if (editMode)
  1307. {
  1308. state = GUI_STATE_PRESSED;
  1309. framesCounter++;
  1310. int key = GetKeyPressed();
  1311. int keyCount = strlen(text);
  1312. // Only allow keys in range [32..125]
  1313. if (keyCount < (textSize - 1))
  1314. {
  1315. int maxWidth = (bounds.width - (GuiGetStyle(DEFAULT, INNER_PADDING)*2));
  1316. if (GetTextWidth(text) < (maxWidth - GuiGetStyle(DEFAULT, TEXT_SIZE)))
  1317. {
  1318. if (((key >= 32) && (key <= 125)) ||
  1319. ((key >= 128) && (key < 255)))
  1320. {
  1321. text[keyCount] = (char)key;
  1322. keyCount++;
  1323. }
  1324. }
  1325. }
  1326. // Delete text
  1327. if (keyCount > 0)
  1328. {
  1329. if (IsKeyPressed(KEY_BACKSPACE))
  1330. {
  1331. keyCount--;
  1332. text[keyCount] = '\0';
  1333. framesCounter = 0;
  1334. if (keyCount < 0) keyCount = 0;
  1335. }
  1336. else if (IsKeyDown(KEY_BACKSPACE))
  1337. {
  1338. if ((framesCounter > TEXTEDIT_CURSOR_BLINK_FRAMES) && (framesCounter%2) == 0) keyCount--;
  1339. text[keyCount] = '\0';
  1340. if (keyCount < 0) keyCount = 0;
  1341. }
  1342. }
  1343. }
  1344. if (!editMode)
  1345. {
  1346. if (CheckCollisionPointRec(mousePoint, bounds))
  1347. {
  1348. state = GUI_STATE_FOCUSED;
  1349. if (IsMouseButtonPressed(0)) pressed = true;
  1350. }
  1351. }
  1352. else
  1353. {
  1354. if (IsKeyPressed(KEY_ENTER) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(0))) pressed = true;
  1355. }
  1356. if (pressed) framesCounter = 0;
  1357. }
  1358. //--------------------------------------------------------------------
  1359. // Draw control
  1360. //--------------------------------------------------------------------
  1361. DrawRectangleLinesEx(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha));
  1362. if (state == GUI_STATE_PRESSED)
  1363. {
  1364. DrawRectangle(bounds.x + GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.height - 2*GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_FOCUSED)), guiAlpha));
  1365. // Draw blinking cursor
  1366. // TODO: Consider TEXTBOX TEXT_ALIGNMENT
  1367. if (editMode && ((framesCounter/20)%2 == 0)) DrawRectangle(bounds.x + GuiGetStyle(TEXTBOX, INNER_PADDING) + GetTextWidth(text) + 2, bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE), 1, GuiGetStyle(DEFAULT, TEXT_SIZE)*2, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)), guiAlpha));
  1368. }
  1369. else if (state == GUI_STATE_DISABLED)
  1370. {
  1371. DrawRectangle(bounds.x + GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.height - 2*GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_DISABLED)), guiAlpha));
  1372. }
  1373. GuiDrawText(text, GetTextBounds(TEXTBOX, bounds), GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha));
  1374. //--------------------------------------------------------------------
  1375. return pressed;
  1376. }
  1377. // Text Box control with multiple lines
  1378. RAYGUIDEF bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode)
  1379. {
  1380. static int framesCounter = 0; // Required for blinking cursor
  1381. GuiControlState state = guiState;
  1382. bool pressed = false;
  1383. bool textHasChange = false;
  1384. int currentLine = 0;
  1385. //const char *numChars = NULL;
  1386. // Security check because font is used directly in this control
  1387. if (guiFont.texture.id == 0) guiFont = GetFontDefault();
  1388. // Update control
  1389. //--------------------------------------------------------------------
  1390. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  1391. {
  1392. Vector2 mousePoint = GetMousePosition();
  1393. if (editMode)
  1394. {
  1395. state = GUI_STATE_PRESSED;
  1396. framesCounter++;
  1397. int keyCount = strlen(text);
  1398. int maxWidth = (bounds.width - (GuiGetStyle(TEXTBOX, INNER_PADDING)*2));
  1399. int maxHeight = (bounds.height - (GuiGetStyle(TEXTBOX, INNER_PADDING)*2));
  1400. //numChars = TextFormat("%i/%i", keyCount, textSize - 1);
  1401. // Only allow keys in range [32..125]
  1402. if (keyCount < (textSize - 1))
  1403. {
  1404. int key = GetKeyPressed();
  1405. if (MeasureTextEx(guiFont, text, GuiGetStyle(DEFAULT, TEXT_SIZE), 1).y < (maxHeight - GuiGetStyle(DEFAULT, TEXT_SIZE)))
  1406. {
  1407. if (IsKeyPressed(KEY_ENTER))
  1408. {
  1409. text[keyCount] = '\n';
  1410. keyCount++;
  1411. }
  1412. else if (((key >= 32) && (key <= 125)) ||
  1413. ((key >= 128) && (key < 255)))
  1414. {
  1415. text[keyCount] = (char)key;
  1416. keyCount++;
  1417. textHasChange = true;
  1418. }
  1419. }
  1420. else if (GetTextWidth(strrchr(text, '\n')) < (maxWidth - GuiGetStyle(DEFAULT, TEXT_SIZE)))
  1421. {
  1422. if (((key >= 32) && (key <= 125)) ||
  1423. ((key >= 128) && (key < 255)))
  1424. {
  1425. text[keyCount] = (char)key;
  1426. keyCount++;
  1427. textHasChange = true;
  1428. }
  1429. }
  1430. }
  1431. // Delete text
  1432. if (keyCount > 0)
  1433. {
  1434. if (IsKeyPressed(KEY_BACKSPACE))
  1435. {
  1436. keyCount--;
  1437. text[keyCount] = '\0';
  1438. framesCounter = 0;
  1439. if (keyCount < 0) keyCount = 0;
  1440. textHasChange = true;
  1441. }
  1442. else if (IsKeyDown(KEY_BACKSPACE))
  1443. {
  1444. if ((framesCounter > TEXTEDIT_CURSOR_BLINK_FRAMES) && (framesCounter%2) == 0) keyCount--;
  1445. text[keyCount] = '\0';
  1446. if (keyCount < 0) keyCount = 0;
  1447. textHasChange = true;
  1448. }
  1449. }
  1450. // Introduce automatic new line if necessary
  1451. if (textHasChange)
  1452. {
  1453. textHasChange = false;
  1454. char *lastLine = strrchr(text, '\n');
  1455. int maxWidth = (bounds.width - (GuiGetStyle(TEXTBOX, INNER_PADDING)*2));
  1456. if (lastLine != NULL)
  1457. {
  1458. if (GetTextWidth(lastLine) > maxWidth)
  1459. {
  1460. int firstIndex = lastLine - text;
  1461. char *lastSpace = strrchr(lastLine, 32);
  1462. if (lastSpace != NULL)
  1463. {
  1464. int secondIndex = lastSpace - lastLine;
  1465. text[firstIndex + secondIndex] = '\n';
  1466. }
  1467. else
  1468. {
  1469. int len = (lastLine != NULL)? strlen(lastLine) : 0;
  1470. char lastChar = lastLine[len - 1];
  1471. lastLine[len - 1] = '\n';
  1472. lastLine[len] = lastChar;
  1473. lastLine[len + 1] = '\0';
  1474. keyCount++;
  1475. }
  1476. }
  1477. }
  1478. else
  1479. {
  1480. if (GetTextWidth(text) > maxWidth)
  1481. {
  1482. char *lastSpace = strrchr(text, 32);
  1483. if (lastSpace != NULL)
  1484. {
  1485. int index = lastSpace - text;
  1486. text[index] = '\n';
  1487. }
  1488. else
  1489. {
  1490. int len = (lastLine != NULL)? strlen(lastLine) : 0;
  1491. char lastChar = lastLine[len - 1];
  1492. lastLine[len - 1] = '\n';
  1493. lastLine[len] = lastChar;
  1494. lastLine[len + 1] = '\0';
  1495. keyCount++;
  1496. }
  1497. }
  1498. }
  1499. }
  1500. // Counting how many new lines
  1501. for (int i = 0; i < keyCount; i++)
  1502. {
  1503. if (text[i] == '\n') currentLine++;
  1504. }
  1505. }
  1506. // Changing edit mode
  1507. if (!editMode)
  1508. {
  1509. if (CheckCollisionPointRec(mousePoint, bounds))
  1510. {
  1511. state = GUI_STATE_FOCUSED;
  1512. if (IsMouseButtonPressed(0)) pressed = true;
  1513. }
  1514. }
  1515. else
  1516. {
  1517. if (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(0)) pressed = true;
  1518. }
  1519. if (pressed) framesCounter = 0;
  1520. }
  1521. //--------------------------------------------------------------------
  1522. // Draw control
  1523. //--------------------------------------------------------------------
  1524. DrawRectangleLinesEx(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha));
  1525. if (state == GUI_STATE_PRESSED)
  1526. {
  1527. DrawRectangle(bounds.x + GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.height - 2*GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_FOCUSED)), guiAlpha));
  1528. if (editMode)
  1529. {
  1530. if ((framesCounter/20)%2 == 0)
  1531. {
  1532. char *line = NULL;
  1533. if (currentLine > 0) line = strrchr(text, '\n');
  1534. else line = text;
  1535. // Draw text cursor
  1536. DrawRectangle(bounds.x + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(TEXTBOX, INNER_PADDING) + GetTextWidth(line),
  1537. bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(TEXTBOX, INNER_PADDING)/2 + ((GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(TEXTBOX, INNER_PADDING))*currentLine),
  1538. 1, GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(TEXTBOX, INNER_PADDING), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_FOCUSED)), guiAlpha));
  1539. }
  1540. // Draw characters counter
  1541. //GuiDrawText(numChars, (Vector2){ bounds.x + bounds.width - GetTextWidth(numChars) - GuiGetStyle(TEXTBOX, INNER_PADDING), bounds.y + bounds.height - GuiGetStyle(DEFAULT, TEXT_SIZE) - GuiGetStyle(TEXTBOX, INNER_PADDING) }, Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT_COLOR_PRESSED)), guiAlpha/2));
  1542. }
  1543. }
  1544. else if (state == GUI_STATE_DISABLED)
  1545. {
  1546. DrawRectangle(bounds.x + GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(TEXTBOX, BORDER_WIDTH), bounds.height - 2*GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_DISABLED)), guiAlpha));
  1547. }
  1548. GuiDrawText(text, GetTextBounds(TEXTBOX, bounds), GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha));
  1549. //--------------------------------------------------------------------
  1550. return pressed;
  1551. }
  1552. // Slider control with pro parameters
  1553. // NOTE: Other GuiSlider*() controls use this one
  1554. RAYGUIDEF float GuiSliderPro(Rectangle bounds, const char *text, float value, float minValue, float maxValue, int sliderWidth, bool showValue)
  1555. {
  1556. GuiControlState state = guiState;
  1557. int sliderValue = (int)(((value - minValue)/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH)));
  1558. Rectangle slider = { bounds.x, bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, INNER_PADDING),
  1559. 0, bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, INNER_PADDING) };
  1560. if (sliderWidth > 0) // Slider
  1561. {
  1562. slider.x += (sliderValue - sliderWidth/2);
  1563. slider.width = sliderWidth;
  1564. }
  1565. else if (sliderWidth == 0) // SliderBar
  1566. {
  1567. slider.x += GuiGetStyle(SLIDER, BORDER_WIDTH);
  1568. slider.width = sliderValue;
  1569. }
  1570. Rectangle textBounds = { 0 };
  1571. textBounds.width = GetTextWidth(text); // TODO: Consider text icon
  1572. textBounds.height = GuiGetStyle(DEFAULT, TEXT_SIZE);
  1573. textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SLIDER, TEXT_PADDING);
  1574. textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
  1575. // Update control
  1576. //--------------------------------------------------------------------
  1577. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  1578. {
  1579. Vector2 mousePoint = GetMousePosition();
  1580. if (CheckCollisionPointRec(mousePoint, bounds))
  1581. {
  1582. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
  1583. {
  1584. state = GUI_STATE_PRESSED;
  1585. // Get equivalent value and slider position from mousePoint.x
  1586. value = ((maxValue - minValue)*(mousePoint.x - (float)(bounds.x + sliderWidth/2)))/(float)(bounds.width - sliderWidth) + minValue;
  1587. if (sliderWidth > 0) slider.x = mousePoint.x - slider.width/2; // Slider
  1588. else if (sliderWidth == 0) slider.width = sliderValue; // SliderBar
  1589. }
  1590. else state = GUI_STATE_FOCUSED;
  1591. }
  1592. if (value > maxValue) value = maxValue;
  1593. else if (value < minValue) value = minValue;
  1594. }
  1595. // Bar limits check
  1596. if (sliderWidth > 0) // Slider
  1597. {
  1598. if (slider.x <= (bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH))) slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH);
  1599. else if ((slider.x + slider.width) >= (bounds.x + bounds.width)) slider.x = bounds.x + bounds.width - slider.width - GuiGetStyle(SLIDER, BORDER_WIDTH);
  1600. }
  1601. else if (sliderWidth == 0) // SliderBar
  1602. {
  1603. if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH);
  1604. }
  1605. //--------------------------------------------------------------------
  1606. // Draw control
  1607. //--------------------------------------------------------------------
  1608. DrawRectangleLinesEx(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(SLIDER, BORDER + (state*3))), guiAlpha));
  1609. DrawRectangle(bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH), bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH), bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(SLIDER, (state != GUI_STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)), guiAlpha));
  1610. DrawRectangleRec(slider, Fade(GetColor(GuiGetStyle(SLIDER, (state == GUI_STATE_NORMAL)? BASE_COLOR_PRESSED : (BASE + (state*3)))), guiAlpha));
  1611. GuiDrawText(text, textBounds, GuiGetStyle(SLIDER, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))), guiAlpha));
  1612. // TODO: Review showValue parameter, really ugly...
  1613. if (showValue) GuiDrawText(TextFormat("%.02f", value), (Rectangle){ bounds.x + bounds.width + GuiGetStyle(SLIDER, TEXT_PADDING),
  1614. bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2 + GuiGetStyle(SLIDER, INNER_PADDING),
  1615. GuiGetStyle(DEFAULT, TEXT_SIZE), GuiGetStyle(DEFAULT, TEXT_SIZE) }, GUI_TEXT_ALIGN_LEFT,
  1616. Fade(GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))), guiAlpha));
  1617. //--------------------------------------------------------------------
  1618. return value;
  1619. }
  1620. // Slider control extended, returns selected value and has text
  1621. RAYGUIDEF float GuiSlider(Rectangle bounds, const char *text, float value, float minValue, float maxValue, bool showValue)
  1622. {
  1623. return GuiSliderPro(bounds, text, value, minValue, maxValue, GuiGetStyle(SLIDER, SLIDER_WIDTH), showValue);
  1624. }
  1625. // Slider Bar control extended, returns selected value
  1626. RAYGUIDEF float GuiSliderBar(Rectangle bounds, const char *text, float value, float minValue, float maxValue, bool showValue)
  1627. {
  1628. return GuiSliderPro(bounds, text, value, minValue, maxValue, 0, showValue);
  1629. }
  1630. // Progress Bar control extended, shows current progress value
  1631. RAYGUIDEF float GuiProgressBar(Rectangle bounds, const char *text, float value, float minValue, float maxValue, bool showValue)
  1632. {
  1633. GuiControlState state = guiState;
  1634. Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH),
  1635. bounds.y + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) + GuiGetStyle(PROGRESSBAR, INNER_PADDING), 0,
  1636. bounds.height - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - 2*GuiGetStyle(PROGRESSBAR, INNER_PADDING) };
  1637. // Update control
  1638. //--------------------------------------------------------------------
  1639. if (state != GUI_STATE_DISABLED) progress.width = (int)(value/(maxValue - minValue)*(float)(bounds.width - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)));
  1640. //--------------------------------------------------------------------
  1641. // Draw control
  1642. //--------------------------------------------------------------------
  1643. if (showValue) GuiLabel((Rectangle){ bounds.x + bounds.width + GuiGetStyle(SLIDER, TEXT_PADDING), bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2 + GuiGetStyle(SLIDER, INNER_PADDING), GuiGetStyle(DEFAULT, TEXT_SIZE), GuiGetStyle(DEFAULT, TEXT_SIZE) }, TextFormat("%.02f", value));
  1644. DrawRectangleLinesEx(bounds, GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(PROGRESSBAR, (state != GUI_STATE_DISABLED)? BORDER_COLOR_NORMAL : BORDER_COLOR_DISABLED)), guiAlpha));
  1645. DrawRectangle(bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)), guiAlpha));
  1646. DrawRectangleRec(progress, Fade(GetColor(GuiGetStyle(PROGRESSBAR, (state != GUI_STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)), guiAlpha));
  1647. //--------------------------------------------------------------------
  1648. return value;
  1649. }
  1650. // Status Bar control
  1651. RAYGUIDEF void GuiStatusBar(Rectangle bounds, const char *text)
  1652. {
  1653. GuiControlState state = guiState;
  1654. // Draw control
  1655. //--------------------------------------------------------------------
  1656. DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(DEFAULT, (state != GUI_STATE_DISABLED)? BORDER_COLOR_NORMAL : BORDER_COLOR_DISABLED)), guiAlpha));
  1657. DrawRectangleRec((Rectangle){ bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - GuiGetStyle(DEFAULT, BORDER_WIDTH)*2, bounds.height - GuiGetStyle(DEFAULT, BORDER_WIDTH)*2 }, Fade(GetColor(GuiGetStyle(DEFAULT, (state != GUI_STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)), guiAlpha));
  1658. GuiDrawText(text, GetTextBounds(DEFAULT, bounds), GuiGetStyle(DEFAULT, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(DEFAULT, (state != GUI_STATE_DISABLED)? TEXT_COLOR_NORMAL : TEXT_COLOR_DISABLED)), guiAlpha));
  1659. //--------------------------------------------------------------------
  1660. }
  1661. // Dummy rectangle control, intended for placeholding
  1662. RAYGUIDEF void GuiDummyRec(Rectangle bounds, const char *text)
  1663. {
  1664. GuiControlState state = guiState;
  1665. // Update control
  1666. //--------------------------------------------------------------------
  1667. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  1668. {
  1669. Vector2 mousePoint = GetMousePosition();
  1670. // Check button state
  1671. if (CheckCollisionPointRec(mousePoint, bounds))
  1672. {
  1673. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
  1674. else state = GUI_STATE_FOCUSED;
  1675. }
  1676. }
  1677. //--------------------------------------------------------------------
  1678. // Draw control
  1679. //--------------------------------------------------------------------
  1680. DrawRectangleRec(bounds, Fade(GetColor(GuiGetStyle(DEFAULT, (state != GUI_STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)), guiAlpha));
  1681. GuiDrawText(text, GetTextBounds(DEFAULT, bounds), GUI_TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(BUTTON, (state != GUI_STATE_DISABLED)? TEXT_COLOR_NORMAL : TEXT_COLOR_DISABLED)), guiAlpha));
  1682. //------------------------------------------------------------------
  1683. }
  1684. // Scroll Bar control
  1685. RAYGUIDEF int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue)
  1686. {
  1687. GuiControlState state = guiState;
  1688. // Is the scrollbar horizontal or vertical?
  1689. bool isVertical = (bounds.width > bounds.height)? false : true;
  1690. // The size (width or height depending on scrollbar type) of the spinner buttons
  1691. const int spinnerSize = GuiGetStyle(SCROLLBAR, SHOW_SPINNER_BUTTONS)? (isVertical? bounds.width - 2 * GuiGetStyle(SCROLLBAR, BORDER_WIDTH) : bounds.height - 2 * GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0;
  1692. // Spinner buttons [<] [>] [∧] [∨]
  1693. Rectangle spinnerUpLeft, spinnerDownRight;
  1694. // Actual area of the scrollbar excluding the spinner buttons
  1695. Rectangle scrollbar; // ------------
  1696. // Slider bar that moves --[///]-----
  1697. Rectangle slider;
  1698. // Normalize value
  1699. if (value > maxValue) value = maxValue;
  1700. if (value < minValue) value = minValue;
  1701. const int range = maxValue - minValue;
  1702. int sliderSize = GuiGetStyle(SCROLLBAR, SLIDER_SIZE);
  1703. // Calculate rectangles for all of the components
  1704. spinnerUpLeft = (Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), spinnerSize, spinnerSize };
  1705. if (isVertical)
  1706. {
  1707. spinnerDownRight = (Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.y + bounds.height - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), spinnerSize, spinnerSize};
  1708. scrollbar = (Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, INNER_PADDING), spinnerUpLeft.y + spinnerUpLeft.height, bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, INNER_PADDING)), bounds.height - spinnerUpLeft.height - spinnerDownRight.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) };
  1709. sliderSize = (sliderSize >= scrollbar.height)? (scrollbar.height - 2) : sliderSize; // Make sure the slider won't get outside of the scrollbar
  1710. slider = (Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SLIDER_PADDING),scrollbar.y + (int)(((float)(value - minValue)/range)*(scrollbar.height - sliderSize)),bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SLIDER_PADDING)), sliderSize };
  1711. }
  1712. else
  1713. {
  1714. spinnerDownRight = (Rectangle){ bounds.x + bounds.width - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), spinnerSize, spinnerSize};
  1715. scrollbar = (Rectangle){ spinnerUpLeft.x + spinnerUpLeft.width, bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, INNER_PADDING), bounds.width - spinnerUpLeft.width - spinnerDownRight.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, INNER_PADDING))};
  1716. sliderSize = (sliderSize >= scrollbar.width)? (scrollbar.width - 2) : sliderSize; // Make sure the slider won't get outside of the scrollbar
  1717. slider = (Rectangle){ scrollbar.x + (int)(((float)(value - minValue)/range)*(scrollbar.width - sliderSize)), bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SLIDER_PADDING), sliderSize, bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SLIDER_PADDING)) };
  1718. }
  1719. // Update control
  1720. //--------------------------------------------------------------------
  1721. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  1722. {
  1723. Vector2 mousePoint = GetMousePosition();
  1724. if (CheckCollisionPointRec(mousePoint, bounds))
  1725. {
  1726. state = GUI_STATE_FOCUSED;
  1727. // Handle mouse wheel
  1728. int wheel = GetMouseWheelMove();
  1729. if (wheel != 0) value += wheel;
  1730. if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
  1731. {
  1732. if (CheckCollisionPointRec(mousePoint, spinnerUpLeft)) value -= range/GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
  1733. else if (CheckCollisionPointRec(mousePoint, spinnerDownRight)) value += range/GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
  1734. state = GUI_STATE_PRESSED;
  1735. }
  1736. else if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
  1737. {
  1738. if (!isVertical)
  1739. {
  1740. Rectangle scrollArea = { spinnerUpLeft.x + spinnerUpLeft.width, spinnerUpLeft.y, scrollbar.width, bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)};
  1741. if (CheckCollisionPointRec(mousePoint, scrollArea)) value = ((float)(mousePoint.x - scrollArea.x - slider.width/2)*range)/(scrollArea.width - slider.width) + minValue;
  1742. }
  1743. else
  1744. {
  1745. Rectangle scrollArea = { spinnerUpLeft.x, spinnerUpLeft.y+spinnerUpLeft.height, bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), scrollbar.height};
  1746. if (CheckCollisionPointRec(mousePoint, scrollArea)) value = ((float)(mousePoint.y - scrollArea.y - slider.height/2)*range)/(scrollArea.height - slider.height) + minValue;
  1747. }
  1748. }
  1749. }
  1750. // Normalize value
  1751. if (value > maxValue) value = maxValue;
  1752. if (value < minValue) value = minValue;
  1753. }
  1754. //--------------------------------------------------------------------
  1755. // Draw control
  1756. //--------------------------------------------------------------------
  1757. DrawRectangleRec(bounds, Fade(GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED)), guiAlpha)); // Draw the background
  1758. DrawRectangleRec(scrollbar, Fade(GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL)), guiAlpha)); // Draw the scrollbar active area background
  1759. DrawRectangleLinesEx(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), guiAlpha));
  1760. DrawRectangleRec(slider, Fade(GetColor(GuiGetStyle(SLIDER, BORDER + state*3)), guiAlpha)); // Draw the slider bar
  1761. // Draw arrows using lines
  1762. const int padding = (spinnerSize - GuiGetStyle(SCROLLBAR, ARROWS_SIZE))/2;
  1763. const Vector2 lineCoords[] =
  1764. {
  1765. //coordinates for < 0,1,2
  1766. {spinnerUpLeft.x + padding, spinnerUpLeft.y + spinnerSize/2},
  1767. {spinnerUpLeft.x + spinnerSize - padding, spinnerUpLeft.y + padding },
  1768. {spinnerUpLeft.x + spinnerSize - padding, spinnerUpLeft.y + spinnerSize - padding},
  1769. //coordinates for > 3,4,5
  1770. {spinnerDownRight.x + padding, spinnerDownRight.y + padding},
  1771. {spinnerDownRight.x + spinnerSize - padding, spinnerDownRight.y + spinnerSize/2 },
  1772. {spinnerDownRight.x + padding, spinnerDownRight.y + spinnerSize - padding},
  1773. //coordinates for ∧ 6,7,8
  1774. {spinnerUpLeft.x + spinnerSize/2, spinnerUpLeft.y + padding},
  1775. {spinnerUpLeft.x + padding, spinnerUpLeft.y + spinnerSize - padding},
  1776. {spinnerUpLeft.x + spinnerSize - padding, spinnerUpLeft.y + spinnerSize - padding},
  1777. //coordinates for ∨ 9,10,11
  1778. {spinnerDownRight.x + padding, spinnerDownRight.y + padding},
  1779. {spinnerDownRight.x + spinnerSize/2, spinnerDownRight.y + spinnerSize - padding },
  1780. {spinnerDownRight.x + spinnerSize - padding, spinnerDownRight.y + padding}
  1781. };
  1782. Color lineColor = Fade(GetColor(GuiGetStyle(BUTTON, TEXT + state*3)), guiAlpha);
  1783. if (GuiGetStyle(SCROLLBAR, SHOW_SPINNER_BUTTONS))
  1784. {
  1785. if (isVertical)
  1786. {
  1787. // Draw ∧
  1788. DrawLineEx(lineCoords[6], lineCoords[7], 3.0f, lineColor);
  1789. DrawLineEx(lineCoords[6], lineCoords[8], 3.0f, lineColor);
  1790. // Draw ∨
  1791. DrawLineEx(lineCoords[9], lineCoords[10], 3.0f, lineColor);
  1792. DrawLineEx(lineCoords[11], lineCoords[10], 3.0f, lineColor);
  1793. }
  1794. else
  1795. {
  1796. // Draw <
  1797. DrawLineEx(lineCoords[0], lineCoords[1], 3.0f, lineColor);
  1798. DrawLineEx(lineCoords[0], lineCoords[2], 3.0f, lineColor);
  1799. // Draw >
  1800. DrawLineEx(lineCoords[3], lineCoords[4], 3.0f, lineColor);
  1801. DrawLineEx(lineCoords[5], lineCoords[4], 3.0f, lineColor);
  1802. }
  1803. }
  1804. //--------------------------------------------------------------------
  1805. return value;
  1806. }
  1807. // List Element control, returns element state
  1808. static bool GuiListElement(Rectangle bounds, const char *text, bool active, bool editMode)
  1809. {
  1810. GuiControlState state = guiState;
  1811. if (!guiLocked && editMode) state = GUI_STATE_NORMAL;
  1812. // Update control
  1813. //--------------------------------------------------------------------
  1814. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  1815. {
  1816. Vector2 mousePoint = GetMousePosition();
  1817. if (CheckCollisionPointRec(mousePoint, bounds))
  1818. {
  1819. if (!active)
  1820. {
  1821. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
  1822. else state = GUI_STATE_FOCUSED;
  1823. }
  1824. if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) active = !active;
  1825. }
  1826. }
  1827. //--------------------------------------------------------------------
  1828. // Draw control
  1829. //--------------------------------------------------------------------
  1830. // Draw element rectangle
  1831. switch (state)
  1832. {
  1833. case GUI_STATE_NORMAL:
  1834. {
  1835. if (active)
  1836. {
  1837. DrawRectangle(bounds.x, bounds.y, bounds.width, bounds.height, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)), guiAlpha));
  1838. DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), guiAlpha));
  1839. }
  1840. } break;
  1841. case GUI_STATE_FOCUSED:
  1842. {
  1843. DrawRectangle(bounds.x, bounds.y, bounds.width, bounds.height, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED)), guiAlpha));
  1844. DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), guiAlpha));
  1845. } break;
  1846. case GUI_STATE_PRESSED:
  1847. {
  1848. DrawRectangle(bounds.x, bounds.y, bounds.width, bounds.height, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)), guiAlpha));
  1849. DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), guiAlpha));
  1850. } break;
  1851. case GUI_STATE_DISABLED:
  1852. {
  1853. if (active)
  1854. {
  1855. DrawRectangle(bounds.x, bounds.y, bounds.width, bounds.height, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED)), guiAlpha));
  1856. DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_NORMAL)), guiAlpha));
  1857. }
  1858. } break;
  1859. default: break;
  1860. }
  1861. // Draw text depending on state
  1862. if (state == GUI_STATE_NORMAL) GuiDrawText(text, GetTextBounds(DEFAULT, bounds), GuiGetStyle(DEFAULT, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, active? TEXT_COLOR_PRESSED : TEXT_COLOR_NORMAL)), guiAlpha));
  1863. else if (state == GUI_STATE_DISABLED) GuiDrawText(text, GetTextBounds(DEFAULT, bounds), GuiGetStyle(DEFAULT, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, active? TEXT_COLOR_NORMAL : TEXT_COLOR_DISABLED)), guiAlpha));
  1864. else GuiDrawText(text, GetTextBounds(DEFAULT, bounds), GuiGetStyle(DEFAULT, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT + state*3)), guiAlpha));
  1865. //--------------------------------------------------------------------
  1866. return active;
  1867. }
  1868. // List View control
  1869. RAYGUIDEF bool GuiListView(Rectangle bounds, const char *text, int *active, int *scrollIndex, bool editMode)
  1870. {
  1871. bool result = 0;
  1872. int count = 0;
  1873. const char **textList = GuiTextSplit(text, &count, NULL);
  1874. result = GuiListViewEx(bounds, textList, count, NULL, active, NULL, scrollIndex, editMode);
  1875. return result;
  1876. }
  1877. // List View control extended parameters
  1878. // NOTE: Elements could be disabled individually and focused element could be obtained:
  1879. // int *enabled defines an array with enabled elements inside the list
  1880. // int *focus returns focused element (may be not pressed)
  1881. RAYGUIDEF bool GuiListViewEx(Rectangle bounds, const char **text, int count, int *enabled, int *active, int *focus, int *scrollIndex, bool editMode)
  1882. {
  1883. GuiControlState state = guiState;
  1884. bool pressed = false;
  1885. int focusElement = -1;
  1886. int startIndex = (scrollIndex == NULL)? 0 : *scrollIndex;
  1887. bool useScrollBar = true;
  1888. bool pressedKey = false;
  1889. int visibleElements = bounds.height/(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING));
  1890. if ((startIndex < 0) || (startIndex > count - visibleElements)) startIndex = 0;
  1891. int endIndex = startIndex + visibleElements;
  1892. int auxActive = *active;
  1893. float barHeight = bounds.height;
  1894. float minBarHeight = 10;
  1895. // Update control
  1896. //--------------------------------------------------------------------
  1897. // All the elements fit inside ListView and dont need scrollbar.
  1898. if (visibleElements >= count)
  1899. {
  1900. useScrollBar = false;
  1901. startIndex = 0;
  1902. endIndex = count;
  1903. }
  1904. // Calculate position X and width to draw each element.
  1905. int posX = bounds.x + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING);
  1906. int elementWidth = bounds.width - 2*GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) - GuiGetStyle(DEFAULT, BORDER_WIDTH);
  1907. if (useScrollBar)
  1908. {
  1909. posX = GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE? posX + GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : posX;
  1910. elementWidth = bounds.width - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) - 2*GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) - GuiGetStyle(DEFAULT, BORDER_WIDTH);
  1911. }
  1912. Rectangle scrollBarRect = { bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) };
  1913. if (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_RIGHT_SIDE) scrollBarRect.x = posX + elementWidth + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING);
  1914. // Area without the scrollbar
  1915. Rectangle viewArea = { posX, bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), elementWidth, bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) };
  1916. if ((state != GUI_STATE_DISABLED) && !guiLocked) // && !guiLocked
  1917. {
  1918. Vector2 mousePoint = GetMousePosition();
  1919. if (editMode)
  1920. {
  1921. state = GUI_STATE_PRESSED;
  1922. // Change active with keys
  1923. if (IsKeyPressed(KEY_UP))
  1924. {
  1925. if (auxActive > 0)
  1926. {
  1927. auxActive--;
  1928. if ((useScrollBar) && (auxActive < startIndex)) startIndex--;
  1929. }
  1930. pressedKey = true;
  1931. }
  1932. else if (IsKeyPressed(KEY_DOWN))
  1933. {
  1934. if (auxActive < count - 1)
  1935. {
  1936. auxActive++;
  1937. if ((useScrollBar) && (auxActive >= endIndex)) startIndex++;
  1938. }
  1939. pressedKey = true;
  1940. }
  1941. if (useScrollBar)
  1942. {
  1943. endIndex = startIndex + visibleElements;
  1944. if (CheckCollisionPointRec(mousePoint, viewArea))
  1945. {
  1946. int wheel = GetMouseWheelMove();
  1947. if (wheel < 0 && endIndex < count) startIndex -= wheel;
  1948. else if (wheel > 0 && startIndex > 0) startIndex -= wheel;
  1949. }
  1950. if (pressedKey)
  1951. {
  1952. pressedKey = false;
  1953. if ((auxActive < startIndex) || (auxActive >= endIndex)) startIndex = auxActive;
  1954. }
  1955. if (startIndex < 0) startIndex = 0;
  1956. else if (startIndex > (count - (endIndex - startIndex)))
  1957. {
  1958. startIndex = count - (endIndex - startIndex);
  1959. }
  1960. endIndex = startIndex + visibleElements;
  1961. if (endIndex > count) endIndex = count;
  1962. }
  1963. }
  1964. if (!editMode)
  1965. {
  1966. if (CheckCollisionPointRec(mousePoint, viewArea))
  1967. {
  1968. state = GUI_STATE_FOCUSED;
  1969. if (IsMouseButtonPressed(0)) pressed = true;
  1970. startIndex -= GetMouseWheelMove();
  1971. if (startIndex < 0) startIndex = 0;
  1972. else if (startIndex > (count - (endIndex - startIndex)))
  1973. {
  1974. startIndex = count - (endIndex - startIndex);
  1975. }
  1976. pressed = true;
  1977. }
  1978. }
  1979. else
  1980. {
  1981. if (!CheckCollisionPointRec(mousePoint, viewArea))
  1982. {
  1983. if (IsMouseButtonPressed(0) || (GetMouseWheelMove() != 0)) pressed = true;
  1984. }
  1985. }
  1986. // Get focused element
  1987. for (int i = startIndex; i < endIndex; i++)
  1988. {
  1989. if (CheckCollisionPointRec(mousePoint, (Rectangle){ posX, bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), elementWidth, GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }))
  1990. {
  1991. focusElement = i;
  1992. }
  1993. }
  1994. }
  1995. const int slider = GuiGetStyle(SCROLLBAR, SLIDER_SIZE); // Save default slider size
  1996. // Calculate percentage of visible elements and apply same percentage to scrollbar
  1997. if (useScrollBar)
  1998. {
  1999. float percentVisible = (endIndex - startIndex)*100/count;
  2000. barHeight *= percentVisible/100;
  2001. if (barHeight < minBarHeight) barHeight = minBarHeight;
  2002. else if (barHeight > bounds.height) barHeight = bounds.height;
  2003. GuiSetStyle(SCROLLBAR, SLIDER_SIZE, barHeight); // Change slider size
  2004. }
  2005. //--------------------------------------------------------------------
  2006. // Draw control
  2007. //--------------------------------------------------------------------
  2008. DrawRectangleRec(bounds, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background
  2009. // Draw scrollBar
  2010. if (useScrollBar)
  2011. {
  2012. const int scrollSpeed = GuiGetStyle(SCROLLBAR, SCROLL_SPEED); // Save default scroll speed
  2013. GuiSetStyle(SCROLLBAR, SCROLL_SPEED, count - visibleElements); // Hack to make the spinner buttons work
  2014. int index = scrollIndex != NULL? *scrollIndex : startIndex;
  2015. index = GuiScrollBar(scrollBarRect, index, 0, count - visibleElements);
  2016. GuiSetStyle(SCROLLBAR, SCROLL_SPEED, scrollSpeed); // Reset scroll speed to default
  2017. GuiSetStyle(SCROLLBAR, SLIDER_SIZE, slider); // Reset slider size to default
  2018. // FIXME: Quick hack to make this thing work, think of a better way
  2019. if (scrollIndex != NULL && CheckCollisionPointRec(GetMousePosition(), scrollBarRect) && IsMouseButtonDown(MOUSE_LEFT_BUTTON))
  2020. {
  2021. startIndex = index;
  2022. if (startIndex < 0) startIndex = 0;
  2023. if (startIndex > (count - (endIndex - startIndex)))
  2024. {
  2025. startIndex = count - (endIndex - startIndex);
  2026. }
  2027. endIndex = startIndex + visibleElements;
  2028. if (endIndex > count) endIndex = count;
  2029. }
  2030. }
  2031. DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), guiAlpha));
  2032. // Draw ListView states
  2033. switch (state)
  2034. {
  2035. case GUI_STATE_NORMAL:
  2036. {
  2037. for (int i = startIndex; i < endIndex; i++)
  2038. {
  2039. if ((enabled != NULL) && (enabled[i] == 0))
  2040. {
  2041. GuiDisable();
  2042. GuiListElement((Rectangle){ posX, bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), elementWidth, GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], false, false);
  2043. GuiEnable();
  2044. }
  2045. else if (i == auxActive)
  2046. {
  2047. GuiDisable();
  2048. GuiListElement((Rectangle){ posX, bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), elementWidth, GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], true, false);
  2049. GuiEnable();
  2050. }
  2051. else GuiListElement((Rectangle){ posX, bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), elementWidth, GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], false, false);
  2052. }
  2053. } break;
  2054. case GUI_STATE_FOCUSED:
  2055. {
  2056. for (int i = startIndex; i < endIndex; i++)
  2057. {
  2058. if ((enabled != NULL) && (enabled[i] == 0))
  2059. {
  2060. GuiDisable();
  2061. GuiListElement((Rectangle){ posX, bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), elementWidth, GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], false, false);
  2062. GuiEnable();
  2063. }
  2064. else if (i == auxActive) GuiListElement((Rectangle){ posX, bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), elementWidth, GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], true, false);
  2065. else GuiListElement((Rectangle){ posX, bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), elementWidth, GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], false, false);
  2066. }
  2067. } break;
  2068. case GUI_STATE_PRESSED:
  2069. {
  2070. for (int i = startIndex; i < endIndex; i++)
  2071. {
  2072. if ((enabled != NULL) && (enabled[i] == 0))
  2073. {
  2074. GuiDisable();
  2075. GuiListElement((Rectangle){ posX, bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), elementWidth, GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], false, false);
  2076. GuiEnable();
  2077. }
  2078. else if ((i == auxActive) && editMode)
  2079. {
  2080. if (GuiListElement((Rectangle){ posX, bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), elementWidth, GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], true, true) == false) auxActive = -1;
  2081. }
  2082. else
  2083. {
  2084. if (GuiListElement((Rectangle){ posX, bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), elementWidth, GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], false, true) == true) auxActive = i;
  2085. }
  2086. }
  2087. } break;
  2088. case GUI_STATE_DISABLED:
  2089. {
  2090. for (int i = startIndex; i < endIndex; i++)
  2091. {
  2092. if (i == auxActive) GuiListElement((Rectangle){ posX, bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), elementWidth, GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], true, false);
  2093. else GuiListElement((Rectangle){ posX, bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), elementWidth, GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], false, false);
  2094. }
  2095. } break;
  2096. default: break;
  2097. }
  2098. //--------------------------------------------------------------------
  2099. if (scrollIndex != NULL) *scrollIndex = startIndex;
  2100. if (focus != NULL) *focus = focusElement;
  2101. *active = auxActive;
  2102. return pressed;
  2103. }
  2104. // Color Panel control
  2105. RAYGUIDEF Color GuiColorPanel(Rectangle bounds, Color color)
  2106. {
  2107. GuiControlState state = guiState;
  2108. Vector2 pickerSelector = { 0 };
  2109. Vector3 vcolor = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
  2110. Vector3 hsv = ConvertRGBtoHSV(vcolor);
  2111. pickerSelector.x = bounds.x + (float)hsv.y*bounds.width; // HSV: Saturation
  2112. pickerSelector.y = bounds.y + (1.0f - (float)hsv.z)*bounds.height; // HSV: Value
  2113. Vector3 maxHue = { hsv.x, 1.0f, 1.0f };
  2114. Vector3 rgbHue = ConvertHSVtoRGB(maxHue);
  2115. Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x),
  2116. (unsigned char)(255.0f*rgbHue.y),
  2117. (unsigned char)(255.0f*rgbHue.z), 255 };
  2118. // Update control
  2119. //--------------------------------------------------------------------
  2120. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  2121. {
  2122. Vector2 mousePoint = GetMousePosition();
  2123. if (CheckCollisionPointRec(mousePoint, bounds))
  2124. {
  2125. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
  2126. {
  2127. state = GUI_STATE_PRESSED;
  2128. pickerSelector = mousePoint;
  2129. // Calculate color from picker
  2130. Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y };
  2131. colorPick.x /= (float)bounds.width; // Get normalized value on x
  2132. colorPick.y /= (float)bounds.height; // Get normalized value on y
  2133. hsv.y = colorPick.x;
  2134. hsv.z = 1.0f - colorPick.y;
  2135. Vector3 rgb = ConvertHSVtoRGB(hsv);
  2136. // NOTE: Vector3ToColor() only available on raylib 1.8.1
  2137. color = (Color){ (unsigned char)(255.0f*rgb.x),
  2138. (unsigned char)(255.0f*rgb.y),
  2139. (unsigned char)(255.0f*rgb.z),
  2140. (unsigned char)(255.0f*(float)color.a/255.0f) };
  2141. }
  2142. else state = GUI_STATE_FOCUSED;
  2143. }
  2144. }
  2145. //--------------------------------------------------------------------
  2146. // Draw control
  2147. //--------------------------------------------------------------------
  2148. if (state != GUI_STATE_DISABLED)
  2149. {
  2150. DrawRectangleGradientEx(bounds, Fade(WHITE, guiAlpha), Fade(WHITE, guiAlpha), Fade(maxHueCol, guiAlpha), Fade(maxHueCol, guiAlpha));
  2151. DrawRectangleGradientEx(bounds, Fade(BLACK, 0), Fade(BLACK, guiAlpha), Fade(BLACK, guiAlpha), Fade(BLACK, 0));
  2152. // Draw color picker: selector
  2153. DrawRectangle(pickerSelector.x - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, pickerSelector.y - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE), GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE), Fade(WHITE, guiAlpha));
  2154. }
  2155. else
  2156. {
  2157. DrawRectangleGradientEx(bounds, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(Fade(BLACK, 0.6f), guiAlpha), Fade(Fade(BLACK, 0.6f), guiAlpha), Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.6f), guiAlpha));
  2158. }
  2159. DrawRectangleLines(bounds.x, bounds.y, bounds.width, bounds.height, Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha));
  2160. //--------------------------------------------------------------------
  2161. return color;
  2162. }
  2163. // Color Bar Alpha control
  2164. // NOTE: Returns alpha value normalized [0..1]
  2165. RAYGUIDEF float GuiColorBarAlpha(Rectangle bounds, float alpha)
  2166. {
  2167. #define COLORBARALPHA_CHECKED_SIZE 10
  2168. GuiControlState state = guiState;
  2169. Rectangle selector = { bounds.x + alpha*bounds.width - GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING), bounds.y - GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING), GuiGetStyle(COLORPICKER, BAR_SELECTOR_HEIGHT), bounds.height + GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING)*2 };
  2170. // Update control
  2171. //--------------------------------------------------------------------
  2172. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  2173. {
  2174. Vector2 mousePoint = GetMousePosition();
  2175. if (CheckCollisionPointRec(mousePoint, bounds) ||
  2176. CheckCollisionPointRec(mousePoint, selector))
  2177. {
  2178. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
  2179. {
  2180. state = GUI_STATE_PRESSED;
  2181. selector.x = mousePoint.x - selector.width/2;
  2182. alpha = (mousePoint.x - bounds.x)/bounds.width;
  2183. if (alpha <= 0.0f) alpha = 0.0f;
  2184. if (alpha >= 1.0f) alpha = 1.0f;
  2185. //selector.x = bounds.x + (int)(((alpha - 0)/(100 - 0))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))) - selector.width/2;
  2186. }
  2187. else state = GUI_STATE_FOCUSED;
  2188. }
  2189. }
  2190. //--------------------------------------------------------------------
  2191. // Draw control
  2192. //--------------------------------------------------------------------
  2193. // Draw alpha bar: checked background
  2194. if (state != GUI_STATE_DISABLED)
  2195. {
  2196. for (int i = 0; i < bounds.width/COLORBARALPHA_CHECKED_SIZE; i++) DrawRectangle(bounds.x + COLORBARALPHA_CHECKED_SIZE*(i%((int)bounds.width/COLORBARALPHA_CHECKED_SIZE)), bounds.y, bounds.width/(bounds.width/COLORBARALPHA_CHECKED_SIZE), COLORBARALPHA_CHECKED_SIZE, (i%2)? Fade(Fade(GRAY, 0.4f), guiAlpha) : Fade(Fade(RAYWHITE, 0.4f), guiAlpha));
  2197. for (int i = 0; i < bounds.width/COLORBARALPHA_CHECKED_SIZE; i++) DrawRectangle(bounds.x + COLORBARALPHA_CHECKED_SIZE*(i%((int)bounds.width/COLORBARALPHA_CHECKED_SIZE)), bounds.y + COLORBARALPHA_CHECKED_SIZE, bounds.width/(bounds.width/COLORBARALPHA_CHECKED_SIZE), COLORBARALPHA_CHECKED_SIZE, (i%2)? Fade(Fade(RAYWHITE, 0.4f), guiAlpha) : Fade(Fade(GRAY, 0.4f), guiAlpha));
  2198. DrawRectangleGradientH(bounds.x, bounds.y, bounds.width, bounds.height, Fade((Color){ 255,255,255,0 }, guiAlpha), Fade((Color){ 0,0,0,255 }, guiAlpha));
  2199. }
  2200. else DrawRectangleGradientH(bounds.x, bounds.y, bounds.width, bounds.height, Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha));
  2201. DrawRectangleLines(bounds.x, bounds.y, bounds.width, bounds.height, Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha));
  2202. switch (state)
  2203. {
  2204. case GUI_STATE_NORMAL: DrawRectangle(selector.x , selector.y, selector.width, selector.height, Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_PRESSED)), guiAlpha)); break;
  2205. case GUI_STATE_FOCUSED: DrawRectangle(selector.x, selector.y, selector.width, selector.height, Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_FOCUSED)), guiAlpha)); break;
  2206. case GUI_STATE_PRESSED: DrawRectangle(selector.x, selector.y, selector.width, selector.height, Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_PRESSED)), guiAlpha)); break;
  2207. case GUI_STATE_DISABLED: DrawRectangleRec(selector, Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha)); break;
  2208. default: break;
  2209. }
  2210. //--------------------------------------------------------------------
  2211. return alpha;
  2212. }
  2213. // Color Bar Hue control
  2214. // NOTE: Returns hue value normalized [0..1]
  2215. RAYGUIDEF float GuiColorBarHue(Rectangle bounds, float hue)
  2216. {
  2217. GuiControlState state = guiState;
  2218. Rectangle selector = { bounds.x - GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING), bounds.y + hue/360.0f*bounds.height - GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING), bounds.width + GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING)*2, GuiGetStyle(COLORPICKER, BAR_SELECTOR_HEIGHT) };
  2219. // Update control
  2220. //--------------------------------------------------------------------
  2221. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  2222. {
  2223. Vector2 mousePoint = GetMousePosition();
  2224. if (CheckCollisionPointRec(mousePoint, bounds) ||
  2225. CheckCollisionPointRec(mousePoint, selector))
  2226. {
  2227. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
  2228. {
  2229. state = GUI_STATE_PRESSED;
  2230. selector.y = mousePoint.y - selector.height/2;
  2231. hue = (mousePoint.y - bounds.y)*360/bounds.height;
  2232. if (hue <= 0.0f) hue = 0.0f;
  2233. if (hue >= 359.0f) hue = 359.0f;
  2234. }
  2235. else state = GUI_STATE_FOCUSED;
  2236. /*if (IsKeyDown(KEY_UP))
  2237. {
  2238. hue -= 2.0f;
  2239. if (hue <= 0.0f) hue = 0.0f;
  2240. }
  2241. else if (IsKeyDown(KEY_DOWN))
  2242. {
  2243. hue += 2.0f;
  2244. if (hue >= 360.0f) hue = 360.0f;
  2245. }*/
  2246. }
  2247. }
  2248. //--------------------------------------------------------------------
  2249. // Draw control
  2250. //--------------------------------------------------------------------
  2251. if (state != GUI_STATE_DISABLED)
  2252. {
  2253. // Draw hue bar:color bars
  2254. DrawRectangleGradientV(bounds.x + GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING)/2, bounds.y + GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING)/2, bounds.width - GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING), (int)bounds.height/6, Fade((Color){ 255,0,0,255 }, guiAlpha), Fade((Color){ 255,255,0,255 }, guiAlpha));
  2255. DrawRectangleGradientV(bounds.x + GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING)/2, bounds.y + (int)bounds.height/6 + GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING)/2, bounds.width - GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING), (int)bounds.height/6, Fade((Color){ 255,255,0,255 }, guiAlpha), Fade((Color){ 0,255,0,255 }, guiAlpha));
  2256. DrawRectangleGradientV(bounds.x + GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING)/2, bounds.y + 2*((int)bounds.height/6) + GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING)/2, bounds.width - GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING), (int)bounds.height/6, Fade((Color){ 0,255,0,255 }, guiAlpha), Fade((Color){ 0,255,255,255 }, guiAlpha));
  2257. DrawRectangleGradientV(bounds.x + GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING)/2, bounds.y + 3*((int)bounds.height/6) + GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING)/2, bounds.width - GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING), (int)bounds.height/6, Fade((Color){ 0,255,255,255 }, guiAlpha), Fade((Color){ 0,0,255,255 }, guiAlpha));
  2258. DrawRectangleGradientV(bounds.x + GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING)/2, bounds.y + 4*((int)bounds.height/6) + GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING)/2, bounds.width - GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING), (int)bounds.height/6, Fade((Color){ 0,0,255,255 }, guiAlpha), Fade((Color){ 255,0,255,255 }, guiAlpha));
  2259. DrawRectangleGradientV(bounds.x + GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING)/2, bounds.y + 5*((int)bounds.height/6) + GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING)/2, bounds.width - GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING), (int)bounds.height/6 - GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING), Fade((Color){ 255,0,255,255 }, guiAlpha), Fade((Color){ 255,0,0,255 }, guiAlpha));
  2260. }
  2261. else
  2262. {
  2263. DrawRectangleGradientV(bounds.x, bounds.y, bounds.width, bounds.height, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha));
  2264. }
  2265. // Draw hue bar: selector
  2266. DrawRectangleLines(bounds.x, bounds.y, bounds.width, bounds.height, Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha));
  2267. DrawRectangle(selector.x, selector.y, selector.width, selector.height, Fade(GetColor(GuiGetStyle(COLORPICKER, (state == GUI_STATE_NORMAL)? BORDER_COLOR_PRESSED : (BORDER + state*3))), guiAlpha));
  2268. //--------------------------------------------------------------------
  2269. return hue;
  2270. }
  2271. // TODO: Color GuiColorBarSat() [WHITE->color]
  2272. // TODO: Color GuiColorBarValue() [BLACK->color], HSV / HSL
  2273. // TODO: float GuiColorBarLuminance() [BLACK->WHITE]
  2274. // Color Picker control
  2275. // NOTE: It's divided in multiple controls:
  2276. // Color GuiColorPanel() - Color select panel
  2277. // float GuiColorBarAlpha(Rectangle bounds, float alpha)
  2278. // float GuiColorBarHue(Rectangle bounds, float value)
  2279. // NOTE: bounds define GuiColorPanel() size
  2280. RAYGUIDEF Color GuiColorPicker(Rectangle bounds, Color color)
  2281. {
  2282. color = GuiColorPanel(bounds, color);
  2283. Rectangle boundsHue = { bounds.x + bounds.width + GuiGetStyle(COLORPICKER, BAR_PADDING), bounds.y, GuiGetStyle(COLORPICKER, BAR_WIDTH), bounds.height };
  2284. //Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) };
  2285. Vector3 hsv = ConvertRGBtoHSV((Vector3){ color.r/255.0f, color.g/255.0f, color.b/255.0f });
  2286. hsv.x = GuiColorBarHue(boundsHue, hsv.x);
  2287. //color.a = (unsigned char)(GuiColorBarAlpha(boundsAlpha, (float)color.a/255.0f)*255.0f);
  2288. Vector3 rgb = ConvertHSVtoRGB(hsv);
  2289. color = (Color){ (unsigned char)(rgb.x*255.0f), (unsigned char)(rgb.y*255.0f), (unsigned char)(rgb.z*255.0f), color.a };
  2290. return color;
  2291. }
  2292. // Message Box control
  2293. RAYGUIDEF int GuiMessageBox(Rectangle bounds, const char *windowTitle, const char *message, const char *buttons)
  2294. {
  2295. #define MESSAGEBOX_BUTTON_HEIGHT 24
  2296. #define MESSAGEBOX_BUTTON_PADDING 10
  2297. int clicked = -1; // Returns clicked button from buttons list, 0 refers to closed window button
  2298. int buttonsCount = 0;
  2299. const char **buttonsText = GuiTextSplit(buttons, &buttonsCount, NULL);
  2300. Vector2 textSize = MeasureTextEx(guiFont, message, GuiGetStyle(DEFAULT, TEXT_SIZE), 1);
  2301. Rectangle textBounds = { 0 };
  2302. textBounds.x = bounds.x + bounds.width/2 - textSize.x/2;
  2303. textBounds.y = bounds.y + WINDOW_STATUSBAR_HEIGHT + (bounds.height - WINDOW_STATUSBAR_HEIGHT)/4 - textSize.y/2;
  2304. textBounds.width = textSize.x;
  2305. textBounds.height = textSize.y;
  2306. Rectangle buttonBounds = { 0 };
  2307. buttonBounds.x = bounds.x + MESSAGEBOX_BUTTON_PADDING;
  2308. buttonBounds.y = bounds.y + bounds.height/2 + bounds.height/4 - MESSAGEBOX_BUTTON_HEIGHT/2;
  2309. buttonBounds.width = (bounds.width - MESSAGEBOX_BUTTON_PADDING*(buttonsCount + 1))/buttonsCount;
  2310. buttonBounds.height = MESSAGEBOX_BUTTON_HEIGHT;
  2311. // Draw control
  2312. //--------------------------------------------------------------------
  2313. if (GuiWindowBox(bounds, windowTitle)) clicked = 0;
  2314. int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT);
  2315. GuiSetStyle(LABEL, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
  2316. GuiLabel(textBounds, message);
  2317. GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment);
  2318. prevTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
  2319. GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
  2320. for (int i = 0; i < buttonsCount; i++)
  2321. {
  2322. if (GuiButton(buttonBounds, buttonsText[i])) clicked = i + 1;
  2323. buttonBounds.x += (buttonBounds.width + MESSAGEBOX_BUTTON_PADDING);
  2324. }
  2325. GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevTextAlignment);
  2326. //--------------------------------------------------------------------
  2327. return clicked;
  2328. }
  2329. // Grid control
  2330. // NOTE: Returns grid mouse-hover selected cell
  2331. // About drawing lines at subpixel spacing, simple put, not easy solution:
  2332. // https://stackoverflow.com/questions/4435450/2d-opengl-drawing-lines-that-dont-exactly-fit-pixel-raster
  2333. RAYGUIDEF Vector2 GuiGrid(Rectangle bounds, float spacing, int subdivs)
  2334. {
  2335. #define GRID_COLOR_ALPHA 0.15f // Grid lines alpha amount
  2336. GuiControlState state = guiState;
  2337. Vector2 mousePoint = GetMousePosition();
  2338. Vector2 currentCell = { -1, -1 };
  2339. int linesV = ((int)(bounds.width/spacing) + 1)*subdivs;
  2340. int linesH = ((int)(bounds.height/spacing) + 1)*subdivs;
  2341. // Update control
  2342. //--------------------------------------------------------------------
  2343. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  2344. {
  2345. if (CheckCollisionPointRec(mousePoint, bounds))
  2346. {
  2347. currentCell.x = (int)((mousePoint.x - bounds.x)/spacing);
  2348. currentCell.y = (int)((mousePoint.y - bounds.y)/spacing);
  2349. }
  2350. }
  2351. //--------------------------------------------------------------------
  2352. // Draw control
  2353. //--------------------------------------------------------------------
  2354. switch (state)
  2355. {
  2356. case GUI_STATE_NORMAL:
  2357. {
  2358. // Draw vertical grid lines
  2359. for (int i = 0; i < linesV; i++)
  2360. {
  2361. DrawRectangleRec((Rectangle){ bounds.x + spacing*i, bounds.y, 1, bounds.height }, ((i%subdivs) == 0)? Fade(GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)), GRID_COLOR_ALPHA*4) : Fade(GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)), GRID_COLOR_ALPHA));
  2362. }
  2363. // Draw horizontal grid lines
  2364. for (int i = 0; i < linesH; i++)
  2365. {
  2366. DrawRectangleRec((Rectangle){ bounds.x, bounds.y + spacing*i, bounds.width, 1 }, ((i%subdivs) == 0)? Fade(GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)), GRID_COLOR_ALPHA*4) : Fade(GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)), GRID_COLOR_ALPHA));
  2367. }
  2368. } break;
  2369. default: break;
  2370. }
  2371. return currentCell;
  2372. }
  2373. //----------------------------------------------------------------------------------
  2374. // Styles loading functions
  2375. //----------------------------------------------------------------------------------
  2376. // Load raygui style file (.rgs)
  2377. RAYGUIDEF void GuiLoadStyle(const char *fileName)
  2378. {
  2379. FILE *rgsFile = fopen(fileName, "rb");
  2380. if (rgsFile != NULL)
  2381. {
  2382. unsigned int value = 0;
  2383. char signature[5] = "";
  2384. short version = 0;
  2385. short numControls = 0;
  2386. short numPropsDefault = 0;
  2387. short numPropsExtended = 0;
  2388. fread(signature, 1, 4, rgsFile);
  2389. fread(&version, 1, sizeof(short), rgsFile);
  2390. fread(&numControls, 1, sizeof(short), rgsFile);
  2391. fread(&numPropsDefault, 1, sizeof(short), rgsFile);
  2392. fread(&numPropsExtended, 1, sizeof(short), rgsFile);
  2393. if ((signature[0] == 'r') &&
  2394. (signature[1] == 'G') &&
  2395. (signature[2] == 'S') &&
  2396. (signature[3] == ' '))
  2397. {
  2398. for (int i = 0; i < NUM_CONTROLS; i++)
  2399. {
  2400. for (int j = 0; j < NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED; j++)
  2401. {
  2402. fread(&value, 1, sizeof(unsigned int), rgsFile);
  2403. GuiSetStyle(i, j, value);
  2404. }
  2405. }
  2406. // Font loading is highly dependant on raylib API to load font data and image
  2407. // TODO: Find some mechanism to support it in standalone mode
  2408. #if !defined(RAYGUI_STANDALONE)
  2409. // Load custom font if available
  2410. int fontDataSize = 0;
  2411. fwrite(&fontDataSize, 1, sizeof(int), rgsFile);
  2412. if (fontDataSize > 0)
  2413. {
  2414. Font font = { 0 };
  2415. int fontType = 0; // 0-Normal, 1-SDF
  2416. Rectangle whiteRec = { 0 };
  2417. fread(&font.baseSize, 1, sizeof(int), rgsFile);
  2418. fread(&font.charsCount, 1, sizeof(int), rgsFile);
  2419. fread(&fontType, 1, sizeof(int), rgsFile);
  2420. // Load font white rectangle
  2421. fread(&whiteRec, 1, sizeof(Rectangle), rgsFile);
  2422. // Load font image parameters
  2423. int fontImageSize = 0;
  2424. fread(&fontImageSize, 1, sizeof(int), rgsFile);
  2425. if (fontImageSize > 0)
  2426. {
  2427. Image imFont = { 0 };
  2428. imFont.mipmaps = 1;
  2429. fread(&imFont.width, 1, sizeof(int), rgsFile);
  2430. fread(&imFont.height, 1, sizeof(int), rgsFile);
  2431. fread(&imFont.format, 1, sizeof(int), rgsFile);
  2432. fread(&imFont.data, 1, fontImageSize, rgsFile);
  2433. font.texture = LoadTextureFromImage(imFont);
  2434. UnloadImage(imFont);
  2435. }
  2436. // Load font chars data
  2437. font.chars = (CharInfo *)calloc(font.charsCount, sizeof(CharInfo));
  2438. for (int i = 0; i < font.charsCount; i++)
  2439. {
  2440. fread(&font.chars[i].rec, 1, sizeof(Rectangle), rgsFile);
  2441. fread(&font.chars[i].value, 1, sizeof(int), rgsFile);
  2442. fread(&font.chars[i].offsetX, 1, sizeof(int), rgsFile);
  2443. fread(&font.chars[i].offsetY, 1, sizeof(int), rgsFile);
  2444. fread(&font.chars[i].advanceX, 1, sizeof(int), rgsFile);
  2445. }
  2446. GuiFont(font);
  2447. // Set font texture source rectangle to be used as white texture to draw shapes
  2448. // NOTE: This way, all gui can be draw using a single draw call
  2449. if ((whiteRec.width != 0) && (whiteRec.height != 0)) SetShapesTexture(font.texture, whiteRec);
  2450. }
  2451. #endif
  2452. }
  2453. fclose(rgsFile);
  2454. }
  2455. }
  2456. // Load style from a palette values array
  2457. RAYGUIDEF void GuiLoadStyleProps(const int *props, int count)
  2458. {
  2459. int completeSets = count/(NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED);
  2460. int uncompleteSetProps = count%(NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED);
  2461. // Load style palette values from array (complete property sets)
  2462. for (int i = 0; i < completeSets; i++)
  2463. {
  2464. for (int j = 0; j < (NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED); i++) GuiSetStyle(i, j, props[i]);
  2465. }
  2466. // Load style palette values from array (uncomplete property set)
  2467. for (int k = 0; k < uncompleteSetProps; k++) GuiSetStyle(completeSets, k, props[completeSets*(NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED) + k]);
  2468. }
  2469. // Load style default over global style
  2470. RAYGUIDEF void GuiLoadStyleDefault(void)
  2471. {
  2472. // We set this variable first to avoid cyclic function calls
  2473. // when calling GuiSetStyle() and GuiGetStyle()
  2474. guiStyleLoaded = true;
  2475. // Initialize default LIGHT style property values
  2476. GuiSetStyle(DEFAULT, BORDER_COLOR_NORMAL, 0x838383ff);
  2477. GuiSetStyle(DEFAULT, BASE_COLOR_NORMAL, 0xc9c9c9ff);
  2478. GuiSetStyle(DEFAULT, TEXT_COLOR_NORMAL, 0x686868ff);
  2479. GuiSetStyle(DEFAULT, BORDER_COLOR_FOCUSED, 0x5bb2d9ff);
  2480. GuiSetStyle(DEFAULT, BASE_COLOR_FOCUSED, 0xc9effeff);
  2481. GuiSetStyle(DEFAULT, TEXT_COLOR_FOCUSED, 0x6c9bbcff);
  2482. GuiSetStyle(DEFAULT, BORDER_COLOR_PRESSED, 0x0492c7ff);
  2483. GuiSetStyle(DEFAULT, BASE_COLOR_PRESSED, 0x97e8ffff);
  2484. GuiSetStyle(DEFAULT, TEXT_COLOR_PRESSED, 0x368bafff);
  2485. GuiSetStyle(DEFAULT, BORDER_COLOR_DISABLED, 0xb5c1c2ff);
  2486. GuiSetStyle(DEFAULT, BASE_COLOR_DISABLED, 0xe6e9e9ff);
  2487. GuiSetStyle(DEFAULT, TEXT_COLOR_DISABLED, 0xaeb7b8ff);
  2488. GuiSetStyle(DEFAULT, BORDER_WIDTH, 1);
  2489. GuiSetStyle(DEFAULT, INNER_PADDING, 1);
  2490. GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
  2491. // Populate all controls with default style
  2492. for (int i = 1; i < NUM_CONTROLS; i++)
  2493. {
  2494. for (int j = 0; j < NUM_PROPS_DEFAULT; j++) GuiSetStyle(i, j, GuiGetStyle(DEFAULT, j));
  2495. }
  2496. // Initialize extended property values
  2497. // NOTE: By default, extended property values are initialized to 0
  2498. GuiSetStyle(DEFAULT, TEXT_SIZE, 10);
  2499. GuiSetStyle(DEFAULT, TEXT_SPACING, 1);
  2500. GuiSetStyle(DEFAULT, LINE_COLOR, 0x90abb5ff); // DEFAULT specific property
  2501. GuiSetStyle(DEFAULT, BACKGROUND_COLOR, 0xf5f5f5ff); // DEFAULT specific property
  2502. GuiSetStyle(LABEL, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT);
  2503. GuiSetStyle(BUTTON, BORDER_WIDTH, 2);
  2504. GuiSetStyle(BUTTON, INNER_PADDING, 4);
  2505. GuiSetStyle(TOGGLE, GROUP_PADDING, 2);
  2506. GuiSetStyle(SLIDER, SLIDER_WIDTH, 15);
  2507. GuiSetStyle(SLIDER, TEXT_PADDING, 5);
  2508. GuiSetStyle(CHECKBOX, CHECK_TEXT_PADDING, 5);
  2509. GuiSetStyle(COMBOBOX, SELECTOR_WIDTH, 30);
  2510. GuiSetStyle(COMBOBOX, SELECTOR_PADDING, 2);
  2511. GuiSetStyle(DROPDOWNBOX, ARROW_RIGHT_PADDING, 16);
  2512. GuiSetStyle(TEXTBOX, INNER_PADDING, 4);
  2513. GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT);
  2514. GuiSetStyle(TEXTBOX, MULTILINE_PADDING, 5);
  2515. GuiSetStyle(TEXTBOX, SPINNER_BUTTON_WIDTH, 20); // SPINNER specific property
  2516. GuiSetStyle(TEXTBOX, SPINNER_BUTTON_PADDING, 2); // SPINNER specific property
  2517. GuiSetStyle(TEXTBOX, SPINNER_BUTTON_BORDER_WIDTH, 1); // SPINNER specific property
  2518. //GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER); // TODO.
  2519. GuiSetStyle(COLORPICKER, COLOR_SELECTOR_SIZE, 6);
  2520. GuiSetStyle(COLORPICKER, BAR_WIDTH, 0x14);
  2521. GuiSetStyle(COLORPICKER, BAR_PADDING, 0xa);
  2522. GuiSetStyle(COLORPICKER, BAR_SELECTOR_HEIGHT, 6);
  2523. GuiSetStyle(COLORPICKER, BAR_SELECTOR_PADDING, 2);
  2524. GuiSetStyle(LISTVIEW, ELEMENTS_HEIGHT, 0x1e);
  2525. GuiSetStyle(LISTVIEW, ELEMENTS_PADDING, 2);
  2526. GuiSetStyle(LISTVIEW, SCROLLBAR_WIDTH, 10);
  2527. GuiSetStyle(LISTVIEW, SCROLLBAR_SIDE, SCROLLBAR_RIGHT_SIDE);
  2528. GuiSetStyle(SCROLLBAR, BORDER_WIDTH, 0);
  2529. GuiSetStyle(SCROLLBAR, SHOW_SPINNER_BUTTONS, 0);
  2530. GuiSetStyle(SCROLLBAR, ARROWS_SIZE, 6);
  2531. GuiSetStyle(SCROLLBAR, INNER_PADDING, 0);
  2532. GuiSetStyle(SCROLLBAR, SLIDER_PADDING, 0);
  2533. GuiSetStyle(SCROLLBAR, SLIDER_SIZE, 16);
  2534. GuiSetStyle(SCROLLBAR, SCROLL_SPEED, 10);
  2535. }
  2536. // Updates controls style with default values
  2537. RAYGUIDEF void GuiUpdateStyleComplete(void)
  2538. {
  2539. // Populate all controls with default style
  2540. // NOTE: Extended style properties are ignored
  2541. for (int i = 1; i < NUM_CONTROLS; i++)
  2542. {
  2543. for (int j = 0; j < NUM_PROPS_DEFAULT; j++) GuiSetStyle(i, j, GuiGetStyle(DEFAULT, j));
  2544. }
  2545. }
  2546. // Get text with icon id prepended
  2547. // NOTE: Useful to add icons by name id (enum) instead of
  2548. // a number that can change between ricon versions
  2549. RAYGUIDEF const char *GuiIconText(int iconId, const char *text)
  2550. {
  2551. static char buffer[1024] = { 0 };
  2552. memset(buffer, 0, 1024);
  2553. sprintf(buffer, "#%03i#", iconId);
  2554. if (text != NULL)
  2555. {
  2556. for (int i = 5; i < 1024; i++)
  2557. {
  2558. buffer[i] = text[i - 5];
  2559. if (text[i - 5] == '\0') break;
  2560. }
  2561. }
  2562. return buffer;
  2563. }
  2564. //----------------------------------------------------------------------------------
  2565. // Module specific Functions Definition
  2566. //----------------------------------------------------------------------------------
  2567. // Split controls text into multiple strings
  2568. // Also check for multiple columns (required by GuiToggleGroup())
  2569. static const char **GuiTextSplit(const char *text, int *count, int *textRow)
  2570. {
  2571. // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
  2572. // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
  2573. // all used memory is static... it has some limitations:
  2574. // 1. Maximum number of possible split strings is set by MAX_SUBSTRINGS_COUNT
  2575. // 2. Maximum size of text to split is MAX_TEXT_BUFFER_LENGTH
  2576. #define MAX_TEXT_BUFFER_LENGTH 1024
  2577. #define MAX_SUBSTRINGS_COUNT 64
  2578. static const char *result[MAX_SUBSTRINGS_COUNT] = { NULL };
  2579. static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
  2580. memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
  2581. result[0] = buffer;
  2582. int counter = 1;
  2583. if (textRow != NULL) textRow[0] = 0;
  2584. // Count how many substrings we have on text and point to every one
  2585. for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
  2586. {
  2587. buffer[i] = text[i];
  2588. if (buffer[i] == '\0') break;
  2589. else if ((buffer[i] == ';') || (buffer[i] == '\n'))
  2590. {
  2591. result[counter] = buffer + i + 1;
  2592. if (textRow != NULL)
  2593. {
  2594. if (buffer[i] == '\n') textRow[counter] = textRow[counter - 1] + 1;
  2595. else textRow[counter] = textRow[counter - 1];
  2596. }
  2597. buffer[i] = '\0'; // Set an end of string at this point
  2598. counter++;
  2599. if (counter == MAX_SUBSTRINGS_COUNT) break;
  2600. }
  2601. }
  2602. *count = counter;
  2603. return result;
  2604. }
  2605. // Convert color data from RGB to HSV
  2606. // NOTE: Color data should be passed normalized
  2607. static Vector3 ConvertRGBtoHSV(Vector3 rgb)
  2608. {
  2609. Vector3 hsv = { 0.0f };
  2610. float min = 0.0f;
  2611. float max = 0.0f;
  2612. float delta = 0.0f;
  2613. min = (rgb.x < rgb.y)? rgb.x : rgb.y;
  2614. min = (min < rgb.z)? min : rgb.z;
  2615. max = (rgb.x > rgb.y)? rgb.x : rgb.y;
  2616. max = (max > rgb.z)? max : rgb.z;
  2617. hsv.z = max; // Value
  2618. delta = max - min;
  2619. if (delta < 0.00001f)
  2620. {
  2621. hsv.y = 0.0f;
  2622. hsv.x = 0.0f; // Undefined, maybe NAN?
  2623. return hsv;
  2624. }
  2625. if (max > 0.0f)
  2626. {
  2627. // NOTE: If max is 0, this divide would cause a crash
  2628. hsv.y = (delta/max); // Saturation
  2629. }
  2630. else
  2631. {
  2632. // NOTE: If max is 0, then r = g = b = 0, s = 0, h is undefined
  2633. hsv.y = 0.0f;
  2634. hsv.x = 0.0f; // Undefined, maybe NAN?
  2635. return hsv;
  2636. }
  2637. // NOTE: Comparing float values could not work properly
  2638. if (rgb.x >= max) hsv.x = (rgb.y - rgb.z)/delta; // Between yellow & magenta
  2639. else
  2640. {
  2641. if (rgb.y >= max) hsv.x = 2.0f + (rgb.z - rgb.x)/delta; // Between cyan & yellow
  2642. else hsv.x = 4.0f + (rgb.x - rgb.y)/delta; // Between magenta & cyan
  2643. }
  2644. hsv.x *= 60.0f; // Convert to degrees
  2645. if (hsv.x < 0.0f) hsv.x += 360.0f;
  2646. return hsv;
  2647. }
  2648. // Convert color data from HSV to RGB
  2649. // NOTE: Color data should be passed normalized
  2650. static Vector3 ConvertHSVtoRGB(Vector3 hsv)
  2651. {
  2652. Vector3 rgb = { 0.0f };
  2653. float hh = 0.0f, p = 0.0f, q = 0.0f, t = 0.0f, ff = 0.0f;
  2654. long i = 0;
  2655. // NOTE: Comparing float values could not work properly
  2656. if (hsv.y <= 0.0f)
  2657. {
  2658. rgb.x = hsv.z;
  2659. rgb.y = hsv.z;
  2660. rgb.z = hsv.z;
  2661. return rgb;
  2662. }
  2663. hh = hsv.x;
  2664. if (hh >= 360.0f) hh = 0.0f;
  2665. hh /= 60.0f;
  2666. i = (long)hh;
  2667. ff = hh - i;
  2668. p = hsv.z*(1.0f - hsv.y);
  2669. q = hsv.z*(1.0f - (hsv.y*ff));
  2670. t = hsv.z*(1.0f - (hsv.y*(1.0f - ff)));
  2671. switch (i)
  2672. {
  2673. case 0:
  2674. {
  2675. rgb.x = hsv.z;
  2676. rgb.y = t;
  2677. rgb.z = p;
  2678. } break;
  2679. case 1:
  2680. {
  2681. rgb.x = q;
  2682. rgb.y = hsv.z;
  2683. rgb.z = p;
  2684. } break;
  2685. case 2:
  2686. {
  2687. rgb.x = p;
  2688. rgb.y = hsv.z;
  2689. rgb.z = t;
  2690. } break;
  2691. case 3:
  2692. {
  2693. rgb.x = p;
  2694. rgb.y = q;
  2695. rgb.z = hsv.z;
  2696. } break;
  2697. case 4:
  2698. {
  2699. rgb.x = t;
  2700. rgb.y = p;
  2701. rgb.z = hsv.z;
  2702. } break;
  2703. case 5:
  2704. default:
  2705. {
  2706. rgb.x = hsv.z;
  2707. rgb.y = p;
  2708. rgb.z = q;
  2709. } break;
  2710. }
  2711. return rgb;
  2712. }
  2713. #if defined(RAYGUI_STANDALONE)
  2714. // Returns a Color struct from hexadecimal value
  2715. static Color GetColor(int hexValue)
  2716. {
  2717. Color color;
  2718. color.r = (unsigned char)(hexValue >> 24) & 0xFF;
  2719. color.g = (unsigned char)(hexValue >> 16) & 0xFF;
  2720. color.b = (unsigned char)(hexValue >> 8) & 0xFF;
  2721. color.a = (unsigned char)hexValue & 0xFF;
  2722. return color;
  2723. }
  2724. // Returns hexadecimal value for a Color
  2725. static int ColorToInt(Color color)
  2726. {
  2727. return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a);
  2728. }
  2729. // Check if point is inside rectangle
  2730. static bool CheckCollisionPointRec(Vector2 point, Rectangle rec)
  2731. {
  2732. bool collision = false;
  2733. if ((point.x >= rec.x) && (point.x <= (rec.x + rec.width)) &&
  2734. (point.y >= rec.y) && (point.y <= (rec.y + rec.height))) collision = true;
  2735. return collision;
  2736. }
  2737. // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
  2738. static Color Fade(Color color, float alpha)
  2739. {
  2740. if (alpha < 0.0f) alpha = 0.0f;
  2741. else if (alpha > 1.0f) alpha = 1.0f;
  2742. return (Color){color.r, color.g, color.b, (unsigned char)(255.0f*alpha)};
  2743. }
  2744. // Formatting of text with variables to 'embed'
  2745. static const char *TextFormat(const char *text, ...)
  2746. {
  2747. #define MAX_FORMATTEXT_LENGTH 64
  2748. static char buffer[MAX_FORMATTEXT_LENGTH];
  2749. va_list args;
  2750. va_start(args, text);
  2751. vsprintf(buffer, text, args);
  2752. va_end(args);
  2753. return buffer;
  2754. }
  2755. #endif // RAYGUI_STANDALONE
  2756. #endif // RAYGUI_IMPLEMENTATION