raygui.h 197 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540
  1. /*******************************************************************************************
  2. *
  3. * raygui v2.5 - A simple and easy-to-use immediate-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. * Controls provided:
  11. *
  12. * # Container/separators Controls
  13. * - WindowBox
  14. * - GroupBox
  15. * - Line
  16. * - Panel
  17. *
  18. * # Basic Controls
  19. * - Label
  20. * - Button
  21. * - LabelButton --> Label
  22. * - ImageButton --> Button
  23. * - ImageButtonEx --> Button
  24. * - Toggle
  25. * - ToggleGroup --> Toggle
  26. * - CheckBox
  27. * - ComboBox
  28. * - DropdownBox
  29. * - TextBox
  30. * - TextBoxMulti
  31. * - ValueBox --> TextBox
  32. * - Spinner --> Button, ValueBox
  33. * - Slider
  34. * - SliderBar --> Slider
  35. * - ProgressBar
  36. * - StatusBar
  37. * - ScrollBar
  38. * - ScrollPanel
  39. * - DummyRec
  40. * - Grid
  41. *
  42. * # Advance Controls
  43. * - ListView --> ListElement
  44. * - ColorPicker --> ColorPanel, ColorBarHue
  45. * - MessageBox --> Label, Button
  46. * - TextInputBox --> Label, TextBox, Button
  47. *
  48. * It also provides a set of functions for styling the controls based on its properties (size, color).
  49. *
  50. * CONFIGURATION:
  51. *
  52. * #define RAYGUI_IMPLEMENTATION
  53. * Generates the implementation of the library into the included file.
  54. * If not defined, the library is in header only mode and can be included in other headers
  55. * or source files without problems. But only ONE file should hold the implementation.
  56. *
  57. * #define RAYGUI_STATIC (defined by default)
  58. * The generated implementation will stay private inside implementation file and all
  59. * internal symbols and functions will only be visible inside that file.
  60. *
  61. * #define RAYGUI_STANDALONE
  62. * Avoid raylib.h header inclusion in this file. Data types defined on raylib are defined
  63. * internally in the library and input management and drawing functions must be provided by
  64. * the user (check library implementation for further details).
  65. *
  66. * #define RAYGUI_RICONS_SUPPORT
  67. * Includes ricons.h header defining a set of 128 icons (binary format) to be used on
  68. * multiple controls and following raygui styles
  69. *
  70. * #define RAYGUI_TEXTBOX_EXTENDED
  71. * Enables the advance GuiTextBox()/GuiValueBox()/GuiSpinner() implementation with
  72. * text selection support and text copy/cut/paste support
  73. *
  74. * VERSIONS HISTORY:
  75. * 2.5 (28-May-2019) Implemented extended GuiTextBox(), GuiValueBox(), GuiSpinner()
  76. * 2.3 (29-Apr-2019) Added rIcons auxiliar library and support for it, multiple controls reviewed
  77. * Refactor all controls drawing mechanism to use control state
  78. * 2.2 (05-Feb-2019) Added GuiScrollBar(), GuiScrollPanel(), reviewed GuiListView(), removed Gui*Ex() controls
  79. * 2.1 (26-Dec-2018) Redesign of GuiCheckBox(), GuiComboBox(), GuiDropdownBox(), GuiToggleGroup() > Use combined text string
  80. * Complete redesign of style system (breaking change)
  81. * 2.0 (08-Nov-2018) Support controls guiLock and custom fonts, reviewed GuiComboBox(), GuiListView()...
  82. * 1.9 (09-Oct-2018) Controls review: GuiGrid(), GuiTextBox(), GuiTextBoxMulti(), GuiValueBox()...
  83. * 1.8 (01-May-2018) Lot of rework and redesign to align with rGuiStyler and rGuiLayout
  84. * 1.5 (21-Jun-2017) Working in an improved styles system
  85. * 1.4 (15-Jun-2017) Rewritten all GUI functions (removed useless ones)
  86. * 1.3 (12-Jun-2017) Redesigned styles system
  87. * 1.1 (01-Jun-2017) Complete review of the library
  88. * 1.0 (07-Jun-2016) Converted to header-only by Ramon Santamaria.
  89. * 0.9 (07-Mar-2016) Reviewed and tested by Albert Martos, Ian Eito, Sergio Martinez and Ramon Santamaria.
  90. * 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria.
  91. *
  92. * CONTRIBUTORS:
  93. * Ramon Santamaria: Supervision, review, redesign, update and maintenance...
  94. * Vlad Adrian: Complete rewrite of GuiTextBox() to support extended features (2019)
  95. * Sergio Martinez: Review, testing (2015) and redesign of multiple controls (2018)
  96. * Adria Arranz: Testing and Implementation of additional controls (2018)
  97. * Jordi Jorba: Testing and Implementation of additional controls (2018)
  98. * Albert Martos: Review and testing of the library (2015)
  99. * Ian Eito: Review and testing of the library (2015)
  100. * Kevin Gato: Initial implementation of basic components (2014)
  101. * Daniel Nicolas: Initial implementation of basic components (2014)
  102. *
  103. *
  104. * LICENSE: zlib/libpng
  105. *
  106. * Copyright (c) 2014-2019 Ramon Santamaria (@raysan5)
  107. *
  108. * This software is provided "as-is", without any express or implied warranty. In no event
  109. * will the authors be held liable for any damages arising from the use of this software.
  110. *
  111. * Permission is granted to anyone to use this software for any purpose, including commercial
  112. * applications, and to alter it and redistribute it freely, subject to the following restrictions:
  113. *
  114. * 1. The origin of this software must not be misrepresented; you must not claim that you
  115. * wrote the original software. If you use this software in a product, an acknowledgment
  116. * in the product documentation would be appreciated but is not required.
  117. *
  118. * 2. Altered source versions must be plainly marked as such, and must not be misrepresented
  119. * as being the original software.
  120. *
  121. * 3. This notice may not be removed or altered from any source distribution.
  122. *
  123. **********************************************************************************************/
  124. #ifndef RAYGUI_H
  125. #define RAYGUI_H
  126. #define RAYGUI_VERSION "2.5-dev"
  127. #if !defined(RAYGUI_STANDALONE)
  128. #include "raylib.h"
  129. #endif
  130. #if defined(RAYGUI_IMPLEMENTATION)
  131. #if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED)
  132. #define RAYGUIDEF __declspec(dllexport) extern // We are building raygui as a Win32 shared library (.dll).
  133. #elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED)
  134. #define RAYGUIDEF __declspec(dllimport) // We are using raygui as a Win32 shared library (.dll)
  135. #else
  136. #ifdef __cplusplus
  137. #define RAYGUIDEF extern "C" // Functions visible from other files (no name mangling of functions in C++)
  138. #else
  139. #define RAYGUIDEF extern // Functions visible from other files
  140. #endif
  141. #endif
  142. #elif defined(RAYGUI_STATIC)
  143. #define RAYGUIDEF static // Functions just visible to module including this file
  144. #endif
  145. #include <stdlib.h> // Required for: atoi()
  146. //----------------------------------------------------------------------------------
  147. // Defines and Macros
  148. //----------------------------------------------------------------------------------
  149. #define TEXTEDIT_CURSOR_BLINK_FRAMES 20 // Text edit controls cursor blink timming
  150. #define NUM_CONTROLS 16 // Number of standard controls
  151. #define NUM_PROPS_DEFAULT 16 // Number of standard properties
  152. #define NUM_PROPS_EXTENDED 8 // Number of extended properties
  153. //----------------------------------------------------------------------------------
  154. // Types and Structures Definition
  155. // NOTE: Some types are required for RAYGUI_STANDALONE usage
  156. //----------------------------------------------------------------------------------
  157. #if defined(RAYGUI_STANDALONE)
  158. #ifndef __cplusplus
  159. // Boolean type
  160. #ifndef true
  161. typedef enum { false, true } bool;
  162. #endif
  163. #endif
  164. // Vector2 type
  165. typedef struct Vector2 {
  166. float x;
  167. float y;
  168. } Vector2;
  169. // Vector3 type
  170. typedef struct Vector3 {
  171. float x;
  172. float y;
  173. float z;
  174. } Vector3;
  175. // Color type, RGBA (32bit)
  176. typedef struct Color {
  177. unsigned char r;
  178. unsigned char g;
  179. unsigned char b;
  180. unsigned char a;
  181. } Color;
  182. // Rectangle type
  183. typedef struct Rectangle {
  184. int x;
  185. int y;
  186. int width;
  187. int height;
  188. } Rectangle;
  189. // Texture2D type
  190. // NOTE: It should be provided by user
  191. typedef struct Texture2D Texture2D;
  192. // Font type
  193. // NOTE: It should be provided by user
  194. typedef struct Font Font;
  195. #endif
  196. #if defined(RAYGUI_TEXTBOX_EXTENDED)
  197. // Gui text box state data
  198. typedef struct GuiTextBoxState {
  199. int cursor; // Cursor position in text
  200. int start; // Text start position (from where we begin drawing the text)
  201. int index; // Text start index (index inside the text of `start` always in sync)
  202. int select; // Marks position of cursor when selection has started
  203. } GuiTextBoxState;
  204. #endif
  205. // Gui control state
  206. typedef enum {
  207. GUI_STATE_NORMAL = 0,
  208. GUI_STATE_FOCUSED,
  209. GUI_STATE_PRESSED,
  210. GUI_STATE_DISABLED,
  211. } GuiControlState;
  212. // Gui control text alignment
  213. typedef enum {
  214. GUI_TEXT_ALIGN_LEFT = 0,
  215. GUI_TEXT_ALIGN_CENTER,
  216. GUI_TEXT_ALIGN_RIGHT,
  217. } GuiTextAlignment;
  218. // Gui controls
  219. typedef enum {
  220. DEFAULT = 0,
  221. LABEL, // LABELBUTTON
  222. BUTTON, // IMAGEBUTTON
  223. TOGGLE, // TOGGLEGROUP
  224. SLIDER, // SLIDERBAR
  225. PROGRESSBAR,
  226. CHECKBOX,
  227. COMBOBOX,
  228. DROPDOWNBOX,
  229. TEXTBOX, // TEXTBOXMULTI
  230. VALUEBOX,
  231. SPINNER,
  232. LISTVIEW,
  233. COLORPICKER,
  234. SCROLLBAR,
  235. RESERVED
  236. } GuiControl;
  237. // Gui base properties for every control
  238. typedef enum {
  239. BORDER_COLOR_NORMAL = 0,
  240. BASE_COLOR_NORMAL,
  241. TEXT_COLOR_NORMAL,
  242. BORDER_COLOR_FOCUSED,
  243. BASE_COLOR_FOCUSED,
  244. TEXT_COLOR_FOCUSED,
  245. BORDER_COLOR_PRESSED,
  246. BASE_COLOR_PRESSED,
  247. TEXT_COLOR_PRESSED,
  248. BORDER_COLOR_DISABLED,
  249. BASE_COLOR_DISABLED,
  250. TEXT_COLOR_DISABLED,
  251. BORDER_WIDTH,
  252. INNER_PADDING,
  253. TEXT_ALIGNMENT,
  254. RESERVED02
  255. } GuiControlProperty;
  256. // Gui extended properties depend on control
  257. // NOTE: We reserve a fixed size of additional properties per control
  258. // DEFAULT properties
  259. typedef enum {
  260. TEXT_SIZE = 16,
  261. TEXT_SPACING,
  262. LINE_COLOR,
  263. BACKGROUND_COLOR,
  264. } GuiDefaultProperty;
  265. // Label
  266. //typedef enum { } GuiLabelProperty;
  267. // Button
  268. //typedef enum { } GuiButtonProperty;
  269. // Toggle / ToggleGroup
  270. typedef enum {
  271. GROUP_PADDING = 16,
  272. } GuiToggleProperty;
  273. // Slider / SliderBar
  274. typedef enum {
  275. SLIDER_WIDTH = 16,
  276. TEXT_PADDING
  277. } GuiSliderProperty;
  278. // ProgressBar
  279. //typedef enum { } GuiProgressBarProperty;
  280. // CheckBox
  281. typedef enum {
  282. CHECK_TEXT_PADDING = 16
  283. } GuiCheckBoxProperty;
  284. // ComboBox
  285. typedef enum {
  286. SELECTOR_WIDTH = 16,
  287. SELECTOR_PADDING
  288. } GuiComboBoxProperty;
  289. // DropdownBox
  290. typedef enum {
  291. ARROW_RIGHT_PADDING = 16,
  292. } GuiDropdownBoxProperty;
  293. // TextBox / TextBoxMulti / ValueBox / Spinner
  294. typedef enum {
  295. MULTILINE_PADDING = 16,
  296. COLOR_SELECTED_FG,
  297. COLOR_SELECTED_BG
  298. } GuiTextBoxProperty;
  299. typedef enum {
  300. SELECT_BUTTON_WIDTH = 16,
  301. SELECT_BUTTON_PADDING,
  302. SELECT_BUTTON_BORDER_WIDTH
  303. } GuiSpinnerProperty;
  304. // ScrollBar
  305. typedef enum {
  306. ARROWS_SIZE = 16,
  307. SLIDER_PADDING,
  308. SLIDER_SIZE,
  309. SCROLL_SPEED,
  310. ARROWS_VISIBLE
  311. } GuiScrollBarProperty;
  312. // ScrollBar side
  313. typedef enum {
  314. SCROLLBAR_LEFT_SIDE = 0,
  315. SCROLLBAR_RIGHT_SIDE
  316. } GuiScrollBarSide;
  317. // ListView
  318. typedef enum {
  319. ELEMENTS_HEIGHT = 16,
  320. ELEMENTS_PADDING,
  321. SCROLLBAR_WIDTH,
  322. SCROLLBAR_SIDE, // This property defines vertical scrollbar side (SCROLLBAR_LEFT_SIDE or SCROLLBAR_RIGHT_SIDE)
  323. } GuiListViewProperty;
  324. // ColorPicker
  325. typedef enum {
  326. COLOR_SELECTOR_SIZE = 16,
  327. BAR_WIDTH, // Lateral bar width
  328. BAR_PADDING, // Lateral bar separation from panel
  329. BAR_SELECTOR_HEIGHT, // Lateral bar selector height
  330. BAR_SELECTOR_PADDING // Lateral bar selector outer padding
  331. } GuiColorPickerProperty;
  332. //----------------------------------------------------------------------------------
  333. // Global Variables Definition
  334. //----------------------------------------------------------------------------------
  335. // ...
  336. //----------------------------------------------------------------------------------
  337. // Module Functions Declaration
  338. //----------------------------------------------------------------------------------
  339. // Global gui modification functions
  340. RAYGUIDEF void GuiEnable(void); // Enable gui controls (global state)
  341. RAYGUIDEF void GuiDisable(void); // Disable gui controls (global state)
  342. RAYGUIDEF void GuiLock(void); // Lock gui controls (global state)
  343. RAYGUIDEF void GuiUnlock(void); // Unlock gui controls (global state)
  344. RAYGUIDEF void GuiState(int state); // Set gui state (global state)
  345. RAYGUIDEF void GuiFont(Font font); // Set gui custom font (global state)
  346. RAYGUIDEF void GuiFade(float alpha); // Set gui controls alpha (global state), alpha goes from 0.0f to 1.0f
  347. // Style set/get functions
  348. RAYGUIDEF void GuiSetStyle(int control, int property, int value); // Set one style property
  349. RAYGUIDEF int GuiGetStyle(int control, int property); // Get one style property
  350. #if defined(RAYGUI_TEXTBOX_EXTENDED)
  351. // GuiTextBox() extended functions
  352. RAYGUIDEF void GuiTextBoxSetActive(Rectangle bounds); // Sets the active textbox
  353. RAYGUIDEF Rectangle GuiTextBoxGetActive(void); // Get bounds of active textbox
  354. RAYGUIDEF void GuiTextBoxSetCursor(int cursor); // Set cursor position of active textbox
  355. RAYGUIDEF int GuiTextBoxGetCursor(void); // Get cursor position of active textbox
  356. RAYGUIDEF void GuiTextBoxSetSelection(int start, int length); // Set selection of active textbox
  357. RAYGUIDEF Vector2 GuiTextBoxGetSelection(void); // Get selection of active textbox (x - selection start y - selection length)
  358. RAYGUIDEF bool GuiTextBoxIsActive(Rectangle bounds); // Returns true if a textbox control with specified `bounds` is the active textbox
  359. RAYGUIDEF GuiTextBoxState GuiTextBoxGetState(void); // Get state for the active textbox
  360. RAYGUIDEF void GuiTextBoxSetState(GuiTextBoxState state); // Set state for the active textbox (state must be valid else things will break)
  361. RAYGUIDEF void GuiTextBoxSelectAll(const char *text); // Select all characters in the active textbox (same as pressing `CTRL` + `A`)
  362. RAYGUIDEF void GuiTextBoxCopy(const char *text); // Copy selected text to clipboard from the active textbox (same as pressing `CTRL` + `C`)
  363. RAYGUIDEF void GuiTextBoxPaste(char *text, int textSize); // Paste text from clipboard into the textbox (same as pressing `CTRL` + `V`)
  364. RAYGUIDEF void GuiTextBoxCut(char *text); // Cut selected text in the active textbox and copy it to clipboard (same as pressing `CTRL` + `X`)
  365. RAYGUIDEF int GuiTextBoxDelete(char *text, int length, bool before); // Deletes a character or selection before from the active textbox (depending on `before`). Returns bytes deleted.
  366. RAYGUIDEF int GuiTextBoxGetByteIndex(const char *text, int start, int from, int to); // Get the byte index for a character starting at position `from` with index `start` until position `to`.
  367. #endif
  368. // Container/separator controls, useful for controls organization
  369. RAYGUIDEF bool GuiWindowBox(Rectangle bounds, const char *text); // Window Box control, shows a window that can be closed
  370. RAYGUIDEF void GuiGroupBox(Rectangle bounds, const char *text); // Group Box control with title name
  371. RAYGUIDEF void GuiLine(Rectangle bounds, const char *text); // Line separator control, could contain text
  372. RAYGUIDEF void GuiPanel(Rectangle bounds); // Panel control, useful to group controls
  373. RAYGUIDEF Rectangle GuiScrollPanel(Rectangle bounds, Rectangle content, Vector2 *scroll); // Scroll Panel control
  374. // Basic controls set
  375. RAYGUIDEF void GuiLabel(Rectangle bounds, const char *text); // Label control, shows text
  376. RAYGUIDEF bool GuiButton(Rectangle bounds, const char *text); // Button control, returns true when clicked
  377. RAYGUIDEF bool GuiLabelButton(Rectangle bounds, const char *text); // Label button control, show true when clicked
  378. RAYGUIDEF bool GuiImageButton(Rectangle bounds, Texture2D texture); // Image button control, returns true when clicked
  379. RAYGUIDEF bool GuiImageButtonEx(Rectangle bounds, Texture2D texture, Rectangle texSource, const char *text); // Image button extended control, returns true when clicked
  380. RAYGUIDEF bool GuiToggle(Rectangle bounds, const char *text, bool active); // Toggle Button control, returns true when active
  381. RAYGUIDEF int GuiToggleGroup(Rectangle bounds, const char *text, int active); // Toggle Group control, returns active toggle index
  382. RAYGUIDEF bool GuiCheckBox(Rectangle bounds, const char *text, bool checked); // Check Box control, returns true when active
  383. RAYGUIDEF int GuiComboBox(Rectangle bounds, const char *text, int active); // Combo Box control, returns selected item index
  384. RAYGUIDEF bool GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode); // Dropdown Box control, returns selected item
  385. RAYGUIDEF bool GuiSpinner(Rectangle bounds, int *value, int minValue, int maxValue, bool editMode); // Spinner control, returns selected value
  386. RAYGUIDEF bool GuiValueBox(Rectangle bounds, int *value, int minValue, int maxValue, bool editMode); // Value Box control, updates input text with numbers
  387. RAYGUIDEF bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode); // Text Box control, updates input text
  388. RAYGUIDEF bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode); // Text Box control with multiple lines
  389. RAYGUIDEF float GuiSlider(Rectangle bounds, const char *text, float value, float minValue, float maxValue, bool showValue); // Slider control, returns selected value
  390. RAYGUIDEF float GuiSliderBar(Rectangle bounds, const char *text, float value, float minValue, float maxValue, bool showValue); // Slider Bar control, returns selected value
  391. RAYGUIDEF float GuiProgressBar(Rectangle bounds, const char *text, float value, float minValue, float maxValue, bool showValue); // Progress Bar control, shows current progress value
  392. RAYGUIDEF void GuiStatusBar(Rectangle bounds, const char *text); // Status Bar control, shows info text
  393. RAYGUIDEF void GuiDummyRec(Rectangle bounds, const char *text); // Dummy control for placeholders
  394. RAYGUIDEF int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll Bar control
  395. RAYGUIDEF Vector2 GuiGrid(Rectangle bounds, float spacing, int subdivs); // Grid control
  396. // Advance controls set
  397. RAYGUIDEF bool GuiListView(Rectangle bounds, const char *text, int *active, int *scrollIndex, bool editMode); // List View control, returns selected list element index
  398. 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
  399. RAYGUIDEF int GuiMessageBox(Rectangle bounds, const char *windowTitle, const char *message, const char *buttons); // Message Box control, displays a message
  400. RAYGUIDEF int GuiTextInputBox(Rectangle bounds, const char *windowTitle, const char *message, char *text, const char *buttons); // Text Input Box control, ask for text
  401. RAYGUIDEF Color GuiColorPicker(Rectangle bounds, Color color); // Color Picker control
  402. // Styles loading functions
  403. RAYGUIDEF void GuiLoadStyle(const char *fileName); // Load style file (.rgs)
  404. RAYGUIDEF void GuiLoadStyleProps(const int *props, int count); // Load style properties from array
  405. RAYGUIDEF void GuiLoadStyleDefault(void); // Load style default over global style
  406. RAYGUIDEF void GuiUpdateStyleComplete(void); // Updates full style properties set with default values
  407. /*
  408. typedef GuiStyle (unsigned int *)
  409. RAYGUIDEF GuiStyle LoadGuiStyle(const char *fileName); // Load style from file (.rgs)
  410. RAYGUIDEF void UnloadGuiStyle(GuiStyle style); // Unload style
  411. */
  412. RAYGUIDEF const char *GuiIconText(int iconId, const char *text); // Get text with icon id prepended
  413. #endif // RAYGUI_H
  414. /***********************************************************************************
  415. *
  416. * RAYGUI IMPLEMENTATION
  417. *
  418. ************************************************************************************/
  419. #if defined(RAYGUI_IMPLEMENTATION)
  420. #if defined(RAYGUI_RICONS_SUPPORT)
  421. #if defined(RAYGUI_STANDALONE)
  422. #define RICONS_STANDALONE
  423. #endif
  424. #define RICONS_IMPLEMENTATION
  425. #include "ricons.h" // Required for: raygui icons
  426. #endif
  427. #include <stdio.h> // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), vsprintf()
  428. #include <string.h> // Required for: strlen() on GuiTextBox()
  429. #if defined(RAYGUI_STANDALONE)
  430. #include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end()
  431. #endif
  432. #ifdef __cplusplus
  433. #define RAYGUI_CLITERAL(name) name
  434. #else
  435. #define RAYGUI_CLITERAL(name) (name)
  436. #endif
  437. //----------------------------------------------------------------------------------
  438. // Defines and Macros
  439. //----------------------------------------------------------------------------------
  440. //...
  441. //----------------------------------------------------------------------------------
  442. // Types and Structures Definition
  443. //----------------------------------------------------------------------------------
  444. // Gui control property style element
  445. typedef enum { BORDER = 0, BASE, TEXT, OTHER } GuiPropertyElement;
  446. //----------------------------------------------------------------------------------
  447. // Global Variables Definition
  448. //----------------------------------------------------------------------------------
  449. static GuiControlState guiState = GUI_STATE_NORMAL;
  450. static Font guiFont = { 0 }; // NOTE: Highly coupled to raylib
  451. static bool guiLocked = false;
  452. static float guiAlpha = 1.0f;
  453. // Global gui style array (allocated on heap by default)
  454. // NOTE: In raygui we manage a single int array with all the possible style properties.
  455. // When a new style is loaded, it loads over the global style... but default gui style
  456. // could always be recovered with GuiLoadStyleDefault()
  457. static unsigned int guiStyle[NUM_CONTROLS*(NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED)] = { 0 };
  458. static bool guiStyleLoaded = false;
  459. #if defined(RAYGUI_TEXTBOX_EXTENDED)
  460. static Rectangle guiTextBoxActive = { 0 }; // Area of the currently active textbox
  461. static GuiTextBoxState guiTextBoxState = { .cursor = -1, .start = 0, .index = 0, .select = -1 }; // Keeps state of the active textbox
  462. #endif
  463. //----------------------------------------------------------------------------------
  464. // Standalone Mode Functions Declaration
  465. //
  466. // NOTE: raygui depend on some raylib input and drawing functions
  467. // To use raygui as standalone library, below functions must be defined by the user
  468. //----------------------------------------------------------------------------------
  469. #if defined(RAYGUI_STANDALONE)
  470. #define KEY_RIGHT 262
  471. #define KEY_LEFT 263
  472. #define KEY_DOWN 264
  473. #define KEY_UP 265
  474. #define KEY_BACKSPACE 259
  475. #define KEY_ENTER 257
  476. #define MOUSE_LEFT_BUTTON 0
  477. // Input required functions
  478. //-------------------------------------------------------------------------------
  479. static Vector2 GetMousePosition(void);
  480. static int GetMouseWheelMove(void);
  481. static bool IsMouseButtonDown(int button);
  482. static bool IsMouseButtonPressed(int button);
  483. static bool IsMouseButtonReleased(int button);
  484. static bool IsKeyDown(int key);
  485. static bool IsKeyPressed(int key);
  486. static int GetKeyPressed(void); // -- GuiTextBox(), GuiTextBoxMulti(), GuiValueBox()
  487. //-------------------------------------------------------------------------------
  488. // Drawing required functions
  489. //-------------------------------------------------------------------------------
  490. static void DrawRectangle(int x, int y, int width, int height, Color color);
  491. static void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // -- GuiColorPicker()
  492. static void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // -- GuiDropdownBox(), GuiScrollBar()
  493. static void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint); // -- GuiImageButtonEx()
  494. //-------------------------------------------------------------------------------
  495. // Text required functions
  496. //-------------------------------------------------------------------------------
  497. static Font GetFontDefault(void); // -- GuiLoadStyleDefault()
  498. static Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // -- GetTextWidth(), GuiTextBoxMulti()
  499. static void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // -- GuiDrawText()
  500. static Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCount); // -- GuiLoadStyle()
  501. //-------------------------------------------------------------------------------
  502. // raylib functions already implemented in raygui
  503. //-------------------------------------------------------------------------------
  504. static Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value
  505. static int ColorToInt(Color color); // Returns hexadecimal value for a Color
  506. static Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
  507. static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle
  508. static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed'
  509. static void DrawRectangleRec(Rectangle rec, Color color); // Draw rectangle filled with color
  510. static void DrawRectangleLinesEx(Rectangle rec, int lineThick, Color color); // Draw rectangle outlines
  511. static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2); // Draw rectangle vertical gradient
  512. //-------------------------------------------------------------------------------
  513. #endif // RAYGUI_STANDALONE
  514. //----------------------------------------------------------------------------------
  515. // Module specific Functions Declaration
  516. //----------------------------------------------------------------------------------
  517. // List Element control, returns element state
  518. static bool GuiListElement(Rectangle bounds, const char *text, bool active, bool editMode);
  519. static Vector3 ConvertHSVtoRGB(Vector3 hsv); // Convert color data from HSV to RGB
  520. static Vector3 ConvertRGBtoHSV(Vector3 rgb); // Convert color data from RGB to HSV
  521. // Gui get text width using default font
  522. static int GetTextWidth(const char *text) // TODO: GetTextSize()
  523. {
  524. Vector2 size = { 0 };
  525. if ((text != NULL) && (text[0] != '\0')) size = MeasureTextEx(guiFont, text, GuiGetStyle(DEFAULT, TEXT_SIZE), GuiGetStyle(DEFAULT, TEXT_SPACING));
  526. // TODO: Consider text icon width here???
  527. return (int)size.x;
  528. }
  529. // Get text bounds considering control bounds
  530. static Rectangle GetTextBounds(int control, Rectangle bounds)
  531. {
  532. Rectangle textBounds = { 0 };
  533. textBounds.x = bounds.x + GuiGetStyle(control, BORDER_WIDTH) + GuiGetStyle(control, INNER_PADDING);
  534. textBounds.y = bounds.y + GuiGetStyle(control, BORDER_WIDTH) + GuiGetStyle(control, INNER_PADDING);
  535. textBounds.width = bounds.width - 2*(GuiGetStyle(control, BORDER_WIDTH) + GuiGetStyle(control, INNER_PADDING));
  536. textBounds.height = bounds.height - 2*(GuiGetStyle(control, BORDER_WIDTH) + GuiGetStyle(control, INNER_PADDING));
  537. switch (control)
  538. {
  539. case COMBOBOX: bounds.width -= (GuiGetStyle(control, SELECTOR_WIDTH) + GuiGetStyle(control, SELECTOR_PADDING)); break;
  540. case CHECKBOX: bounds.x += (bounds.width + GuiGetStyle(control, CHECK_TEXT_PADDING)); break;
  541. default: break;
  542. }
  543. // TODO: Special cases (no label): COMBOBOX, DROPDOWNBOX, SPINNER, LISTVIEW (scrollbar?)
  544. // More special cases (label side): CHECKBOX, SLIDER
  545. return textBounds;
  546. }
  547. // Get text icon if provided and move text cursor
  548. static const char *GetTextIcon(const char *text, int *iconId)
  549. {
  550. #if defined(RAYGUI_RICONS_SUPPORT)
  551. if (text[0] == '#') // Maybe we have an icon!
  552. {
  553. char iconValue[4] = { 0 };
  554. int i = 1;
  555. for (i = 1; i < 4; i++)
  556. {
  557. if ((text[i] != '#') && (text[i] != '\0')) iconValue[i - 1] = text[i];
  558. else break;
  559. }
  560. iconValue[3] = '\0';
  561. *iconId = atoi(iconValue);
  562. // Move text pointer after icon
  563. // WARNING: If only icon provided, it could point to EOL character!
  564. if (*iconId > 0) text += (i + 1);
  565. }
  566. #endif
  567. return text;
  568. }
  569. // Gui draw text using default font
  570. static void GuiDrawText(const char *text, Rectangle bounds, int alignment, Color tint)
  571. {
  572. #define VALIGN_OFFSET(h) ((int)h%2) // Vertical alignment for pixel perfect
  573. if ((text != NULL) && (text[0] != '\0'))
  574. {
  575. int iconId = 0;
  576. text = GetTextIcon(text, &iconId); // Check text for icon and move cursor
  577. // Get text position depending on alignment and iconId
  578. //---------------------------------------------------------------------------------
  579. #define ICON_TEXT_PADDING 4
  580. Vector2 position = { bounds.x, bounds.y };
  581. // NOTE: We get text size after icon been processed
  582. int textWidth = GetTextWidth(text);
  583. int textHeight = GuiGetStyle(DEFAULT, TEXT_SIZE);
  584. #if defined(RAYGUI_RICONS_SUPPORT)
  585. if (iconId > 0)
  586. {
  587. textWidth += RICONS_SIZE;
  588. // WARNING: If only icon provided, text could be pointing to eof character!
  589. if ((text != NULL) && (text[0] != '\0')) textWidth += ICON_TEXT_PADDING;
  590. }
  591. #endif
  592. // Check guiTextAlign global variables
  593. switch (alignment)
  594. {
  595. case GUI_TEXT_ALIGN_LEFT:
  596. {
  597. position.x = bounds.x;
  598. position.y = bounds.y + bounds.height/2 - textHeight/2 + VALIGN_OFFSET(bounds.height);
  599. } break;
  600. case GUI_TEXT_ALIGN_CENTER:
  601. {
  602. position.x = bounds.x + bounds.width/2 - textWidth/2;
  603. position.y = bounds.y + bounds.height/2 - textHeight/2 + VALIGN_OFFSET(bounds.height);
  604. } break;
  605. case GUI_TEXT_ALIGN_RIGHT:
  606. {
  607. position.x = bounds.x + bounds.width - textWidth;
  608. position.y = bounds.y + bounds.height/2 - textHeight/2 + VALIGN_OFFSET(bounds.height);
  609. } break;
  610. default: break;
  611. }
  612. //---------------------------------------------------------------------------------
  613. // Draw text (with icon if available)
  614. //---------------------------------------------------------------------------------
  615. #if defined(RAYGUI_RICONS_SUPPORT)
  616. #define ICON_TEXT_PADDING 4
  617. if (iconId > 0)
  618. {
  619. // NOTE: We consider icon height, probably different than text size
  620. DrawIcon(iconId, RAYGUI_CLITERAL(Vector2){ position.x, bounds.y + bounds.height/2 - RICONS_SIZE/2 + VALIGN_OFFSET(bounds.height) }, 1, tint);
  621. position.x += (RICONS_SIZE + ICON_TEXT_PADDING);
  622. }
  623. #endif
  624. DrawTextEx(guiFont, text, position, GuiGetStyle(DEFAULT, TEXT_SIZE), GuiGetStyle(DEFAULT, TEXT_SPACING), tint);
  625. //---------------------------------------------------------------------------------
  626. }
  627. }
  628. // Split controls text into multiple strings
  629. // Also check for multiple columns (required by GuiToggleGroup())
  630. static const char **GuiTextSplit(const char *text, int *count, int *textRow);
  631. //----------------------------------------------------------------------------------
  632. // Module Functions Definition
  633. //----------------------------------------------------------------------------------
  634. // Enable gui global state
  635. RAYGUIDEF void GuiEnable(void) { guiState = GUI_STATE_NORMAL; }
  636. // Disable gui global state
  637. RAYGUIDEF void GuiDisable(void) { guiState = GUI_STATE_DISABLED; }
  638. // Lock gui global state
  639. RAYGUIDEF void GuiLock(void) { guiLocked = true; }
  640. // Unlock gui global state
  641. RAYGUIDEF void GuiUnlock(void) { guiLocked = false; }
  642. // Set gui state (global state)
  643. RAYGUIDEF void GuiState(int state) { guiState = (GuiControlState)state; }
  644. // Define custom gui font
  645. RAYGUIDEF void GuiFont(Font font)
  646. {
  647. if (font.texture.id > 0)
  648. {
  649. guiFont = font;
  650. GuiSetStyle(DEFAULT, TEXT_SIZE, font.baseSize);
  651. }
  652. }
  653. // Set gui controls alpha global state
  654. RAYGUIDEF void GuiFade(float alpha)
  655. {
  656. if (alpha < 0.0f) alpha = 0.0f;
  657. else if (alpha > 1.0f) alpha = 1.0f;
  658. guiAlpha = alpha;
  659. }
  660. // Set control style property value
  661. RAYGUIDEF void GuiSetStyle(int control, int property, int value)
  662. {
  663. if (!guiStyleLoaded) GuiLoadStyleDefault();
  664. guiStyle[control*(NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED) + property] = value;
  665. }
  666. // Get control style property value
  667. RAYGUIDEF int GuiGetStyle(int control, int property)
  668. {
  669. if (!guiStyleLoaded) GuiLoadStyleDefault();
  670. return guiStyle[control*(NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED) + property];
  671. }
  672. #if defined(RAYGUI_TEXTBOX_EXTENDED)
  673. // Sets the active textbox (reseting state of the previous active textbox)
  674. RAYGUIDEF void GuiTextBoxSetActive(Rectangle bounds)
  675. {
  676. guiTextBoxActive = bounds;
  677. guiTextBoxState = (GuiTextBoxState){ .cursor = -1, .start = 0, .index = 0, .select = -1 };
  678. }
  679. // Gets bounds of active textbox
  680. RAYGUIDEF Rectangle GuiTextBoxGetActive(void) { return guiTextBoxActive; }
  681. // Set cursor position of active textbox
  682. RAYGUIDEF void GuiTextBoxSetCursor(int cursor)
  683. {
  684. guiTextBoxState.cursor = (cursor < 0) ? -1 : cursor;
  685. guiTextBoxState.start = -1; // Mark this to be recalculated
  686. }
  687. // Get cursor position of active textbox
  688. RAYGUIDEF int GuiTextBoxGetCursor(void) { return guiTextBoxState.cursor; }
  689. // Set selection of active textbox
  690. RAYGUIDEF void GuiTextBoxSetSelection(int start, int length)
  691. {
  692. if(start < 0) start = 0;
  693. if(length < 0) length = 0;
  694. GuiTextBoxSetCursor(start + length);
  695. guiTextBoxState.select = start;
  696. }
  697. // Get selection of active textbox
  698. RAYGUIDEF Vector2 GuiTextBoxGetSelection(void)
  699. {
  700. if(guiTextBoxState.select == -1 || guiTextBoxState.select == guiTextBoxState.cursor)
  701. return RAYGUI_CLITERAL(Vector2){ 0 };
  702. else if(guiTextBoxState.cursor > guiTextBoxState.select)
  703. return RAYGUI_CLITERAL(Vector2){ guiTextBoxState.select, guiTextBoxState.cursor - guiTextBoxState.select };
  704. return RAYGUI_CLITERAL(Vector2){ guiTextBoxState.cursor, guiTextBoxState.select - guiTextBoxState.cursor };
  705. }
  706. // Returns true if a textbox control with specified `bounds` is the active textbox
  707. RAYGUIDEF bool GuiTextBoxIsActive(Rectangle bounds)
  708. {
  709. return (bounds.x == guiTextBoxActive.x && bounds.y == guiTextBoxActive.y &&
  710. bounds.width == guiTextBoxActive.width && bounds.height == guiTextBoxActive.height);
  711. }
  712. RAYGUIDEF GuiTextBoxState GuiTextBoxGetState(void) { return guiTextBoxState; }
  713. RAYGUIDEF void GuiTextBoxSetState(GuiTextBoxState state)
  714. {
  715. // NOTE: should we check if state values are valid ?!?
  716. guiTextBoxState = state;
  717. }
  718. #endif
  719. // Window Box control
  720. RAYGUIDEF bool GuiWindowBox(Rectangle bounds, const char *text)
  721. {
  722. #define WINDOW_CLOSE_BUTTON_PADDING 2
  723. #define WINDOW_STATUSBAR_HEIGHT 24
  724. GuiControlState state = guiState;
  725. bool clicked = false;
  726. Rectangle statusBar = { bounds.x, bounds.y, bounds.width, WINDOW_STATUSBAR_HEIGHT };
  727. if (bounds.height < WINDOW_STATUSBAR_HEIGHT*2) bounds.height = WINDOW_STATUSBAR_HEIGHT*2;
  728. Rectangle buttonRec = { statusBar.x + statusBar.width - GuiGetStyle(DEFAULT, BORDER_WIDTH) - WINDOW_CLOSE_BUTTON_PADDING - 20,
  729. statusBar.y + GuiGetStyle(DEFAULT, BORDER_WIDTH) + WINDOW_CLOSE_BUTTON_PADDING, 18, 18 };
  730. // Update control
  731. //--------------------------------------------------------------------
  732. // NOTE: Logic is directly managed by button
  733. //--------------------------------------------------------------------
  734. // Draw control
  735. //--------------------------------------------------------------------
  736. // Draw window base
  737. DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(DEFAULT, BORDER + (state*3))), guiAlpha));
  738. DrawRectangleRec(RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH),
  739. bounds.width - GuiGetStyle(DEFAULT, BORDER_WIDTH)*2, bounds.height - GuiGetStyle(DEFAULT, BORDER_WIDTH)*2 },
  740. Fade(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)), guiAlpha));
  741. // Draw window header as status bar
  742. int defaultPadding = GuiGetStyle(DEFAULT, INNER_PADDING);
  743. int defaultTextAlign = GuiGetStyle(DEFAULT, TEXT_ALIGNMENT);
  744. GuiSetStyle(DEFAULT, INNER_PADDING, 8);
  745. GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT);
  746. GuiStatusBar(statusBar, text);
  747. GuiSetStyle(DEFAULT, INNER_PADDING, defaultPadding);
  748. GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, defaultTextAlign);
  749. // Draw window close button
  750. int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
  751. int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
  752. GuiSetStyle(BUTTON, BORDER_WIDTH, 1);
  753. GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
  754. #if defined(RAYGUI_RICONS_SUPPORT)
  755. clicked = GuiButton(buttonRec, GuiIconText(RICON_CROSS_SMALL, NULL));
  756. #else
  757. clicked = GuiButton(buttonRec, "x");
  758. #endif
  759. GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
  760. GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment);
  761. //--------------------------------------------------------------------
  762. return clicked;
  763. }
  764. // Group Box control with title name
  765. RAYGUIDEF void GuiGroupBox(Rectangle bounds, const char *text)
  766. {
  767. #define GROUPBOX_LINE_THICK 1
  768. #define GROUPBOX_TEXT_PADDING 10
  769. #define GROUPBOX_PADDING 2
  770. GuiControlState state = guiState;
  771. // Draw control
  772. //--------------------------------------------------------------------
  773. DrawRectangle(bounds.x, bounds.y, GROUPBOX_LINE_THICK, bounds.height, Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)), guiAlpha));
  774. 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));
  775. 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));
  776. GuiLine(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, bounds.width, 1 }, text);
  777. //--------------------------------------------------------------------
  778. }
  779. // Line control
  780. RAYGUIDEF void GuiLine(Rectangle bounds, const char *text)
  781. {
  782. #define LINE_THICK 1
  783. #define LINE_TEXT_PADDING 10
  784. #define LINE_TEXT_SPACING 2
  785. GuiControlState state = guiState;
  786. Color color = Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)), guiAlpha);
  787. // Draw control
  788. //--------------------------------------------------------------------
  789. if (text == NULL) DrawRectangle(bounds.x, bounds.y + bounds.height/2, bounds.width, 1, color);
  790. else
  791. {
  792. Rectangle textBounds = { 0 };
  793. textBounds.width = GetTextWidth(text) + 2*LINE_TEXT_SPACING; // TODO: Consider text icon
  794. textBounds.height = GuiGetStyle(DEFAULT, TEXT_SIZE);
  795. textBounds.x = bounds.x + LINE_TEXT_PADDING + LINE_TEXT_SPACING;
  796. textBounds.y = bounds.y - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
  797. // Draw line with embedded text label: "--- text --------------"
  798. DrawRectangle(bounds.x, bounds.y, LINE_TEXT_PADDING, 1, color);
  799. GuiLabel(textBounds, text);
  800. 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);
  801. }
  802. //--------------------------------------------------------------------
  803. }
  804. // Panel control
  805. RAYGUIDEF void GuiPanel(Rectangle bounds)
  806. {
  807. #define PANEL_BORDER_WIDTH 1
  808. GuiControlState state = guiState;
  809. // Draw control
  810. //--------------------------------------------------------------------
  811. DrawRectangleRec(bounds, Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BASE_COLOR_DISABLED : BACKGROUND_COLOR)), guiAlpha));
  812. DrawRectangleLinesEx(bounds, PANEL_BORDER_WIDTH, Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BORDER_COLOR_DISABLED: LINE_COLOR)), guiAlpha));
  813. //--------------------------------------------------------------------
  814. }
  815. // Scroll Panel control
  816. RAYGUIDEF Rectangle GuiScrollPanel(Rectangle bounds, Rectangle content, Vector2 *scroll)
  817. {
  818. GuiControlState state = guiState;
  819. Vector2 scrollPos = { 0.0f, 0.0f };
  820. if (scroll != NULL) scrollPos = *scroll;
  821. bool hasHorizontalScrollBar = (content.width > bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false;
  822. bool hasVerticalScrollBar = (content.height > bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false;
  823. // Recheck to account for the other scrollbar being visible
  824. if (!hasHorizontalScrollBar) hasHorizontalScrollBar = (hasVerticalScrollBar && (content.width > (bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false;
  825. if (!hasVerticalScrollBar) hasVerticalScrollBar = (hasHorizontalScrollBar && (content.height > (bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false;
  826. const int horizontalScrollBarWidth = hasHorizontalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0;
  827. const int verticalScrollBarWidth = hasVerticalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0;
  828. const Rectangle horizontalScrollBar = { (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE) ? (float)bounds.x + verticalScrollBarWidth : (float)bounds.x) + GuiGetStyle(DEFAULT, BORDER_WIDTH), (float)bounds.y + bounds.height - horizontalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH), (float)bounds.width - verticalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH), (float)horizontalScrollBarWidth };
  829. const Rectangle verticalScrollBar = { (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE) ? (float)bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)bounds.x + bounds.width - verticalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH)), (float)bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), (float)verticalScrollBarWidth, (float)bounds.height - horizontalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) };
  830. // Calculate view area (area without the scrollbars)
  831. Rectangle view = (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)?
  832. RAYGUI_CLITERAL(Rectangle){ bounds.x + verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth, bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth } :
  833. RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth, bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth };
  834. // Clip view area to the actual content size
  835. if (view.width > content.width) view.width = content.width;
  836. if (view.height > content.height) view.height = content.height;
  837. // TODO: Review!
  838. 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);
  839. 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);
  840. const int verticalMin = hasVerticalScrollBar? -GuiGetStyle(DEFAULT, BORDER_WIDTH) : -GuiGetStyle(DEFAULT, BORDER_WIDTH);
  841. const int verticalMax = hasVerticalScrollBar? content.height - bounds.height + horizontalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH) : -GuiGetStyle(DEFAULT, BORDER_WIDTH);
  842. // Update control
  843. //--------------------------------------------------------------------
  844. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  845. {
  846. Vector2 mousePoint = GetMousePosition();
  847. // Check button state
  848. if (CheckCollisionPointRec(mousePoint, bounds))
  849. {
  850. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
  851. else state = GUI_STATE_FOCUSED;
  852. if (hasHorizontalScrollBar)
  853. {
  854. if (IsKeyDown(KEY_RIGHT)) scrollPos.x -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
  855. if (IsKeyDown(KEY_LEFT)) scrollPos.x += GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
  856. }
  857. if (hasVerticalScrollBar)
  858. {
  859. if (IsKeyDown(KEY_DOWN)) scrollPos.y -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
  860. if (IsKeyDown(KEY_UP)) scrollPos.y += GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
  861. }
  862. scrollPos.y += GetMouseWheelMove()*20;
  863. }
  864. }
  865. // Normalize scroll values
  866. if (scrollPos.x > -horizontalMin) scrollPos.x = -horizontalMin;
  867. if (scrollPos.x < -horizontalMax) scrollPos.x = -horizontalMax;
  868. if (scrollPos.y > -verticalMin) scrollPos.y = -verticalMin;
  869. if (scrollPos.y < -verticalMax) scrollPos.y = -verticalMax;
  870. //--------------------------------------------------------------------
  871. // Draw control
  872. //--------------------------------------------------------------------
  873. DrawRectangleRec(bounds, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background
  874. // Save size of the scrollbar slider
  875. const int slider = GuiGetStyle(SCROLLBAR, SLIDER_SIZE);
  876. // Draw horizontal scrollbar if visible
  877. if (hasHorizontalScrollBar)
  878. {
  879. // Change scrollbar slider size to show the diff in size between the content width and the widget width
  880. GuiSetStyle(SCROLLBAR, SLIDER_SIZE, ((bounds.width - 2 * GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth)/content.width)*(bounds.width - 2 * GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth));
  881. scrollPos.x = -GuiScrollBar(horizontalScrollBar, -scrollPos.x, horizontalMin, horizontalMax);
  882. }
  883. // Draw vertical scrollbar if visible
  884. if (hasVerticalScrollBar)
  885. {
  886. // Change scrollbar slider size to show the diff in size between the content height and the widget height
  887. GuiSetStyle(SCROLLBAR, SLIDER_SIZE, ((bounds.height - 2 * GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth)/content.height)* (bounds.height - 2 * GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth));
  888. scrollPos.y = -GuiScrollBar(verticalScrollBar, -scrollPos.y, verticalMin, verticalMax);
  889. }
  890. // Draw detail corner rectangle if both scroll bars are visible
  891. if (hasHorizontalScrollBar && hasVerticalScrollBar)
  892. {
  893. // TODO: Consider scroll bars side
  894. DrawRectangle(horizontalScrollBar.x + horizontalScrollBar.width + 2,
  895. verticalScrollBar.y + verticalScrollBar.height + 2,
  896. horizontalScrollBarWidth - 4, verticalScrollBarWidth - 4,
  897. Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT + (state * 3))), guiAlpha));
  898. }
  899. // Set scrollbar slider size back to the way it was before
  900. GuiSetStyle(SCROLLBAR, SLIDER_SIZE, slider);
  901. // Draw scrollbar lines depending on current state
  902. DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, (float)BORDER + (state*3))), guiAlpha));
  903. //--------------------------------------------------------------------
  904. if (scroll != NULL) *scroll = scrollPos;
  905. return view;
  906. }
  907. // Label control
  908. RAYGUIDEF void GuiLabel(Rectangle bounds, const char *text)
  909. {
  910. GuiControlState state = guiState;
  911. // Update control
  912. //--------------------------------------------------------------------
  913. // ...
  914. //--------------------------------------------------------------------
  915. // Draw control
  916. //--------------------------------------------------------------------
  917. GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LABEL, (state == GUI_STATE_DISABLED)? TEXT_COLOR_DISABLED : TEXT_COLOR_NORMAL)), guiAlpha));
  918. //--------------------------------------------------------------------
  919. }
  920. // Button control, returns true when clicked
  921. RAYGUIDEF bool GuiButton(Rectangle bounds, const char *text)
  922. {
  923. GuiControlState state = guiState;
  924. bool pressed = false;
  925. // Update control
  926. //--------------------------------------------------------------------
  927. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  928. {
  929. Vector2 mousePoint = GetMousePosition();
  930. // Check button state
  931. if (CheckCollisionPointRec(mousePoint, bounds))
  932. {
  933. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
  934. else state = GUI_STATE_FOCUSED;
  935. if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true;
  936. }
  937. }
  938. //--------------------------------------------------------------------
  939. // Draw control
  940. //--------------------------------------------------------------------
  941. DrawRectangleLinesEx(bounds, GuiGetStyle(BUTTON, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(BUTTON, BORDER + (state*3))), guiAlpha));
  942. 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));
  943. GuiDrawText(text, GetTextBounds(BUTTON, bounds), GuiGetStyle(BUTTON, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(BUTTON, TEXT + (state*3))), guiAlpha));
  944. //------------------------------------------------------------------
  945. return pressed;
  946. }
  947. // Label button control
  948. RAYGUIDEF bool GuiLabelButton(Rectangle bounds, const char *text)
  949. {
  950. GuiControlState state = guiState;
  951. bool pressed = false;
  952. // Update control
  953. //--------------------------------------------------------------------
  954. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  955. {
  956. Vector2 mousePoint = GetMousePosition();
  957. // Check checkbox state
  958. if (CheckCollisionPointRec(mousePoint, bounds))
  959. {
  960. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
  961. else state = GUI_STATE_FOCUSED;
  962. if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true;
  963. }
  964. }
  965. //--------------------------------------------------------------------
  966. // Draw control
  967. //--------------------------------------------------------------------
  968. GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha));
  969. //--------------------------------------------------------------------
  970. return pressed;
  971. }
  972. // Image button control, returns true when clicked
  973. RAYGUIDEF bool GuiImageButton(Rectangle bounds, Texture2D texture)
  974. {
  975. return GuiImageButtonEx(bounds, texture, RAYGUI_CLITERAL(Rectangle){ 0, 0, (float)texture.width, (float)texture.height }, NULL);
  976. }
  977. // Image button control, returns true when clicked
  978. RAYGUIDEF bool GuiImageButtonEx(Rectangle bounds, Texture2D texture, Rectangle texSource, const char *text)
  979. {
  980. GuiControlState state = guiState;
  981. bool clicked = false;
  982. // Update control
  983. //--------------------------------------------------------------------
  984. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  985. {
  986. Vector2 mousePoint = GetMousePosition();
  987. // Check button state
  988. if (CheckCollisionPointRec(mousePoint, bounds))
  989. {
  990. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
  991. else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) clicked = true;
  992. else state = GUI_STATE_FOCUSED;
  993. }
  994. }
  995. //--------------------------------------------------------------------
  996. // Draw control
  997. //--------------------------------------------------------------------
  998. DrawRectangleLinesEx(bounds, GuiGetStyle(BUTTON, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(BUTTON, BORDER + (state*3))), guiAlpha));
  999. 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));
  1000. if (text != NULL) GuiDrawText(text, GetTextBounds(BUTTON, bounds), GuiGetStyle(BUTTON, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(BUTTON, TEXT + (state*3))), guiAlpha));
  1001. if (texture.id > 0) DrawTextureRec(texture, texSource, RAYGUI_CLITERAL(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));
  1002. //------------------------------------------------------------------
  1003. return clicked;
  1004. }
  1005. // Toggle Button control, returns true when active
  1006. RAYGUIDEF bool GuiToggle(Rectangle bounds, const char *text, bool active)
  1007. {
  1008. GuiControlState state = guiState;
  1009. // Update control
  1010. //--------------------------------------------------------------------
  1011. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  1012. {
  1013. Vector2 mousePoint = GetMousePosition();
  1014. // Check toggle button state
  1015. if (CheckCollisionPointRec(mousePoint, bounds))
  1016. {
  1017. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
  1018. else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
  1019. {
  1020. state = GUI_STATE_NORMAL;
  1021. active = !active;
  1022. }
  1023. else state = GUI_STATE_FOCUSED;
  1024. }
  1025. }
  1026. //--------------------------------------------------------------------
  1027. // Draw control
  1028. //--------------------------------------------------------------------
  1029. if (state == GUI_STATE_NORMAL)
  1030. {
  1031. DrawRectangleLinesEx(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TOGGLE, (active? BORDER_COLOR_PRESSED : (BORDER + state*3)))), guiAlpha));
  1032. 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));
  1033. GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TOGGLE, (active? TEXT_COLOR_PRESSED : (TEXT + state*3)))), guiAlpha));
  1034. }
  1035. else
  1036. {
  1037. DrawRectangleLinesEx(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TOGGLE, BORDER + state*3)), guiAlpha));
  1038. 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));
  1039. GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TOGGLE, TEXT + state*3)), guiAlpha));
  1040. }
  1041. //--------------------------------------------------------------------
  1042. return active;
  1043. }
  1044. // Toggle Group control, returns toggled button index
  1045. RAYGUIDEF int GuiToggleGroup(Rectangle bounds, const char *text, int active)
  1046. {
  1047. float initBoundsX = bounds.x;
  1048. // Get substrings elements from text (elements pointers)
  1049. int rows[64] = { 0 };
  1050. int elementsCount = 0;
  1051. const char **elementsPtrs = GuiTextSplit(text, &elementsCount, rows);
  1052. int prevRow = rows[0];
  1053. for (int i = 0; i < elementsCount; i++)
  1054. {
  1055. if (prevRow != rows[i])
  1056. {
  1057. bounds.x = initBoundsX;
  1058. bounds.y += (bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING));
  1059. prevRow = rows[i];
  1060. }
  1061. if (i == active) GuiToggle(bounds, elementsPtrs[i], true);
  1062. else if (GuiToggle(bounds, elementsPtrs[i], false) == true) active = i;
  1063. bounds.x += (bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING));
  1064. }
  1065. return active;
  1066. }
  1067. // Check Box control, returns true when active
  1068. RAYGUIDEF bool GuiCheckBox(Rectangle bounds, const char *text, bool checked)
  1069. {
  1070. GuiControlState state = guiState;
  1071. Rectangle textBounds = { 0 };
  1072. textBounds.x = bounds.x + bounds.width + GuiGetStyle(CHECKBOX, CHECK_TEXT_PADDING);
  1073. textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
  1074. textBounds.width = GetTextWidth(text); // TODO: Consider text icon
  1075. textBounds.height = GuiGetStyle(DEFAULT, TEXT_SIZE);
  1076. // Update control
  1077. //--------------------------------------------------------------------
  1078. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  1079. {
  1080. Vector2 mousePoint = GetMousePosition();
  1081. // Check checkbox state
  1082. if (CheckCollisionPointRec(mousePoint, RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, bounds.width + textBounds.width + GuiGetStyle(CHECKBOX, CHECK_TEXT_PADDING), bounds.height }))
  1083. {
  1084. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
  1085. else state = GUI_STATE_FOCUSED;
  1086. if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) checked = !checked;
  1087. }
  1088. }
  1089. //--------------------------------------------------------------------
  1090. // Draw control
  1091. //--------------------------------------------------------------------
  1092. DrawRectangleLinesEx(bounds, GuiGetStyle(CHECKBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(CHECKBOX, BORDER + (state*3))), guiAlpha));
  1093. if (checked) DrawRectangle(bounds.x + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, INNER_PADDING),
  1094. bounds.y + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, INNER_PADDING),
  1095. bounds.width - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, INNER_PADDING)),
  1096. bounds.height - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, INNER_PADDING)),
  1097. Fade(GetColor(GuiGetStyle(CHECKBOX, TEXT + state*3)), guiAlpha));
  1098. // NOTE: Forced left text alignment
  1099. GuiDrawText(text, textBounds, GUI_TEXT_ALIGN_LEFT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha));
  1100. //--------------------------------------------------------------------
  1101. return checked;
  1102. }
  1103. // Combo Box control, returns selected item index
  1104. RAYGUIDEF int GuiComboBox(Rectangle bounds, const char *text, int active)
  1105. {
  1106. GuiControlState state = guiState;
  1107. bounds.width -= (GuiGetStyle(COMBOBOX, SELECTOR_WIDTH) + GuiGetStyle(COMBOBOX, SELECTOR_PADDING));
  1108. Rectangle selector = { (float)bounds.x + bounds.width + GuiGetStyle(COMBOBOX, SELECTOR_PADDING),
  1109. (float)bounds.y, (float)GuiGetStyle(COMBOBOX, SELECTOR_WIDTH), (float)bounds.height };
  1110. // Get substrings elements from text (elements pointers, lengths and count)
  1111. int elementsCount = 0;
  1112. const char **elementsPtrs = GuiTextSplit(text, &elementsCount, NULL);
  1113. if (active < 0) active = 0;
  1114. else if (active > elementsCount - 1) active = elementsCount - 1;
  1115. // Update control
  1116. //--------------------------------------------------------------------
  1117. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  1118. {
  1119. Vector2 mousePoint = GetMousePosition();
  1120. if (CheckCollisionPointRec(mousePoint, bounds) ||
  1121. CheckCollisionPointRec(mousePoint, selector))
  1122. {
  1123. if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
  1124. {
  1125. active += 1;
  1126. if (active >= elementsCount) active = 0;
  1127. }
  1128. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
  1129. else state = GUI_STATE_FOCUSED;
  1130. }
  1131. }
  1132. //--------------------------------------------------------------------
  1133. // Draw control
  1134. //--------------------------------------------------------------------
  1135. // Draw combo box main
  1136. DrawRectangleLinesEx(bounds, GuiGetStyle(COMBOBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(COMBOBOX, BORDER + (state*3))), guiAlpha));
  1137. 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));
  1138. GuiDrawText(elementsPtrs[active], GetTextBounds(COMBOBOX, bounds), GuiGetStyle(COMBOBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(COMBOBOX, TEXT + (state*3))), guiAlpha));
  1139. // Draw selector using a custom button
  1140. // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values
  1141. int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
  1142. int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
  1143. GuiSetStyle(BUTTON, BORDER_WIDTH, 1);
  1144. GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
  1145. GuiButton(selector, TextFormat("%i/%i", active + 1, elementsCount));
  1146. GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign);
  1147. GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
  1148. //--------------------------------------------------------------------
  1149. return active;
  1150. }
  1151. // Dropdown Box control, returns selected item
  1152. RAYGUIDEF bool GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode)
  1153. {
  1154. GuiControlState state = guiState;
  1155. // Get substrings elements from text (elements pointers, lengths and count)
  1156. int elementsCount = 0;
  1157. const char **elementsPtrs = GuiTextSplit(text, &elementsCount, NULL);
  1158. bool pressed = false;
  1159. int auxActive = *active;
  1160. Rectangle closeBounds = bounds;
  1161. Rectangle openBounds = bounds;
  1162. openBounds.height *= (elementsCount + 1);
  1163. // Update control
  1164. //--------------------------------------------------------------------
  1165. if (guiLocked && editMode) guiLocked = false;
  1166. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  1167. {
  1168. Vector2 mousePoint = GetMousePosition();
  1169. if (editMode) state = GUI_STATE_PRESSED;
  1170. if (!editMode)
  1171. {
  1172. if (CheckCollisionPointRec(mousePoint, closeBounds))
  1173. {
  1174. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
  1175. if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
  1176. else state = GUI_STATE_FOCUSED;
  1177. }
  1178. }
  1179. else
  1180. {
  1181. if (CheckCollisionPointRec(mousePoint, closeBounds))
  1182. {
  1183. if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true;
  1184. }
  1185. else if (!CheckCollisionPointRec(mousePoint, openBounds))
  1186. {
  1187. if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true;
  1188. }
  1189. }
  1190. }
  1191. //--------------------------------------------------------------------
  1192. // Draw control
  1193. //--------------------------------------------------------------------
  1194. // TODO: Review this ugly hack... DROPDOWNBOX depends on GuiListElement() that uses DEFAULT_TEXT_ALIGNMENT
  1195. int tempTextAlign = GuiGetStyle(DEFAULT, TEXT_ALIGNMENT);
  1196. GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT));
  1197. switch (state)
  1198. {
  1199. case GUI_STATE_NORMAL:
  1200. {
  1201. DrawRectangle(bounds.x, bounds.y, bounds.width, bounds.height, Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_NORMAL)), guiAlpha));
  1202. DrawRectangleLinesEx(bounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_NORMAL)), guiAlpha));
  1203. GuiListElement(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, bounds.width, bounds.height }, elementsPtrs[auxActive], false, false);
  1204. } break;
  1205. case GUI_STATE_FOCUSED:
  1206. {
  1207. GuiListElement(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, bounds.width, bounds.height }, elementsPtrs[auxActive], false, editMode);
  1208. } break;
  1209. case GUI_STATE_PRESSED:
  1210. {
  1211. if (!editMode) GuiListElement(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, bounds.width, bounds.height }, elementsPtrs[auxActive], true, true);
  1212. if (editMode)
  1213. {
  1214. GuiPanel(openBounds);
  1215. GuiListElement(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, bounds.width, bounds.height }, elementsPtrs[auxActive], true, true);
  1216. for (int i = 0; i < elementsCount; i++)
  1217. {
  1218. if (i == auxActive && editMode)
  1219. {
  1220. if (GuiListElement(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height*(i + 1) + GuiGetStyle(DROPDOWNBOX, INNER_PADDING),
  1221. bounds.width, bounds.height - GuiGetStyle(DROPDOWNBOX, INNER_PADDING) },
  1222. elementsPtrs[i], true, true) == false) pressed = true;
  1223. }
  1224. else
  1225. {
  1226. if (GuiListElement(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height*(i+1) + GuiGetStyle(DROPDOWNBOX, INNER_PADDING),
  1227. bounds.width, bounds.height - GuiGetStyle(DROPDOWNBOX, INNER_PADDING) },
  1228. elementsPtrs[i], false, true))
  1229. {
  1230. auxActive = i;
  1231. pressed = true;
  1232. }
  1233. }
  1234. }
  1235. }
  1236. } break;
  1237. case GUI_STATE_DISABLED:
  1238. {
  1239. DrawRectangle(bounds.x, bounds.y, bounds.width, bounds.height, Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_DISABLED)), guiAlpha));
  1240. DrawRectangleLinesEx(bounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_DISABLED)), guiAlpha));
  1241. GuiListElement(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, bounds.width, bounds.height }, elementsPtrs[auxActive], false, false);
  1242. } break;
  1243. default: break;
  1244. }
  1245. GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, tempTextAlign);
  1246. // TODO: Avoid this function, use icon instead or 'v'
  1247. DrawTriangle(RAYGUI_CLITERAL(Vector2){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_RIGHT_PADDING), bounds.y + bounds.height/2 - 2 },
  1248. RAYGUI_CLITERAL(Vector2){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_RIGHT_PADDING) + 5, bounds.y + bounds.height/2 - 2 + 5 },
  1249. RAYGUI_CLITERAL(Vector2){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_RIGHT_PADDING) + 10, bounds.y + bounds.height/2 - 2 },
  1250. Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))), guiAlpha));
  1251. //GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_RIGHT_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 },
  1252. // GUI_TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))), guiAlpha));
  1253. //--------------------------------------------------------------------
  1254. *active = auxActive;
  1255. return pressed;
  1256. }
  1257. #if defined(RAYGUI_TEXTBOX_EXTENDED)
  1258. // Spinner control, returns selected value
  1259. // NOTE: Requires static variables: timer, valueSpeed - ERROR!
  1260. RAYGUIDEF bool GuiSpinner(Rectangle bounds, int *value, int minValue, int maxValue, bool editMode)
  1261. {
  1262. #define GUI_SPINNER_HOLD_SPEED 0.2f // Min 200ms delay
  1263. static float timer = 0.0f;
  1264. int tempValue = *value;
  1265. const float time = GetTime(); // Get current time
  1266. bool pressed = false, active = GuiTextBoxIsActive(bounds);
  1267. Rectangle spinner = { bounds.x + GuiGetStyle(SPINNER, SELECT_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SELECT_BUTTON_PADDING), bounds.y,
  1268. bounds.width - 2*(GuiGetStyle(SPINNER, SELECT_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SELECT_BUTTON_PADDING)), bounds.height };
  1269. Rectangle leftButtonBound = { bounds.x, bounds.y, GuiGetStyle(SPINNER, SELECT_BUTTON_WIDTH), bounds.height };
  1270. Rectangle rightButtonBound = { bounds.x + bounds.width - GuiGetStyle(SPINNER, SELECT_BUTTON_WIDTH), bounds.y, GuiGetStyle(SPINNER, SELECT_BUTTON_WIDTH), bounds.height };
  1271. // Update control
  1272. //--------------------------------------------------------------------
  1273. Vector2 mouse = GetMousePosition();
  1274. if (tempValue < minValue) tempValue = minValue;
  1275. if (tempValue > maxValue) tempValue = maxValue;
  1276. if (editMode)
  1277. {
  1278. if (!active)
  1279. {
  1280. // This becomes the active textbox when mouse is pressed or held inside bounds
  1281. if ((IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsMouseButtonDown(MOUSE_LEFT_BUTTON)) &&
  1282. CheckCollisionPointRec(mouse, bounds))
  1283. {
  1284. GuiTextBoxSetActive(bounds);
  1285. active = true;
  1286. }
  1287. }
  1288. }
  1289. // Reset timer when one of the buttons is clicked (without this, holding the button down will not behave correctly)
  1290. if ((CheckCollisionPointRec(mouse, leftButtonBound) || CheckCollisionPointRec(mouse, rightButtonBound)) &&
  1291. IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
  1292. {
  1293. timer = time;
  1294. }
  1295. //--------------------------------------------------------------------
  1296. // Draw control
  1297. //--------------------------------------------------------------------
  1298. if (GuiTextBoxIsActive(bounds)) guiTextBoxActive = spinner; // Set our spinner as the active textbox
  1299. pressed = GuiValueBox(spinner, &tempValue, minValue, maxValue, editMode);
  1300. if (GuiTextBoxIsActive(spinner)) guiTextBoxActive = bounds; // Revert change
  1301. // Draw value selector custom buttons
  1302. // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values
  1303. int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
  1304. GuiSetStyle(BUTTON, BORDER_WIDTH, GuiGetStyle(SPINNER, BORDER_WIDTH));
  1305. int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
  1306. GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
  1307. char *icon = "<";
  1308. #if defined(RAYGUI_RICONS_SUPPORT)
  1309. icon = (char *)GuiIconText(RICON_ARROW_LEFT_FILL, NULL);
  1310. #endif
  1311. if (GuiButton(leftButtonBound, icon) || // NOTE: also decrease value when the button is held down
  1312. (IsMouseButtonDown(MOUSE_LEFT_BUTTON) &&
  1313. CheckCollisionPointRec(mouse, leftButtonBound) &&
  1314. (time - timer) > GUI_SPINNER_HOLD_SPEED))
  1315. {
  1316. tempValue--;
  1317. }
  1318. icon = ">";
  1319. #if defined(RAYGUI_RICONS_SUPPORT)
  1320. icon = (char *)GuiIconText(RICON_ARROW_RIGHT_FILL, NULL);
  1321. #endif
  1322. if (GuiButton(rightButtonBound, icon) || // NOTE: also increase value when the button is held down
  1323. (IsMouseButtonDown(MOUSE_LEFT_BUTTON) &&
  1324. CheckCollisionPointRec(mouse, rightButtonBound) &&
  1325. (time - timer) > GUI_SPINNER_HOLD_SPEED))
  1326. {
  1327. tempValue++;
  1328. }
  1329. GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign);
  1330. GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
  1331. //--------------------------------------------------------------------
  1332. if (tempValue < minValue) tempValue = minValue;
  1333. if (tempValue > maxValue) tempValue = maxValue;
  1334. // Reset timer
  1335. if (active && (((time - timer) > GUI_SPINNER_HOLD_SPEED) || (timer == 0.0f) || (timer > time))) timer = time;
  1336. *value = tempValue;
  1337. return pressed;
  1338. }
  1339. // Value Box control, updates input text with numbers
  1340. RAYGUIDEF bool GuiValueBox(Rectangle bounds, int *value, int minValue, int maxValue, bool editMode)
  1341. {
  1342. #define VALUEBOX_MAX_CHARS 32
  1343. char text[VALUEBOX_MAX_CHARS + 1] = { 0 };
  1344. sprintf(text, "%i", *value);
  1345. bool pressed = GuiTextBox(bounds, text, VALUEBOX_MAX_CHARS, editMode);
  1346. *value = atoi(text);
  1347. if (*value > maxValue) *value = maxValue;
  1348. else if (*value < minValue) *value = minValue;
  1349. return pressed;
  1350. }
  1351. enum {
  1352. GUI_MEASURE_MODE_CURSOR_END = 0xA,
  1353. GUI_MEASURE_MODE_CURSOR_POS,
  1354. GUI_MEASURE_MODE_CURSOR_COORDS,
  1355. };
  1356. // Required by GuiTextBox()
  1357. // Highly synchronized with calculations in DrawTextRecEx()
  1358. static int GuiMeasureTextBox(const char *text, int length, Rectangle rec, int *pos, int mode)
  1359. {
  1360. // Get gui font properties
  1361. const Font font = guiFont;
  1362. const float fontSize = GuiGetStyle(DEFAULT, TEXT_SIZE);
  1363. const float spacing = GuiGetStyle(DEFAULT, TEXT_SPACING);
  1364. int textOffsetX = 0; // Offset between characters
  1365. float scaleFactor = 0.0f;
  1366. int letter = 0; // Current character
  1367. int index = 0; // Index position in sprite font
  1368. scaleFactor = fontSize/font.baseSize;
  1369. int i = 0, k = 0;
  1370. int glyphWidth = 0;
  1371. for (i = 0; i < length; i++, k++)
  1372. {
  1373. glyphWidth = 0;
  1374. int next = 1;
  1375. letter = GetNextCodepoint(&text[i], &next);
  1376. if (letter == 0x3f) next = 1;
  1377. index = GetGlyphIndex(font, letter);
  1378. i += next - 1;
  1379. if (letter != '\n')
  1380. {
  1381. glyphWidth = (font.chars[index].advanceX == 0)?
  1382. (int)(font.chars[index].rec.width*scaleFactor + spacing):
  1383. (int)(font.chars[index].advanceX*scaleFactor + spacing);
  1384. if ((textOffsetX + glyphWidth + 1) >= rec.width) break;
  1385. if ((mode == GUI_MEASURE_MODE_CURSOR_POS) && (*pos == k)) break;
  1386. else if (mode == GUI_MEASURE_MODE_CURSOR_COORDS)
  1387. {
  1388. // Check if the mouse pointer is inside the glyph rect
  1389. Rectangle grec = {rec.x + textOffsetX - 1, rec.y, glyphWidth, (font.baseSize + font.baseSize/2)*scaleFactor - 1 };
  1390. Vector2 mouse = GetMousePosition();
  1391. if (CheckCollisionPointRec(mouse, grec))
  1392. {
  1393. // Smooth selection by dividing the glyph rectangle into 2 equal parts and checking where the mouse resides
  1394. if (mouse.x > (grec.x + glyphWidth/2))
  1395. {
  1396. textOffsetX += glyphWidth;
  1397. k++;
  1398. }
  1399. break;
  1400. }
  1401. }
  1402. }
  1403. else break;
  1404. textOffsetX += glyphWidth;
  1405. }
  1406. *pos = k;
  1407. return (rec.x + textOffsetX - 1);
  1408. }
  1409. static int GetPrevCodepoint(const char *text, const char *start, int *prev)
  1410. {
  1411. int c = 0x3f;
  1412. char *p = (char *)text;
  1413. *prev = 1;
  1414. for (int i = 0; (p >= start) && (i < 4); p--, i++)
  1415. {
  1416. if ((((unsigned char)*p) >> 6) != 2)
  1417. {
  1418. c = GetNextCodepoint(p, prev);
  1419. break;
  1420. }
  1421. }
  1422. return c;
  1423. }
  1424. // Required by GuiTextBoxEx()
  1425. // Highly synchronized with calculations in DrawTextRecEx()
  1426. static int GuiMeasureTextBoxRev(const char *text, int length, Rectangle rec, int *pos)
  1427. {
  1428. // Get gui font properties
  1429. const Font font = guiFont;
  1430. const float fontSize = GuiGetStyle(DEFAULT, TEXT_SIZE);
  1431. const float spacing = GuiGetStyle(DEFAULT, TEXT_SPACING);
  1432. int textOffsetX = 0; // Offset between characters
  1433. float scaleFactor = 0.0f;
  1434. int letter = 0; // Current character
  1435. int index = 0; // Index position in sprite font
  1436. scaleFactor = fontSize/font.baseSize;
  1437. int i = 0, k = 0;
  1438. int glyphWidth = 0, prev = 1;
  1439. for (i = length; i >= 0; i--, k++)
  1440. {
  1441. glyphWidth = 0;
  1442. letter = GetPrevCodepoint(&text[i], &text[0], &prev);
  1443. if (letter == 0x3f) prev = 1;
  1444. index = GetGlyphIndex(font, letter);
  1445. i -= prev - 1;
  1446. if (letter != '\n')
  1447. {
  1448. glyphWidth = (font.chars[index].advanceX == 0)?
  1449. (int)(font.chars[index].rec.width*scaleFactor + spacing):
  1450. (int)(font.chars[index].advanceX*scaleFactor + spacing);
  1451. if ((textOffsetX + glyphWidth + 1) >= rec.width) break;
  1452. }
  1453. else break;
  1454. textOffsetX += glyphWidth;
  1455. }
  1456. *pos = k;
  1457. return (i + prev);
  1458. }
  1459. // Calculate cursor coordinates based on the cursor position `pos` inside the `text`.
  1460. static inline int GuiTextBoxGetCursorCoordinates(const char *text, int length, Rectangle rec, int pos)
  1461. {
  1462. return GuiMeasureTextBox(text, length, rec, &pos, GUI_MEASURE_MODE_CURSOR_POS);
  1463. }
  1464. // Calculate cursor position in textbox based on mouse coordinates.
  1465. static inline int GuiTextBoxGetCursorFromMouse(const char *text, int length, Rectangle rec, int* pos)
  1466. {
  1467. return GuiMeasureTextBox(text, length, rec, pos, GUI_MEASURE_MODE_CURSOR_COORDS);
  1468. }
  1469. // Calculates how many characters is the textbox able to draw inside rec
  1470. static inline int GuiTextBoxMaxCharacters(const char *text, int length, Rectangle rec)
  1471. {
  1472. int pos = -1;
  1473. GuiMeasureTextBox(text, length, rec, &pos, GUI_MEASURE_MODE_CURSOR_END);
  1474. return pos;
  1475. }
  1476. // Returns total number of characters(codepoints) in a UTF8 encoded `text` until `\0` or a `\n` is found.
  1477. // NOTE: If a invalid UTF8 sequence is encountered a `?`(0x3f) codepoint is counted instead.
  1478. static inline unsigned int GuiCountCodepointsUntilNewline(const char *text)
  1479. {
  1480. unsigned int len = 0;
  1481. char *ptr = (char*)&text[0];
  1482. while ((*ptr != '\0') && (*ptr != '\n'))
  1483. {
  1484. int next = 0;
  1485. int letter = GetNextCodepoint(ptr, &next);
  1486. if (letter == 0x3f) ptr += 1;
  1487. else ptr += next;
  1488. ++len;
  1489. }
  1490. return len;
  1491. }
  1492. static inline void MoveTextBoxCursorRight(const char* text, int length, Rectangle textRec)
  1493. {
  1494. // FIXME: Counting codepoints each time we press the key is expensive, find another way
  1495. int count = GuiCountCodepointsUntilNewline(text);
  1496. if (guiTextBoxState.cursor < count ) guiTextBoxState.cursor++;
  1497. const int max = GuiTextBoxMaxCharacters(&text[guiTextBoxState.index], length - guiTextBoxState.index, textRec);
  1498. if ((guiTextBoxState.cursor - guiTextBoxState.start) > max)
  1499. {
  1500. const int cidx = GuiTextBoxGetByteIndex(text, guiTextBoxState.index, guiTextBoxState.start, guiTextBoxState.cursor);
  1501. int pos = 0;
  1502. guiTextBoxState.index = GuiMeasureTextBoxRev(text, cidx - 1, textRec, &pos);
  1503. guiTextBoxState.start = guiTextBoxState.cursor - pos;
  1504. }
  1505. }
  1506. static inline void MoveTextBoxCursorLeft(const char* text)
  1507. {
  1508. if (guiTextBoxState.cursor > 0) guiTextBoxState.cursor--;
  1509. if (guiTextBoxState.cursor < guiTextBoxState.start)
  1510. {
  1511. int prev = 0;
  1512. int letter = GetPrevCodepoint(&text[guiTextBoxState.index - 1], text, &prev);
  1513. if (letter == 0x3f) prev = 1;
  1514. guiTextBoxState.start--;
  1515. guiTextBoxState.index -= prev;
  1516. }
  1517. }
  1518. RAYGUIDEF int GuiTextBoxGetByteIndex(const char *text, int start, int from, int to)
  1519. {
  1520. int i = start, k = from;
  1521. while ((text[i] != '\0') && (k < to))
  1522. {
  1523. int j = 0;
  1524. int letter = GetNextCodepoint(&text[i], &j);
  1525. if (letter == 0x3f) j = 1;
  1526. i += j;
  1527. ++k;
  1528. }
  1529. return i;
  1530. }
  1531. RAYGUIDEF int GuiTextBoxDelete(char *text, int length, bool before)
  1532. {
  1533. if ((guiTextBoxState.cursor != -1) && (text != NULL))
  1534. {
  1535. int startIdx = 0, endIdx = 0;
  1536. if ((guiTextBoxState.select != -1) && (guiTextBoxState.select != guiTextBoxState.cursor))
  1537. {
  1538. // Delete selection
  1539. int start = guiTextBoxState.cursor;
  1540. int end = guiTextBoxState.select;
  1541. if (guiTextBoxState.cursor > guiTextBoxState.select)
  1542. {
  1543. start = guiTextBoxState.select;
  1544. end = guiTextBoxState.cursor;
  1545. }
  1546. // Convert to byte indexes
  1547. startIdx = GuiTextBoxGetByteIndex(text, 0, 0, start);
  1548. endIdx = GuiTextBoxGetByteIndex(text, 0, 0, end);
  1549. // Adjust text box state
  1550. guiTextBoxState.cursor = start; // Always set cursor to start of selection
  1551. if (guiTextBoxState.select < guiTextBoxState.start) guiTextBoxState.start = -1; // Force to recalculate on the next frame
  1552. }
  1553. else
  1554. {
  1555. if (before)
  1556. {
  1557. // Delete character before cursor
  1558. if (guiTextBoxState.cursor != 0)
  1559. {
  1560. endIdx = GuiTextBoxGetByteIndex(text, 0, 0, guiTextBoxState.cursor);
  1561. guiTextBoxState.cursor--;
  1562. startIdx = GuiTextBoxGetByteIndex(text, 0, 0, guiTextBoxState.cursor);
  1563. if (guiTextBoxState.cursor < guiTextBoxState.start) guiTextBoxState.start = -1; // Force to recalculate on the next frame
  1564. }
  1565. }
  1566. else
  1567. {
  1568. // Delete character after cursor
  1569. if (guiTextBoxState.cursor + 1 <= GuiCountCodepointsUntilNewline(text))
  1570. {
  1571. startIdx = GuiTextBoxGetByteIndex(text, 0, 0, guiTextBoxState.cursor);
  1572. endIdx = GuiTextBoxGetByteIndex(text, 0, 0, guiTextBoxState.cursor+1);
  1573. }
  1574. }
  1575. }
  1576. memmove(&text[startIdx], &text[endIdx], length - endIdx);
  1577. text[length - (endIdx - startIdx)] = '\0';
  1578. guiTextBoxState.select = -1; // Always deselect
  1579. return (endIdx - startIdx);
  1580. }
  1581. return 0;
  1582. }
  1583. RAYGUIDEF void GuiTextBoxSelectAll(const char *text)
  1584. {
  1585. guiTextBoxState.cursor = GuiCountCodepointsUntilNewline(text);
  1586. if (guiTextBoxState.cursor > 0)
  1587. {
  1588. guiTextBoxState.select = 0;
  1589. guiTextBoxState.start = -1; // Force recalculate on the next frame
  1590. }
  1591. else guiTextBoxState.select = -1;
  1592. }
  1593. RAYGUIDEF void GuiTextBoxCopy(const char *text)
  1594. {
  1595. if ((text != NULL) &&
  1596. (guiTextBoxState.select != -1) &&
  1597. (guiTextBoxState.cursor != -1) &&
  1598. (guiTextBoxState.select != guiTextBoxState.cursor))
  1599. {
  1600. int start = guiTextBoxState.cursor;
  1601. int end = guiTextBoxState.select;
  1602. if (guiTextBoxState.cursor > guiTextBoxState.select)
  1603. {
  1604. start = guiTextBoxState.select;
  1605. end = guiTextBoxState.cursor;
  1606. }
  1607. // Convert to byte indexes
  1608. start = GuiTextBoxGetByteIndex(text, 0, 0, start);
  1609. end = GuiTextBoxGetByteIndex(text, 0, 0, end);
  1610. // FIXME: `TextSubtext()` only lets use copy MAX_TEXT_BUFFER_LENGTH (1024) bytes
  1611. // maybe modify `SetClipboardText()` so we can use it only on part of a string
  1612. const char *clipText = TextSubtext(text, start, end - start);
  1613. SetClipboardText(clipText);
  1614. }
  1615. }
  1616. // Paste text from clipboard into the active textbox.
  1617. // `text` is the pointer to the buffer used by the textbox while `textSize` is the text buffer max size
  1618. RAYGUIDEF void GuiTextBoxPaste(char *text, int textSize)
  1619. {
  1620. const char *clipText = GetClipboardText(); // GLFW guaratees this should be UTF8 encoded!
  1621. int length = strlen(text);
  1622. if ((text != NULL) && (clipText != NULL) && (guiTextBoxState.cursor != -1))
  1623. {
  1624. if ((guiTextBoxState.select != -1) && (guiTextBoxState.select != guiTextBoxState.cursor))
  1625. {
  1626. // If there's a selection we'll have to delete it first
  1627. length -= GuiTextBoxDelete(text, length, true);
  1628. }
  1629. int clipLen = strlen(clipText); // We want the length in bytes
  1630. // Calculate how many bytes can we copy from clipboard text before we run out of space
  1631. int size = ((length + clipLen) <= textSize) ? clipLen : textSize - length;
  1632. // Make room by shifting to right the bytes after cursor
  1633. int startIdx = GuiTextBoxGetByteIndex(text, 0, 0, guiTextBoxState.cursor);
  1634. int endIdx = startIdx + size;
  1635. memmove(&text[endIdx], &text[startIdx], length - startIdx);
  1636. text[length + size] = '\0'; // Set the NULL char
  1637. // At long last copy the clipboard text
  1638. memcpy(&text[startIdx], clipText, size);
  1639. // Set cursor position at the end of the pasted text
  1640. guiTextBoxState.cursor = 0;
  1641. for (int i = 0; i < (startIdx + size); guiTextBoxState.cursor++)
  1642. {
  1643. int next = 0;
  1644. int letter = GetNextCodepoint(&text[i], &next);
  1645. if (letter != 0x3f) i += next;
  1646. else i += 1;
  1647. }
  1648. guiTextBoxState.start = -1; // Force to recalculate on the next frame
  1649. }
  1650. }
  1651. RAYGUIDEF void GuiTextBoxCut(char* text)
  1652. {
  1653. if ((text != NULL) &&
  1654. (guiTextBoxState.select != -1) &&
  1655. (guiTextBoxState.cursor != -1) &&
  1656. (guiTextBoxState.select != guiTextBoxState.cursor))
  1657. {
  1658. // First copy selection to clipboard;
  1659. int start = guiTextBoxState.cursor, end = guiTextBoxState.select;
  1660. if (guiTextBoxState.cursor > guiTextBoxState.select)
  1661. {
  1662. start = guiTextBoxState.select;
  1663. end = guiTextBoxState.cursor;
  1664. }
  1665. // Convert to byte indexes
  1666. int startIdx = GuiTextBoxGetByteIndex(text, 0, 0, start);
  1667. int endIdx = GuiTextBoxGetByteIndex(text, 0, 0, end);
  1668. // FIXME: `TextSubtext()` only lets use copy MAX_TEXT_BUFFER_LENGTH (1024) bytes
  1669. // maybe modify `SetClipboardText()` so we can use it only on parts of a string
  1670. const char *clipText = TextSubtext(text, startIdx, endIdx - startIdx);
  1671. SetClipboardText(clipText);
  1672. // Now delete selection (copy data over it)
  1673. int len = strlen(text);
  1674. memmove(&text[startIdx], &text[endIdx], len - endIdx);
  1675. text[len - (endIdx - startIdx)] = '\0';
  1676. // Adjust text box state
  1677. guiTextBoxState.cursor = start; // Always set cursor to start of selection
  1678. if (guiTextBoxState.select < guiTextBoxState.start) guiTextBoxState.start = -1; // Force to recalculate
  1679. guiTextBoxState.select = -1; // Deselect
  1680. }
  1681. }
  1682. static int EncodeCodepoint(unsigned int c, char out[5])
  1683. {
  1684. int len = 0;
  1685. if (c <= 0x7f)
  1686. {
  1687. out[0] = (char)c;
  1688. len = 1;
  1689. }
  1690. else if (c <= 0x7ff)
  1691. {
  1692. out[0] = (char)(((c >> 6) & 0x1f) | 0xc0);
  1693. out[1] = (char)((c & 0x3f) | 0x80);
  1694. len = 2;
  1695. }
  1696. else if (c <= 0xffff)
  1697. {
  1698. out[0] = (char)(((c >> 12) & 0x0f) | 0xe0);
  1699. out[1] = (char)(((c >> 6) & 0x3f) | 0x80);
  1700. out[2] = (char)((c & 0x3f) | 0x80);
  1701. len = 3;
  1702. }
  1703. else if (c <= 0x10ffff)
  1704. {
  1705. out[0] = (char)(((c >> 18) & 0x07) | 0xf0);
  1706. out[1] = (char)(((c >> 12) & 0x3f) | 0x80);
  1707. out[2] = (char)(((c >> 6) & 0x3f) | 0x80);
  1708. out[3] = (char)((c & 0x3f) | 0x80);
  1709. len = 4;
  1710. }
  1711. out[len] = 0;
  1712. return len;
  1713. }
  1714. // A text box control supporting text selection, cursor positioning and commonly used keyboard shortcuts.
  1715. // NOTE 1: Requires static variables: framesCounter
  1716. // NOTE 2: Returns if KEY_ENTER pressed (useful for data validation)
  1717. RAYGUIDEF bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
  1718. {
  1719. // Define the cursor movement/selection speed when movement keys are held/pressed
  1720. #define GUI_TEXTBOX_CURSOR_SPEED_MODIFIER 5
  1721. static int framesCounter = 0; // Required for blinking cursor
  1722. GuiControlState state = guiState;
  1723. bool pressed = false;
  1724. // Make sure length doesn't exceed `textSize`. `textSize` is actually the max amount of characters the textbox can handle.
  1725. int length = strlen(text);
  1726. if (length > textSize)
  1727. {
  1728. text[textSize] = '\0';
  1729. length = textSize;
  1730. }
  1731. // Make sure we have enough room to draw at least 1 character
  1732. if ((bounds.width - 2*GuiGetStyle(TEXTBOX, INNER_PADDING)) < GuiGetStyle(DEFAULT, TEXT_SIZE))
  1733. {
  1734. bounds.width = GuiGetStyle(DEFAULT, TEXT_SIZE) + 2*GuiGetStyle(TEXTBOX, INNER_PADDING);
  1735. }
  1736. // Center the text vertically
  1737. int verticalPadding = (bounds.height - 2*GuiGetStyle(TEXTBOX, BORDER_WIDTH) - GuiGetStyle(DEFAULT, TEXT_SIZE))/2;
  1738. if (verticalPadding < 0)
  1739. {
  1740. // Make sure the height is sufficient
  1741. bounds.height = 2*GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(DEFAULT, TEXT_SIZE);
  1742. verticalPadding = 0;
  1743. }
  1744. // Calculate the drawing area for the text inside the control `bounds`
  1745. Rectangle textRec = { bounds.x + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(TEXTBOX, INNER_PADDING),
  1746. bounds.y + verticalPadding + GuiGetStyle(TEXTBOX, BORDER_WIDTH),
  1747. bounds.width - 2*(GuiGetStyle(TEXTBOX, INNER_PADDING) + GuiGetStyle(TEXTBOX, BORDER_WIDTH)),
  1748. GuiGetStyle(DEFAULT, TEXT_SIZE) };
  1749. Vector2 cursorPos = { textRec.x, textRec.y }; // This holds the coordinates inside textRec of the cursor at current position and will be recalculated later
  1750. bool active = GuiTextBoxIsActive(bounds); // Check if this textbox is the global active textbox
  1751. int selStart = 0, selLength = 0, textStartIndex = 0;
  1752. // Update control
  1753. //--------------------------------------------------------------------
  1754. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  1755. {
  1756. const Vector2 mousePoint = GetMousePosition();
  1757. if (editMode)
  1758. {
  1759. // Check if we are the global active textbox
  1760. // A textbox becomes active when the user clicks it :)
  1761. if (!active)
  1762. {
  1763. if (CheckCollisionPointRec(mousePoint, bounds) &&
  1764. (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)))
  1765. {
  1766. // Hurray!!! we just became the active textbox
  1767. active = true;
  1768. GuiTextBoxSetActive(bounds);
  1769. }
  1770. }
  1771. else if (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_RIGHT_BUTTON))
  1772. {
  1773. // When active and the right mouse is clicked outside the textbox we should deactivate it
  1774. GuiTextBoxSetActive(RAYGUI_CLITERAL(Rectangle){0,0,-1,-1}); // Set a dummy rect as the active textbox bounds
  1775. active = false;
  1776. }
  1777. if (active)
  1778. {
  1779. state = GUI_STATE_PRESSED;
  1780. framesCounter++;
  1781. // Make sure state doesn't have invalid values
  1782. if (guiTextBoxState.cursor > length) guiTextBoxState.cursor = -1;
  1783. if (guiTextBoxState.select > length) guiTextBoxState.select = -1;
  1784. if (guiTextBoxState.start > length) guiTextBoxState.start = -1;
  1785. // Check textbox state for changes and recalculate if necesary
  1786. if (guiTextBoxState.cursor == -1)
  1787. {
  1788. // Set cursor to last visible character in textbox
  1789. guiTextBoxState.cursor = GuiTextBoxMaxCharacters(text, length, textRec);
  1790. }
  1791. if (guiTextBoxState.start == -1)
  1792. {
  1793. // Force recalculate text start position and text start index
  1794. // NOTE: start and index are always in sync
  1795. // start will hold the starting character position from where the text will be drawn
  1796. // while index will hold the byte index inside the text for that character
  1797. if (guiTextBoxState.cursor == 0)
  1798. {
  1799. guiTextBoxState.start = guiTextBoxState.index = 0; // No need to recalculate
  1800. }
  1801. else
  1802. {
  1803. int pos = 0;
  1804. int len = GuiTextBoxGetByteIndex(text, 0, 0, guiTextBoxState.cursor);
  1805. guiTextBoxState.index = GuiMeasureTextBoxRev(text, len, textRec, &pos);
  1806. guiTextBoxState.start = guiTextBoxState.cursor - pos + 1;
  1807. }
  1808. }
  1809. // -----------------
  1810. // HANDLE KEY INPUT
  1811. // -----------------
  1812. // * -> | LSHIFT + -> move cursor to the right | increase selection by one
  1813. // * <- | LSHIFT + <- move cursor to the left | decrease selection by one
  1814. // * HOME | LSHIFT + HOME moves cursor to start of text | selects text from cursor to start of text
  1815. // * END | LSHIFT + END move cursor to end of text | selects text from cursor until end of text
  1816. // * CTRL + A select all characters in text
  1817. // * CTRL + C copy selected text
  1818. // * CTRL + X cut selected text
  1819. // * CTRL + V remove selected text, if any, then paste clipboard data
  1820. // * DEL delete character or selection after cursor
  1821. // * BACKSPACE delete character or selection before cursor
  1822. // TODO: Add more shortcuts (insert mode, select word, moveto/select prev/next word ...)
  1823. if (IsKeyPressed(KEY_RIGHT) ||
  1824. (IsKeyDown(KEY_RIGHT) && (framesCounter%GUI_TEXTBOX_CURSOR_SPEED_MODIFIER == 0)))
  1825. {
  1826. if (IsKeyDown(KEY_LEFT_SHIFT))
  1827. {
  1828. // Selecting
  1829. if (guiTextBoxState.select == -1) guiTextBoxState.select = guiTextBoxState.cursor; // Mark selection start
  1830. MoveTextBoxCursorRight(text, length, textRec);
  1831. }
  1832. else
  1833. {
  1834. if (guiTextBoxState.select != -1 && guiTextBoxState.select != guiTextBoxState.cursor)
  1835. {
  1836. // Deselect and move cursor to end of selection
  1837. if (guiTextBoxState.cursor < guiTextBoxState.select)
  1838. {
  1839. guiTextBoxState.cursor = guiTextBoxState.select - 1;
  1840. MoveTextBoxCursorRight(text, length, textRec);
  1841. }
  1842. }
  1843. else
  1844. {
  1845. // Move cursor to the right
  1846. MoveTextBoxCursorRight(text, length, textRec);
  1847. }
  1848. guiTextBoxState.select = -1;
  1849. }
  1850. framesCounter = 0;
  1851. }
  1852. else if (IsKeyPressed(KEY_LEFT) || (IsKeyDown(KEY_LEFT) && (framesCounter%GUI_TEXTBOX_CURSOR_SPEED_MODIFIER == 0)))
  1853. {
  1854. if (IsKeyDown(KEY_LEFT_SHIFT))
  1855. {
  1856. // Selecting
  1857. if (guiTextBoxState.select == -1) guiTextBoxState.select = guiTextBoxState.cursor; // Mark selection start
  1858. MoveTextBoxCursorLeft(text);
  1859. }
  1860. else
  1861. {
  1862. if ((guiTextBoxState.select != -1) && (guiTextBoxState.select != guiTextBoxState.cursor))
  1863. {
  1864. // Deselect and move cursor to start of selection
  1865. if (guiTextBoxState.cursor > guiTextBoxState.select)
  1866. {
  1867. guiTextBoxState.cursor = guiTextBoxState.select;
  1868. if (guiTextBoxState.start > guiTextBoxState.cursor)
  1869. {
  1870. guiTextBoxState.start = guiTextBoxState.cursor;
  1871. guiTextBoxState.index = GuiTextBoxGetByteIndex(text, 0, 0, guiTextBoxState.start); // Recalculate byte index
  1872. }
  1873. }
  1874. }
  1875. else
  1876. {
  1877. // Move cursor to the left
  1878. MoveTextBoxCursorLeft(text);
  1879. }
  1880. guiTextBoxState.select = -1;
  1881. }
  1882. framesCounter = 0;
  1883. }
  1884. else if (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(KEY_BACKSPACE) && (framesCounter%GUI_TEXTBOX_CURSOR_SPEED_MODIFIER) == 0))
  1885. {
  1886. GuiTextBoxDelete(text, length, true);
  1887. }
  1888. else if (IsKeyPressed(KEY_DELETE) || (IsKeyDown(KEY_DELETE) && (framesCounter%GUI_TEXTBOX_CURSOR_SPEED_MODIFIER) == 0))
  1889. {
  1890. GuiTextBoxDelete(text, length, false);
  1891. }
  1892. else if (IsKeyPressed(KEY_HOME))
  1893. {
  1894. if (IsKeyDown(KEY_LEFT_SHIFT))
  1895. {
  1896. // Select from start of text to cursor
  1897. if ((guiTextBoxState.select > guiTextBoxState.cursor) ||
  1898. ((guiTextBoxState.select == -1) && (guiTextBoxState.cursor != 0)))
  1899. {
  1900. guiTextBoxState.select = guiTextBoxState.cursor;
  1901. }
  1902. }
  1903. else guiTextBoxState.select = -1; // Deselect everything
  1904. // Move cursor to start of text
  1905. guiTextBoxState.cursor = guiTextBoxState.start = guiTextBoxState.index = 0;
  1906. framesCounter = 0;
  1907. }
  1908. else if (IsKeyPressed(KEY_END))
  1909. {
  1910. int max = GuiCountCodepointsUntilNewline(text);
  1911. if (IsKeyDown(KEY_LEFT_SHIFT))
  1912. {
  1913. if ((guiTextBoxState.select == -1) && (guiTextBoxState.cursor != max))
  1914. {
  1915. guiTextBoxState.select = guiTextBoxState.cursor;
  1916. }
  1917. }
  1918. else guiTextBoxState.select = -1; // Deselect everything
  1919. int pos = 0;
  1920. guiTextBoxState.cursor = max;
  1921. int len = GuiTextBoxGetByteIndex(text, 0, 0, guiTextBoxState.cursor);
  1922. guiTextBoxState.index = GuiMeasureTextBoxRev(text, len, textRec, &pos);
  1923. guiTextBoxState.start = guiTextBoxState.cursor - pos + 1;
  1924. }
  1925. else if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_A))
  1926. {
  1927. // `CTRL + A` Select all
  1928. GuiTextBoxSelectAll(text);
  1929. }
  1930. else if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_C))
  1931. {
  1932. // `CTRL + C` Copy selected text to clipboard
  1933. GuiTextBoxCopy(text);
  1934. }
  1935. else if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_X))
  1936. {
  1937. // `CTRL + X` Cut selected text
  1938. GuiTextBoxCut(text);
  1939. }
  1940. else if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_V))
  1941. {
  1942. // `CTRL + V` Paste clipboard text
  1943. GuiTextBoxPaste(text, textSize);
  1944. }
  1945. else if (IsKeyPressed(KEY_ENTER))
  1946. {
  1947. pressed = true;
  1948. }
  1949. else
  1950. {
  1951. int key = GetKeyPressed();
  1952. if ((key >= 32) && ((guiTextBoxState.cursor + 1) < textSize))
  1953. {
  1954. if ((guiTextBoxState.select != -1) && (guiTextBoxState.select != guiTextBoxState.cursor))
  1955. {
  1956. // Delete selection
  1957. GuiTextBoxDelete(text, length, true);
  1958. }
  1959. // Decode codepoint
  1960. char out[5] = {0};
  1961. int sz = EncodeCodepoint(key, &out[0]);
  1962. if (sz != 0)
  1963. {
  1964. int startIdx = GuiTextBoxGetByteIndex(text, 0, 0, guiTextBoxState.cursor);
  1965. int endIdx = startIdx + sz;
  1966. if (endIdx <= textSize && length < textSize - 1)
  1967. {
  1968. guiTextBoxState.cursor++;
  1969. guiTextBoxState.select = -1;
  1970. memmove(&text[endIdx], &text[startIdx], length - startIdx);
  1971. memcpy(&text[startIdx], &out[0], sz);
  1972. length += sz;
  1973. text[length] = '\0';
  1974. if (guiTextBoxState.start != -1)
  1975. {
  1976. const int max = GuiTextBoxMaxCharacters(&text[guiTextBoxState.index], length - guiTextBoxState.index, textRec);
  1977. if ((guiTextBoxState.cursor - guiTextBoxState.start) > max) guiTextBoxState.start = -1;
  1978. }
  1979. }
  1980. }
  1981. }
  1982. }
  1983. // -------------
  1984. // HANDLE MOUSE
  1985. // -------------
  1986. if (CheckCollisionPointRec(mousePoint, bounds))
  1987. {
  1988. if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
  1989. {
  1990. if (CheckCollisionPointRec(mousePoint, textRec))
  1991. {
  1992. GuiTextBoxGetCursorFromMouse(&text[guiTextBoxState.index], length - guiTextBoxState.index, textRec, &guiTextBoxState.cursor);
  1993. guiTextBoxState.cursor += guiTextBoxState.start;
  1994. guiTextBoxState.select = -1;
  1995. }
  1996. else
  1997. {
  1998. // Clicked outside the `textRec` but still inside bounds
  1999. if (mousePoint.x <= bounds.x+bounds.width/2) guiTextBoxState.cursor = 0 + guiTextBoxState.start;
  2000. else guiTextBoxState.cursor = guiTextBoxState.start + GuiTextBoxMaxCharacters(&text[guiTextBoxState.index], length - guiTextBoxState.index, textRec);
  2001. guiTextBoxState.select = -1;
  2002. }
  2003. }
  2004. else if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
  2005. {
  2006. int cursor = guiTextBoxState.cursor - guiTextBoxState.start;
  2007. bool move = false;
  2008. if (CheckCollisionPointRec(mousePoint, textRec))
  2009. {
  2010. GuiTextBoxGetCursorFromMouse(&text[guiTextBoxState.index], length - guiTextBoxState.index, textRec, &cursor);
  2011. }
  2012. else
  2013. {
  2014. // Clicked outside the `textRec` but still inside bounds, this means that we must move the text
  2015. move = true;
  2016. if (mousePoint.x > bounds.x+bounds.width/2)
  2017. {
  2018. cursor = GuiTextBoxMaxCharacters(&text[guiTextBoxState.index], length - guiTextBoxState.index, textRec);
  2019. }
  2020. }
  2021. guiTextBoxState.cursor = cursor + guiTextBoxState.start;
  2022. if (guiTextBoxState.select == -1)
  2023. {
  2024. // Mark start of selection
  2025. guiTextBoxState.select = guiTextBoxState.cursor;
  2026. }
  2027. // Move the text when cursor is positioned before or after the text
  2028. if ((framesCounter%GUI_TEXTBOX_CURSOR_SPEED_MODIFIER) == 0 && move)
  2029. {
  2030. if (cursor == 0) MoveTextBoxCursorLeft(text);
  2031. else if (cursor == GuiTextBoxMaxCharacters(&text[guiTextBoxState.index], length - guiTextBoxState.index, textRec))
  2032. {
  2033. MoveTextBoxCursorRight(text, length, textRec);
  2034. }
  2035. }
  2036. }
  2037. }
  2038. // Calculate X coordinate of the blinking cursor
  2039. cursorPos.x = GuiTextBoxGetCursorCoordinates(&text[guiTextBoxState.index], length - guiTextBoxState.index, textRec, guiTextBoxState.cursor - guiTextBoxState.start);
  2040. // Update variables
  2041. textStartIndex = guiTextBoxState.index;
  2042. if (guiTextBoxState.select == -1)
  2043. {
  2044. selStart = guiTextBoxState.cursor;
  2045. selLength = 0;
  2046. }
  2047. else if (guiTextBoxState.cursor > guiTextBoxState.select)
  2048. {
  2049. selStart = guiTextBoxState.select;
  2050. selLength = guiTextBoxState.cursor - guiTextBoxState.select;
  2051. }
  2052. else
  2053. {
  2054. selStart = guiTextBoxState.cursor;
  2055. selLength = guiTextBoxState.select - guiTextBoxState.cursor;
  2056. }
  2057. // We aren't drawing all of the text so make sure `DrawTextRecEx()` is selecting things correctly
  2058. if (guiTextBoxState.start > selStart)
  2059. {
  2060. selLength -= guiTextBoxState.start - selStart;
  2061. selStart = 0;
  2062. }
  2063. else selStart = selStart - guiTextBoxState.start;
  2064. }
  2065. else state = GUI_STATE_FOCUSED;
  2066. }
  2067. else
  2068. {
  2069. if (CheckCollisionPointRec(mousePoint, bounds))
  2070. {
  2071. state = GUI_STATE_FOCUSED;
  2072. if (IsMouseButtonPressed(0)) pressed = true;
  2073. }
  2074. if (active && IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_C))
  2075. {
  2076. // If active copy all text to clipboard even when disabled
  2077. // Backup textbox state
  2078. int select = guiTextBoxState.select;
  2079. int cursor = guiTextBoxState.cursor;
  2080. int start = guiTextBoxState.start;
  2081. if (guiTextBoxState.select == -1 || guiTextBoxState.select == guiTextBoxState.cursor)
  2082. {
  2083. // If no selection then mark all text to be copied to clipboard
  2084. GuiTextBoxSelectAll(text);
  2085. }
  2086. GuiTextBoxCopy(text);
  2087. // Restore textbox state
  2088. guiTextBoxState.select = select;
  2089. guiTextBoxState.cursor = cursor;
  2090. guiTextBoxState.start = start;
  2091. }
  2092. }
  2093. }
  2094. // Draw control
  2095. //--------------------------------------------------------------------
  2096. DrawRectangleLinesEx(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha));
  2097. if (state == GUI_STATE_PRESSED)
  2098. {
  2099. 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));
  2100. if (editMode && active && ((framesCounter/TEXTEDIT_CURSOR_BLINK_FRAMES)%2 == 0) && selLength == 0)
  2101. {
  2102. // Draw the blinking cursor
  2103. DrawRectangle(cursorPos.x, cursorPos.y, 1, GuiGetStyle(DEFAULT, TEXT_SIZE), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)), guiAlpha));
  2104. }
  2105. }
  2106. else if (state == GUI_STATE_DISABLED)
  2107. {
  2108. 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));
  2109. }
  2110. // Finally draw the text and selection
  2111. DrawTextRecEx(guiFont, &text[textStartIndex], textRec, GuiGetStyle(DEFAULT, TEXT_SIZE), GuiGetStyle(DEFAULT, TEXT_SPACING), false, Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha), selStart, selLength, GetColor(GuiGetStyle(TEXTBOX, COLOR_SELECTED_FG)), GetColor(GuiGetStyle(TEXTBOX, COLOR_SELECTED_BG)));
  2112. return pressed;
  2113. }
  2114. #else // !RAYGUI_TEXTBOX_EXTENDED
  2115. // Spinner control, returns selected value
  2116. // NOTE: Requires static variables: framesCounter, valueSpeed - ERROR!
  2117. RAYGUIDEF bool GuiSpinner(Rectangle bounds, int *value, int minValue, int maxValue, bool editMode)
  2118. {
  2119. bool pressed = false;
  2120. int tempValue = *value;
  2121. Rectangle spinner = { bounds.x + GuiGetStyle(SPINNER, SELECT_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SELECT_BUTTON_PADDING), bounds.y,
  2122. bounds.width - 2*(GuiGetStyle(SPINNER, SELECT_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SELECT_BUTTON_PADDING)), bounds.height };
  2123. Rectangle leftButtonBound = { (float)bounds.x, (float)bounds.y, (float)GuiGetStyle(SPINNER, SELECT_BUTTON_WIDTH), (float)bounds.height };
  2124. Rectangle rightButtonBound = { (float)bounds.x + bounds.width - GuiGetStyle(SPINNER, SELECT_BUTTON_WIDTH), (float)bounds.y, (float)GuiGetStyle(SPINNER, SELECT_BUTTON_WIDTH), (float)bounds.height };
  2125. // Update control
  2126. //--------------------------------------------------------------------
  2127. if (!editMode)
  2128. {
  2129. if (tempValue < minValue) tempValue = minValue;
  2130. if (tempValue > maxValue) tempValue = maxValue;
  2131. }
  2132. //--------------------------------------------------------------------
  2133. // Draw control
  2134. //--------------------------------------------------------------------
  2135. // TODO: Set Spinner properties for ValueBox
  2136. pressed = GuiValueBox(spinner, &tempValue, minValue, maxValue, editMode);
  2137. // Draw value selector custom buttons
  2138. // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values
  2139. int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
  2140. GuiSetStyle(BUTTON, BORDER_WIDTH, GuiGetStyle(SPINNER, BORDER_WIDTH));
  2141. int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
  2142. GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
  2143. #if defined(RAYGUI_RICONS_SUPPORT)
  2144. if (GuiButton(leftButtonBound, GuiIconText(RICON_ARROW_LEFT_FILL, NULL))) tempValue--;
  2145. if (GuiButton(rightButtonBound, GuiIconText(RICON_ARROW_RIGHT_FILL, NULL))) tempValue++;
  2146. #else
  2147. if (GuiButton(leftButtonBound, "<")) tempValue--;
  2148. if (GuiButton(rightButtonBound, ">")) tempValue++;
  2149. #endif
  2150. GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign);
  2151. GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
  2152. //--------------------------------------------------------------------
  2153. *value = tempValue;
  2154. return pressed;
  2155. }
  2156. // Value Box control, updates input text with numbers
  2157. // NOTE: Requires static variables: framesCounter
  2158. RAYGUIDEF bool GuiValueBox(Rectangle bounds, int *value, int minValue, int maxValue, bool editMode)
  2159. {
  2160. #define VALUEBOX_MAX_CHARS 32
  2161. static int framesCounter = 0; // Required for blinking cursor
  2162. GuiControlState state = guiState;
  2163. bool pressed = false;
  2164. char text[VALUEBOX_MAX_CHARS + 1] = "\0";
  2165. sprintf(text, "%i", *value);
  2166. // Update control
  2167. //--------------------------------------------------------------------
  2168. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  2169. {
  2170. Vector2 mousePoint = GetMousePosition();
  2171. bool valueHasChanged = false;
  2172. if (editMode)
  2173. {
  2174. state = GUI_STATE_PRESSED;
  2175. framesCounter++;
  2176. int keyCount = strlen(text);
  2177. // Only allow keys in range [48..57]
  2178. if (keyCount < VALUEBOX_MAX_CHARS)
  2179. {
  2180. int maxWidth = (bounds.width - (GuiGetStyle(VALUEBOX, INNER_PADDING)*2));
  2181. if (GetTextWidth(text) < maxWidth)
  2182. {
  2183. int key = GetKeyPressed();
  2184. if ((key >= 48) && (key <= 57))
  2185. {
  2186. text[keyCount] = (char)key;
  2187. keyCount++;
  2188. valueHasChanged = true;
  2189. }
  2190. }
  2191. }
  2192. // Delete text
  2193. if (keyCount > 0)
  2194. {
  2195. if (IsKeyPressed(KEY_BACKSPACE))
  2196. {
  2197. keyCount--;
  2198. text[keyCount] = '\0';
  2199. framesCounter = 0;
  2200. if (keyCount < 0) keyCount = 0;
  2201. valueHasChanged = true;
  2202. }
  2203. else if (IsKeyDown(KEY_BACKSPACE))
  2204. {
  2205. if ((framesCounter > TEXTEDIT_CURSOR_BLINK_FRAMES) && (framesCounter%2) == 0) keyCount--;
  2206. text[keyCount] = '\0';
  2207. if (keyCount < 0) keyCount = 0;
  2208. valueHasChanged = true;
  2209. }
  2210. }
  2211. if (valueHasChanged) *value = atoi(text);
  2212. }
  2213. else
  2214. {
  2215. if (*value > maxValue) *value = maxValue;
  2216. else if (*value < minValue) *value = minValue;
  2217. }
  2218. if (!editMode)
  2219. {
  2220. if (CheckCollisionPointRec(mousePoint, bounds))
  2221. {
  2222. state = GUI_STATE_FOCUSED;
  2223. if (IsMouseButtonPressed(0)) pressed = true;
  2224. }
  2225. }
  2226. else
  2227. {
  2228. if (IsKeyPressed(KEY_ENTER) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(0))) pressed = true;
  2229. }
  2230. if (pressed) framesCounter = 0;
  2231. }
  2232. //--------------------------------------------------------------------
  2233. // Draw control
  2234. //--------------------------------------------------------------------
  2235. DrawRectangleLinesEx(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), guiAlpha));
  2236. if (state == GUI_STATE_PRESSED)
  2237. {
  2238. DrawRectangle(bounds.x + GuiGetStyle(VALUEBOX, BORDER_WIDTH), bounds.y + GuiGetStyle(VALUEBOX, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), bounds.height - 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_PRESSED)), guiAlpha));
  2239. if (editMode && ((framesCounter/20)%2 == 0)) DrawRectangle(bounds.x + GetTextWidth(text)/2 + bounds.width/2 + 2, bounds.y + GuiGetStyle(VALUEBOX, INNER_PADDING), 1, bounds.height - GuiGetStyle(VALUEBOX, INNER_PADDING)*2, Fade(GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED)), guiAlpha));
  2240. }
  2241. else if (state == GUI_STATE_DISABLED)
  2242. {
  2243. DrawRectangle(bounds.x + GuiGetStyle(VALUEBOX, BORDER_WIDTH), bounds.y + GuiGetStyle(VALUEBOX, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), bounds.height - 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_DISABLED)), guiAlpha));
  2244. }
  2245. GuiDrawText(text, GetTextBounds(VALUEBOX, bounds), GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3))), guiAlpha));
  2246. //--------------------------------------------------------------------
  2247. return pressed;
  2248. }
  2249. // Text Box control, updates input text
  2250. // NOTE 1: Requires static variables: framesCounter
  2251. // NOTE 2: Returns if KEY_ENTER pressed (useful for data validation)
  2252. RAYGUIDEF bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
  2253. {
  2254. static int framesCounter = 0; // Required for blinking cursor
  2255. GuiControlState state = guiState;
  2256. bool pressed = false;
  2257. // Update control
  2258. //--------------------------------------------------------------------
  2259. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  2260. {
  2261. Vector2 mousePoint = GetMousePosition();
  2262. if (editMode)
  2263. {
  2264. state = GUI_STATE_PRESSED;
  2265. framesCounter++;
  2266. int key = GetKeyPressed();
  2267. int keyCount = strlen(text);
  2268. // Only allow keys in range [32..125]
  2269. if (keyCount < (textSize - 1))
  2270. {
  2271. int maxWidth = (bounds.width - (GuiGetStyle(DEFAULT, INNER_PADDING)*2));
  2272. if (GetTextWidth(text) < (maxWidth - GuiGetStyle(DEFAULT, TEXT_SIZE)))
  2273. {
  2274. if (((key >= 32) && (key <= 125)) ||
  2275. ((key >= 128) && (key < 255)))
  2276. {
  2277. text[keyCount] = (char)key;
  2278. keyCount++;
  2279. text[keyCount] = '\0';
  2280. }
  2281. }
  2282. }
  2283. // Delete text
  2284. if (keyCount > 0)
  2285. {
  2286. if (IsKeyPressed(KEY_BACKSPACE))
  2287. {
  2288. keyCount--;
  2289. text[keyCount] = '\0';
  2290. framesCounter = 0;
  2291. if (keyCount < 0) keyCount = 0;
  2292. }
  2293. else if (IsKeyDown(KEY_BACKSPACE))
  2294. {
  2295. if ((framesCounter > TEXTEDIT_CURSOR_BLINK_FRAMES) && (framesCounter%2) == 0) keyCount--;
  2296. text[keyCount] = '\0';
  2297. if (keyCount < 0) keyCount = 0;
  2298. }
  2299. }
  2300. }
  2301. if (!editMode)
  2302. {
  2303. if (CheckCollisionPointRec(mousePoint, bounds))
  2304. {
  2305. state = GUI_STATE_FOCUSED;
  2306. if (IsMouseButtonPressed(0)) pressed = true;
  2307. }
  2308. }
  2309. else
  2310. {
  2311. if (IsKeyPressed(KEY_ENTER) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(0))) pressed = true;
  2312. }
  2313. if (pressed) framesCounter = 0;
  2314. }
  2315. //--------------------------------------------------------------------
  2316. // Draw control
  2317. //--------------------------------------------------------------------
  2318. DrawRectangleLinesEx(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha));
  2319. if (state == GUI_STATE_PRESSED)
  2320. {
  2321. 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_PRESSED)), guiAlpha));
  2322. // Draw blinking cursor
  2323. if (editMode && ((framesCounter/20)%2 == 0)) DrawRectangle(bounds.x + GuiGetStyle(TEXTBOX, INNER_PADDING) + GetTextWidth(text) + 2 + bounds.width/2*GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE), 1, GuiGetStyle(DEFAULT, TEXT_SIZE)*2, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)), guiAlpha));
  2324. }
  2325. else if (state == GUI_STATE_DISABLED)
  2326. {
  2327. 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));
  2328. }
  2329. GuiDrawText(text, GetTextBounds(TEXTBOX, bounds), GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha));
  2330. //--------------------------------------------------------------------
  2331. return pressed;
  2332. }
  2333. #endif
  2334. // Text Box control with multiple lines
  2335. RAYGUIDEF bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode)
  2336. {
  2337. static int framesCounter = 0; // Required for blinking cursor
  2338. GuiControlState state = guiState;
  2339. bool pressed = false;
  2340. bool textHasChange = false;
  2341. int currentLine = 0;
  2342. //const char *numChars = NULL;
  2343. // Update control
  2344. //--------------------------------------------------------------------
  2345. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  2346. {
  2347. Vector2 mousePoint = GetMousePosition();
  2348. if (editMode)
  2349. {
  2350. state = GUI_STATE_PRESSED;
  2351. framesCounter++;
  2352. int keyCount = strlen(text);
  2353. int maxWidth = (bounds.width - (GuiGetStyle(TEXTBOX, INNER_PADDING)*2));
  2354. int maxHeight = (bounds.height - (GuiGetStyle(TEXTBOX, INNER_PADDING)*2));
  2355. //numChars = TextFormat("%i/%i", keyCount, textSize - 1);
  2356. // Only allow keys in range [32..125]
  2357. if (keyCount < (textSize - 1))
  2358. {
  2359. int key = GetKeyPressed();
  2360. if (MeasureTextEx(guiFont, text, GuiGetStyle(DEFAULT, TEXT_SIZE), 1).y < (maxHeight - GuiGetStyle(DEFAULT, TEXT_SIZE)))
  2361. {
  2362. if (IsKeyPressed(KEY_ENTER))
  2363. {
  2364. text[keyCount] = '\n';
  2365. keyCount++;
  2366. }
  2367. else if (((key >= 32) && (key <= 125)) ||
  2368. ((key >= 128) && (key < 255)))
  2369. {
  2370. text[keyCount] = (char)key;
  2371. keyCount++;
  2372. textHasChange = true;
  2373. }
  2374. }
  2375. else if (GetTextWidth(strrchr(text, '\n')) < (maxWidth - GuiGetStyle(DEFAULT, TEXT_SIZE)))
  2376. {
  2377. if (((key >= 32) && (key <= 125)) ||
  2378. ((key >= 128) && (key < 255)))
  2379. {
  2380. text[keyCount] = (char)key;
  2381. keyCount++;
  2382. textHasChange = true;
  2383. }
  2384. }
  2385. }
  2386. // Delete text
  2387. if (keyCount > 0)
  2388. {
  2389. if (IsKeyPressed(KEY_BACKSPACE))
  2390. {
  2391. keyCount--;
  2392. text[keyCount] = '\0';
  2393. framesCounter = 0;
  2394. if (keyCount < 0) keyCount = 0;
  2395. textHasChange = true;
  2396. }
  2397. else if (IsKeyDown(KEY_BACKSPACE))
  2398. {
  2399. if ((framesCounter > TEXTEDIT_CURSOR_BLINK_FRAMES) && (framesCounter%2) == 0) keyCount--;
  2400. text[keyCount] = '\0';
  2401. if (keyCount < 0) keyCount = 0;
  2402. textHasChange = true;
  2403. }
  2404. }
  2405. // Introduce automatic new line if necessary
  2406. if (textHasChange)
  2407. {
  2408. textHasChange = false;
  2409. char *lastLine = strrchr(text, '\n');
  2410. int maxWidth = (bounds.width - (GuiGetStyle(TEXTBOX, INNER_PADDING)*2));
  2411. if (lastLine != NULL)
  2412. {
  2413. if (GetTextWidth(lastLine) > maxWidth)
  2414. {
  2415. int firstIndex = lastLine - text;
  2416. char *lastSpace = strrchr(lastLine, 32);
  2417. if (lastSpace != NULL)
  2418. {
  2419. int secondIndex = lastSpace - lastLine;
  2420. text[firstIndex + secondIndex] = '\n';
  2421. }
  2422. else
  2423. {
  2424. int len = (lastLine != NULL)? strlen(lastLine) : 0;
  2425. char lastChar = lastLine[len - 1];
  2426. lastLine[len - 1] = '\n';
  2427. lastLine[len] = lastChar;
  2428. lastLine[len + 1] = '\0';
  2429. keyCount++;
  2430. }
  2431. }
  2432. }
  2433. else
  2434. {
  2435. if (GetTextWidth(text) > maxWidth)
  2436. {
  2437. char *lastSpace = strrchr(text, 32);
  2438. if (lastSpace != NULL)
  2439. {
  2440. int index = lastSpace - text;
  2441. text[index] = '\n';
  2442. }
  2443. else
  2444. {
  2445. int len = (lastLine != NULL)? strlen(lastLine) : 0;
  2446. char lastChar = lastLine[len - 1];
  2447. lastLine[len - 1] = '\n';
  2448. lastLine[len] = lastChar;
  2449. lastLine[len + 1] = '\0';
  2450. keyCount++;
  2451. }
  2452. }
  2453. }
  2454. }
  2455. // Counting how many new lines
  2456. for (int i = 0; i < keyCount; i++)
  2457. {
  2458. if (text[i] == '\n') currentLine++;
  2459. }
  2460. }
  2461. // Changing edit mode
  2462. if (!editMode)
  2463. {
  2464. if (CheckCollisionPointRec(mousePoint, bounds))
  2465. {
  2466. state = GUI_STATE_FOCUSED;
  2467. if (IsMouseButtonPressed(0)) pressed = true;
  2468. }
  2469. }
  2470. else
  2471. {
  2472. if (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(0)) pressed = true;
  2473. }
  2474. if (pressed) framesCounter = 0;
  2475. }
  2476. //--------------------------------------------------------------------
  2477. // Draw control
  2478. //--------------------------------------------------------------------
  2479. DrawRectangleLinesEx(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha));
  2480. if (state == GUI_STATE_PRESSED)
  2481. {
  2482. 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_PRESSED)), guiAlpha));
  2483. if (editMode)
  2484. {
  2485. if ((framesCounter/20)%2 == 0)
  2486. {
  2487. char *line = NULL;
  2488. if (currentLine > 0) line = strrchr(text, '\n');
  2489. else line = text;
  2490. // Draw text cursor
  2491. DrawRectangle(bounds.x + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(TEXTBOX, INNER_PADDING) + GetTextWidth(line),
  2492. bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(TEXTBOX, INNER_PADDING)/2 + ((GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(TEXTBOX, INNER_PADDING))*currentLine),
  2493. 1, GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(TEXTBOX, INNER_PADDING), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_FOCUSED)), guiAlpha));
  2494. }
  2495. // Draw characters counter
  2496. //GuiDrawText(numChars, RAYGUI_CLITERAL(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));
  2497. }
  2498. }
  2499. else if (state == GUI_STATE_DISABLED)
  2500. {
  2501. 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));
  2502. }
  2503. GuiDrawText(text, GetTextBounds(TEXTBOX, bounds), GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha));
  2504. //--------------------------------------------------------------------
  2505. return pressed;
  2506. }
  2507. // Slider control with pro parameters
  2508. // NOTE: Other GuiSlider*() controls use this one
  2509. RAYGUIDEF float GuiSliderPro(Rectangle bounds, const char *text, float value, float minValue, float maxValue, int sliderWidth, bool showValue)
  2510. {
  2511. GuiControlState state = guiState;
  2512. int sliderValue = (int)(((value - minValue)/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH)));
  2513. Rectangle slider = { bounds.x, bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, INNER_PADDING),
  2514. 0, bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, INNER_PADDING) };
  2515. if (sliderWidth > 0) // Slider
  2516. {
  2517. slider.x += (sliderValue - sliderWidth/2);
  2518. slider.width = sliderWidth;
  2519. }
  2520. else if (sliderWidth == 0) // SliderBar
  2521. {
  2522. slider.x += GuiGetStyle(SLIDER, BORDER_WIDTH);
  2523. slider.width = sliderValue;
  2524. }
  2525. Rectangle textBounds = { 0 };
  2526. textBounds.width = GetTextWidth(text); // TODO: Consider text icon
  2527. textBounds.height = GuiGetStyle(DEFAULT, TEXT_SIZE);
  2528. textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SLIDER, TEXT_PADDING);
  2529. textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
  2530. // Update control
  2531. //--------------------------------------------------------------------
  2532. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  2533. {
  2534. Vector2 mousePoint = GetMousePosition();
  2535. if (CheckCollisionPointRec(mousePoint, bounds))
  2536. {
  2537. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
  2538. {
  2539. state = GUI_STATE_PRESSED;
  2540. // Get equivalent value and slider position from mousePoint.x
  2541. value = ((maxValue - minValue)*(mousePoint.x - (float)(bounds.x + sliderWidth/2)))/(float)(bounds.width - sliderWidth) + minValue;
  2542. if (sliderWidth > 0) slider.x = mousePoint.x - slider.width/2; // Slider
  2543. else if (sliderWidth == 0) slider.width = sliderValue; // SliderBar
  2544. }
  2545. else state = GUI_STATE_FOCUSED;
  2546. }
  2547. if (value > maxValue) value = maxValue;
  2548. else if (value < minValue) value = minValue;
  2549. }
  2550. // Bar limits check
  2551. if (sliderWidth > 0) // Slider
  2552. {
  2553. if (slider.x <= (bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH))) slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH);
  2554. else if ((slider.x + slider.width) >= (bounds.x + bounds.width)) slider.x = bounds.x + bounds.width - slider.width - GuiGetStyle(SLIDER, BORDER_WIDTH);
  2555. }
  2556. else if (sliderWidth == 0) // SliderBar
  2557. {
  2558. if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH);
  2559. }
  2560. //--------------------------------------------------------------------
  2561. // Draw control
  2562. //--------------------------------------------------------------------
  2563. DrawRectangleLinesEx(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(SLIDER, BORDER + (state*3))), guiAlpha));
  2564. 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));
  2565. // Draw slider internal bar (depends on state)
  2566. if ((state == GUI_STATE_NORMAL) || (state == GUI_STATE_PRESSED)) DrawRectangleRec(slider, Fade(GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED)), guiAlpha));
  2567. else if (state == GUI_STATE_FOCUSED) DrawRectangleRec(slider, Fade(GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_FOCUSED)), guiAlpha));
  2568. GuiDrawText(text, textBounds, GuiGetStyle(SLIDER, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))), guiAlpha));
  2569. // TODO: Review showValue parameter, really ugly...
  2570. if (showValue) GuiDrawText(TextFormat("%.02f", value), RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width + GuiGetStyle(SLIDER, TEXT_PADDING),
  2571. (float)bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2 + GuiGetStyle(SLIDER, INNER_PADDING),
  2572. (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SIZE) }, GUI_TEXT_ALIGN_LEFT,
  2573. Fade(GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))), guiAlpha));
  2574. //--------------------------------------------------------------------
  2575. return value;
  2576. }
  2577. // Slider control extended, returns selected value and has text
  2578. RAYGUIDEF float GuiSlider(Rectangle bounds, const char *text, float value, float minValue, float maxValue, bool showValue)
  2579. {
  2580. return GuiSliderPro(bounds, text, value, minValue, maxValue, GuiGetStyle(SLIDER, SLIDER_WIDTH), showValue);
  2581. }
  2582. // Slider Bar control extended, returns selected value
  2583. RAYGUIDEF float GuiSliderBar(Rectangle bounds, const char *text, float value, float minValue, float maxValue, bool showValue)
  2584. {
  2585. return GuiSliderPro(bounds, text, value, minValue, maxValue, 0, showValue);
  2586. }
  2587. // Progress Bar control extended, shows current progress value
  2588. RAYGUIDEF float GuiProgressBar(Rectangle bounds, const char *text, float value, float minValue, float maxValue, bool showValue)
  2589. {
  2590. GuiControlState state = guiState;
  2591. Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH),
  2592. bounds.y + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) + GuiGetStyle(PROGRESSBAR, INNER_PADDING), 0,
  2593. bounds.height - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - 2*GuiGetStyle(PROGRESSBAR, INNER_PADDING) };
  2594. // Update control
  2595. //--------------------------------------------------------------------
  2596. if (state != GUI_STATE_DISABLED) progress.width = (int)(value/(maxValue - minValue)*(float)(bounds.width - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)));
  2597. //--------------------------------------------------------------------
  2598. // Draw control
  2599. //--------------------------------------------------------------------
  2600. if (showValue) GuiLabel(RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width + GuiGetStyle(SLIDER, TEXT_PADDING), (float)bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2 + GuiGetStyle(SLIDER, INNER_PADDING), (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SIZE) }, TextFormat("%.02f", value));
  2601. DrawRectangleLinesEx(bounds, GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(PROGRESSBAR, BORDER + (state*3))), guiAlpha));
  2602. // Draw slider internal progress bar (depends on state)
  2603. if ((state == GUI_STATE_NORMAL) || (state == GUI_STATE_PRESSED)) DrawRectangleRec(progress, Fade(GetColor(GuiGetStyle(PROGRESSBAR, BASE_COLOR_PRESSED)), guiAlpha));
  2604. else if (state == GUI_STATE_FOCUSED) DrawRectangleRec(progress, Fade(GetColor(GuiGetStyle(PROGRESSBAR, TEXT_COLOR_FOCUSED)), guiAlpha));
  2605. //--------------------------------------------------------------------
  2606. return value;
  2607. }
  2608. // Status Bar control
  2609. RAYGUIDEF void GuiStatusBar(Rectangle bounds, const char *text)
  2610. {
  2611. GuiControlState state = guiState;
  2612. // Draw control
  2613. //--------------------------------------------------------------------
  2614. DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(DEFAULT, (state != GUI_STATE_DISABLED)? BORDER_COLOR_NORMAL : BORDER_COLOR_DISABLED)), guiAlpha));
  2615. DrawRectangleRec(RAYGUI_CLITERAL(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));
  2616. GuiDrawText(text, GetTextBounds(DEFAULT, bounds), GuiGetStyle(DEFAULT, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(DEFAULT, (state != GUI_STATE_DISABLED)? TEXT_COLOR_NORMAL : TEXT_COLOR_DISABLED)), guiAlpha));
  2617. //--------------------------------------------------------------------
  2618. }
  2619. // Dummy rectangle control, intended for placeholding
  2620. RAYGUIDEF void GuiDummyRec(Rectangle bounds, const char *text)
  2621. {
  2622. GuiControlState state = guiState;
  2623. // Update control
  2624. //--------------------------------------------------------------------
  2625. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  2626. {
  2627. Vector2 mousePoint = GetMousePosition();
  2628. // Check button state
  2629. if (CheckCollisionPointRec(mousePoint, bounds))
  2630. {
  2631. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
  2632. else state = GUI_STATE_FOCUSED;
  2633. }
  2634. }
  2635. //--------------------------------------------------------------------
  2636. // Draw control
  2637. //--------------------------------------------------------------------
  2638. DrawRectangleRec(bounds, Fade(GetColor(GuiGetStyle(DEFAULT, (state != GUI_STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)), guiAlpha));
  2639. GuiDrawText(text, GetTextBounds(DEFAULT, bounds), GUI_TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(BUTTON, (state != GUI_STATE_DISABLED)? TEXT_COLOR_NORMAL : TEXT_COLOR_DISABLED)), guiAlpha));
  2640. //------------------------------------------------------------------
  2641. }
  2642. // Scroll Bar control
  2643. RAYGUIDEF int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue)
  2644. {
  2645. GuiControlState state = guiState;
  2646. // Is the scrollbar horizontal or vertical?
  2647. bool isVertical = (bounds.width > bounds.height)? false : true;
  2648. // The size (width or height depending on scrollbar type) of the spinner buttons
  2649. const int spinnerSize = GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)? (isVertical? bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) : bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0;
  2650. // Arrow buttons [<] [>] [∧] [∨]
  2651. Rectangle arrowUpLeft = { 0 };
  2652. Rectangle arrowDownRight = { 0 };
  2653. // Actual area of the scrollbar excluding the arrow buttons
  2654. Rectangle scrollbar = { 0 };
  2655. // Slider bar that moves --[///]-----
  2656. Rectangle slider = { 0 };
  2657. // Normalize value
  2658. if (value > maxValue) value = maxValue;
  2659. if (value < minValue) value = minValue;
  2660. const int range = maxValue - minValue;
  2661. int sliderSize = GuiGetStyle(SCROLLBAR, SLIDER_SIZE);
  2662. // Calculate rectangles for all of the components
  2663. arrowUpLeft = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize };
  2664. if (isVertical)
  2665. {
  2666. arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + bounds.height - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize};
  2667. scrollbar = RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, INNER_PADDING), arrowUpLeft.y + arrowUpLeft.height, bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, INNER_PADDING)), bounds.height - arrowUpLeft.height - arrowDownRight.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) };
  2668. sliderSize = (sliderSize >= scrollbar.height)? (scrollbar.height - 2) : sliderSize; // Make sure the slider won't get outside of the scrollbar
  2669. slider = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SLIDER_PADDING), (float)scrollbar.y + (int)(((float)(value - minValue)/range)*(scrollbar.height - sliderSize)), (float)bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SLIDER_PADDING)), (float)sliderSize };
  2670. }
  2671. else
  2672. {
  2673. arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize};
  2674. scrollbar = RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x + arrowUpLeft.width, bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, INNER_PADDING), bounds.width - arrowUpLeft.width - arrowDownRight.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, INNER_PADDING))};
  2675. sliderSize = (sliderSize >= scrollbar.width)? (scrollbar.width - 2) : sliderSize; // Make sure the slider won't get outside of the scrollbar
  2676. slider = RAYGUI_CLITERAL(Rectangle){ (float)scrollbar.x + (int)(((float)(value - minValue)/range)*(scrollbar.width - sliderSize)), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SLIDER_PADDING), (float)sliderSize, (float)bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SLIDER_PADDING)) };
  2677. }
  2678. // Update control
  2679. //--------------------------------------------------------------------
  2680. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  2681. {
  2682. Vector2 mousePoint = GetMousePosition();
  2683. if (CheckCollisionPointRec(mousePoint, bounds))
  2684. {
  2685. state = GUI_STATE_FOCUSED;
  2686. // Handle mouse wheel
  2687. int wheel = GetMouseWheelMove();
  2688. if (wheel != 0) value += wheel;
  2689. if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
  2690. {
  2691. if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= range/GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
  2692. else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += range/GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
  2693. state = GUI_STATE_PRESSED;
  2694. }
  2695. else if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
  2696. {
  2697. if (!isVertical)
  2698. {
  2699. Rectangle scrollArea = { arrowUpLeft.x + arrowUpLeft.width, arrowUpLeft.y, scrollbar.width, bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)};
  2700. if (CheckCollisionPointRec(mousePoint, scrollArea)) value = ((float)(mousePoint.x - scrollArea.x - slider.width/2)*range)/(scrollArea.width - slider.width) + minValue;
  2701. }
  2702. else
  2703. {
  2704. Rectangle scrollArea = { arrowUpLeft.x, arrowUpLeft.y+arrowUpLeft.height, bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), scrollbar.height};
  2705. if (CheckCollisionPointRec(mousePoint, scrollArea)) value = ((float)(mousePoint.y - scrollArea.y - slider.height/2)*range)/(scrollArea.height - slider.height) + minValue;
  2706. }
  2707. }
  2708. }
  2709. // Normalize value
  2710. if (value > maxValue) value = maxValue;
  2711. if (value < minValue) value = minValue;
  2712. }
  2713. //--------------------------------------------------------------------
  2714. // Draw control
  2715. //--------------------------------------------------------------------
  2716. DrawRectangleRec(bounds, Fade(GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED)), guiAlpha)); // Draw the background
  2717. DrawRectangleRec(scrollbar, Fade(GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL)), guiAlpha)); // Draw the scrollbar active area background
  2718. DrawRectangleLinesEx(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), guiAlpha));
  2719. DrawRectangleRec(slider, Fade(GetColor(GuiGetStyle(SLIDER, BORDER + state*3)), guiAlpha)); // Draw the slider bar
  2720. // Draw arrows
  2721. const int padding = (spinnerSize - GuiGetStyle(SCROLLBAR, ARROWS_SIZE))/2;
  2722. const Vector2 lineCoords[] =
  2723. {
  2724. // Coordinates for < 0,1,2
  2725. { arrowUpLeft.x + padding, arrowUpLeft.y + spinnerSize/2 },
  2726. { arrowUpLeft.x + spinnerSize - padding, arrowUpLeft.y + padding },
  2727. { arrowUpLeft.x + spinnerSize - padding, arrowUpLeft.y + spinnerSize - padding },
  2728. // Coordinates for > 3,4,5
  2729. { arrowDownRight.x + padding, arrowDownRight.y + padding },
  2730. { arrowDownRight.x + spinnerSize - padding, arrowDownRight.y + spinnerSize/2 },
  2731. { arrowDownRight.x + padding, arrowDownRight.y + spinnerSize - padding },
  2732. // Coordinates for ∧ 6,7,8
  2733. { arrowUpLeft.x + spinnerSize/2, arrowUpLeft.y + padding },
  2734. { arrowUpLeft.x + padding, arrowUpLeft.y + spinnerSize - padding },
  2735. { arrowUpLeft.x + spinnerSize - padding, arrowUpLeft.y + spinnerSize - padding },
  2736. // Coordinates for ∨ 9,10,11
  2737. { arrowDownRight.x + padding, arrowDownRight.y + padding },
  2738. { arrowDownRight.x + spinnerSize/2, arrowDownRight.y + spinnerSize - padding },
  2739. { arrowDownRight.x + spinnerSize - padding, arrowDownRight.y + padding }
  2740. };
  2741. Color lineColor = Fade(GetColor(GuiGetStyle(BUTTON, TEXT + state*3)), guiAlpha);
  2742. if (GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE))
  2743. {
  2744. if (isVertical)
  2745. {
  2746. DrawTriangle(lineCoords[6], lineCoords[7], lineCoords[8], lineColor);
  2747. DrawTriangle(lineCoords[9], lineCoords[10], lineCoords[11], lineColor);
  2748. }
  2749. else
  2750. {
  2751. DrawTriangle(lineCoords[2], lineCoords[1], lineCoords[0], lineColor);
  2752. DrawTriangle(lineCoords[5], lineCoords[4], lineCoords[3], lineColor);
  2753. }
  2754. }
  2755. //--------------------------------------------------------------------
  2756. return value;
  2757. }
  2758. // List Element control, returns element state
  2759. static bool GuiListElement(Rectangle bounds, const char *text, bool active, bool editMode)
  2760. {
  2761. GuiControlState state = guiState;
  2762. if (!guiLocked && editMode) state = GUI_STATE_NORMAL;
  2763. // Update control
  2764. //--------------------------------------------------------------------
  2765. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  2766. {
  2767. Vector2 mousePoint = GetMousePosition();
  2768. if (CheckCollisionPointRec(mousePoint, bounds))
  2769. {
  2770. if (!active)
  2771. {
  2772. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED;
  2773. else state = GUI_STATE_FOCUSED;
  2774. }
  2775. if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) active = !active;
  2776. }
  2777. }
  2778. //--------------------------------------------------------------------
  2779. // Draw control
  2780. //--------------------------------------------------------------------
  2781. // Draw element rectangle
  2782. switch (state)
  2783. {
  2784. case GUI_STATE_NORMAL:
  2785. {
  2786. if (active)
  2787. {
  2788. DrawRectangle(bounds.x, bounds.y, bounds.width, bounds.height, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)), guiAlpha));
  2789. DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), guiAlpha));
  2790. }
  2791. } break;
  2792. case GUI_STATE_FOCUSED:
  2793. {
  2794. DrawRectangle(bounds.x, bounds.y, bounds.width, bounds.height, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED)), guiAlpha));
  2795. DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), guiAlpha));
  2796. } break;
  2797. case GUI_STATE_PRESSED:
  2798. {
  2799. DrawRectangle(bounds.x, bounds.y, bounds.width, bounds.height, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)), guiAlpha));
  2800. DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), guiAlpha));
  2801. } break;
  2802. case GUI_STATE_DISABLED:
  2803. {
  2804. if (active)
  2805. {
  2806. DrawRectangle(bounds.x, bounds.y, bounds.width, bounds.height, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED)), guiAlpha));
  2807. DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_NORMAL)), guiAlpha));
  2808. }
  2809. } break;
  2810. default: break;
  2811. }
  2812. // Draw text depending on state
  2813. 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));
  2814. 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));
  2815. else GuiDrawText(text, GetTextBounds(DEFAULT, bounds), GuiGetStyle(DEFAULT, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT + state*3)), guiAlpha));
  2816. //--------------------------------------------------------------------
  2817. return active;
  2818. }
  2819. // List View control
  2820. RAYGUIDEF bool GuiListView(Rectangle bounds, const char *text, int *active, int *scrollIndex, bool editMode)
  2821. {
  2822. bool result = 0;
  2823. int count = 0;
  2824. const char **textList = GuiTextSplit(text, &count, NULL);
  2825. result = GuiListViewEx(bounds, textList, count, NULL, active, NULL, scrollIndex, editMode);
  2826. return result;
  2827. }
  2828. // List View control extended parameters
  2829. // NOTE: Elements could be disabled individually and focused element could be obtained:
  2830. // int *enabled defines an array with enabled elements inside the list
  2831. // int *focus returns focused element (may be not pressed)
  2832. RAYGUIDEF bool GuiListViewEx(Rectangle bounds, const char **text, int count, int *enabled, int *active, int *focus, int *scrollIndex, bool editMode)
  2833. {
  2834. GuiControlState state = guiState;
  2835. bool pressed = false;
  2836. int focusElement = -1;
  2837. int startIndex = (scrollIndex == NULL)? 0 : *scrollIndex;
  2838. bool useScrollBar = true;
  2839. bool pressedKey = false;
  2840. int visibleElements = bounds.height/(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING));
  2841. if ((startIndex < 0) || (startIndex > count - visibleElements)) startIndex = 0;
  2842. int endIndex = startIndex + visibleElements;
  2843. int auxActive = *active;
  2844. float barHeight = bounds.height;
  2845. float minBarHeight = 10;
  2846. // Update control
  2847. //--------------------------------------------------------------------
  2848. // All the elements fit inside ListView and dont need scrollbar.
  2849. if (visibleElements >= count)
  2850. {
  2851. useScrollBar = false;
  2852. startIndex = 0;
  2853. endIndex = count;
  2854. }
  2855. // Calculate position X and width to draw each element.
  2856. int posX = bounds.x + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING);
  2857. int elementWidth = bounds.width - 2*GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) - GuiGetStyle(DEFAULT, BORDER_WIDTH);
  2858. if (useScrollBar)
  2859. {
  2860. posX = GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE? posX + GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : posX;
  2861. elementWidth = bounds.width - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) - 2*GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) - GuiGetStyle(DEFAULT, BORDER_WIDTH);
  2862. }
  2863. Rectangle scrollBarRect = { (float)bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), (float)GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), (float)bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) };
  2864. if (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_RIGHT_SIDE) scrollBarRect.x = posX + elementWidth + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING);
  2865. // Area without the scrollbar
  2866. Rectangle viewArea = { (float)posX, (float)bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), (float)elementWidth, (float)bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) };
  2867. if ((state != GUI_STATE_DISABLED) && !guiLocked) // && !guiLocked
  2868. {
  2869. Vector2 mousePoint = GetMousePosition();
  2870. if (editMode)
  2871. {
  2872. state = GUI_STATE_PRESSED;
  2873. // Change active with keys
  2874. if (IsKeyPressed(KEY_UP))
  2875. {
  2876. if (auxActive > 0)
  2877. {
  2878. auxActive--;
  2879. if ((useScrollBar) && (auxActive < startIndex)) startIndex--;
  2880. }
  2881. pressedKey = true;
  2882. }
  2883. else if (IsKeyPressed(KEY_DOWN))
  2884. {
  2885. if (auxActive < count - 1)
  2886. {
  2887. auxActive++;
  2888. if ((useScrollBar) && (auxActive >= endIndex)) startIndex++;
  2889. }
  2890. pressedKey = true;
  2891. }
  2892. if (useScrollBar)
  2893. {
  2894. endIndex = startIndex + visibleElements;
  2895. if (CheckCollisionPointRec(mousePoint, viewArea))
  2896. {
  2897. int wheel = GetMouseWheelMove();
  2898. if (wheel < 0 && endIndex < count) startIndex -= wheel;
  2899. else if (wheel > 0 && startIndex > 0) startIndex -= wheel;
  2900. }
  2901. if (pressedKey)
  2902. {
  2903. pressedKey = false;
  2904. if ((auxActive < startIndex) || (auxActive >= endIndex)) startIndex = auxActive;
  2905. }
  2906. if (startIndex < 0) startIndex = 0;
  2907. else if (startIndex > (count - (endIndex - startIndex)))
  2908. {
  2909. startIndex = count - (endIndex - startIndex);
  2910. }
  2911. endIndex = startIndex + visibleElements;
  2912. if (endIndex > count) endIndex = count;
  2913. }
  2914. }
  2915. if (!editMode)
  2916. {
  2917. if (CheckCollisionPointRec(mousePoint, viewArea))
  2918. {
  2919. state = GUI_STATE_FOCUSED;
  2920. if (IsMouseButtonPressed(0)) pressed = true;
  2921. startIndex -= GetMouseWheelMove();
  2922. if (startIndex < 0) startIndex = 0;
  2923. else if (startIndex > (count - (endIndex - startIndex)))
  2924. {
  2925. startIndex = count - (endIndex - startIndex);
  2926. }
  2927. pressed = true;
  2928. }
  2929. }
  2930. else
  2931. {
  2932. if (!CheckCollisionPointRec(mousePoint, viewArea))
  2933. {
  2934. if (IsMouseButtonPressed(0) || (GetMouseWheelMove() != 0)) pressed = true;
  2935. }
  2936. }
  2937. // Get focused element
  2938. for (int i = startIndex; i < endIndex; i++)
  2939. {
  2940. if (CheckCollisionPointRec(mousePoint, RAYGUI_CLITERAL(Rectangle){ (float)posX, (float)bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), (float)elementWidth, (float)GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }))
  2941. {
  2942. focusElement = i;
  2943. }
  2944. }
  2945. }
  2946. const int slider = GuiGetStyle(SCROLLBAR, SLIDER_SIZE); // Save default slider size
  2947. // Calculate percentage of visible elements and apply same percentage to scrollbar
  2948. if (useScrollBar)
  2949. {
  2950. float percentVisible = (endIndex - startIndex)*100/count;
  2951. barHeight *= percentVisible/100;
  2952. if (barHeight < minBarHeight) barHeight = minBarHeight;
  2953. else if (barHeight > bounds.height) barHeight = bounds.height;
  2954. GuiSetStyle(SCROLLBAR, SLIDER_SIZE, barHeight); // Change slider size
  2955. }
  2956. //--------------------------------------------------------------------
  2957. // Draw control
  2958. //--------------------------------------------------------------------
  2959. DrawRectangleRec(bounds, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background
  2960. // Draw scrollBar
  2961. if (useScrollBar)
  2962. {
  2963. const int scrollSpeed = GuiGetStyle(SCROLLBAR, SCROLL_SPEED); // Save default scroll speed
  2964. GuiSetStyle(SCROLLBAR, SCROLL_SPEED, count - visibleElements); // Hack to make the spinner buttons work
  2965. int index = scrollIndex != NULL? *scrollIndex : startIndex;
  2966. index = GuiScrollBar(scrollBarRect, index, 0, count - visibleElements);
  2967. GuiSetStyle(SCROLLBAR, SCROLL_SPEED, scrollSpeed); // Reset scroll speed to default
  2968. GuiSetStyle(SCROLLBAR, SLIDER_SIZE, slider); // Reset slider size to default
  2969. // FIXME: Quick hack to make this thing work, think of a better way
  2970. if (scrollIndex != NULL && CheckCollisionPointRec(GetMousePosition(), scrollBarRect) && IsMouseButtonDown(MOUSE_LEFT_BUTTON))
  2971. {
  2972. startIndex = index;
  2973. if (startIndex < 0) startIndex = 0;
  2974. if (startIndex > (count - (endIndex - startIndex)))
  2975. {
  2976. startIndex = count - (endIndex - startIndex);
  2977. }
  2978. endIndex = startIndex + visibleElements;
  2979. if (endIndex > count) endIndex = count;
  2980. }
  2981. }
  2982. DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), guiAlpha));
  2983. // Draw ListView states
  2984. switch (state)
  2985. {
  2986. case GUI_STATE_NORMAL:
  2987. {
  2988. for (int i = startIndex; i < endIndex; i++)
  2989. {
  2990. if ((enabled != NULL) && (enabled[i] == 0))
  2991. {
  2992. GuiDisable();
  2993. GuiListElement(RAYGUI_CLITERAL(Rectangle){ (float)posX, (float)bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), (float)elementWidth, (float)GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], false, false);
  2994. GuiEnable();
  2995. }
  2996. else if (i == auxActive)
  2997. {
  2998. GuiDisable();
  2999. GuiListElement(RAYGUI_CLITERAL(Rectangle){ (float)posX, (float)bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), (float)elementWidth, (float)GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], true, false);
  3000. GuiEnable();
  3001. }
  3002. else GuiListElement(RAYGUI_CLITERAL(Rectangle){ (float)posX, (float)bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), (float)elementWidth, (float)GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], false, false);
  3003. }
  3004. } break;
  3005. case GUI_STATE_FOCUSED:
  3006. {
  3007. for (int i = startIndex; i < endIndex; i++)
  3008. {
  3009. if ((enabled != NULL) && (enabled[i] == 0))
  3010. {
  3011. GuiDisable();
  3012. GuiListElement(RAYGUI_CLITERAL(Rectangle){ (float)posX, (float)bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), (float)elementWidth, (float)GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], false, false);
  3013. GuiEnable();
  3014. }
  3015. else if (i == auxActive) GuiListElement(RAYGUI_CLITERAL(Rectangle){ (float)posX, (float)bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), (float)elementWidth, (float)GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], true, false);
  3016. else GuiListElement(RAYGUI_CLITERAL(Rectangle){ (float)posX, (float)bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), (float)elementWidth, (float)GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], false, false);
  3017. }
  3018. } break;
  3019. case GUI_STATE_PRESSED:
  3020. {
  3021. for (int i = startIndex; i < endIndex; i++)
  3022. {
  3023. if ((enabled != NULL) && (enabled[i] == 0))
  3024. {
  3025. GuiDisable();
  3026. GuiListElement(RAYGUI_CLITERAL(Rectangle){ (float)posX, (float)bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), (float)elementWidth, (float)GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], false, false);
  3027. GuiEnable();
  3028. }
  3029. else if ((i == auxActive) && editMode)
  3030. {
  3031. if (GuiListElement(RAYGUI_CLITERAL(Rectangle){ (float)posX, (float)bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), (float)elementWidth, (float)GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], true, true) == false) auxActive = -1;
  3032. }
  3033. else
  3034. {
  3035. if (GuiListElement(RAYGUI_CLITERAL(Rectangle){ (float)posX, (float)bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), (float)elementWidth, (float)GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], false, true) == true) auxActive = i;
  3036. }
  3037. }
  3038. } break;
  3039. case GUI_STATE_DISABLED:
  3040. {
  3041. for (int i = startIndex; i < endIndex; i++)
  3042. {
  3043. if (i == auxActive) GuiListElement(RAYGUI_CLITERAL(Rectangle){ (float)posX, (float)bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), (float)elementWidth, (float)GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], true, false);
  3044. else GuiListElement(RAYGUI_CLITERAL(Rectangle){ (float)posX, (float)bounds.y + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH) + (i - startIndex)*(GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) + GuiGetStyle(LISTVIEW, ELEMENTS_PADDING)), (float)elementWidth, (float)GuiGetStyle(LISTVIEW, ELEMENTS_HEIGHT) }, text[i], false, false);
  3045. }
  3046. } break;
  3047. default: break;
  3048. }
  3049. //--------------------------------------------------------------------
  3050. if (scrollIndex != NULL) *scrollIndex = startIndex;
  3051. if (focus != NULL) *focus = focusElement;
  3052. *active = auxActive;
  3053. return pressed;
  3054. }
  3055. // Color Panel control
  3056. RAYGUIDEF Color GuiColorPanelEx(Rectangle bounds, Color color, float hue)
  3057. {
  3058. GuiControlState state = guiState;
  3059. Vector2 pickerSelector = { 0 };
  3060. Vector3 vcolor = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
  3061. Vector3 hsv = ConvertRGBtoHSV(vcolor);
  3062. pickerSelector.x = bounds.x + (float)hsv.y*bounds.width; // HSV: Saturation
  3063. pickerSelector.y = bounds.y + (1.0f - (float)hsv.z)*bounds.height; // HSV: Value
  3064. Vector3 maxHue = { hue >= 0.0f ? hue : hsv.x, 1.0f, 1.0f };
  3065. Vector3 rgbHue = ConvertHSVtoRGB(maxHue);
  3066. Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x),
  3067. (unsigned char)(255.0f*rgbHue.y),
  3068. (unsigned char)(255.0f*rgbHue.z), 255 };
  3069. const Color colWhite = { 255, 255, 255, 255 };
  3070. const Color colBlack = { 0, 0, 0, 255 };
  3071. // Update control
  3072. //--------------------------------------------------------------------
  3073. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  3074. {
  3075. Vector2 mousePoint = GetMousePosition();
  3076. if (CheckCollisionPointRec(mousePoint, bounds))
  3077. {
  3078. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
  3079. {
  3080. state = GUI_STATE_PRESSED;
  3081. pickerSelector = mousePoint;
  3082. // Calculate color from picker
  3083. Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y };
  3084. colorPick.x /= (float)bounds.width; // Get normalized value on x
  3085. colorPick.y /= (float)bounds.height; // Get normalized value on y
  3086. hsv.y = colorPick.x;
  3087. hsv.z = 1.0f - colorPick.y;
  3088. Vector3 rgb = ConvertHSVtoRGB(hsv);
  3089. // NOTE: Vector3ToColor() only available on raylib 1.8.1
  3090. color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x),
  3091. (unsigned char)(255.0f*rgb.y),
  3092. (unsigned char)(255.0f*rgb.z),
  3093. (unsigned char)(255.0f*(float)color.a/255.0f) };
  3094. }
  3095. else state = GUI_STATE_FOCUSED;
  3096. }
  3097. }
  3098. //--------------------------------------------------------------------
  3099. // Draw control
  3100. //--------------------------------------------------------------------
  3101. if (state != GUI_STATE_DISABLED)
  3102. {
  3103. DrawRectangleGradientEx(bounds, Fade(colWhite, guiAlpha), Fade(colWhite, guiAlpha), Fade(maxHueCol, guiAlpha), Fade(maxHueCol, guiAlpha));
  3104. DrawRectangleGradientEx(bounds, Fade(colBlack, 0), Fade(colBlack, guiAlpha), Fade(colBlack, guiAlpha), Fade(colBlack, 0));
  3105. // Draw color picker: selector
  3106. 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(colWhite, guiAlpha));
  3107. }
  3108. else
  3109. {
  3110. DrawRectangleGradientEx(bounds, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.6f), guiAlpha));
  3111. }
  3112. DrawRectangleLinesEx(bounds, 1, Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha));
  3113. //--------------------------------------------------------------------
  3114. return color;
  3115. }
  3116. RAYGUIDEF Color GuiColorPanel(Rectangle bounds, Color color)
  3117. {
  3118. return GuiColorPanelEx(bounds, color, -1.0f);
  3119. }
  3120. // Color Bar Alpha control
  3121. // NOTE: Returns alpha value normalized [0..1]
  3122. RAYGUIDEF float GuiColorBarAlpha(Rectangle bounds, float alpha)
  3123. {
  3124. #define COLORBARALPHA_CHECKED_SIZE 10
  3125. GuiControlState state = guiState;
  3126. Rectangle selector = { (float)bounds.x + alpha*bounds.width - GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING), (float)bounds.y - GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING), (float)GuiGetStyle(COLORPICKER, BAR_SELECTOR_HEIGHT), (float)bounds.height + GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING)*2 };
  3127. // Update control
  3128. //--------------------------------------------------------------------
  3129. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  3130. {
  3131. Vector2 mousePoint = GetMousePosition();
  3132. if (CheckCollisionPointRec(mousePoint, bounds) ||
  3133. CheckCollisionPointRec(mousePoint, selector))
  3134. {
  3135. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
  3136. {
  3137. state = GUI_STATE_PRESSED;
  3138. selector.x = mousePoint.x - selector.width/2;
  3139. alpha = (mousePoint.x - bounds.x)/bounds.width;
  3140. if (alpha <= 0.0f) alpha = 0.0f;
  3141. if (alpha >= 1.0f) alpha = 1.0f;
  3142. //selector.x = bounds.x + (int)(((alpha - 0)/(100 - 0))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))) - selector.width/2;
  3143. }
  3144. else state = GUI_STATE_FOCUSED;
  3145. }
  3146. }
  3147. //--------------------------------------------------------------------
  3148. // Draw control
  3149. //--------------------------------------------------------------------
  3150. // Draw alpha bar: checked background
  3151. if (state != GUI_STATE_DISABLED)
  3152. {
  3153. int checksX = bounds.width/COLORBARALPHA_CHECKED_SIZE;
  3154. int checksY = bounds.height/COLORBARALPHA_CHECKED_SIZE;
  3155. for (int x = 0; x < checksX; x++)
  3156. {
  3157. for (int y = 0; y < checksY; y++)
  3158. {
  3159. DrawRectangle(bounds.x + x*COLORBARALPHA_CHECKED_SIZE,
  3160. bounds.y + y*COLORBARALPHA_CHECKED_SIZE,
  3161. COLORBARALPHA_CHECKED_SIZE, COLORBARALPHA_CHECKED_SIZE,
  3162. ((x + y)%2)? Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.4f), guiAlpha) :
  3163. Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.4f), guiAlpha));
  3164. }
  3165. }
  3166. DrawRectangleGradientEx(bounds, RAYGUI_CLITERAL(Color){ 255, 255, 255, 0 }, RAYGUI_CLITERAL(Color){ 255, 255, 255, 0 }, Fade(RAYGUI_CLITERAL(Color){ 0, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 0, 255 }, guiAlpha));
  3167. }
  3168. else DrawRectangleGradientEx(bounds, Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha));
  3169. DrawRectangleLinesEx(bounds, 1, Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha));
  3170. // Draw alpha bar: selector
  3171. DrawRectangleRec(selector, Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha));
  3172. //--------------------------------------------------------------------
  3173. return alpha;
  3174. }
  3175. // Color Bar Hue control
  3176. // NOTE: Returns hue value normalized [0..1]
  3177. RAYGUIDEF float GuiColorBarHue(Rectangle bounds, float hue)
  3178. {
  3179. GuiControlState state = guiState;
  3180. Rectangle selector = { (float)bounds.x - GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING), (float)bounds.y + hue/360.0f*bounds.height - GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING), (float)bounds.width + GuiGetStyle(COLORPICKER, BAR_SELECTOR_PADDING)*2, (float)GuiGetStyle(COLORPICKER, BAR_SELECTOR_HEIGHT) };
  3181. // Update control
  3182. //--------------------------------------------------------------------
  3183. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  3184. {
  3185. Vector2 mousePoint = GetMousePosition();
  3186. if (CheckCollisionPointRec(mousePoint, bounds) ||
  3187. CheckCollisionPointRec(mousePoint, selector))
  3188. {
  3189. if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
  3190. {
  3191. state = GUI_STATE_PRESSED;
  3192. selector.y = mousePoint.y - selector.height/2;
  3193. hue = (mousePoint.y - bounds.y)*360/bounds.height;
  3194. if (hue <= 0.0f) hue = 0.0f;
  3195. if (hue >= 359.0f) hue = 359.0f;
  3196. }
  3197. else state = GUI_STATE_FOCUSED;
  3198. /*if (IsKeyDown(KEY_UP))
  3199. {
  3200. hue -= 2.0f;
  3201. if (hue <= 0.0f) hue = 0.0f;
  3202. }
  3203. else if (IsKeyDown(KEY_DOWN))
  3204. {
  3205. hue += 2.0f;
  3206. if (hue >= 360.0f) hue = 360.0f;
  3207. }*/
  3208. }
  3209. }
  3210. //--------------------------------------------------------------------
  3211. // Draw control
  3212. //--------------------------------------------------------------------
  3213. if (state != GUI_STATE_DISABLED)
  3214. {
  3215. // Draw hue bar:color bars
  3216. 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(RAYGUI_CLITERAL(Color){ 255,0,0,255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255,255,0,255 }, guiAlpha));
  3217. 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(RAYGUI_CLITERAL(Color){ 255,255,0,255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0,255,0,255 }, guiAlpha));
  3218. 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(RAYGUI_CLITERAL(Color){ 0,255,0,255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0,255,255,255 }, guiAlpha));
  3219. 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(RAYGUI_CLITERAL(Color){ 0,255,255,255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0,0,255,255 }, guiAlpha));
  3220. 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(RAYGUI_CLITERAL(Color){ 0,0,255,255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255,0,255,255 }, guiAlpha));
  3221. 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(RAYGUI_CLITERAL(Color){ 255,0,255,255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255,0,0,255 }, guiAlpha));
  3222. }
  3223. else 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));
  3224. DrawRectangleLinesEx(bounds, 1, Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha));
  3225. // Draw hue bar: selector
  3226. DrawRectangleRec(selector, Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha));
  3227. //--------------------------------------------------------------------
  3228. return hue;
  3229. }
  3230. // TODO: Color GuiColorBarSat() [WHITE->color]
  3231. // TODO: Color GuiColorBarValue() [BLACK->color], HSV / HSL
  3232. // TODO: float GuiColorBarLuminance() [BLACK->WHITE]
  3233. // Color Picker control
  3234. // NOTE: It's divided in multiple controls:
  3235. // Color GuiColorPanel() - Color select panel
  3236. // float GuiColorBarAlpha(Rectangle bounds, float alpha)
  3237. // float GuiColorBarHue(Rectangle bounds, float value)
  3238. // NOTE: bounds define GuiColorPanel() size
  3239. RAYGUIDEF Color GuiColorPicker(Rectangle bounds, Color color)
  3240. {
  3241. color = GuiColorPanel(bounds, color);
  3242. Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, BAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, BAR_WIDTH), (float)bounds.height };
  3243. //Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) };
  3244. Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ color.r/255.0f, color.g/255.0f, color.b/255.0f });
  3245. hsv.x = GuiColorBarHue(boundsHue, hsv.x);
  3246. //color.a = (unsigned char)(GuiColorBarAlpha(boundsAlpha, (float)color.a/255.0f)*255.0f);
  3247. Vector3 rgb = ConvertHSVtoRGB(hsv);
  3248. color = RAYGUI_CLITERAL(Color){ (unsigned char)(rgb.x*255.0f), (unsigned char)(rgb.y*255.0f), (unsigned char)(rgb.z*255.0f), color.a };
  3249. return color;
  3250. }
  3251. // Message Box control
  3252. RAYGUIDEF int GuiMessageBox(Rectangle bounds, const char *windowTitle, const char *message, const char *buttons)
  3253. {
  3254. #define MESSAGEBOX_BUTTON_HEIGHT 24
  3255. #define MESSAGEBOX_BUTTON_PADDING 10
  3256. int clicked = -1; // Returns clicked button from buttons list, 0 refers to closed window button
  3257. int buttonsCount = 0;
  3258. const char **buttonsText = GuiTextSplit(buttons, &buttonsCount, NULL);
  3259. Vector2 textSize = MeasureTextEx(guiFont, message, GuiGetStyle(DEFAULT, TEXT_SIZE), 1);
  3260. Rectangle textBounds = { 0 };
  3261. textBounds.x = bounds.x + bounds.width/2 - textSize.x/2;
  3262. textBounds.y = bounds.y + WINDOW_STATUSBAR_HEIGHT + (bounds.height - WINDOW_STATUSBAR_HEIGHT)/4 - textSize.y/2;
  3263. textBounds.width = textSize.x;
  3264. textBounds.height = textSize.y;
  3265. Rectangle buttonBounds = { 0 };
  3266. buttonBounds.x = bounds.x + MESSAGEBOX_BUTTON_PADDING;
  3267. buttonBounds.y = bounds.y + bounds.height/2 + bounds.height/4 - MESSAGEBOX_BUTTON_HEIGHT/2;
  3268. buttonBounds.width = (bounds.width - MESSAGEBOX_BUTTON_PADDING*(buttonsCount + 1))/buttonsCount;
  3269. buttonBounds.height = MESSAGEBOX_BUTTON_HEIGHT;
  3270. // Draw control
  3271. //--------------------------------------------------------------------
  3272. if (GuiWindowBox(bounds, windowTitle)) clicked = 0;
  3273. int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT);
  3274. GuiSetStyle(LABEL, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
  3275. GuiLabel(textBounds, message);
  3276. GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment);
  3277. prevTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
  3278. GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
  3279. for (int i = 0; i < buttonsCount; i++)
  3280. {
  3281. if (GuiButton(buttonBounds, buttonsText[i])) clicked = i + 1;
  3282. buttonBounds.x += (buttonBounds.width + MESSAGEBOX_BUTTON_PADDING);
  3283. }
  3284. GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevTextAlignment);
  3285. //--------------------------------------------------------------------
  3286. return clicked;
  3287. }
  3288. // Text Input Box control, ask for text
  3289. RAYGUIDEF int GuiTextInputBox(Rectangle bounds, const char *windowTitle, const char *message, char *text, const char *buttons)
  3290. {
  3291. int btnIndex = -1;
  3292. // TODO: GuiTextInputBox()
  3293. return btnIndex;
  3294. }
  3295. // Grid control
  3296. // NOTE: Returns grid mouse-hover selected cell
  3297. // About drawing lines at subpixel spacing, simple put, not easy solution:
  3298. // https://stackoverflow.com/questions/4435450/2d-opengl-drawing-lines-that-dont-exactly-fit-pixel-raster
  3299. RAYGUIDEF Vector2 GuiGrid(Rectangle bounds, float spacing, int subdivs)
  3300. {
  3301. #define GRID_COLOR_ALPHA 0.15f // Grid lines alpha amount
  3302. GuiControlState state = guiState;
  3303. Vector2 mousePoint = GetMousePosition();
  3304. Vector2 currentCell = { -1, -1 };
  3305. int linesV = ((int)(bounds.width/spacing) + 1)*subdivs;
  3306. int linesH = ((int)(bounds.height/spacing) + 1)*subdivs;
  3307. // Update control
  3308. //--------------------------------------------------------------------
  3309. if ((state != GUI_STATE_DISABLED) && !guiLocked)
  3310. {
  3311. if (CheckCollisionPointRec(mousePoint, bounds))
  3312. {
  3313. currentCell.x = (int)((mousePoint.x - bounds.x)/spacing);
  3314. currentCell.y = (int)((mousePoint.y - bounds.y)/spacing);
  3315. }
  3316. }
  3317. //--------------------------------------------------------------------
  3318. // Draw control
  3319. //--------------------------------------------------------------------
  3320. switch (state)
  3321. {
  3322. case GUI_STATE_NORMAL:
  3323. {
  3324. // Draw vertical grid lines
  3325. for (int i = 0; i < linesV; i++)
  3326. {
  3327. DrawRectangleRec(RAYGUI_CLITERAL(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));
  3328. }
  3329. // Draw horizontal grid lines
  3330. for (int i = 0; i < linesH; i++)
  3331. {
  3332. DrawRectangleRec(RAYGUI_CLITERAL(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));
  3333. }
  3334. } break;
  3335. default: break;
  3336. }
  3337. return currentCell;
  3338. }
  3339. //----------------------------------------------------------------------------------
  3340. // Styles loading functions
  3341. //----------------------------------------------------------------------------------
  3342. // Load raygui style file (.rgs)
  3343. RAYGUIDEF void GuiLoadStyle(const char *fileName)
  3344. {
  3345. bool tryBinary = false;
  3346. // Try reading the files as text file first
  3347. FILE *rgsFile = fopen(fileName, "rt");
  3348. if (rgsFile != NULL)
  3349. {
  3350. char buffer[256] = { 0 };
  3351. fgets(buffer, 256, rgsFile);
  3352. if (buffer[0] == '#')
  3353. {
  3354. int controlId = 0;
  3355. int propertyId = 0;
  3356. int propertyValue = 0;
  3357. while (!feof(rgsFile))
  3358. {
  3359. switch (buffer[0])
  3360. {
  3361. case 'p':
  3362. {
  3363. sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue);
  3364. if (controlId == 0) // DEFAULT control
  3365. {
  3366. // If a DEFAULT property is loaded, it is propagated to all controls,
  3367. // NOTE: All DEFAULT properties should be defined first in the file
  3368. GuiSetStyle(0, propertyId, propertyValue);
  3369. if (propertyId < NUM_PROPS_DEFAULT) for (int i = 1; i < NUM_CONTROLS; i++) GuiSetStyle(i, propertyId, propertyValue);
  3370. }
  3371. else GuiSetStyle(controlId, propertyId, propertyValue);
  3372. } break;
  3373. case 'f':
  3374. {
  3375. int fontSize = 0;
  3376. int fontSpacing = 0;
  3377. char fontFileName[256] = { 0 };
  3378. sscanf(buffer, "f %d %d %[^\n]s", &fontSize, &fontSpacing, fontFileName);
  3379. Font font = LoadFontEx(FormatText("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, NULL, 0);
  3380. if ((font.texture.id > 0) && (font.charsCount > 0))
  3381. {
  3382. GuiFont(font);
  3383. GuiSetStyle(DEFAULT, TEXT_SIZE, fontSize);
  3384. GuiSetStyle(DEFAULT, TEXT_SPACING, fontSpacing);
  3385. }
  3386. } break;
  3387. default: break;
  3388. }
  3389. fgets(buffer, 256, rgsFile);
  3390. }
  3391. }
  3392. else tryBinary = true;
  3393. fclose(rgsFile);
  3394. }
  3395. else return;
  3396. if (tryBinary)
  3397. {
  3398. rgsFile = fopen(fileName, "rb");
  3399. if (rgsFile == NULL) return;
  3400. char signature[5] = "";
  3401. short version = 0;
  3402. short reserved = 0;
  3403. int propertiesCount = 0;
  3404. fread(signature, 1, 4, rgsFile);
  3405. fread(&version, 1, sizeof(short), rgsFile);
  3406. fread(&reserved, 1, sizeof(short), rgsFile);
  3407. fread(&propertiesCount, 1, sizeof(int), rgsFile);
  3408. if ((signature[0] == 'r') &&
  3409. (signature[1] == 'G') &&
  3410. (signature[2] == 'S') &&
  3411. (signature[3] == ' '))
  3412. {
  3413. short controlId = 0;
  3414. short propertyId = 0;
  3415. int propertyValue = 0;
  3416. for (int i = 0; i < propertiesCount; i++)
  3417. {
  3418. fread(&controlId, 1, sizeof(short), rgsFile);
  3419. fread(&propertyId, 1, sizeof(short), rgsFile);
  3420. fread(&propertyValue, 1, sizeof(int), rgsFile);
  3421. if (controlId == 0) // DEFAULT control
  3422. {
  3423. // If a DEFAULT property is loaded, it is propagated to all controls
  3424. // NOTE: All DEFAULT properties should be defined first in the file
  3425. GuiSetStyle(0, (int)propertyId, propertyValue);
  3426. if (propertyId < NUM_PROPS_DEFAULT) for (int i = 1; i < NUM_CONTROLS; i++) GuiSetStyle(i, (int)propertyId, propertyValue);
  3427. }
  3428. else GuiSetStyle((int)controlId, (int)propertyId, propertyValue);
  3429. }
  3430. // Font loading is highly dependant on raylib API to load font data and image
  3431. // TODO: Find some mechanism to support it in standalone mode
  3432. #if !defined(RAYGUI_STANDALONE)
  3433. // Load custom font if available
  3434. int fontDataSize = 0;
  3435. fread(&fontDataSize, 1, sizeof(int), rgsFile);
  3436. if (fontDataSize > 0)
  3437. {
  3438. Font font = { 0 };
  3439. int fontType = 0; // 0-Normal, 1-SDF
  3440. Rectangle whiteRec = { 0 };
  3441. fread(&font.baseSize, 1, sizeof(int), rgsFile);
  3442. fread(&font.charsCount, 1, sizeof(int), rgsFile);
  3443. fread(&fontType, 1, sizeof(int), rgsFile);
  3444. // Load font white rectangle
  3445. fread(&whiteRec, 1, sizeof(Rectangle), rgsFile);
  3446. // Load font image parameters
  3447. int fontImageSize = 0;
  3448. fread(&fontImageSize, 1, sizeof(int), rgsFile);
  3449. if (fontImageSize > 0)
  3450. {
  3451. Image imFont = { 0 };
  3452. imFont.mipmaps = 1;
  3453. fread(&imFont.width, 1, sizeof(int), rgsFile);
  3454. fread(&imFont.height, 1, sizeof(int), rgsFile);
  3455. fread(&imFont.format, 1, sizeof(int), rgsFile);
  3456. imFont.data = (unsigned char *)malloc(fontImageSize);
  3457. fread(imFont.data, 1, fontImageSize, rgsFile);
  3458. font.texture = LoadTextureFromImage(imFont);
  3459. UnloadImage(imFont);
  3460. }
  3461. // Load font chars data
  3462. font.chars = (CharInfo *)calloc(font.charsCount, sizeof(CharInfo));
  3463. for (int i = 0; i < font.charsCount; i++)
  3464. {
  3465. fread(&font.recs[i], 1, sizeof(Rectangle), rgsFile);
  3466. fread(&font.chars[i].value, 1, sizeof(int), rgsFile);
  3467. fread(&font.chars[i].offsetX, 1, sizeof(int), rgsFile);
  3468. fread(&font.chars[i].offsetY, 1, sizeof(int), rgsFile);
  3469. fread(&font.chars[i].advanceX, 1, sizeof(int), rgsFile);
  3470. }
  3471. GuiFont(font);
  3472. // Set font texture source rectangle to be used as white texture to draw shapes
  3473. // NOTE: This way, all gui can be draw using a single draw call
  3474. if ((whiteRec.width != 0) && (whiteRec.height != 0)) SetShapesTexture(font.texture, whiteRec);
  3475. }
  3476. #endif
  3477. }
  3478. fclose(rgsFile);
  3479. }
  3480. }
  3481. // Load style from a palette values array
  3482. RAYGUIDEF void GuiLoadStyleProps(const int *props, int count)
  3483. {
  3484. int completeSets = count/(NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED);
  3485. int uncompleteSetProps = count%(NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED);
  3486. // Load style palette values from array (complete property sets)
  3487. for (int i = 0; i < completeSets; i++)
  3488. {
  3489. for (int j = 0; j < (NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED); j++) GuiSetStyle(i, j, props[i]);
  3490. }
  3491. // Load style palette values from array (uncomplete property set)
  3492. for (int k = 0; k < uncompleteSetProps; k++) GuiSetStyle(completeSets, k, props[completeSets*(NUM_PROPS_DEFAULT + NUM_PROPS_EXTENDED) + k]);
  3493. }
  3494. // Load style default over global style
  3495. RAYGUIDEF void GuiLoadStyleDefault(void)
  3496. {
  3497. // We set this variable first to avoid cyclic function calls
  3498. // when calling GuiSetStyle() and GuiGetStyle()
  3499. guiStyleLoaded = true;
  3500. // Initialize default LIGHT style property values
  3501. GuiSetStyle(DEFAULT, BORDER_COLOR_NORMAL, 0x838383ff);
  3502. GuiSetStyle(DEFAULT, BASE_COLOR_NORMAL, 0xc9c9c9ff);
  3503. GuiSetStyle(DEFAULT, TEXT_COLOR_NORMAL, 0x686868ff);
  3504. GuiSetStyle(DEFAULT, BORDER_COLOR_FOCUSED, 0x5bb2d9ff);
  3505. GuiSetStyle(DEFAULT, BASE_COLOR_FOCUSED, 0xc9effeff);
  3506. GuiSetStyle(DEFAULT, TEXT_COLOR_FOCUSED, 0x6c9bbcff);
  3507. GuiSetStyle(DEFAULT, BORDER_COLOR_PRESSED, 0x0492c7ff);
  3508. GuiSetStyle(DEFAULT, BASE_COLOR_PRESSED, 0x97e8ffff);
  3509. GuiSetStyle(DEFAULT, TEXT_COLOR_PRESSED, 0x368bafff);
  3510. GuiSetStyle(DEFAULT, BORDER_COLOR_DISABLED, 0xb5c1c2ff);
  3511. GuiSetStyle(DEFAULT, BASE_COLOR_DISABLED, 0xe6e9e9ff);
  3512. GuiSetStyle(DEFAULT, TEXT_COLOR_DISABLED, 0xaeb7b8ff);
  3513. GuiSetStyle(DEFAULT, BORDER_WIDTH, 1);
  3514. GuiSetStyle(DEFAULT, INNER_PADDING, 1);
  3515. GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
  3516. // Populate all controls with default style
  3517. for (int i = 1; i < NUM_CONTROLS; i++)
  3518. {
  3519. for (int j = 0; j < NUM_PROPS_DEFAULT; j++) GuiSetStyle(i, j, GuiGetStyle(DEFAULT, j));
  3520. }
  3521. guiFont = GetFontDefault(); // Initialize default font
  3522. // Initialize extended property values
  3523. // NOTE: By default, extended property values are initialized to 0
  3524. GuiSetStyle(DEFAULT, TEXT_SIZE, 10);
  3525. GuiSetStyle(DEFAULT, TEXT_SPACING, 1);
  3526. GuiSetStyle(DEFAULT, LINE_COLOR, 0x90abb5ff); // DEFAULT specific property
  3527. GuiSetStyle(DEFAULT, BACKGROUND_COLOR, 0xf5f5f5ff); // DEFAULT specific property
  3528. GuiSetStyle(LABEL, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT);
  3529. GuiSetStyle(BUTTON, BORDER_WIDTH, 2);
  3530. GuiSetStyle(BUTTON, INNER_PADDING, 4);
  3531. GuiSetStyle(TOGGLE, GROUP_PADDING, 2);
  3532. GuiSetStyle(SLIDER, SLIDER_WIDTH, 15);
  3533. GuiSetStyle(SLIDER, TEXT_PADDING, 5);
  3534. GuiSetStyle(CHECKBOX, CHECK_TEXT_PADDING, 5);
  3535. GuiSetStyle(COMBOBOX, SELECTOR_WIDTH, 30);
  3536. GuiSetStyle(COMBOBOX, SELECTOR_PADDING, 2);
  3537. GuiSetStyle(DROPDOWNBOX, ARROW_RIGHT_PADDING, 16);
  3538. GuiSetStyle(TEXTBOX, INNER_PADDING, 4);
  3539. GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT);
  3540. GuiSetStyle(TEXTBOX, MULTILINE_PADDING, 5);
  3541. GuiSetStyle(TEXTBOX, COLOR_SELECTED_FG, 0xf0fffeff);
  3542. GuiSetStyle(TEXTBOX, COLOR_SELECTED_BG, 0x839affe0);
  3543. GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER);
  3544. GuiSetStyle(SPINNER, SELECT_BUTTON_WIDTH, 20);
  3545. GuiSetStyle(SPINNER, SELECT_BUTTON_PADDING, 2);
  3546. GuiSetStyle(SPINNER, SELECT_BUTTON_BORDER_WIDTH, 1);
  3547. GuiSetStyle(SCROLLBAR, BORDER_WIDTH, 0);
  3548. GuiSetStyle(SCROLLBAR, ARROWS_VISIBLE, 0);
  3549. GuiSetStyle(SCROLLBAR, INNER_PADDING, 0);
  3550. GuiSetStyle(SCROLLBAR, ARROWS_SIZE, 6);
  3551. GuiSetStyle(SCROLLBAR, SLIDER_PADDING, 0);
  3552. GuiSetStyle(SCROLLBAR, SLIDER_SIZE, 16);
  3553. GuiSetStyle(SCROLLBAR, SCROLL_SPEED, 10);
  3554. GuiSetStyle(LISTVIEW, ELEMENTS_HEIGHT, 0x1e);
  3555. GuiSetStyle(LISTVIEW, ELEMENTS_PADDING, 2);
  3556. GuiSetStyle(LISTVIEW, SCROLLBAR_WIDTH, 10);
  3557. GuiSetStyle(LISTVIEW, SCROLLBAR_SIDE, SCROLLBAR_RIGHT_SIDE);
  3558. GuiSetStyle(COLORPICKER, COLOR_SELECTOR_SIZE, 6);
  3559. GuiSetStyle(COLORPICKER, BAR_WIDTH, 0x14);
  3560. GuiSetStyle(COLORPICKER, BAR_PADDING, 0xa);
  3561. GuiSetStyle(COLORPICKER, BAR_SELECTOR_HEIGHT, 6);
  3562. GuiSetStyle(COLORPICKER, BAR_SELECTOR_PADDING, 2);
  3563. }
  3564. // Updates controls style with default values
  3565. RAYGUIDEF void GuiUpdateStyleComplete(void)
  3566. {
  3567. // Populate all controls with default style
  3568. // NOTE: Extended style properties are ignored
  3569. for (int i = 1; i < NUM_CONTROLS; i++)
  3570. {
  3571. for (int j = 0; j < NUM_PROPS_DEFAULT; j++) GuiSetStyle(i, j, GuiGetStyle(DEFAULT, j));
  3572. }
  3573. }
  3574. // Get text with icon id prepended
  3575. // NOTE: Useful to add icons by name id (enum) instead of
  3576. // a number that can change between ricon versions
  3577. RAYGUIDEF const char *GuiIconText(int iconId, const char *text)
  3578. {
  3579. static char buffer[1024] = { 0 };
  3580. memset(buffer, 0, 1024);
  3581. sprintf(buffer, "#%03i#", iconId);
  3582. if (text != NULL)
  3583. {
  3584. for (int i = 5; i < 1024; i++)
  3585. {
  3586. buffer[i] = text[i - 5];
  3587. if (text[i - 5] == '\0') break;
  3588. }
  3589. }
  3590. return buffer;
  3591. }
  3592. //----------------------------------------------------------------------------------
  3593. // Module specific Functions Definition
  3594. //----------------------------------------------------------------------------------
  3595. // Split controls text into multiple strings
  3596. // Also check for multiple columns (required by GuiToggleGroup())
  3597. static const char **GuiTextSplit(const char *text, int *count, int *textRow)
  3598. {
  3599. // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
  3600. // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
  3601. // all used memory is static... it has some limitations:
  3602. // 1. Maximum number of possible split strings is set by MAX_SUBSTRINGS_COUNT
  3603. // 2. Maximum size of text to split is MAX_TEXT_BUFFER_LENGTH
  3604. #define MAX_TEXT_BUFFER_LENGTH 1024
  3605. #define MAX_SUBSTRINGS_COUNT 64
  3606. static const char *result[MAX_SUBSTRINGS_COUNT] = { NULL };
  3607. static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
  3608. memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
  3609. result[0] = buffer;
  3610. int counter = 1;
  3611. if (textRow != NULL) textRow[0] = 0;
  3612. // Count how many substrings we have on text and point to every one
  3613. for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
  3614. {
  3615. buffer[i] = text[i];
  3616. if (buffer[i] == '\0') break;
  3617. else if ((buffer[i] == ';') || (buffer[i] == '\n'))
  3618. {
  3619. result[counter] = buffer + i + 1;
  3620. if (textRow != NULL)
  3621. {
  3622. if (buffer[i] == '\n') textRow[counter] = textRow[counter - 1] + 1;
  3623. else textRow[counter] = textRow[counter - 1];
  3624. }
  3625. buffer[i] = '\0'; // Set an end of string at this point
  3626. counter++;
  3627. if (counter == MAX_SUBSTRINGS_COUNT) break;
  3628. }
  3629. }
  3630. *count = counter;
  3631. return result;
  3632. }
  3633. // Convert color data from RGB to HSV
  3634. // NOTE: Color data should be passed normalized
  3635. static Vector3 ConvertRGBtoHSV(Vector3 rgb)
  3636. {
  3637. Vector3 hsv = { 0 };
  3638. float min = 0.0f;
  3639. float max = 0.0f;
  3640. float delta = 0.0f;
  3641. min = (rgb.x < rgb.y)? rgb.x : rgb.y;
  3642. min = (min < rgb.z)? min : rgb.z;
  3643. max = (rgb.x > rgb.y)? rgb.x : rgb.y;
  3644. max = (max > rgb.z)? max : rgb.z;
  3645. hsv.z = max; // Value
  3646. delta = max - min;
  3647. if (delta < 0.00001f)
  3648. {
  3649. hsv.y = 0.0f;
  3650. hsv.x = 0.0f; // Undefined, maybe NAN?
  3651. return hsv;
  3652. }
  3653. if (max > 0.0f)
  3654. {
  3655. // NOTE: If max is 0, this divide would cause a crash
  3656. hsv.y = (delta/max); // Saturation
  3657. }
  3658. else
  3659. {
  3660. // NOTE: If max is 0, then r = g = b = 0, s = 0, h is undefined
  3661. hsv.y = 0.0f;
  3662. hsv.x = 0.0f; // Undefined, maybe NAN?
  3663. return hsv;
  3664. }
  3665. // NOTE: Comparing float values could not work properly
  3666. if (rgb.x >= max) hsv.x = (rgb.y - rgb.z)/delta; // Between yellow & magenta
  3667. else
  3668. {
  3669. if (rgb.y >= max) hsv.x = 2.0f + (rgb.z - rgb.x)/delta; // Between cyan & yellow
  3670. else hsv.x = 4.0f + (rgb.x - rgb.y)/delta; // Between magenta & cyan
  3671. }
  3672. hsv.x *= 60.0f; // Convert to degrees
  3673. if (hsv.x < 0.0f) hsv.x += 360.0f;
  3674. return hsv;
  3675. }
  3676. // Convert color data from HSV to RGB
  3677. // NOTE: Color data should be passed normalized
  3678. static Vector3 ConvertHSVtoRGB(Vector3 hsv)
  3679. {
  3680. Vector3 rgb = { 0 };
  3681. float hh = 0.0f, p = 0.0f, q = 0.0f, t = 0.0f, ff = 0.0f;
  3682. long i = 0;
  3683. // NOTE: Comparing float values could not work properly
  3684. if (hsv.y <= 0.0f)
  3685. {
  3686. rgb.x = hsv.z;
  3687. rgb.y = hsv.z;
  3688. rgb.z = hsv.z;
  3689. return rgb;
  3690. }
  3691. hh = hsv.x;
  3692. if (hh >= 360.0f) hh = 0.0f;
  3693. hh /= 60.0f;
  3694. i = (long)hh;
  3695. ff = hh - i;
  3696. p = hsv.z*(1.0f - hsv.y);
  3697. q = hsv.z*(1.0f - (hsv.y*ff));
  3698. t = hsv.z*(1.0f - (hsv.y*(1.0f - ff)));
  3699. switch (i)
  3700. {
  3701. case 0:
  3702. {
  3703. rgb.x = hsv.z;
  3704. rgb.y = t;
  3705. rgb.z = p;
  3706. } break;
  3707. case 1:
  3708. {
  3709. rgb.x = q;
  3710. rgb.y = hsv.z;
  3711. rgb.z = p;
  3712. } break;
  3713. case 2:
  3714. {
  3715. rgb.x = p;
  3716. rgb.y = hsv.z;
  3717. rgb.z = t;
  3718. } break;
  3719. case 3:
  3720. {
  3721. rgb.x = p;
  3722. rgb.y = q;
  3723. rgb.z = hsv.z;
  3724. } break;
  3725. case 4:
  3726. {
  3727. rgb.x = t;
  3728. rgb.y = p;
  3729. rgb.z = hsv.z;
  3730. } break;
  3731. case 5:
  3732. default:
  3733. {
  3734. rgb.x = hsv.z;
  3735. rgb.y = p;
  3736. rgb.z = q;
  3737. } break;
  3738. }
  3739. return rgb;
  3740. }
  3741. #if defined(RAYGUI_STANDALONE)
  3742. // Returns a Color struct from hexadecimal value
  3743. static Color GetColor(int hexValue)
  3744. {
  3745. Color color;
  3746. color.r = (unsigned char)(hexValue >> 24) & 0xFF;
  3747. color.g = (unsigned char)(hexValue >> 16) & 0xFF;
  3748. color.b = (unsigned char)(hexValue >> 8) & 0xFF;
  3749. color.a = (unsigned char)hexValue & 0xFF;
  3750. return color;
  3751. }
  3752. // Returns hexadecimal value for a Color
  3753. static int ColorToInt(Color color)
  3754. {
  3755. return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a);
  3756. }
  3757. // Check if point is inside rectangle
  3758. static bool CheckCollisionPointRec(Vector2 point, Rectangle rec)
  3759. {
  3760. bool collision = false;
  3761. if ((point.x >= rec.x) && (point.x <= (rec.x + rec.width)) &&
  3762. (point.y >= rec.y) && (point.y <= (rec.y + rec.height))) collision = true;
  3763. return collision;
  3764. }
  3765. // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
  3766. static Color Fade(Color color, float alpha)
  3767. {
  3768. if (alpha < 0.0f) alpha = 0.0f;
  3769. else if (alpha > 1.0f) alpha = 1.0f;
  3770. return RAYGUI_CLITERAL(Color){ color.r, color.g, color.b, (unsigned char)(255.0f*alpha) };
  3771. }
  3772. // Formatting of text with variables to 'embed'
  3773. static const char *TextFormat(const char *text, ...)
  3774. {
  3775. #define MAX_FORMATTEXT_LENGTH 64
  3776. static char buffer[MAX_FORMATTEXT_LENGTH];
  3777. va_list args;
  3778. va_start(args, text);
  3779. vsprintf(buffer, text, args);
  3780. va_end(args);
  3781. return buffer;
  3782. }
  3783. // Draw rectangle filled with color
  3784. static void DrawRectangleRec(Rectangle rec, Color color)
  3785. {
  3786. DrawRectangle(rec.x, rec.y, rec.width, rec.height, color);
  3787. }
  3788. // Draw rectangle border lines with color
  3789. static void DrawRectangleLinesEx(Rectangle rec, int lineThick, Color color)
  3790. {
  3791. DrawRectangle(rec.x, rec.y, rec.width, lineThick, color);
  3792. DrawRectangle(rec.x, rec.y + lineThick, lineThick, rec.height - 2*lineThick, color);
  3793. DrawRectangle(rec.x + rec.width - lineThick, rec.y + lineThick, lineThick, rec.height - 2*lineThick, color);
  3794. DrawRectangle(rec.x, rec.y + rec.height - lineThick, rec.width, lineThick, color);
  3795. }
  3796. // Draw rectangle with vertical gradient fill color
  3797. // NOTE: This function is only used by GuiColorPicker()
  3798. static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2)
  3799. {
  3800. Rectangle bounds = { (float)posX, (float)posY, (float)width, (float)height };
  3801. DrawRectangleGradientEx(bounds, color1, color2, color2, color1);
  3802. }
  3803. #endif // RAYGUI_STANDALONE
  3804. #endif // RAYGUI_IMPLEMENTATION