imspinner.h 234 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462
  1. #ifndef _IMSPINNER_H_
  2. #define _IMSPINNER_H_
  3. /*
  4. * The MIT License (MIT)
  5. *
  6. * Copyright (c) 2021-2022 Dalerank
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in all
  16. * copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  24. * SOFTWARE.
  25. *
  26. */
  27. #include <functional>
  28. #include <array>
  29. #include <vector>
  30. #include <cmath>
  31. #include <map>
  32. #include <cctype>
  33. #ifdef __has_include
  34. #if !__has_include(<imgui.h>)
  35. #error "Couldn't find imgui.h in the header include path, please add it to the path!"
  36. #endif // !<imgui.h>
  37. #endif // __has_include
  38. // imgui headers
  39. #include "imgui.h"
  40. #include "imgui_internal.h"
  41. namespace ImSpinner
  42. {
  43. static const ImColor white{1.f, 1.f, 1.f, 1.f};
  44. static const ImColor half_white{1.f, 1.f, 1.f, 0.5f};
  45. static const ImColor red{1.f,0.f,0.f,1.f};
  46. #define DECLPROP(name, type, def) \
  47. struct name { \
  48. type value = def; \
  49. operator type() { return value; } \
  50. name(const type& v) : value(v) {} \
  51. };
  52. enum SpinnerTypeT {
  53. e_st_rainbow = 0,
  54. e_st_angle,
  55. e_st_dots,
  56. e_st_ang,
  57. e_st_vdots,
  58. e_st_bounce_ball,
  59. e_st_eclipse,
  60. e_st_ingyang,
  61. e_st_count
  62. };
  63. using float_ptr = float *;
  64. constexpr float PI_DIV_4 = IM_PI / 4.f;
  65. constexpr float PI_DIV_2 = IM_PI / 2.f;
  66. constexpr float PI_2 = IM_PI * 2.f;
  67. template<class T> constexpr float PI_DIV(T d) { return IM_PI / (float)d; }
  68. template<class T> constexpr float PI_2_DIV(T d) { return PI_2 / (float)d; }
  69. DECLPROP (SpinnerType, SpinnerTypeT, e_st_rainbow)
  70. DECLPROP (Radius, float, 16.f)
  71. DECLPROP (Speed, float, 1.f)
  72. DECLPROP (Thickness, float, 1.f)
  73. DECLPROP (Color, ImColor, white)
  74. DECLPROP (BgColor, ImColor, white)
  75. DECLPROP (AltColor, ImColor, white)
  76. DECLPROP (Angle, float, IM_PI)
  77. DECLPROP (AngleMin, float, IM_PI)
  78. DECLPROP (AngleMax, float, IM_PI)
  79. DECLPROP (FloatPtr, float_ptr, nullptr)
  80. DECLPROP (Dots, int, 0)
  81. DECLPROP (MiddleDots, int, 0)
  82. DECLPROP (MinThickness, float, 0.f)
  83. DECLPROP (Reverse, bool, false)
  84. DECLPROP (Delta, float, 0.f)
  85. #undef DECLPROP
  86. namespace detail {
  87. // SpinnerBegin is a function that starts a spinner widget, used to display an animation indicating that
  88. // a task is in progress. It returns true if the widget is visible and can be used, or false if it should be skipped.
  89. inline bool SpinnerBegin(const char *label, float radius, ImVec2 &pos, ImVec2 &size, ImVec2 &centre, int &num_segments) {
  90. ImGuiWindow *window = ImGui::GetCurrentWindow();
  91. if (window->SkipItems)
  92. return false;
  93. ImGuiContext &g = *GImGui;
  94. const ImGuiStyle &style = g.Style;
  95. const ImGuiID id = window->GetID(label);
  96. pos = window->DC.CursorPos;
  97. // The size of the spinner is set to twice the radius, plus some padding based on the style
  98. size = ImVec2((radius) * 2, (radius + style.FramePadding.y) * 2);
  99. const ImRect bb(pos, ImVec2(pos.x + size.x, pos.y + size.y));
  100. ImGui::ItemSize(bb, style.FramePadding.y);
  101. num_segments = window->DrawList->_CalcCircleAutoSegmentCount(radius);
  102. centre = bb.GetCenter();
  103. // If the item cannot be added to the window, return false
  104. if (!ImGui::ItemAdd(bb, id))
  105. return false;
  106. return true;
  107. }
  108. #define IMPLRPOP(basetype,type) basetype m_##type; \
  109. void set##type(const basetype& v) { m_##type = v;} \
  110. void set(type h) { m_##type = h.value;} \
  111. template<typename First, typename... Args> \
  112. void set(const type& h, const Args&... args) { set##type(h.value); this->template set<Args...>(args...); }
  113. struct SpinnerConfig {
  114. SpinnerConfig() {}
  115. template<typename none = void> void set() {}
  116. template<typename... Args>
  117. SpinnerConfig(const Args&... args) { this->template set<Args...>(args...); }
  118. IMPLRPOP(SpinnerTypeT, SpinnerType)
  119. IMPLRPOP(float, Radius)
  120. IMPLRPOP(float, Speed)
  121. IMPLRPOP(float, Thickness)
  122. IMPLRPOP(ImColor, Color)
  123. IMPLRPOP(ImColor, BgColor)
  124. IMPLRPOP(ImColor, AltColor)
  125. IMPLRPOP(float, Angle)
  126. IMPLRPOP(float, AngleMin)
  127. IMPLRPOP(float, AngleMax)
  128. IMPLRPOP(float_ptr, FloatPtr)
  129. IMPLRPOP(int, Dots)
  130. IMPLRPOP(int, MiddleDots)
  131. IMPLRPOP(float, MinThickness)
  132. IMPLRPOP(bool, Reverse)
  133. IMPLRPOP(float, Delta)
  134. };
  135. #undef IMPLRPOP
  136. }
  137. #define SPINNER_HEADER(pos, size, centre, num_segments) \
  138. ImVec2 pos, size, centre; int num_segments; \
  139. if (!detail::SpinnerBegin(label, radius, pos, size, centre, num_segments)) { return; }; \
  140. ImGuiWindow *window = ImGui::GetCurrentWindow(); \
  141. auto circle = [&] (const std::function<ImVec2 (int)>& point_func, ImU32 dbc, float dth) { \
  142. window->DrawList->PathClear(); \
  143. for (int i = 0; i < num_segments; i++) { \
  144. ImVec2 p = point_func(i); \
  145. window->DrawList->PathLineTo(ImVec2(centre.x + p.x, centre.y + p.y)); \
  146. } \
  147. window->DrawList->PathStroke(dbc, 0, dth); \
  148. }
  149. inline ImColor color_alpha(ImColor c, float alpha) { c.Value.w *= alpha * ImGui::GetStyle().Alpha; return c; }
  150. inline float damped_spring (double mass, double stiffness, double damping, double time, float a = PI_DIV_2, float b = PI_DIV_2) {
  151. double omega = sqrt(stiffness / mass);
  152. double alpha = damping / (2.0 * mass);
  153. double exponent = exp(-alpha * time);
  154. double cosTerm = cos(omega * sqrt(1 - alpha * alpha) * time);
  155. float result = (float)(exponent * cosTerm);
  156. return ((result *= a) + b);
  157. };
  158. inline float damped_gravity(float limtime) {
  159. float time = 0.0f, initialHeight = 10.f, height = initialHeight, velocity = 0.0f, prtime = 0.0f;
  160. while (height >= 0.0f) {
  161. if (prtime >= limtime) { return height / 10.f; }
  162. time += 0.01f; prtime += 0.01f;
  163. height = initialHeight - 0.5f * 9.81f * time * time;
  164. if (height < 0.0f) { initialHeight = 0.0f; time = 0.0f; }
  165. }
  166. return 0.f;
  167. }
  168. /*
  169. const char *label: A string label for the spinner, used to identify it in ImGui.
  170. float radius: The radius of the spinner.
  171. float thickness: The thickness of the spinner's border.
  172. const ImColor &color: The color of the spinner.
  173. float speed: The speed of the spinning animation.
  174. float ang_min: Minimum angle of spinning.
  175. float ang_max: Maximum angle of spinning.
  176. int arcs: Number of arcs of the spinner.
  177. */
  178. inline void SpinnerRainbow(const char *label, float radius, float thickness, const ImColor &color, float speed, float ang_min = 0.f, float ang_max = PI_2, int arcs = 1)
  179. {
  180. SPINNER_HEADER(pos, size, centre, num_segments);
  181. for (int i = 0; i < arcs; ++i)
  182. {
  183. const float rb = (radius / arcs) * (i + 1);
  184. const float start = ImAbs(ImSin((float)ImGui::GetTime()) * (num_segments - 5));
  185. const float a_min = ImMax(ang_min, (float)PI_2 * ((float)start) / (float)num_segments + (IM_PI / arcs) * i);
  186. const float a_max = ImMin(ang_max, (float)PI_2 * ((float)num_segments + 3 * (i + 1)) / (float)num_segments);
  187. circle([&] (int i) {
  188. const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
  189. const float rspeed = a + (float)ImGui::GetTime() * speed;
  190. return ImVec2(ImCos(rspeed) * rb, ImSin(rspeed) * rb);
  191. }, color_alpha(color, 1.f), thickness);
  192. }
  193. }
  194. inline void SpinnerRainbowMix(const char *label, float radius, float thickness, const ImColor &color, float speed, float ang_min = 0.f, float ang_max = PI_2, int arcs = 1, int mode = 0)
  195. {
  196. SPINNER_HEADER(pos, size, centre, num_segments);
  197. float out_h, out_s, out_v;
  198. ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, out_h, out_s, out_v);
  199. for (int i = 0; i < arcs; ++i)
  200. {
  201. const float rb = (radius / arcs) * (i + 1);
  202. const float start = ImAbs(ImSin((float)ImGui::GetTime()) * (num_segments - 5));
  203. const float a_min = ImMax(ang_min, (float)PI_2 * ((float)start) / (float)num_segments + (IM_PI / arcs) * i);
  204. const float a_max = ImMin(ang_max, (float)PI_2 * ((float)num_segments + 3 * (i + 1)) / (float)num_segments);
  205. const float koeff = mode ? (1.1f - 1.f / (i+1)) : 1.f;
  206. ImColor c = ImColor::HSV(out_h + i * (1.f / arcs), out_s, out_v);
  207. circle([&] (int i) {
  208. const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
  209. const float rspeed = a + (float)ImGui::GetTime() * speed * koeff;
  210. return ImVec2(ImCos(rspeed) * rb, ImSin(rspeed) * rb);
  211. }, color_alpha(c, 1.f), thickness);
  212. }
  213. }
  214. // This function draws a rotating heart spinner.
  215. inline void SpinnerRotatingHeart(const char *label, float radius, float thickness, const ImColor &color, float speed, float ang_min = 0.f)
  216. {
  217. // Calculate the position and size of the spinner, as well as the number of segments it will be divided into.
  218. SPINNER_HEADER(pos, size, centre, num_segments);
  219. // Calculate the start angle of the spinner based on the current time and speed.
  220. const float start = (float)ImGui::GetTime() * speed;
  221. // Modify the number of segments to ensure the heart shape is complete.
  222. num_segments = (num_segments * 3) / 2;
  223. // Create a lambda function to rotate points.
  224. auto rotate = [] (const ImVec2 &point, float angle) {
  225. const float s = ImSin(angle), c = ImCos(angle);
  226. return ImVec2(point.x * c - point.y * s, point.x * s + point.y * c);
  227. };
  228. // Calculate the radius of the bottom of the heart.
  229. const float rb = radius * ImMax(0.8f, ImSin(start * 2));
  230. auto scale = [rb] (float v) { return v / 16.f * rb; };
  231. // Draw the heart spinner by calling the circle function, passing in a lambda function that defines the shape of the heart.
  232. circle([&] (int i) {
  233. const float a = PI_2 * i / num_segments;
  234. const float x = (scale(16) * ImPow(ImSin(a), 3));
  235. const float y = -1.f * (scale(13) * ImCos(a) - scale(5) * ImCos(2 * a) - scale(2) * ImCos(3 * a) - ImCos(4 * a));
  236. return rotate(ImVec2(x, y), ang_min);
  237. }, color_alpha(color, 1.f), thickness);
  238. }
  239. // SpinnerAng is a function that draws a spinner widget with a given angle.
  240. inline void SpinnerAng(const char *label, float radius, float thickness, const ImColor &color = white, const ImColor &bg = white, float speed = 2.8f, float angle = IM_PI, int mode = 0)
  241. {
  242. SPINNER_HEADER(pos, size, centre, num_segments); // Get the position, size, centre, and number of segments of the spinner using the SPINNER_HEADER macro.
  243. float start = (float)ImGui::GetTime() * speed; // The start angle of the spinner is calculated based on the current time and the specified speed.
  244. radius = (mode == 2) ? (0.8f + ImCos(start) * 0.2f) * radius : radius;
  245. circle([&] (int i) { // Draw the background of the spinner using the `circle` function, with the specified background color and thickness.
  246. const float a = start + (i * (PI_2 / (num_segments - 1))); // Calculate the angle for each segment based on the start angle and the number of segments.
  247. return ImVec2(ImCos(a) * radius, ImSin(a) * radius);
  248. }, color_alpha(bg, 1.f), thickness);
  249. const float b = (mode == 1) ? damped_gravity(ImSin(start * 1.1f)) * angle : 0.f;
  250. circle([&] (int i) { // Draw the spinner itself using the `circle` function, with the specified color and thickness.
  251. const float a = start - b + (i * angle / num_segments);
  252. return ImVec2(ImCos(a) * radius, ImSin(a) * radius);
  253. }, color_alpha(color, 1.f), thickness);
  254. }
  255. inline void SpinnerAngMix(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, float angle = IM_PI, int arcs = 4, int mode = 0)
  256. {
  257. SPINNER_HEADER(pos, size, centre, num_segments); // Get the position, size, centre, and number of segments of the spinner using the SPINNER_HEADER macro.
  258. for (int i = 0; i < arcs; ++i)
  259. {
  260. const float koeff = (1.1f - 1.f / (i+1));
  261. float start = (float)ImGui::GetTime() * speed * koeff; // The start angle of the spinner is calculated based on the current time and the specified speed.
  262. radius = (mode == 2) ? (0.8f + ImCos(start) * 0.2f) * radius : radius;
  263. const float rb = (radius / arcs) * (i + 1);
  264. const float b = (mode == 1) ? damped_gravity(ImSin(start * 1.1f)) * angle : 0.f;
  265. circle([&] (int i) { // Draw the spinner itself using the `circle` function, with the specified color and thickness.
  266. const float a = start - b + (i * angle / num_segments);
  267. return ImVec2(ImCos(a) * rb, ImSin(a) * rb);
  268. }, color_alpha(color, 1.f), thickness);
  269. }
  270. }
  271. inline void SpinnerLoadingRing(const char *label, float radius, float thickness, const ImColor &color = white, const ImColor &bg = half_white, float speed = 2.8f, int segments = 5)
  272. {
  273. SPINNER_HEADER(pos, size, centre, num_segments);
  274. const float start = ImFmod((float)ImGui::GetTime() * speed, IM_PI); // Calculate the starting angle based on the current time and speed
  275. const float bg_angle_offset = PI_2 / num_segments - 1;
  276. num_segments *= 2; // Double the number of segments for the background ringxxxxxxx
  277. circle([&] (int i) {
  278. return ImVec2(ImCos(i * bg_angle_offset) * radius, ImSin(i * bg_angle_offset) * radius); // Draw the background ring
  279. }, color_alpha(bg, 1.f), thickness);
  280. float out_h, out_s, out_v;
  281. ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, out_h, out_s, out_v); // Convert the color to HSV for variation in segment colors
  282. const float start_ang = (start < PI_DIV_2) ? 0.f : (start - PI_DIV_2) * 4.f; // Calculate the angles and delta angle for each segment
  283. const float angle_offset = ((start < PI_DIV_2) ? PI_2 : (PI_2 - start_ang)) / segments;
  284. const float delta_angle = (start < PI_DIV_2) ? ImSin(start) * angle_offset : angle_offset;
  285. for (int i = 0; i < segments; ++i) // Draw each segment of the loading ring
  286. {
  287. window->DrawList->PathClear();
  288. const float begin_ang = start_ang - PI_DIV_2 + delta_angle * i;
  289. ImColor c = ImColor::HSV(out_h + i * (1.f / segments * 2.f), out_s, out_v);
  290. window->DrawList->PathArcTo(centre, radius, begin_ang, begin_ang + delta_angle, num_segments);
  291. window->DrawList->PathStroke(color_alpha(c, 1.f), false, thickness);
  292. }
  293. }
  294. inline void SpinnerClock(const char *label, float radius, float thickness, const ImColor &color = white, const ImColor &bg = half_white, float speed = 2.8f)
  295. {
  296. SPINNER_HEADER(pos, size, centre, num_segments);
  297. const float start = (float)ImGui::GetTime() * speed;
  298. const float bg_angle_offset = PI_2 / (num_segments - 1);
  299. circle([&] (int i) { return ImVec2(ImCos(i * bg_angle_offset) * radius, ImSin(i * bg_angle_offset) * radius); }, color_alpha(bg, 1.f), thickness);
  300. window->DrawList->AddLine(centre, ImVec2(centre.x + ImCos(start) * radius, centre.y + ImSin(start) * radius), color_alpha(color, 1.f), thickness * 2);
  301. window->DrawList->AddLine(centre, ImVec2(centre.x + ImCos(start * 0.5f) * radius / 2.f, centre.y + ImSin(start * 0.5f) * radius / 2.f), color_alpha(color, 1.f), thickness * 2);
  302. }
  303. inline void SpinnerPulsar(const char *label, float radius, float thickness, const ImColor &bg = half_white, float speed = 2.8f, bool sequence = true)
  304. {
  305. SPINNER_HEADER(pos, size, centre, num_segments);
  306. ImGuiStorage* storage = window->DC.StateStorage;
  307. const ImGuiID radiusbId = window->GetID("##radiusb");
  308. float radius_b = storage->GetFloat(radiusbId, 0.8f);
  309. const float start = (float)ImGui::GetTime() * speed;
  310. const float bg_angle_offset = PI_2 / (num_segments - 1);
  311. float start_r = ImFmod(start, PI_DIV_2);
  312. float radius_k = ImSin(start_r);
  313. float radius1 = radius_k * radius;
  314. circle([&] (int i) {
  315. return ImVec2(ImCos(i * bg_angle_offset) * radius1, ImSin(i * bg_angle_offset) * radius1);
  316. }, color_alpha(bg, 1.f), thickness);
  317. if (sequence) { radius_b -= (0.005f * speed); radius_b = ImMax(radius_k, ImMax(0.8f, radius_b)); }
  318. else { radius_b = (1.f - radius_k); }
  319. storage->SetFloat(radiusbId, radius_b);
  320. float radius_tb = sequence ? ImMax(radius_k, radius_b) * radius : (radius_b * radius);
  321. circle([&] (int i) {
  322. return ImVec2(ImCos(i * bg_angle_offset) * radius_tb, ImSin(i * bg_angle_offset) * radius_tb);
  323. }, color_alpha(bg, 1.f), thickness);
  324. }
  325. inline void SpinnerDoubleFadePulsar(const char *label, float radius, float /*thickness*/, const ImColor &bg = half_white, float speed = 2.8f)
  326. {
  327. SPINNER_HEADER(pos, size, centre, num_segments);
  328. ImGuiStorage* storage = window->DC.StateStorage;
  329. const ImGuiID radiusbId = window->GetID("##radiusb");
  330. float radius_b = storage->GetFloat(radiusbId, 0.8f);
  331. const float start = (float)ImGui::GetTime() * speed;
  332. const float bg_angle_offset = PI_2_DIV(num_segments);
  333. float start_r = ImFmod(start, PI_DIV_2);
  334. float radius_k = ImSin(start_r);
  335. window->DrawList->AddCircleFilled(centre, radius_k * radius, color_alpha(bg, ImMin(0.1f, radius_k)), num_segments);
  336. radius_b = (1.f - radius_k);
  337. storage->SetFloat(radiusbId, radius_b);
  338. window->DrawList->AddCircleFilled(centre, radius_b * radius, color_alpha(bg, ImMin(0.3f, radius_b)), num_segments);
  339. }
  340. inline void SpinnerTwinPulsar(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, int rings = 2)
  341. {
  342. SPINNER_HEADER(pos, size, centre, num_segments);
  343. const float bg_angle_offset = PI_2 / (num_segments - 1);
  344. const float koeff = PI_DIV(2 * rings);
  345. float start = (float)ImGui::GetTime() * speed;
  346. for (int num_ring = 0; num_ring < rings; ++num_ring) {
  347. float radius_k = ImSin(ImFmod(start + (num_ring * koeff), PI_DIV_2));
  348. float radius1 = radius_k * radius;
  349. circle([&] (int i) {
  350. const float a = start + (i * bg_angle_offset);
  351. return ImVec2(ImCos(a) * radius1, ImSin(a) * radius1);
  352. }, color_alpha(color, radius_k > 0.5f ? 2.f - (radius_k * 2.f) : color.Value.w), thickness);
  353. }
  354. }
  355. inline void SpinnerFadePulsar(const char *label, float radius, const ImColor &color = white, float speed = 2.8f, int rings = 2)
  356. {
  357. SPINNER_HEADER(pos, size, centre, num_segments);
  358. const float bg_angle_offset = PI_2_DIV(num_segments);
  359. const float koeff = PI_DIV(2 * rings);
  360. float start = (float)ImGui::GetTime() * speed;
  361. for (int num_ring = 0; num_ring < rings; ++num_ring) {
  362. float radius_k = ImSin(ImFmod(start + (num_ring * koeff), PI_DIV_2));
  363. ImColor c = color_alpha(color, (radius_k > 0.5f) ? (2.f - (radius_k * 2.f)) : color.Value.w);
  364. window->DrawList->AddCircleFilled(centre, radius_k * radius, c, num_segments);
  365. }
  366. }
  367. inline void SpinnerCircularLines(const char *label, float radius, const ImColor &color = white, float speed = 1.8f, int lines = 8)
  368. {
  369. SPINNER_HEADER(pos, size, centre, num_segments);
  370. auto ghalf_pi = [] (float f) -> float { return ImMin(f, PI_DIV_2); };
  371. const float start = ImFmod((float)ImGui::GetTime() * speed, IM_PI);
  372. const float bg_angle_offset = PI_2_DIV(lines);
  373. for (size_t j = 0; j < 3; ++j)
  374. {
  375. const float start_offset = j * PI_DIV(7.f);
  376. const float rmax = ImMax(ImSin(ghalf_pi(start - start_offset)), 0.3f) * radius;
  377. const float rmin = ImMax(ImSin(ghalf_pi(start - PI_DIV_4 - start_offset)), 0.3f) * radius;
  378. ImColor c = color_alpha(color, 1.f - j * 0.3f);
  379. for (size_t i = 0; i <= lines; i++)
  380. {
  381. float a = (i * bg_angle_offset);
  382. window->DrawList->AddLine(ImVec2(centre.x + ImCos(a) * rmin, centre.y + ImSin(a) * rmin),
  383. ImVec2(centre.x + ImCos(a) * rmax, centre.y + ImSin(a) * rmax),
  384. color_alpha(c, 1.f), 1.f);
  385. }
  386. }
  387. }
  388. inline void SpinnerDots(const char *label, float *nextdot, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, size_t dots = 12, float minth = -1.f)
  389. {
  390. SPINNER_HEADER(pos, size, centre, num_segments);
  391. const float start = (float)ImGui::GetTime() * speed;
  392. const float bg_angle_offset = PI_2 / dots;
  393. dots = ImMin(dots, (size_t)32);
  394. const size_t mdots = dots / 2;
  395. float def_nextdot = 0;
  396. float &ref_nextdot = nextdot ? *nextdot : def_nextdot;
  397. if (ref_nextdot < 0.f)
  398. ref_nextdot = (float)dots;
  399. auto thcorrect = [&thickness, &ref_nextdot, &mdots, &minth] (size_t i) {
  400. const float nth = minth < 0.f ? thickness / 2.f : minth;
  401. return ImMax(nth, ImSin(((i - ref_nextdot) / mdots) * IM_PI) * thickness);
  402. };
  403. for (size_t i = 0; i <= dots; i++)
  404. {
  405. float a = start + (i * bg_angle_offset);
  406. a = ImFmod(a, PI_2);
  407. float th = minth < 0 ? thickness / 2.f : minth;
  408. if (ref_nextdot + mdots < dots) {
  409. if (i > ref_nextdot && i < ref_nextdot + mdots)
  410. th = thcorrect(i);
  411. } else {
  412. if ((i > ref_nextdot && i < dots) || (i < ((int)(ref_nextdot + mdots)) % dots))
  413. th = thcorrect(i);
  414. }
  415. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(-a) * radius, centre.y + ImSin(-a) * radius), th, color_alpha(color, 1.f), 8);
  416. }
  417. }
  418. inline void SpinnerVDots(const char *label, float radius, float thickness, const ImColor &color = white, const ImColor &bgcolor = white, float speed = 2.8f, size_t dots = 12, size_t mdots = 6)
  419. {
  420. SPINNER_HEADER(pos, size, centre, num_segments);
  421. const float start = (float)ImGui::GetTime() * speed;
  422. const float bg_angle_offset = PI_2_DIV(dots);
  423. dots = ImMin(dots, (size_t)32);
  424. for (size_t i = 0; i <= dots; i++)
  425. {
  426. float a = ImFmod(start + (i * bg_angle_offset), PI_2);
  427. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(-a) * radius, centre.y + ImSin(-a) * radius), thickness / 2, color_alpha(bgcolor, 1.f), 8);
  428. }
  429. window->DrawList->PathClear();
  430. const float d_ang = (mdots / (float)dots) * PI_2;
  431. const float angle_offset = (d_ang) / dots;
  432. for (size_t i = 0; i < dots; i++)
  433. {
  434. const float a = start + (i * angle_offset);
  435. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * radius, centre.y + ImSin(a) * radius));
  436. }
  437. window->DrawList->PathStroke(color_alpha(color, 1.f), false, thickness);
  438. }
  439. inline void SpinnerBounceDots(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, size_t dots = 3, int mode = 0)
  440. {
  441. SPINNER_HEADER(pos, size, centre, num_segments);
  442. const float nextItemKoeff = 2.5f;
  443. const float heightKoeff = 2.f;
  444. const float heightSpeed = 0.8f;
  445. const float hsize = dots * (thickness * nextItemKoeff) / 2.f - (thickness * nextItemKoeff) * 0.5f;
  446. float start = (float)ImGui::GetTime() * speed;
  447. const float offset = PI_DIV(dots);
  448. for (size_t i = 0; i < dots; i++) {
  449. float a = mode ? damped_spring(1, 10.f, 1.0f, ImSin(ImFmod(start + i * PI_DIV(dots*2), PI_2))) : start + (IM_PI - i * offset);
  450. float y = centre.y + ImSin(a * heightSpeed) * thickness * heightKoeff;
  451. window->DrawList->AddCircleFilled(ImVec2(centre.x - hsize + i * (thickness * nextItemKoeff), ImMin(y, centre.y)), thickness, color_alpha(color, 1.f), 8);
  452. }
  453. }
  454. inline void SpinnerZipDots(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, size_t dots = 5)
  455. {
  456. SPINNER_HEADER(pos, size, centre, num_segments);
  457. const float nextItemKoeff = 3.5f;
  458. const float heightKoeff = 2.f;
  459. const float heightSpeed = 0.8f;
  460. const float hsize = dots * (thickness * nextItemKoeff) / 2.f - (thickness * nextItemKoeff) * 0.5f;
  461. const float start = (float)ImGui::GetTime() * speed;
  462. const float offset = PI_DIV(dots);
  463. for (size_t i = 0; i < dots; i++)
  464. {
  465. const float sina = ImSin((start + (IM_PI - i * offset)) * heightSpeed);
  466. const float y = ImMin(centre.y + sina * thickness * heightKoeff, centre.y);
  467. const float deltay = ImAbs(y - centre.y);
  468. window->DrawList->AddCircleFilled(ImVec2(centre.x - hsize + i * (thickness * nextItemKoeff), y), thickness, color_alpha(color, 1.f), 8);
  469. window->DrawList->AddCircleFilled(ImVec2(centre.x - hsize + i * (thickness * nextItemKoeff), y + 2 * deltay), thickness, color_alpha(color, 1.f), 8);
  470. }
  471. }
  472. inline void SpinnerDotsToPoints(const char *label, float radius, float thickness, float offset_k, const ImColor &color = white, float speed = 1.8f, size_t dots = 5)
  473. {
  474. SPINNER_HEADER(pos, size, centre, num_segments);
  475. const float nextItemKoeff = 3.5f;
  476. const float hsize = dots * (thickness * nextItemKoeff) / 2.f - (thickness * nextItemKoeff) * 0.5f;
  477. const float start = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  478. const float offset = PI_DIV(dots);
  479. float out_h, out_s, out_v;
  480. ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, out_h, out_s, out_v);
  481. if (start < PI_DIV_2) {
  482. const float sina = ImSin(start);
  483. for (size_t i = 0; i < dots; i++) {
  484. const float xx = ImMax(sina * (i * (thickness * nextItemKoeff)), 0.f);
  485. ImColor c = color_alpha(ImColor::HSV(out_h + i * ((1.f / dots) * 2.f), out_s, out_v), 1.f);
  486. window->DrawList->AddCircleFilled(ImVec2(centre.x - hsize + xx, centre.y), thickness, c, 8);
  487. }
  488. } else {
  489. for (size_t i = 0; i < dots; i++) {
  490. const float sina = ImSin(ImMax(start - (IM_PI / dots) * i, PI_DIV_2));
  491. const float xx = ImMax(1.f * (i * (thickness * nextItemKoeff)), 0.f);
  492. const float th = sina * thickness;
  493. ImColor c = color_alpha(ImColor::HSV(out_h + i * ((1.f / dots) * 2.f), out_s, out_v), 1.f);
  494. window->DrawList->AddCircleFilled(ImVec2(centre.x - hsize + xx, centre.y), th, c, 8);
  495. }
  496. }
  497. }
  498. //const float sina = ImSin( ImFmod((start + (IM_PI - i * offset)), PI_DIV_2));
  499. inline void SpinnerDotsToBar(const char *label, float radius, float thickness, float offset_k, const ImColor &color = white, float speed = 2.8f, size_t dots = 5)
  500. {
  501. SPINNER_HEADER(pos, size, centre, num_segments);
  502. const float nextItemKoeff = 3.5f;
  503. const float heightSpeed = 0.8f;
  504. const float hsize = dots * (thickness * nextItemKoeff) / 2.f - (thickness * nextItemKoeff) * 0.5f;
  505. const float start = (float)ImGui::GetTime() * speed;
  506. const float offset = PI_DIV(dots);
  507. const float hradius = (radius);
  508. float out_h, out_s, out_v;
  509. ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, out_h, out_s, out_v);
  510. for (size_t i = 0; i < dots; i++)
  511. {
  512. const float sina = ImSin((start + (IM_PI - i * offset)) * heightSpeed);
  513. const float sinb = ImSin((start + (IM_PI + IM_PI * offset_k - i * offset)) * heightSpeed);
  514. const float y = ImMin(centre.y + sina * hradius, centre.y);
  515. const float y2 = ImMin(sinb, 0.f) * (hradius * offset_k);
  516. const float y3 = (y + y2);
  517. const float deltay = ImAbs(y - centre.y);
  518. ImColor c = color_alpha(ImColor::HSV(out_h + i * ((1.f / dots) * 2.f), out_s, out_v), 1.f);
  519. ImVec2 p1(centre.x - hsize + i * (thickness * nextItemKoeff), y3);
  520. ImVec2 p2(centre.x - hsize + i * (thickness * nextItemKoeff), y3 + 2 * deltay);
  521. window->DrawList->AddCircleFilled(p1, thickness, c, 8);
  522. window->DrawList->AddCircleFilled(p2, thickness, c, 8);
  523. window->DrawList->AddLine(p1, p2, c, thickness * 2.f);
  524. }
  525. }
  526. inline void SpinnerWaveDots(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, int lt = 8)
  527. {
  528. SPINNER_HEADER(pos, size, centre, num_segments);
  529. const float nextItemKoeff = 2.5f;
  530. const float dots = (size.x / (thickness * nextItemKoeff));
  531. const float offset = PI_DIV(dots);
  532. const float start = (float)ImGui::GetTime() * speed;
  533. float out_h, out_s, out_v;
  534. ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, out_h, out_s, out_v);
  535. for (size_t i = 0; i < dots; i++)
  536. {
  537. float a = start + (IM_PI - i * offset);
  538. float y = centre.y + ImSin(a) * (size.y / 2.f);
  539. ImColor c = ImColor::HSV(out_h + i * (1.f / dots * 2.f), out_s, out_v);
  540. window->DrawList->AddCircleFilled(ImVec2(centre.x - (size.x / 2.f) + i * thickness * nextItemKoeff, y), thickness, color_alpha(c, 1.f), lt);
  541. }
  542. }
  543. inline void SpinnerFadeDots(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, int lt = 8, int mode = 0)
  544. {
  545. SPINNER_HEADER(pos, size, centre, num_segments);
  546. const float start = (float)ImGui::GetTime() * speed;
  547. const float nextItemKoeff = 2.5f;
  548. const float dots = (size.x / (thickness * nextItemKoeff));
  549. const float heightSpeed = 0.8f;
  550. for (size_t i = 0; i < dots; i++)
  551. {
  552. float a = mode
  553. ? damped_spring(1, 10.f, 1.0f, ImSin(ImFmod(start + (IM_PI - i * (IM_PI / dots)), PI_2)))
  554. : ImSin(start + (IM_PI - i * (IM_PI / dots)) * heightSpeed);
  555. window->DrawList->AddCircleFilled(ImVec2(centre.x - (size.x / 2.f) + i * thickness * nextItemKoeff, centre.y), thickness, color_alpha(color, ImMax(0.1f, a)), lt);
  556. }
  557. }
  558. inline void SpinnerThreeDots(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, int lt = 8)
  559. {
  560. SPINNER_HEADER(pos, size, centre, num_segments);
  561. const float start = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  562. const float nextItemKoeff = 2.5f;
  563. const float offset = size.x / 4.f;
  564. float ab = start;
  565. int msize = 2;
  566. if (start < IM_PI) { ab = 0; msize = 1; }
  567. for (size_t i = 0; i < msize; i++)
  568. {
  569. float a = ab + i * IM_PI - PI_DIV_2;
  570. window->DrawList->AddCircleFilled(ImVec2(centre.x - offset + ImSin(a) * offset, centre.y + ImCos(a) * offset), thickness, color_alpha(color, 1.f), lt);
  571. }
  572. float ba = start; msize = 2;
  573. if (start > IM_PI && start < PI_2) { ba = 0; msize = 1; }
  574. for (size_t i = 0; i < msize; i++)
  575. {
  576. float a = -ba + i * IM_PI + PI_DIV_2;
  577. window->DrawList->AddCircleFilled(ImVec2(centre.x + offset + ImSin(a) * offset, centre.y + ImCos(a) * offset), thickness, color_alpha(color, 1.f), lt);
  578. }
  579. }
  580. inline void SpinnerFiveDots(const char *label, float radius, float thickness, const ImColor &color = 0xffffffff, float speed = 2.8f, int lt = 8)
  581. {
  582. SPINNER_HEADER(pos, size, centre, num_segments);
  583. const float start = ImFmod((float)ImGui::GetTime() * speed, PI_2 * 2);
  584. const float nextItemKoeff = 2.5f;
  585. const float offset = size.x / 4.f;
  586. float ab = 0;
  587. int msize = 1;
  588. if (start < IM_PI) { ab = start; msize = 2; }
  589. for (size_t i = 0; i < msize; i++)
  590. {
  591. float a = -ab + i * IM_PI - PI_DIV_2;
  592. window->DrawList->AddCircleFilled(ImVec2(centre.x - offset + ImSin(a) * offset, centre.y + ImCos(a) * offset), thickness, color_alpha(color, 1.f), lt);
  593. }
  594. float ba = 0; msize = 1;
  595. if (start > IM_PI && start < PI_2) { ba = start; msize = 2; }
  596. for (size_t i = 0; i < msize; i++)
  597. {
  598. float a = -ba + i * IM_PI;
  599. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImSin(a) * offset, centre.y + offset + ImCos(a) * offset), thickness, color_alpha(color, 1.f), lt);
  600. }
  601. float bc = 0; msize = 1;
  602. if (start > PI_2 && start < IM_PI * 3) { bc = start; msize = 2; }
  603. for (size_t i = 0; i < msize; i++)
  604. {
  605. float a = -bc + i * IM_PI - IM_PI;
  606. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImSin(a) * offset, centre.y - offset + ImCos(a) * offset), thickness, color_alpha(color, 1.f), lt);
  607. }
  608. float bd = 0; msize = 1;
  609. if (start > IM_PI * 3 && start < IM_PI * 4) { bd = start; msize = 2; }
  610. for (size_t i = 0; i < msize; i++)
  611. {
  612. float a = -bd + i * IM_PI + PI_DIV_2;
  613. window->DrawList->AddCircleFilled(ImVec2(centre.x + offset + ImSin(a) * offset, centre.y + ImCos(a) * offset), thickness, color_alpha(color, 1.f), lt);
  614. }
  615. }
  616. inline void Spinner4Caleidospcope(const char *label, float radius, float thickness, const ImColor &color = 0xffffffff, float speed = 2.8f, int lt = 8)
  617. {
  618. SPINNER_HEADER(pos, size, centre, num_segments);
  619. const float start = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  620. const float nextItemKoeff = 2.5f;
  621. const float offset = size.x / 4.f;
  622. float ab = start;
  623. int msize = 2;
  624. float out_h, out_s, out_v;
  625. ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, out_h, out_s, out_v);
  626. for (size_t i = 0; i < msize; i++)
  627. {
  628. float a = ab - i * IM_PI;
  629. ImColor c = color_alpha(ImColor::HSV(out_h + (0.1f * i), out_s, out_v, 0.7f), 1.f);
  630. window->DrawList->AddCircleFilled(ImVec2(centre.x - offset + ImSin(a) * offset, centre.y + ImCos(a) * offset), thickness, c, lt);
  631. }
  632. for (size_t i = 0; i < msize; i++)
  633. {
  634. float a = ab + i * IM_PI + PI_DIV_2;
  635. ImColor c = color_alpha(ImColor::HSV(out_h + 0.2f + (0.1f * i), out_s, out_v, 0.7f), 1.f);
  636. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImSin(a) * offset, centre.y - offset + ImCos(a) * offset), thickness, c, lt);
  637. }
  638. float ba = start; msize = 2;
  639. for (size_t i = 0; i < msize; i++)
  640. {
  641. float a = -ba + i * IM_PI + PI_DIV_2;
  642. ImColor c = color_alpha(ImColor::HSV(out_h + 0.4f + (0.1f * i), out_s, out_v, 0.7f), 1.f);
  643. window->DrawList->AddCircleFilled(ImVec2(centre.x + offset + ImSin(a) * offset, centre.y + ImCos(a) * offset), thickness, c, lt);
  644. }
  645. for (size_t i = 0; i < msize; i++)
  646. {
  647. float a = ab - i * IM_PI + PI_DIV_4;
  648. ImColor c = color_alpha(ImColor::HSV(out_h + 0.6f + (0.1f * i), out_s, out_v, 0.7f), 1.f);
  649. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImSin(a) * offset, centre.y + offset + ImCos(a) * offset), thickness, c, lt);
  650. }
  651. }
  652. inline void SpinnerMultiFadeDots(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, int lt = 8)
  653. {
  654. SPINNER_HEADER(pos, size, centre, num_segments);
  655. const float start = (float)ImGui::GetTime() * speed;
  656. const float nextItemKoeff = 2.5f;
  657. const float dots = (size.x / (thickness * nextItemKoeff));
  658. const float heightSpeed = 0.8f;
  659. for (size_t j = 0; j < dots; j++)
  660. {
  661. for (size_t i = 0; i < dots; i++)
  662. {
  663. float a = start - (IM_PI - i * j * PI_DIV(dots));
  664. window->DrawList->AddCircleFilled(ImVec2(centre.x - (size.x / 2.f) + i * thickness * nextItemKoeff, centre.y - (size.y / 2.f) + j * thickness * nextItemKoeff), thickness, color_alpha(color, ImMax(0.1f, ImSin(a * heightSpeed))), lt);
  665. }
  666. }
  667. }
  668. inline void SpinnerScaleDots(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, int lt = 8)
  669. {
  670. SPINNER_HEADER(pos, size, centre, num_segments);
  671. const float nextItemKoeff = 2.5f;
  672. const float heightSpeed = 0.8f;
  673. const float dots = (size.x / (thickness * nextItemKoeff));
  674. const float start = (float)ImGui::GetTime() * speed;
  675. for (size_t i = 0; i < dots; i++)
  676. {
  677. const float a = start + (IM_PI - i * PI_DIV(dots));
  678. const float th = thickness * ImSin(a * heightSpeed);
  679. window->DrawList->AddCircleFilled(ImVec2(centre.x - (size.x / 2.f) + i * thickness * nextItemKoeff, centre.y), thickness, color_alpha(color, 0.1f), lt);
  680. window->DrawList->AddCircleFilled(ImVec2(centre.x - (size.x / 2.f) + i * thickness * nextItemKoeff, centre.y), th, color_alpha(color, 1.f), lt);
  681. }
  682. }
  683. inline void SpinnerSquareSpins(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f)
  684. {
  685. SPINNER_HEADER(pos, size, centre, num_segments);
  686. const float nextItemKoeff = 2.5f;
  687. const float heightSpeed = 0.8f;
  688. const float dots = (size.x / (thickness * nextItemKoeff));
  689. const float start = (float)ImGui::GetTime() * speed;
  690. for (size_t i = 0; i < dots; i++)
  691. {
  692. const float a = ImFmod(start + i * ((PI_DIV_2 * 0.7f) / dots), PI_DIV_2);
  693. const float th = thickness * (ImCos(a * heightSpeed) * 2.f);
  694. ImVec2 pmin = ImVec2(centre.x - (size.x / 2.f) + i * thickness * nextItemKoeff - thickness, centre.y - thickness);
  695. ImVec2 pmax = ImVec2(centre.x - (size.x / 2.f) + i * thickness * nextItemKoeff + thickness, centre.y + thickness);
  696. window->DrawList->AddRect(pmin, pmax, color_alpha(color, 1.f), 0.f);
  697. ImVec2 lmin = ImVec2(centre.x - (size.x / 2.f) + i * thickness * nextItemKoeff - thickness, centre.y - th + thickness);
  698. ImVec2 lmax = ImVec2(centre.x - (size.x / 2.f) + i * thickness * nextItemKoeff + thickness - 1, centre.y - th + thickness);
  699. window->DrawList->AddLine(lmin, lmax, color_alpha(color, 1.f), 1.f);
  700. }
  701. }
  702. inline void SpinnerMovingDots(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, size_t dots = 3)
  703. {
  704. SPINNER_HEADER(pos, size, centre, num_segments);
  705. const float nextItemKoeff = 2.5f;
  706. const float heightKoeff = 2.f;
  707. const float heightSpeed = 0.8f;
  708. const float start = ImFmod((float)ImGui::GetTime() * speed, size.x);
  709. float offset = 0;
  710. for (size_t i = 0; i < dots; i++)
  711. {
  712. float th = thickness;
  713. offset = ImFmod(start + i * (size.x / dots), size.x);
  714. if (offset < thickness) { th = offset; }
  715. if (offset > size.x - thickness) { th = size.x - offset; }
  716. window->DrawList->AddCircleFilled(ImVec2(pos.x + offset - thickness, centre.y), th, color_alpha(color, 1.f), 8);
  717. }
  718. }
  719. inline void SpinnerRotateDots(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, int dots = 2, int mode = 0)
  720. {
  721. SPINNER_HEADER(pos, size, centre, num_segments);
  722. ImGuiStorage* storage = window->DC.StateStorage;
  723. const ImGuiID velocityId = window->GetID("##velocity");
  724. const ImGuiID vtimeId = window->GetID("##velocitytime");
  725. float velocity = storage->GetFloat(velocityId, 0.f);
  726. float vtime = storage->GetFloat(vtimeId, 0.f);
  727. float dtime = ImFmod((float)vtime, IM_PI);
  728. float start = (vtime += velocity);
  729. if (dtime > 0.f && dtime < PI_DIV_2) { velocity += 0.001f * speed; }
  730. else if (dtime > IM_PI * 0.9f && dtime < IM_PI) { velocity -= 0.01f * speed; }
  731. if (velocity > 0.1f) velocity = 0.1f;
  732. if (velocity < 0.01f) velocity = 0.01f;
  733. storage->SetFloat(velocityId, velocity);
  734. storage->SetFloat(vtimeId, vtime);
  735. window->DrawList->AddCircleFilled(centre, thickness, color_alpha(color, 1.f), 8);
  736. for (int i = 0; i < dots; i++)
  737. {
  738. float a = mode ? start + i * PI_2_DIV(dots) + damped_spring(1, 10.f, 1.0f, ImSin(start + i * PI_2_DIV(dots)), PI_2_DIV(dots), 0)
  739. : start + (i * PI_2_DIV(dots));
  740. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(a) * radius, centre.y + ImSin(a) * radius), thickness, color_alpha(color, 1.f), 8);
  741. }
  742. }
  743. inline void SpinnerOrionDots(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, int arcs = 4)
  744. {
  745. SPINNER_HEADER(pos, size, centre, num_segments);
  746. ImGuiStorage* storage = window->DC.StateStorage;
  747. const ImGuiID velocityId = window->GetID("##velocity");
  748. const ImGuiID vtimeId = window->GetID("##velocitytime");
  749. float velocity = storage->GetFloat(velocityId, 0.f);
  750. float vtime = storage->GetFloat(vtimeId, 0.f);
  751. float dtime = ImFmod((float)vtime, IM_PI);
  752. float start = (vtime += velocity);
  753. if (dtime > 0.f && dtime < PI_DIV_2) { velocity += 0.001f * speed; }
  754. else if (dtime > IM_PI * 0.9f && dtime < IM_PI) { velocity -= 0.01f * speed; }
  755. if (velocity > 0.1f) velocity = 0.1f;
  756. if (velocity < 0.01f) velocity = 0.01f;
  757. storage->SetFloat(velocityId, velocity);
  758. storage->SetFloat(vtimeId, vtime);
  759. window->DrawList->AddCircleFilled(centre, thickness, color_alpha(color, 1.f), 8);
  760. for (int j = 1; j < arcs; ++j) {
  761. const float r = (radius / (arcs + 1)) * j;
  762. for (int i = 0; i < j + 1; i++)
  763. {
  764. const float a = start + (i * PI_2_DIV(j+1));
  765. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(a) * r, centre.y + ImSin(a) * r), thickness, color_alpha(color, 1.f), 8);
  766. }
  767. }
  768. }
  769. inline void SpinnerGalaxyDots(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, int arcs = 4)
  770. {
  771. SPINNER_HEADER(pos, size, centre, num_segments);
  772. ImGuiStorage* storage = window->DC.StateStorage;
  773. const ImGuiID velocityId = window->GetID("##velocity");
  774. const ImGuiID vtimeId = window->GetID("##velocitytime");
  775. float velocity = storage->GetFloat(velocityId, 0.f);
  776. float vtime = storage->GetFloat(vtimeId, 0.f);
  777. float dtime = ImFmod((float)vtime, IM_PI);
  778. float start = (vtime += (velocity * speed));
  779. if (dtime > 0.f && dtime < PI_DIV_2) { velocity += 0.001f; }
  780. else if (dtime > IM_PI * 0.9f && dtime < IM_PI) { velocity -= 0.01f; }
  781. if (velocity > 0.1f) velocity = 0.1f;
  782. if (velocity < 0.01f) velocity = 0.01f;
  783. storage->SetFloat(velocityId, velocity);
  784. storage->SetFloat(vtimeId, vtime);
  785. window->DrawList->AddCircleFilled(centre, thickness, color_alpha(color, 1.f), 8);
  786. for (int j = 1; j < arcs; ++j) {
  787. const float r = ((j / (float)arcs) * radius);
  788. for (int i = 0; i < arcs; i++)
  789. {
  790. const float a = start * (1.f + j * 0.1f) + (i * PI_2_DIV(arcs));
  791. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(a) * r, centre.y + ImSin(a) * r), thickness, color_alpha(color, 1.f), 8);
  792. }
  793. }
  794. }
  795. inline void SpinnerTwinAng(const char *label, float radius1, float radius2, float thickness, const ImColor &color1 = white, const ImColor &color2 = red, float speed = 2.8f, float angle = IM_PI)
  796. {
  797. const float radius = ImMax(radius1, radius2);
  798. SPINNER_HEADER(pos, size, centre, num_segments);
  799. const float start = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  800. const float aoffset = ImFmod((float)ImGui::GetTime(), 1.5f * IM_PI);
  801. const float bofsset = (aoffset > angle) ? angle : aoffset;
  802. const float angle_offset = angle * 2.f / num_segments;
  803. window->DrawList->PathClear();
  804. for (size_t i = 0; i <= 2 * num_segments; i++)
  805. {
  806. const float a = start + (i * angle_offset);
  807. if (i * angle_offset > 2 * bofsset)
  808. break;
  809. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * radius1, centre.y + ImSin(a) * radius1));
  810. }
  811. window->DrawList->PathStroke(color_alpha(color1, 1.f), false, thickness);
  812. window->DrawList->PathClear();
  813. for (size_t i = 0; i < num_segments / 2; i++)
  814. {
  815. const float a = start + (i * angle_offset);
  816. if (i * angle_offset > bofsset)
  817. break;
  818. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * radius2, centre.y + ImSin(a) * radius2));
  819. }
  820. window->DrawList->PathStroke(color_alpha(color2, 1.f), false, thickness);
  821. }
  822. inline void SpinnerFilling(const char *label, float radius, float thickness, const ImColor &color1 = white, const ImColor &color2 = red, float speed = 2.8f)
  823. {
  824. SPINNER_HEADER(pos, size, centre, num_segments);
  825. const float start = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  826. const float angle_offset = PI_2_DIV(num_segments - 1);
  827. circle([&] (int i) {
  828. const float a = (i * angle_offset);
  829. return ImVec2(ImCos(a) * radius, ImSin(a) * radius);
  830. }, color_alpha(color1, 1.f), thickness);
  831. window->DrawList->PathClear();
  832. for (size_t i = 0; i < 2 * num_segments / 2; i++)
  833. {
  834. const float a = (i * angle_offset);
  835. if (a > start)
  836. break;
  837. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * radius, centre.y + ImSin(a) * radius));
  838. }
  839. window->DrawList->PathStroke(color_alpha(color2, 1.f), false, thickness);
  840. }
  841. inline void SpinnerFillingMem(const char *label, float radius, float thickness, const ImColor &color, ImColor &colorbg, float speed)
  842. {
  843. SPINNER_HEADER(pos, size, centre, num_segments);
  844. const float start = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  845. const float angle_offset = PI_2_DIV(num_segments - 1);
  846. num_segments *= 4;
  847. circle([&] (int i) {
  848. const float a = (i * angle_offset);
  849. return ImVec2(ImCos(a) * radius, ImSin(a) * radius);
  850. }, color_alpha(colorbg, 1.f), thickness);
  851. if (start < 0.02f) {
  852. colorbg = color;
  853. }
  854. window->DrawList->PathClear();
  855. for (size_t i = 0; i < 2 * num_segments / 2; i++) {
  856. const float a = (i * angle_offset);
  857. if (a > start)
  858. break;
  859. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * radius, centre.y + ImSin(a) * radius));
  860. }
  861. window->DrawList->PathStroke(color_alpha(color, 1.f), false, thickness);
  862. }
  863. inline void SpinnerTopup(const char *label, float radius1, float radius2, const ImColor &color = red, const ImColor &fg = white, const ImColor &bg = white, float speed = 2.8f)
  864. {
  865. const float radius = ImMax(radius1, radius2);
  866. SPINNER_HEADER(pos, size, centre, num_segments);
  867. const float start = ImFmod((float)ImGui::GetTime() * speed, IM_PI);
  868. window->DrawList->AddCircleFilled(centre, radius1, color_alpha(bg, 1.f), num_segments);
  869. const float abegin = (PI_DIV_2) - start;
  870. const float aend = (PI_DIV_2) + start;
  871. const float angle_offset = (aend - abegin) / num_segments;
  872. window->DrawList->PathClear();
  873. window->DrawList->PathArcTo(centre, radius1, abegin, aend, num_segments * 2);
  874. ImDrawListFlags save = window->DrawList->Flags;
  875. window->DrawList->Flags &= ~ImDrawListFlags_AntiAliasedFill;
  876. window->DrawList->PathFillConvex(color_alpha(color, 1.f));
  877. window->DrawList->AddCircleFilled(centre, radius2, color_alpha(fg, 1.f), num_segments);
  878. window->DrawList->Flags = save;
  879. }
  880. inline void SpinnerTwinAng180(const char *label, float radius1, float radius2, float thickness, const ImColor &color1 = white, const ImColor &color2 = red, float speed = 2.8f)
  881. {
  882. const float radius = ImMax(radius1, radius2);
  883. SPINNER_HEADER(pos, size, centre, num_segments);
  884. num_segments *= 8;
  885. const float start = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  886. const float aoffset = ImFmod((float)ImGui::GetTime(), PI_2);
  887. const float bofsset = (aoffset > IM_PI) ? IM_PI : aoffset;
  888. const float angle_offset = PI_2_DIV(num_segments);
  889. float ared_min = 0, ared = 0;
  890. if (aoffset > IM_PI)
  891. ared_min = aoffset - IM_PI;
  892. window->DrawList->PathClear();
  893. for (size_t i = 0; i <= num_segments / 2 + 1; i++)
  894. {
  895. ared = start + (i * angle_offset);
  896. if (i * angle_offset < ared_min)
  897. continue;
  898. if (i * angle_offset > bofsset)
  899. break;
  900. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(ared) * radius2, centre.y + ImSin(ared) * radius2));
  901. }
  902. window->DrawList->PathStroke(color_alpha(color2, 1.f), false, thickness);
  903. window->DrawList->PathClear();
  904. for (size_t i = 0; i <= 2 * num_segments + 1; i++)
  905. {
  906. const float a = ared + ared_min + (i * angle_offset);
  907. if (i * angle_offset < ared_min)
  908. continue;
  909. if (i * angle_offset > bofsset)
  910. break;
  911. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * radius1, centre.y + ImSin(a) * radius1));
  912. }
  913. window->DrawList->PathStroke(color_alpha(color1, 1.f), false, thickness);
  914. }
  915. inline void SpinnerTwinAng360(const char *label, float radius1, float radius2, float thickness, const ImColor &color1 = white, const ImColor &color2 = red, float speed1 = 2.8f, float speed2 = 2.5f, int mode = 0)
  916. {
  917. const float radius = ImMax(radius1, radius2);
  918. SPINNER_HEADER(pos, size, centre, num_segments);
  919. num_segments *= 4;
  920. float start1 = ImFmod((float)ImGui::GetTime() * speed1, PI_2);
  921. float start2 = ImFmod((float)ImGui::GetTime() * speed2, PI_2);
  922. const float aoffset = ImFmod((float)ImGui::GetTime(), 2.f * IM_PI);
  923. const float bofsset = (aoffset > IM_PI) ? IM_PI : aoffset;
  924. const float angle_offset = PI_2 / num_segments;
  925. float ared_min = 0, ared = 0;
  926. if (aoffset > IM_PI)
  927. ared_min = aoffset - IM_PI;
  928. window->DrawList->PathClear();
  929. for (size_t i = 0; i <= num_segments + 1; i++) {
  930. ared = ( mode ? damped_spring(1, 10.f, 1.0f, ImSin(ImFmod(start1 + 0 * PI_DIV(2), PI_2))) : start1) + (i * angle_offset);
  931. if (i * angle_offset < ared_min * 2) continue;
  932. if (i * angle_offset > bofsset * 2.f) break;
  933. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(ared) * radius2, centre.y + ImSin(ared) * radius2));
  934. }
  935. window->DrawList->PathStroke(color_alpha(color2, 1.f), false, thickness);
  936. window->DrawList->PathClear();
  937. for (size_t i = 0; i <= num_segments + 1; i++) {
  938. ared = (mode ? damped_spring(1, 10.f, 1.0f, ImSin(ImFmod(start2 + 1 * PI_DIV(2), PI_2))) : start2) + (i * angle_offset);
  939. if (i * angle_offset < ared_min * 2) continue;
  940. if (i * angle_offset > bofsset * 2.f) break;
  941. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(-ared) * radius1, centre.y + ImSin(-ared) * radius1));
  942. }
  943. window->DrawList->PathStroke(color_alpha(color1, 1.f), false, thickness);
  944. }
  945. inline void SpinnerIncDots(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, size_t dots = 6)
  946. {
  947. SPINNER_HEADER(pos, size, centre, num_segments);
  948. float start = (float)ImGui::GetTime() * speed;
  949. float astart = ImFmod(start, PI_DIV(dots));
  950. start -= astart;
  951. dots = ImMin<size_t>(dots, 32);
  952. for (size_t i = 0; i <= dots; i++)
  953. {
  954. float a = start + (i * PI_DIV(dots - 1));
  955. ImColor c = color_alpha(color, ImMax(0.1f, i / (float)dots));
  956. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(a) * radius, centre.y + ImSin(a) * radius), thickness, c, 8);
  957. }
  958. }
  959. inline void SpinnerIncFullDots(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, size_t dots = 4)
  960. {
  961. SPINNER_HEADER(pos, size, centre, num_segments);
  962. dots = ImMin<size_t>(dots, 32);
  963. float start = (float)ImGui::GetTime() * speed;
  964. float astart = ImFmod(start, IM_PI / dots);
  965. start -= astart;
  966. const float bg_angle_offset = IM_PI / dots;
  967. for (size_t i = 0; i < dots * 2; i++)
  968. {
  969. float a = start + (i * bg_angle_offset);
  970. ImColor c = color_alpha(color, 0.1f);
  971. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(a) * radius, centre.y + ImSin(a) * radius), thickness, c, 8);
  972. }
  973. for (size_t i = 0; i < dots; i++)
  974. {
  975. float a = start + (i * bg_angle_offset);
  976. ImColor c = color_alpha(color, ImMax(0.1f, i / (float)dots));
  977. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(a) * radius, centre.y + ImSin(a) * radius), thickness, c, 8);
  978. }
  979. }
  980. inline void SpinnerFadeBars(const char *label, float w, const ImColor &color = white, float speed = 2.8f, size_t bars = 3, bool scale = false)
  981. {
  982. float radius = (w * 0.5f) * bars;
  983. SPINNER_HEADER(pos, size, centre, num_segments);
  984. ImGuiContext &g = *GImGui;
  985. const ImGuiStyle &style = g.Style;
  986. const float nextItemKoeff = 1.5f;
  987. const float yOffsetKoeftt = 0.8f;
  988. const float heightSpeed = 0.8f;
  989. const float start = (float)ImGui::GetTime() * speed;
  990. const float offset = IM_PI / bars;
  991. for (size_t i = 0; i < bars; i++)
  992. {
  993. float a = start + (IM_PI - i * offset);
  994. ImColor c = color_alpha(color, ImMax(0.1f, ImSin(a * heightSpeed)));
  995. float h = (scale ? (0.6f + 0.4f * c.Value.w) : 1.f) * size.y / 2;
  996. window->DrawList->AddRectFilled(ImVec2(pos.x + style.FramePadding.x + i * (w * nextItemKoeff) - w / 2, centre.y - h * yOffsetKoeftt),
  997. ImVec2(pos.x + style.FramePadding.x + i * (w * nextItemKoeff) + w / 2, centre.y + h * yOffsetKoeftt), c);
  998. }
  999. }
  1000. inline void SpinnerFadeTris(const char *label, float radius, const ImColor &color = white, float speed = 2.8f, size_t dim = 2, bool scale = false)
  1001. {
  1002. SPINNER_HEADER(pos, size, centre, num_segments);
  1003. ImGuiContext &g = *GImGui;
  1004. const ImGuiStyle &style = g.Style;
  1005. const float nextItemKoeff = 1.5f;
  1006. const float yOffsetKoeftt = 0.8f;
  1007. const float heightSpeed = 0.8f;
  1008. const float start = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  1009. std::vector<ImVec2> points;
  1010. auto pushPoints = [] (std::vector<ImVec2> &pp, const ImVec2 &p1, const ImVec2 &p2, const ImVec2 &p3) { pp.push_back(p1); pp.push_back(p2); pp.push_back(p3); };
  1011. auto hsumPoints = [] (const ImVec2 &p1, const ImVec2 &p2) { return ImVec2((p1.x + p2.x) / 2.f, (p1.y + p2.y) / 2.f); };
  1012. auto splitTriangle = [&] (const ImVec2 &p1, const ImVec2 &p2, const ImVec2 &p3, int numDivisions) {
  1013. pushPoints(points, p1, p2, p3);
  1014. for (int i = 0; i < numDivisions; i++) {
  1015. std::vector<ImVec2> newPoints;
  1016. for (int j = 0; j < points.size() - 2; j += 3) {
  1017. ImVec2 p1 = points[j];
  1018. ImVec2 p2 = points[j + 1];
  1019. ImVec2 p3 = points[j + 2];
  1020. ImVec2 p4((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);
  1021. ImVec2 p5((p2.x + p3.x) / 2, (p2.y + p3.y) / 2);
  1022. ImVec2 p6((p3.x + p1.x) / 2, (p3.y + p1.y) / 2);
  1023. pushPoints(newPoints, p1, p4, p6);
  1024. pushPoints(newPoints, p4, p5, p6);
  1025. pushPoints(newPoints, p4, p2, p5);
  1026. pushPoints(newPoints, p6, p5, p3);
  1027. }
  1028. points = newPoints;
  1029. }
  1030. return points;
  1031. };
  1032. auto calculateAngle = [] (ImVec2 v1, ImVec2 v2, const ImVec2 c) {
  1033. v1.x -= c.x; v1.y -= c.y; v2.x -= c.x; v2.y -= c.y;
  1034. float dotProduct = v1.x * v2.x + v1.y * v2.y;
  1035. float magnitudeV1 = ImSqrt(v1.x * v1.x + v1.y * v1.y);
  1036. float magnitudeV2 = ImSqrt(v2.x * v2.x + v2.y * v2.y);
  1037. float angleInRadians = ImAcos(dotProduct / (magnitudeV1 * magnitudeV2));
  1038. float crossProduct = v1.x * v2.y - v2.x * v1.y;
  1039. float signedAngle = std::copysign(angleInRadians, crossProduct);
  1040. return fmod(signedAngle + PI_2, PI_2);
  1041. };
  1042. const float offset = IM_PI / dim;
  1043. ImVec2 p1 = ImVec2(centre.x + ImSin(0) * radius, centre.y + ImCos(0) * radius);
  1044. ImVec2 p2 = ImVec2(centre.x + ImSin(PI_DIV(3) * 2) * radius, centre.y + ImCos(PI_DIV(3) * 2) * radius);
  1045. ImVec2 p3 = ImVec2(centre.x + ImSin(PI_DIV(3) * 4) * radius, centre.y + ImCos(PI_DIV(3) * 4) * radius);
  1046. std::vector<ImVec2> subdividedPoints = splitTriangle(p1, p2, p3, (int)dim);
  1047. for (size_t i = 0; i < subdividedPoints.size(); i+=3) {
  1048. ImVec2 trisCenter = hsumPoints(hsumPoints(subdividedPoints[i], subdividedPoints[i + 1]), subdividedPoints[i + 2]);
  1049. const float angle = calculateAngle(p1, trisCenter, centre);
  1050. ImColor c = color_alpha(color, 1.f - ImMax(0.1f, ImFmod(start + angle, PI_2) / (float)PI_2));
  1051. window->DrawList->AddTriangleFilled(subdividedPoints[i], subdividedPoints[i+1], subdividedPoints[i+2], c);
  1052. }
  1053. }
  1054. inline void SpinnerBarsRotateFade(const char *label, float rmin, float rmax , float thickness, const ImColor &color = white, float speed = 2.8f, size_t bars = 6)
  1055. {
  1056. float radius = rmax;
  1057. SPINNER_HEADER(pos, size, centre, num_segments);
  1058. float start = (float)ImGui::GetTime() * speed;
  1059. float astart = ImFmod(start, IM_PI / bars);
  1060. start -= astart;
  1061. const float bg_angle_offset = IM_PI / bars;
  1062. bars = ImMin<size_t>(bars, 32);
  1063. for (size_t i = 0; i <= bars; i++)
  1064. {
  1065. float a = start + (i * bg_angle_offset);
  1066. ImColor c = color_alpha(color, ImMax(0.1f, i / (float)bars));
  1067. window->DrawList->AddLine(ImVec2(centre.x + ImCos(a) * rmin, centre.y + ImSin(a) * rmin), ImVec2(centre.x + ImCos(a) * rmax, centre.y + ImSin(a) * rmax), c, thickness);
  1068. }
  1069. }
  1070. inline void SpinnerBarsScaleMiddle(const char *label, float w, const ImColor &color = white, float speed = 2.8f, size_t bars = 3)
  1071. {
  1072. float radius = (w) * bars;
  1073. SPINNER_HEADER(pos, size, centre, num_segments);
  1074. ImGuiContext &g = *GImGui;
  1075. const ImGuiStyle &style = g.Style;
  1076. const float nextItemKoeff = 1.5f;
  1077. const float yOffsetKoeftt = 0.8f;
  1078. const float heightSpeed = 0.8f;
  1079. float start = (float)ImGui::GetTime() * speed;
  1080. const float offset = IM_PI / bars;
  1081. for (size_t i = 0; i < bars; i++)
  1082. {
  1083. float a = start + (IM_PI - i * offset);
  1084. float h = (0.4f + 0.6f * ImMax(0.1f, ImSin(a * heightSpeed))) * (size.y / 2);
  1085. window->DrawList->AddRectFilled(ImVec2(centre.x + style.FramePadding.x + i * (w * nextItemKoeff) - w / 2, centre.y - h * yOffsetKoeftt),
  1086. ImVec2(centre.x + style.FramePadding.x + i * (w * nextItemKoeff) + w / 2, centre.y + h * yOffsetKoeftt), color_alpha(color, 1.f));
  1087. if (i == 0)
  1088. continue;
  1089. window->DrawList->AddRectFilled(ImVec2(centre.x + style.FramePadding.x - i * (w * nextItemKoeff) - w / 2, centre.y - h * yOffsetKoeftt),
  1090. ImVec2(centre.x + style.FramePadding.x - i * (w * nextItemKoeff) + w / 2, centre.y + h * yOffsetKoeftt), color_alpha(color, 1.f));
  1091. }
  1092. }
  1093. inline void SpinnerAngTwin(const char *label, float radius1, float radius2, float thickness, const ImColor &color = white, const ImColor &bg = half_white, float speed = 2.8f, float angle = IM_PI, size_t arcs = 1, int mode = 0)
  1094. {
  1095. float radius = ImMax(radius1, radius2);
  1096. SPINNER_HEADER(pos, size, centre, num_segments);
  1097. float start = (float)ImGui::GetTime()* speed;
  1098. const float bg_angle_offset = PI_2 / num_segments;
  1099. window->DrawList->PathClear();
  1100. for (size_t i = 0; i <= num_segments; i++) {
  1101. const float a = start + (i * bg_angle_offset);
  1102. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * radius1, centre.y + ImSin(a) * radius1));
  1103. }
  1104. window->DrawList->PathStroke(color_alpha(bg, 1.f), false, thickness);
  1105. const float angle_offset = angle / num_segments;
  1106. for (size_t arc_num = 0; arc_num < arcs; ++arc_num) {
  1107. window->DrawList->PathClear();
  1108. float arc_start = 2 * IM_PI / arcs;
  1109. float b = mode ? start + damped_spring(1, 10.f, 1.0f, ImSin(ImFmod(start + arc_num * PI_DIV(2) / arcs, IM_PI)), 1, 0) : start;
  1110. for (size_t i = 0; i < num_segments; i++) {
  1111. const float a = b + arc_start * arc_num + (i * angle_offset);
  1112. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * radius2, centre.y + ImSin(a) * radius2));
  1113. }
  1114. window->DrawList->PathStroke(color_alpha(color, 1.f), false, thickness);
  1115. }
  1116. }
  1117. inline void SpinnerArcRotation(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, size_t arcs = 4, int mode = 0)
  1118. {
  1119. SPINNER_HEADER(pos, size, centre, num_segments);
  1120. const float start = (float)ImGui::GetTime()* speed;
  1121. const float arc_angle = PI_2 / (float)arcs;
  1122. const float angle_offset = arc_angle / num_segments;
  1123. for (size_t arc_num = 0; arc_num < arcs; ++arc_num) {
  1124. window->DrawList->PathClear();
  1125. ImColor c = color_alpha(color, ImMax(0.1f, arc_num / (float)arcs));
  1126. float b = mode ? start + damped_spring(1, 10.f, 1.0f, ImSin(ImFmod(start + arc_num * PI_DIV(2) / arcs, IM_PI)), 1, 0) : start;
  1127. for (size_t i = 0; i <= num_segments; i++) {
  1128. const float a = b + arc_angle * arc_num + (i * angle_offset);
  1129. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * radius, centre.y + ImSin(a) * radius));
  1130. }
  1131. window->DrawList->PathStroke(c, false, thickness);
  1132. }
  1133. }
  1134. inline void SpinnerArcFade(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, size_t arcs = 4)
  1135. {
  1136. SPINNER_HEADER(pos, size, centre, num_segments);
  1137. const float start = ImFmod((float)ImGui::GetTime()* speed, IM_PI * 4.f);
  1138. const float arc_angle = PI_2 / (float)arcs;
  1139. const float angle_offset = arc_angle / num_segments;
  1140. for (size_t arc_num = 0; arc_num < arcs; ++arc_num)
  1141. {
  1142. window->DrawList->PathClear();
  1143. for (size_t i = 0; i <= num_segments + 1; i++)
  1144. {
  1145. const float a = arc_angle * arc_num + (i * angle_offset) - PI_DIV_2 - PI_DIV_4;
  1146. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * radius, centre.y + ImSin(a) * radius));
  1147. }
  1148. const float a = arc_angle * arc_num;
  1149. ImColor c = color;
  1150. if (start < PI_2) {
  1151. c.Value.w = 0.f;
  1152. if (start > a && start < (a + arc_angle)) { c.Value.w = 1.f - (start - a) / (float)arc_angle; }
  1153. else if (start < a) { c.Value.w = 1.f; }
  1154. c.Value.w = ImMax(0.05f, 1.f - c.Value.w);
  1155. } else {
  1156. const float startk = start - PI_2;
  1157. c.Value.w = 0.f;
  1158. if (startk > a && startk < (a + arc_angle)) { c.Value.w = 1.f - (startk - a) / (float)arc_angle; }
  1159. else if (startk < a) { c.Value.w = 1.f; }
  1160. c.Value.w = ImMax(0.05f, c.Value.w);
  1161. }
  1162. window->DrawList->PathStroke(color_alpha(c, 1.f), false, thickness);
  1163. }
  1164. }
  1165. inline void SpinnerSimpleArcFade(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f) {
  1166. SPINNER_HEADER(pos, size, centre, num_segments);
  1167. const float start = ImFmod((float)ImGui::GetTime() * speed, IM_PI * 4.f);
  1168. const float arc_angle = PI_2 / (float)4;
  1169. const float angle_offset = arc_angle / num_segments;
  1170. auto draw_segment = [&] (int arc_num, float delta, auto c, float k, float t) {
  1171. window->DrawList->PathClear();
  1172. for (size_t i = 0; i <= num_segments + 1; i++) {
  1173. const float a = t * start + arc_angle * arc_num + (i * angle_offset) - PI_DIV_2 - PI_DIV_4 + delta;
  1174. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * radius * k, centre.y + ImSin(a) * radius * k));
  1175. }
  1176. window->DrawList->PathStroke(color_alpha(c, 1.f), false, thickness);
  1177. };
  1178. for (size_t arc_num = 0; arc_num < 2; ++arc_num) {
  1179. const float a = arc_angle * arc_num;
  1180. ImColor c = color;
  1181. if (start < PI_2) {
  1182. c.Value.w = 0.f;
  1183. if (start > a && start < (a + arc_angle)) { c.Value.w = 1.f - (start - a) / (float)arc_angle; }
  1184. else if (start < a) { c.Value.w = 1.f; }
  1185. c.Value.w = ImMax(0.05f, 1.f - c.Value.w);
  1186. } else {
  1187. const float startk = start - PI_2;
  1188. c.Value.w = 0.f;
  1189. if (startk > a && startk < (a + arc_angle)) { c.Value.w = 1.f - (startk - a) / (float)arc_angle; }
  1190. else if (startk < a) { c.Value.w = 1.f; }
  1191. c.Value.w = ImMax(0.05f, c.Value.w);
  1192. }
  1193. draw_segment((int)arc_num, 0.f, c, 1.f + arc_num * 0.3f, arc_num > 0 ? -1.0f : 1.0f);
  1194. draw_segment((int)arc_num, IM_PI, c, 1.f + arc_num * 0.3f, arc_num > 0 ? -1.0f : 1.0f);
  1195. }
  1196. }
  1197. inline void SpinnerSquareStrokeFade(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f)
  1198. {
  1199. SPINNER_HEADER(pos, size, centre, num_segments);
  1200. const float start = ImFmod((float)ImGui::GetTime() * speed, IM_PI * 4.f);
  1201. const float arc_angle = PI_DIV_2;
  1202. const float ht = thickness / 2.f;
  1203. for (size_t arc_num = 0; arc_num < 4; ++arc_num)
  1204. {
  1205. float a = arc_angle * arc_num;
  1206. ImColor c = color_alpha(color, 1.f);
  1207. if (start < PI_2) {
  1208. c.Value.w = (start > a && start < (a + arc_angle))
  1209. ? 1.f - (start - a) / (float)arc_angle
  1210. : (start < a ? 1.f : 0.f);
  1211. c.Value.w = ImMax(0.05f, 1.f - c.Value.w);
  1212. } else {
  1213. const float startk = start - PI_2;
  1214. c.Value.w = (startk > a && startk < (a + arc_angle))
  1215. ? 1.f - (startk - a) / (float)arc_angle
  1216. : (startk < a ? 1.f : 0.f);
  1217. c.Value.w = ImMax(0.05f, c.Value.w);
  1218. }
  1219. a -= PI_DIV_4;
  1220. const float r = radius * 1.4f;
  1221. const bool right = ImSin(a) > 0;
  1222. const bool top = ImCos(a) < 0;
  1223. ImVec2 p1(centre.x + ImCos(a) * r, centre.y + ImSin(a) * r);
  1224. ImVec2 p2(centre.x + ImCos(a - PI_DIV_2) * r, centre.y + ImSin(a - PI_DIV_2) * r);
  1225. switch (arc_num) {
  1226. case 0: p1.x -= ht; p2.x -= ht; break;
  1227. case 1: p1.y -= ht; p2.y -= ht; break;
  1228. case 2: p1.x += ht; p2.x += ht; break;
  1229. case 3: p1.y += ht; p2.y += ht; break;
  1230. }
  1231. window->DrawList->AddLine(p1, p2, color_alpha(c, 1.f), thickness);
  1232. }
  1233. }
  1234. inline void SpinnerAsciiSymbolPoints(const char *label, const char* text, float radius, float thickness, const ImColor &color = white, float speed = 2.8f)
  1235. {
  1236. SPINNER_HEADER(pos, size, centre, num_segments);
  1237. if (!text || !*text)
  1238. return;
  1239. const float start = ImFmod((float)ImGui::GetTime() * speed, (float)strlen(text));
  1240. const ImFontGlyph* glyph = ImGui::GetCurrentContext()->Font->FindGlyph(text[(int)start]);
  1241. ImVec2 pp(centre.x - radius, centre.y - radius);
  1242. ImFontAtlas* atlas = ImGui::GetIO().Fonts;
  1243. unsigned char* bitmap;
  1244. int out_width, out_height;
  1245. atlas->GetTexDataAsAlpha8(&bitmap, &out_width, &out_height);
  1246. const int U1 = (int)(glyph->U1 * out_width);
  1247. const int U0 = (int)(glyph->U0 * out_width);
  1248. const int V1 = (int)(glyph->V1 * out_height);
  1249. const int V0 = (int)(glyph->V0 * out_height);
  1250. const float px = size.x / (U1 - U0);
  1251. const float py = size.y / (V1 - V0);
  1252. for (int x = U0, ppx = 0; x < U1; x++, ppx++) {
  1253. for (int y = V0, ppy = 0; y < V1; y++, ppy++) {
  1254. ImVec2 point(pp.x + (ppx * px), pp.y + (ppy * py));
  1255. const unsigned char alpha = bitmap[out_width * y + x];
  1256. window->DrawList->AddCircleFilled(point, thickness * 1.5f, color_alpha({.5f,.5f,.5f,.5f}, alpha / 255.f));
  1257. window->DrawList->AddCircleFilled(point, thickness, color_alpha(color, alpha / 255.f));
  1258. }
  1259. }
  1260. }
  1261. inline void SpinnerTextFading(const char *label, const char* text, float radius, float fsize, const ImColor &color = white, float speed = 2.8f)
  1262. {
  1263. SPINNER_HEADER(pos, size, centre, num_segments);
  1264. if (!text || !*text)
  1265. return;
  1266. const float start = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  1267. const char *last_symbol = ImGui::FindRenderedTextEnd(text);
  1268. const ImVec2 text_size = ImGui::CalcTextSize(text, last_symbol);
  1269. const ImFont* font = ImGui::GetCurrentContext()->Font;
  1270. ImVec2 pp(centre.x - text_size.x / 2.f, centre.y - text_size.y / 2.f);
  1271. const int text_len = (int)(last_symbol - text);
  1272. float out_h, out_s, out_v;
  1273. ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, out_h, out_s, out_v);
  1274. for (int i = 0; text != last_symbol; ++text, ++i) {
  1275. const ImFontGlyph* glyph = ImGui::GetCurrentContext()->Font->FindGlyph(*text);
  1276. const float alpha = ImClamp(ImSin(-start + (i / (float)text_len * PI_DIV_2)), 0.f, 1.f);
  1277. ImColor c = ImColor::HSV(out_h + i * (1.f / text_len), out_s, out_v);
  1278. font->RenderChar(window->DrawList, fsize, pp, color_alpha(c, alpha), (ImWchar)*text);
  1279. pp.x += glyph->AdvanceX;
  1280. }
  1281. }
  1282. inline void SpinnerSevenSegments(const char *label, const char* text, float radius, float thickness, const ImColor &color = white, float speed = 2.8f)
  1283. {
  1284. SPINNER_HEADER(pos, size, centre, num_segments);
  1285. if (!text || !*text)
  1286. return;
  1287. const float start = ImFmod((float)ImGui::GetTime() * speed, (float)strlen(text));
  1288. struct Segment { ImVec2 b, e; };
  1289. const float q = 1.f, hq = q * 0.5f, xq = thickness / radius;
  1290. const Segment segments[] = {{ ImVec2{-hq, 0.0f}, ImVec2{hq, 0.0f} }, /*central*/
  1291. { ImVec2{-hq - xq, 0.0f}, ImVec2{-hq - xq, -q} }, /*left up*/
  1292. { ImVec2{-hq - xq, q}, ImVec2{-hq - xq, xq} }, /*left down*/
  1293. { ImVec2{-hq, q}, ImVec2{hq, q} }, /*center up*/
  1294. { ImVec2{hq + xq, q}, ImVec2{hq + xq, xq} }, /*right down*/
  1295. { ImVec2{hq + xq, 0.0f}, ImVec2{hq + xq, -q} }, /*right up*/
  1296. { ImVec2{-hq, -q}, ImVec2{hq, -q} } /*center down*/};
  1297. const int symbols[][8]{
  1298. //segments
  1299. //g,f,e,d,c,b,a,sym
  1300. // NUMBERS
  1301. {0,1,1,1,1,1,1,0}, //ZERO
  1302. {0,0,0,0,1,1,0,1}, //ONE
  1303. {1,0,1,1,0,1,1,2}, //TWO
  1304. {1,0,0,1,1,1,1,3}, //THREE
  1305. {1,1,0,0,1,1,0,4}, //FOUR
  1306. {1,1,0,1,1,0,1,5}, //FIVE
  1307. {1,1,1,1,1,0,1,6}, //SIX
  1308. {0,0,0,0,1,1,1,7}, //SEVEN
  1309. {1,1,1,1,1,1,1,8}, //EIGHT
  1310. {1,1,0,1,1,1,1,9}, //NINE
  1311. // LETTERS
  1312. {1,1,1,0,1,1,1,'A'}, //LETTER A
  1313. {1,1,1,1,1,0,0,'B'}, //LETTER B
  1314. {0,1,1,1,0,0,1,'C'}, //LETTER C
  1315. {1,0,1,1,1,1,0,'D'}, //LETTER D
  1316. {1,1,1,1,0,0,1,'E'}, //LETTER E
  1317. {1,1,1,0,0,0,1,'F'}, //LETTER F
  1318. {0,1,1,1,1,0,1,'G'}, //LETTER G
  1319. {1,1,1,0,1,0,0,'H'}, //LETTER H
  1320. {0,1,1,0,0,0,0,'I'}, //LETTER I
  1321. {0,0,1,1,1,1,0,'J'}, //LETTER J
  1322. {1,1,1,0,1,0,1,'K'}, //LETTER K
  1323. {0,1,1,1,0,0,0,'L'}, //LETTER L
  1324. {0,0,1,0,1,0,1,'M'}, //LETTER M
  1325. {0,1,1,0,1,1,1,'N'}, //LETTER N
  1326. {0,1,1,1,1,1,1,'O'}, //LETTER O
  1327. {1,1,1,0,0,1,1,'P'}, //LETTER P
  1328. {1,1,0,0,1,1,1,'Q'}, //LETTER Q
  1329. {0,1,1,0,0,1,1,'R'}, //LETTER R
  1330. {1,1,0,1,1,0,1,'S'}, //LETTER S
  1331. {1,1,1,1,0,0,0,'T'}, //LETTER T
  1332. {0,1,1,1,1,1,0,'U'}, //LETTER U
  1333. {0,1,0,1,1,1,0,'V'}, //LETTER V
  1334. {0,1,0,1,0,1,0,'W'}, //LETTER W
  1335. {1,1,1,0,1,1,0,'X'}, //LETTER X
  1336. {1,1,0,1,1,1,0,'Y'}, //LETTER Y
  1337. {1,0,0,1,0,1,1,'Z'}, //LETTER Z
  1338. };
  1339. auto draw_segment = [&] (const Segment &s) {
  1340. ImVec2 p1(centre.x + radius * s.b.x, centre.y + radius * s.b.y);
  1341. ImVec2 p2(centre.x + radius * s.e.x, centre.y + radius * s.e.y);
  1342. window->DrawList->AddLine(p1, p2, color_alpha(color, 1.f), thickness);
  1343. };
  1344. auto draw_symbol = [&] (const int* sq) {
  1345. for (int i = 0; i < 7; ++i)
  1346. sq[i] ? draw_segment(segments[i]) : void();
  1347. };
  1348. char current_char = text[(int)start];
  1349. if (isalpha(current_char)) {
  1350. draw_symbol(symbols[tolower(current_char) - 'a' + 10]);
  1351. } else if (isdigit(current_char)) {
  1352. draw_symbol(symbols[current_char - '0']);
  1353. }
  1354. }
  1355. inline void SpinnerSquareStrokeFill(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f)
  1356. {
  1357. SPINNER_HEADER(pos, size, centre, num_segments);
  1358. const float overt = 3.f;
  1359. const float start = ImFmod((float)ImGui::GetTime() * speed, PI_2 + overt);
  1360. const float arc_angle = 2.f * PI_DIV_4;
  1361. const float ht = thickness / 2.f;
  1362. const float r = radius * 1.4f;
  1363. ImVec2 pp(centre.x + ImCos(-IM_PI * 0.75f) * r, centre.y + ImSin(-IM_PI * 0.75f) * r);
  1364. if (start > PI_2) {
  1365. ImColor c = color;
  1366. const float delta = (start - PI_2) / overt;
  1367. if (delta < 0.5f) {
  1368. c.Value.w = 1.f - delta * 2.f;
  1369. window->DrawList->AddLine(ImVec2(pp.x - ht, pp.y), ImVec2(pp.x + ht, pp.y), color_alpha(c, 1.f), thickness);
  1370. } else {
  1371. c.Value.w = (delta - 0.5f) * 2.f;
  1372. window->DrawList->AddLine(ImVec2(pp.x - ht, pp.y), ImVec2(pp.x + ht, pp.y), color_alpha(color, 1.f), thickness);
  1373. }
  1374. } else {
  1375. window->DrawList->AddLine(ImVec2(pp.x - ht, pp.y), ImVec2(pp.x + ht, pp.y), color_alpha(color, 1.f), thickness);
  1376. }
  1377. if (start < PI_2) {
  1378. for (size_t arc_num = 0; arc_num < 4; ++arc_num) {
  1379. float a = arc_angle * arc_num;
  1380. float segment_progress = (start > a && start < (a + arc_angle))
  1381. ? 1.f - (start - a) / (float)arc_angle
  1382. : (start < a ? 1.f : 0.f);
  1383. a -= PI_DIV_4;
  1384. segment_progress = 1.f - segment_progress;
  1385. ImVec2 p1(centre.x + ImCos(a - PI_DIV_2) * r, centre.y + ImSin(a - PI_DIV_2) * r);
  1386. ImVec2 p2(centre.x + ImCos(a) * r, centre.y + ImSin(a) * r);
  1387. switch (arc_num) {
  1388. case 0: p1.x += ht; p2.x -= ht; p2.x = p1.x + (p2.x - p1.x) * segment_progress; break;
  1389. case 1: p1.y -= ht; p2.y -= ht; p2.y = p1.y + (p2.y - p1.y) * segment_progress; break;
  1390. case 2: p1.x += ht; p2.x += ht; p2.x = p1.x + (p2.x - p1.x) * segment_progress; break;
  1391. case 3: p1.y += ht; p2.y -= ht; p2.y = p1.y + (p2.y - p1.y) * segment_progress; break;
  1392. }
  1393. window->DrawList->AddLine(p1, p2, color_alpha(color, 1.f), thickness);
  1394. }
  1395. }
  1396. }
  1397. inline void SpinnerSquareStrokeLoading(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f)
  1398. {
  1399. SPINNER_HEADER(pos, size, centre, num_segments);
  1400. const float start = ImFmod((float)ImGui::GetTime() * speed, PI_2 );
  1401. const float arc_angle = 2.f * PI_DIV_4;
  1402. const float ht = thickness / 2.f;
  1403. const float best_radius = radius * 1.4f;
  1404. const float delta = (start - PI_2) / 2.f;
  1405. for (size_t arc_num = 0; arc_num < 4; ++arc_num) {
  1406. float a = arc_angle * arc_num;
  1407. a -= PI_DIV_4;
  1408. ImVec2 pp(centre.x + ImCos(a) * best_radius, centre.y + ImSin(a) * best_radius);
  1409. window->DrawList->AddLine(ImVec2(pp.x - ht, pp.y), ImVec2(pp.x + ht, pp.y), color_alpha(color, 1.f), thickness);
  1410. }
  1411. const bool grow = start < IM_PI;
  1412. const float segment_progress = grow ? (start / IM_PI) : (1.f - (start - IM_PI) / IM_PI);
  1413. for (size_t arc_num = 0; arc_num < 4; ++arc_num) {
  1414. float a = arc_angle * arc_num;
  1415. a -= PI_DIV_4;
  1416. const bool right = ImSin(a) > 0;
  1417. const bool top = ImCos(a) < 0;
  1418. ImVec2 p1(centre.x + ImCos(a - PI_DIV_2) * best_radius, centre.y + ImSin(a - PI_DIV_2) * best_radius);
  1419. ImVec2 p2(centre.x + ImCos(a) * best_radius, centre.y + ImSin(a) * best_radius);
  1420. switch (arc_num) {
  1421. case 0: p1.x -= ht; p2.x += ht;
  1422. p1.x = grow ? p1.x : p1.x + (p2.x - p1.x) * (1.f - segment_progress); p2.x = grow ? p1.x + (p2.x - p1.x) * segment_progress : p2.x; break;
  1423. case 1: p1.y -= ht; p2.y += ht;
  1424. p1.y = grow ? p1.y : p1.y + (p2.y - p1.y) * (1.f - segment_progress); p2.y = grow ? p1.y + (p2.y - p1.y) * segment_progress : p2.y; break;
  1425. case 2: p1.x += ht; p2.x -= ht;
  1426. p1.x = grow ? p1.x : grow ? p1.x : p1.x + (p2.x - p1.x) * (1.f - segment_progress); p2.x = grow ? p1.x + (p2.x - p1.x) * segment_progress : p2.x; break;
  1427. case 3: p1.y += ht; p2.y -= ht;
  1428. p1.y = grow ? p1.y : p1.y + (p2.y - p1.y) * (1.f - segment_progress); p2.y = grow ? p1.y + (p2.y - p1.y) * segment_progress : p2.y; break;
  1429. }
  1430. window->DrawList->AddLine(p1, p2, color_alpha(color, 1.f), thickness);
  1431. }
  1432. }
  1433. inline void SpinnerSquareLoading(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f)
  1434. {
  1435. SPINNER_HEADER(pos, size, centre, num_segments);
  1436. const float start = ImFmod((float)ImGui::GetTime() * speed, PI_2 + PI_DIV_2 );
  1437. const float arc_angle = PI_DIV_2;
  1438. const float ht = thickness / 2.f;
  1439. const float best_radius = radius * 1.4f;
  1440. float a = arc_angle * 3 - PI_DIV_4 + (start > PI_2 ? start * 2.f : 0);
  1441. ImVec2 last_pos(centre.x + ImCos(a) * best_radius, centre.y + ImSin(a) * best_radius);
  1442. ImVec2 ppMin, ppMax;
  1443. for (size_t arc_num = 0; arc_num < 4; ++arc_num) {
  1444. a = arc_angle * arc_num - PI_DIV_4 + (start > PI_2 ? start * 2.f : 0);
  1445. ImVec2 pp(centre.x + ImCos(a) * best_radius, centre.y + ImSin(a) * best_radius);
  1446. window->DrawList->AddLine(last_pos, pp, color_alpha(color, 1.f), thickness);
  1447. last_pos = pp;
  1448. if (start < PI_2) {
  1449. if (arc_num == 2) ppMin = ImVec2(centre.x + ImCos(a) * best_radius * 0.8f, centre.y + ImSin(a) * best_radius * 0.8f);
  1450. else if (arc_num == 0) ppMax = ImVec2(centre.x + ImCos(a) * best_radius * 0.8f, centre.y + ImSin(a) * best_radius * 0.8f);
  1451. }
  1452. }
  1453. if (start < PI_2) {
  1454. ppMax.y = ppMin.y + (start / PI_2) * (ppMax.y - ppMin.y);
  1455. window->DrawList->AddRectFilled(ppMin, ppMax, color_alpha(color, 1.f), 0.f);
  1456. }
  1457. }
  1458. inline void SpinnerFilledArcFade(const char *label, float radius, const ImColor &color = white, float speed = 2.8f, size_t arcs = 4, int mode = 0)
  1459. {
  1460. SPINNER_HEADER(pos, size, centre, num_segments);
  1461. const float start = ImFmod((float)ImGui::GetTime()* speed, IM_PI * 4.f);
  1462. const float arc_angle = PI_2 / (float)arcs;
  1463. const float angle_offset = arc_angle / num_segments;
  1464. for (size_t arc_num = 0; arc_num < arcs; ++arc_num)
  1465. {
  1466. const float b = arc_angle * arc_num - PI_DIV_2 - PI_DIV_4;
  1467. const float e = arc_angle * arc_num + arc_angle - PI_DIV_2 - PI_DIV_4;
  1468. const float a = arc_angle * arc_num;
  1469. ImColor c = color;
  1470. float vradius = radius;
  1471. if (start < PI_2) {
  1472. c.Value.w = 0.f;
  1473. if (start > a && start < (a + arc_angle)) { c.Value.w = 1.f - (start - a) / (float)arc_angle; }
  1474. else if (start < a) { c.Value.w = 1.f; }
  1475. c.Value.w = ImMax(0.f, 1.f - c.Value.w);
  1476. if (mode == 1)
  1477. vradius = radius * c.Value.w;
  1478. }
  1479. else
  1480. {
  1481. const float startk = start - PI_2;
  1482. c.Value.w = 0.f;
  1483. if (startk > a && startk < (a + arc_angle)) { c.Value.w = 1.f - (startk - a) / (float)arc_angle; }
  1484. else if (startk < a) { c.Value.w = 1.f; }
  1485. if (mode == 1)
  1486. vradius = radius * c.Value.w;
  1487. }
  1488. window->DrawList->PathClear();
  1489. window->DrawList->PathLineTo(centre);
  1490. for (size_t i = 0; i <= num_segments + 1; i++)
  1491. {
  1492. const float ar = arc_angle * arc_num + (i * angle_offset) - PI_DIV_2 - PI_DIV_4;
  1493. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(ar) * vradius, centre.y + ImSin(ar) * vradius));
  1494. }
  1495. window->DrawList->PathFillConvex(color_alpha(c, 1.f));
  1496. }
  1497. }
  1498. inline void SpinnerPointsArcBounce(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, size_t points = 4, int circles = 2, float rspeed = 0.f)
  1499. {
  1500. SPINNER_HEADER(pos, size, centre, num_segments);
  1501. const float start = ImFmod((float)ImGui::GetTime()* speed, IM_PI * 4.f);
  1502. const float arc_angle = PI_2 / (float)points;
  1503. const float angle_offset = arc_angle / num_segments;
  1504. float dspeed = rspeed;
  1505. for (int c_num = 0; c_num < circles; c_num++)
  1506. {
  1507. float mr = radius * (1.f - (1.f / (circles + 2.f) * c_num));
  1508. float adv_angle = IM_PI * c_num;// *(1.f + (0.1f * circles) * c_num);
  1509. for (size_t arc_num = 0; arc_num < points; ++arc_num)
  1510. {
  1511. const float b = arc_angle * arc_num - PI_DIV_2 - PI_DIV_4;
  1512. const float e = arc_angle * arc_num + arc_angle - PI_DIV_2 - PI_DIV_4;
  1513. const float a = arc_angle * arc_num;
  1514. ImColor c = color;
  1515. float vradius = mr;
  1516. if (start < PI_2) {
  1517. c.Value.w = 0.f;
  1518. if (start > a && start < (a + arc_angle)) { c.Value.w = 1.f - (start - a) / (float)arc_angle; }
  1519. else if (start < a) { c.Value.w = 1.f; }
  1520. c.Value.w = ImMax(0.f, 1.f - c.Value.w);
  1521. vradius = mr * c.Value.w;
  1522. }
  1523. else
  1524. {
  1525. const float startk = start - PI_2;
  1526. c.Value.w = 0.f;
  1527. if (startk > a && startk < (a + arc_angle)) { c.Value.w = 1.f - (startk - a) / (float)arc_angle; }
  1528. else if (startk < a) { c.Value.w = 1.f; }
  1529. vradius = mr * c.Value.w;
  1530. }
  1531. const float ar = start * dspeed + adv_angle + arc_angle * arc_num - PI_DIV_2 - PI_DIV_4;
  1532. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(ar) * vradius, centre.y + ImSin(ar) * vradius), thickness, color_alpha(c, 1.f), 8);
  1533. }
  1534. dspeed += rspeed;
  1535. }
  1536. }
  1537. inline void SpinnerFilledArcColor(const char *label, float radius, const ImColor &color = red, const ImColor &bg = white, float speed = 2.8f, size_t arcs = 4)
  1538. {
  1539. SPINNER_HEADER(pos, size, centre, num_segments);
  1540. const float start = ImFmod((float)ImGui::GetTime()* speed, PI_2);
  1541. const float arc_angle = PI_2 / (float)arcs;
  1542. const float angle_offset = arc_angle / num_segments;
  1543. window->DrawList->AddCircleFilled(centre, radius, color_alpha(bg, 1.f), num_segments * 2);
  1544. for (size_t arc_num = 0; arc_num < arcs; ++arc_num)
  1545. {
  1546. const float b = arc_angle * arc_num - PI_DIV_2;
  1547. const float e = arc_angle * arc_num + arc_angle - PI_DIV_2;
  1548. const float a = arc_angle * arc_num;
  1549. ImColor c = color;
  1550. c.Value.w = 0.f;
  1551. if (start > a && start < (a + arc_angle)) { c.Value.w = 1.f - (start - a) / (float)arc_angle; }
  1552. else if (start < a) { c.Value.w = 1.f; }
  1553. c.Value.w = ImMax(0.f, 1.f - c.Value.w);
  1554. window->DrawList->PathClear();
  1555. window->DrawList->PathLineTo(centre);
  1556. for (size_t i = 0; i < num_segments + 1; i++)
  1557. {
  1558. const float ar = arc_angle * arc_num + (i * angle_offset) - PI_DIV_2;
  1559. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(ar) * radius, centre.y + ImSin(ar) * radius));
  1560. }
  1561. window->DrawList->PathFillConvex(color_alpha(c, 1.f));
  1562. }
  1563. }
  1564. inline void SpinnerFilledArcRing(const char *label, float radius, float thickness, const ImColor &color = red, const ImColor &bg = white, float speed = 2.8f, size_t arcs = 4)
  1565. {
  1566. SPINNER_HEADER(pos, size, centre, num_segments);
  1567. const float pi_div_2 = PI_DIV_2;
  1568. const float pi_div_4 = PI_DIV_4;
  1569. const float pi_mul_2 = PI_2;
  1570. const float start = ImFmod((float)ImGui::GetTime() * speed, pi_mul_2 + pi_div_4);
  1571. const float arc_angle = pi_mul_2 / (float)arcs;
  1572. const float angle_offset = arc_angle / num_segments;
  1573. window->DrawList->PathClear();
  1574. for (size_t i = 0; i < num_segments + 1; i++)
  1575. {
  1576. const float ar_b = (i * (pi_mul_2 / num_segments));
  1577. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(ar_b) * radius, centre.y + ImSin(ar_b) * radius));
  1578. }
  1579. window->DrawList->PathStroke(color_alpha(bg, 1.f), false, thickness);
  1580. for (size_t arc_num = 0; arc_num < arcs; ++arc_num)
  1581. {
  1582. const float b = arc_angle * arc_num - pi_div_2;
  1583. const float e = arc_angle * arc_num + arc_angle - pi_div_2;
  1584. const float a = arc_angle * arc_num;
  1585. float alpha = 0.f;
  1586. if (start > pi_mul_2) { alpha = (start - pi_mul_2) / pi_div_4; }
  1587. else if (start > a && start < (a + arc_angle)) { alpha = 1.f - (start - a) / (float)arc_angle; }
  1588. else if (start < a) { alpha = 1.f; }
  1589. window->DrawList->PathClear();
  1590. for (size_t i = 0; i < num_segments + 1; i++)
  1591. {
  1592. const float ar_b = arc_angle * arc_num + (i * angle_offset) - pi_div_2;
  1593. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(ar_b) * radius, centre.y + ImSin(ar_b) * radius));
  1594. }
  1595. window->DrawList->PathStroke(color_alpha(color, ImMax(0.f, 1.f - alpha)), false, thickness);
  1596. }
  1597. }
  1598. inline void SpinnerArcWedges(const char *label, float radius, const ImColor &color = red, float speed = 2.8f, size_t arcs = 4)
  1599. {
  1600. SPINNER_HEADER(pos, size, centre, num_segments);
  1601. const float start = (float)ImGui::GetTime() * speed;
  1602. const float arc_angle = PI_2 / (float)arcs;
  1603. const float angle_offset = arc_angle / num_segments;
  1604. float out_h, out_s, out_v;
  1605. ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, out_h, out_s, out_v);
  1606. for (size_t arc_num = 0; arc_num < arcs; ++arc_num)
  1607. {
  1608. const float b = arc_angle * arc_num - PI_DIV_2;
  1609. const float e = arc_angle * arc_num + arc_angle - PI_DIV_2;
  1610. const float a = arc_angle * arc_num;
  1611. window->DrawList->PathClear();
  1612. window->DrawList->PathLineTo(centre);
  1613. for (size_t i = 0; i < num_segments + 1; i++)
  1614. {
  1615. const float start_a = ImFmod(start * (1.05f * (arc_num + 1)), PI_2);
  1616. const float ar = start_a + arc_angle * arc_num + (i * angle_offset) - PI_DIV_2;
  1617. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(ar) * radius, centre.y + ImSin(ar) * radius));
  1618. }
  1619. window->DrawList->PathFillConvex(color_alpha(ImColor::HSV(out_h + (1.f / arcs) * arc_num, out_s, out_v, 0.7f), 1.f));
  1620. }
  1621. }
  1622. inline void SpinnerTwinBall(const char *label, float radius1, float radius2, float thickness, float b_thickness, const ImColor &ball = white, const ImColor &bg = half_white, float speed = 2.8f, size_t balls = 2)
  1623. {
  1624. float radius = ImMax(radius1, radius2);
  1625. SPINNER_HEADER(pos, size, centre, num_segments);
  1626. const float start = (float)ImGui::GetTime()* speed;
  1627. const float bg_angle_offset = PI_2 / num_segments;
  1628. window->DrawList->PathClear();
  1629. for (size_t i = 0; i <= num_segments; i++)
  1630. {
  1631. const float a = start + (i * bg_angle_offset);
  1632. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * radius1, centre.y + ImSin(a) * radius1));
  1633. }
  1634. window->DrawList->PathStroke(color_alpha(bg, 1.f), false, thickness);
  1635. for (size_t b_num = 0; b_num < balls; ++b_num)
  1636. {
  1637. float b_start = PI_2 / balls;
  1638. const float a = b_start * b_num + start;
  1639. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(a) * radius2, centre.y + ImSin(a) * radius2), b_thickness, color_alpha(ball, 1.f));
  1640. }
  1641. }
  1642. inline void SpinnerSolarBalls(const char *label, float radius, float thickness, const ImColor &ball = white, const ImColor &bg = half_white, float speed = 2.8f, size_t balls = 4)
  1643. {
  1644. SPINNER_HEADER(pos, size, centre, num_segments);
  1645. const float start = (float)ImGui::GetTime() * speed;
  1646. const float bg_angle_offset = PI_2 / num_segments;
  1647. for (int i = 0; i < balls; ++i) {
  1648. const float rb = (radius / balls) * 1.3f * (i + 1);
  1649. window->DrawList->AddCircle(centre, rb, color_alpha(bg, 1.f), num_segments, thickness * 0.3f);
  1650. }
  1651. for (int i = 0; i < balls; ++i) {
  1652. const float rb = (radius / balls) * 1.3f * (i + 1);
  1653. const float a = start * (1.0f + 0.1f * i);
  1654. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(a) * rb, centre.y + ImSin(a) * rb), thickness, color_alpha(ball, 1.f));
  1655. }
  1656. }
  1657. inline void SpinnerSolarScaleBalls(const char *label, float radius, float thickness, const ImColor &ball = white, float speed = 2.8f, size_t balls = 4)
  1658. {
  1659. SPINNER_HEADER(pos, size, centre, num_segments);
  1660. const float start = ImFmod((float)ImGui::GetTime() * speed, IM_PI * 16.f);
  1661. const float bg_angle_offset = PI_2 / num_segments;
  1662. for (int i = 0; i < balls; ++i) {
  1663. const float rb = (radius / balls) * 1.3f * (i + 1);
  1664. const float a = start * (1.0f + 0.1f * i);
  1665. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(a) * rb, centre.y + ImSin(a) * rb), ((thickness * 2.f) / balls) * i, color_alpha(ball, 1.f));
  1666. }
  1667. }
  1668. inline void SpinnerSolarArcs(const char *label, float radius, float thickness, const ImColor &ball = white, const ImColor &bg = half_white, float speed = 2.8f, size_t balls = 4)
  1669. {
  1670. SPINNER_HEADER(pos, size, centre, num_segments);
  1671. const float start = (float)ImGui::GetTime()* speed;
  1672. const int half_segments = num_segments / 2;
  1673. for (int i = 0; i < balls; ++i)
  1674. {
  1675. const float rb = (radius / balls) * 1.3f * (i + 1);
  1676. const float bg_angle_offset = IM_PI / half_segments;
  1677. const int mul = i % 2 ? -1 : 1;
  1678. window->DrawList->PathClear();
  1679. for (size_t ii = 0; ii <= half_segments; ii++)
  1680. {
  1681. const float a = (ii * bg_angle_offset);
  1682. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * rb, centre.y + ImSin(a) * rb * mul));
  1683. }
  1684. window->DrawList->PathStroke(color_alpha(bg, 1.f), false, thickness * 0.8f);
  1685. }
  1686. for (int i = 0; i < balls; ++i)
  1687. {
  1688. const float rb = (radius / balls) * 1.3f * (i + 1);
  1689. const float a = ImFmod(start * (1.0f + 0.1f * i), PI_2);
  1690. const int mul = i % 2 ? -1 : 1;
  1691. float y = ImSin(a) * rb;
  1692. if ((y > 0 && mul < 0) || (y < 0 && mul > 0)) y = -y;
  1693. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(a) * rb, centre.y + y), thickness, color_alpha(ball, 1.f));
  1694. }
  1695. }
  1696. inline void SpinnerMovingArcs(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, size_t arcs = 4)
  1697. {
  1698. SPINNER_HEADER(pos, size, centre, num_segments);
  1699. const float start = ImFmod((float)ImGui::GetTime() * speed, IM_PI * 2);
  1700. const int half_segments = num_segments / 2;
  1701. for (int i = 0; i < arcs; ++i) {
  1702. const float rb = (radius / arcs) * 1.3f * (i + 1);
  1703. float a = damped_spring(1, 10.f, 1.0f, ImSin(ImFmod(start + i * PI_DIV(arcs), PI_2)));
  1704. const float angle = ImMax(PI_DIV_2, (1.f - i/(float)arcs) * IM_PI);
  1705. circle([&] (int i) {
  1706. const float b = a + (i * angle / num_segments);
  1707. return ImVec2(ImCos(b) * rb, ImSin(b) * rb);
  1708. }, color_alpha(color, 1.f), thickness);
  1709. }
  1710. }
  1711. inline void SpinnerRainbowCircle(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, size_t arcs = 4, float mode = 1)
  1712. {
  1713. SPINNER_HEADER(pos, size, centre, num_segments);
  1714. const float start = (float)ImGui::GetTime() * speed;
  1715. num_segments *= 2;
  1716. const float bg_angle_offset = IM_PI / num_segments;
  1717. float out_h, out_s, out_v;
  1718. ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, out_h, out_s, out_v);
  1719. for (int i = 0; i < arcs; ++i)
  1720. {
  1721. float max_angle = IM_PI - ImFmod(start /* * (1.0 + 0.1f * i) */, IM_PI + PI_DIV_2 + PI_DIV(8));
  1722. max_angle = ImMin(IM_PI, max_angle + (PI_DIV_2 / arcs) * i);
  1723. const float rb = (radius / arcs) * 1.1f * (i + 1);
  1724. ImColor c = ImColor::HSV(out_h + i * (0.8f / arcs), out_s, out_v);
  1725. const int draw_segments = ImMax<int>(0, (int)(max_angle / bg_angle_offset));
  1726. for (int j = 0; j < 2; j++)
  1727. {
  1728. const int mul = j % 2 ? -1 : 1;
  1729. const float py = (j % 2 ? -0.5f : 0.5f) * thickness;
  1730. const float alpha_start = (j % 2 ? 0 : IM_PI) * mode;
  1731. window->DrawList->PathClear();
  1732. for (size_t ii = 0; ii <= draw_segments + 1; ii++)
  1733. {
  1734. const float a = (ii * bg_angle_offset);
  1735. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(IM_PI - alpha_start - a) * rb, centre.y + ImSin(a) * rb * mul + py));
  1736. }
  1737. window->DrawList->PathStroke(color_alpha(c, 1.f), false, thickness * 0.8f);
  1738. }
  1739. }
  1740. }
  1741. inline void SpinnerBounceBall(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, int dots = 1, bool shadow = false)
  1742. {
  1743. SPINNER_HEADER(pos, size, centre, num_segments);
  1744. ImGuiStorage* storage = window->DC.StateStorage;
  1745. const ImGuiID vtimeId = window->GetID("##vtime");
  1746. const ImGuiID hmaxId = window->GetID("##hmax");
  1747. float vtime = storage->GetFloat(vtimeId, 0.f);
  1748. float hmax = storage->GetFloat(hmaxId, 1.f);
  1749. vtime += 0.05f;
  1750. hmax += 0.01f;
  1751. storage->SetFloat(vtimeId, vtime);
  1752. storage->SetFloat(hmaxId, hmax);
  1753. constexpr float rkoeff[9] = {0.1f, 0.15f, 0.17f, 0.25f, 0.31f, 0.19f, 0.08f, 0.24f, 0.9f};
  1754. const int iterations = shadow ? 4 : 1;
  1755. for (int j = 0; j < iterations; j++) {
  1756. ImColor c = color_alpha(color, 1.f - 0.15f * j);
  1757. for (int i = 0; i < dots; i++) {
  1758. float start = ImFmod((float)ImGui::GetTime() * speed * (1 + rkoeff[i % 9]) - (IM_PI / 12.f) * j, IM_PI);
  1759. float sign = ((i % 2 == 0) ? 1.f : -1.f);
  1760. float offset = (i == 0) ? 0.f : (floorf((i+1) / 2.f + 0.1f) * sign * 2.f * thickness);
  1761. float maxht = damped_gravity(ImSin(ImFmod(hmax, IM_PI))) * radius;
  1762. window->DrawList->AddCircleFilled(ImVec2(centre.x + offset, centre.y + radius - ImSin(start) * 2.f * maxht), thickness, c, 8);
  1763. }
  1764. }
  1765. }
  1766. inline void SpinnerPulsarBall(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, bool shadow = false, int mode = 0)
  1767. {
  1768. SPINNER_HEADER(pos, size, centre, num_segments);
  1769. ImGuiStorage* storage = window->DC.StateStorage;
  1770. const int iterations = shadow ? 4 : 1;
  1771. for (int j = 0; j < iterations; j++) {
  1772. ImColor c = color_alpha(color, 1.f - 0.15f * j);
  1773. float start = ImFmod((float)ImGui::GetTime() * speed - (IM_PI / 12.f) * j, IM_PI);
  1774. float maxht = damped_gravity(ImSin(ImFmod(start, IM_PI))) * (radius * 0.6f);
  1775. window->DrawList->AddCircleFilled(ImVec2(centre.x, centre.y), maxht, c, num_segments);
  1776. }
  1777. const float angle_offset = PI_DIV_2 / num_segments;
  1778. const int arcs = 2;
  1779. for (size_t arc_num = 0; arc_num < arcs; ++arc_num) {
  1780. window->DrawList->PathClear();
  1781. float arc_start = 2 * IM_PI / arcs;
  1782. float start = ImFmod((float)ImGui::GetTime() * speed - (IM_PI * arc_num), IM_PI);
  1783. float b = mode ? start + damped_spring(1, 10.f, 1.0f, ImSin(ImFmod(start + arc_num * PI_DIV(2) / arcs, IM_PI)), 1, 0) : start;
  1784. float maxht = (damped_gravity(ImSin(ImFmod(start, IM_PI))) * 0.3f + 0.7f) * radius;
  1785. for (size_t i = 0; i < num_segments; i++) {
  1786. const float a = b + arc_start * arc_num + (i * angle_offset);
  1787. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * maxht, centre.y + ImSin(a) * maxht));
  1788. }
  1789. window->DrawList->PathStroke(color_alpha(color, 1.f), false, thickness);
  1790. }
  1791. }
  1792. inline void SpinnerIncScaleDots(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, size_t dots = 6)
  1793. {
  1794. SPINNER_HEADER(pos, size, centre, num_segments);
  1795. float start = (float)ImGui::GetTime() * speed;
  1796. float astart = ImFmod(start, IM_PI / dots);
  1797. start -= astart;
  1798. const float bg_angle_offset = IM_PI / dots;
  1799. dots = ImMin(dots, (size_t)32);
  1800. for (size_t i = 0; i <= dots; i++)
  1801. {
  1802. float a = start + (i * bg_angle_offset);
  1803. float th = thickness * ImMax(0.1f, i / (float)dots);
  1804. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(a) * radius, centre.y + ImSin(a) * radius), th, color_alpha(color, 1.f), 8);
  1805. }
  1806. }
  1807. inline void SpinnerSomeScaleDots(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, size_t dots = 6, int mode = 0)
  1808. {
  1809. SPINNER_HEADER(pos, size, centre, num_segments);
  1810. float start = (float)ImGui::GetTime() * speed;
  1811. float astart = ImFmod(start, IM_PI / dots);
  1812. start -= astart;
  1813. const float bg_angle_offset = IM_PI / dots;
  1814. dots = ImMin(dots, (size_t)32);
  1815. for (size_t j = 0; j < 4; j++)
  1816. {
  1817. float r = radius * (1.f - (0.15f * j));
  1818. for (size_t i = 0; i <= dots; i++)
  1819. {
  1820. float a = start * (mode ? (1.f + j * 0.05f) : 1.f) + (i * bg_angle_offset);
  1821. float th = thickness * ImMax(0.1f, i / (float)dots);
  1822. float thh = th * (1.f - (0.2f * j));
  1823. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(a) * r, centre.y + ImSin(a) * r), thh, color_alpha(color, 1.f), 8);
  1824. }
  1825. }
  1826. }
  1827. inline void SpinnerAngTriple(const char *label, float radius1, float radius2, float radius3, float thickness, const ImColor &c1 = white, const ImColor &c2 = half_white, const ImColor &c3 = white, float speed = 2.8f, float angle = IM_PI)
  1828. {
  1829. float radius = ImMax(ImMax(radius1, radius2), radius3);
  1830. SPINNER_HEADER(pos, size, centre, num_segments);
  1831. const float start1 = (float)ImGui::GetTime() * speed;
  1832. const float angle_offset = angle / num_segments;
  1833. window->DrawList->PathClear();
  1834. for (size_t i = 0; i < num_segments; i++)
  1835. {
  1836. const float a = start1 + (i * angle_offset);
  1837. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * radius1, centre.y + ImSin(a) * radius1));
  1838. }
  1839. window->DrawList->PathStroke(color_alpha(c1, 1.f), false, thickness);
  1840. float start2 = (float)ImGui::GetTime() * 1.2f * speed;
  1841. window->DrawList->PathClear();
  1842. for (size_t i = 0; i < num_segments; i++)
  1843. {
  1844. const float a = start2 + (i * angle_offset);
  1845. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(-a) * radius2, centre.y + ImSin(-a) * radius2));
  1846. }
  1847. window->DrawList->PathStroke(color_alpha(c2, 1.f), false, thickness);
  1848. float start3 = (float)ImGui::GetTime() * 0.9f * speed;
  1849. window->DrawList->PathClear();
  1850. for (size_t i = 0; i < num_segments; i++)
  1851. {
  1852. const float a = start3 + (i * angle_offset);
  1853. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * radius3, centre.y + ImSin(a) * radius3));
  1854. }
  1855. window->DrawList->PathStroke(color_alpha(c3, 1.f), false, thickness);
  1856. }
  1857. inline void SpinnerAngEclipse(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, float angle = IM_PI)
  1858. {
  1859. SPINNER_HEADER(pos, size, centre, num_segments);
  1860. const float start = (float)ImGui::GetTime()* speed;
  1861. const float angle_offset = angle / num_segments;
  1862. const float th = thickness / num_segments;
  1863. for (size_t i = 0; i < num_segments; i++)
  1864. {
  1865. const float a = start + (i * angle_offset);
  1866. const float a1 = start + ((i+1) * angle_offset);
  1867. window->DrawList->AddLine(ImVec2(centre.x + ImCos(a) * radius, centre.y + ImSin(a) * radius),
  1868. ImVec2(centre.x + ImCos(a1) * radius, centre.y + ImSin(a1) * radius),
  1869. color_alpha(color, 1.f),
  1870. th * i);
  1871. }
  1872. }
  1873. inline void SpinnerIngYang(const char *label, float radius, float thickness, bool reverse, float yang_detlta_r, const ImColor &colorI = white, const ImColor &colorY = white, float speed = 2.8f, float angle = IM_PI * 0.7f)
  1874. {
  1875. SPINNER_HEADER(pos, size, centre, num_segments);
  1876. const float startI = (float)ImGui::GetTime() * speed;
  1877. const float startY = (float)ImGui::GetTime() * (speed + (yang_detlta_r > 0.f ? ImClamp(yang_detlta_r * 0.5f, 0.5f, 2.f) : 0.f));
  1878. const float angle_offset = angle / num_segments;
  1879. const float th = thickness / num_segments;
  1880. for (int i = 0; i < num_segments; i++)
  1881. {
  1882. const float a = startI + (i * angle_offset);
  1883. const float a1 = startI + ((i + 1) * angle_offset);
  1884. window->DrawList->AddLine(ImVec2(centre.x + ImCos(a) * radius, centre.y + ImSin(a) * radius),
  1885. ImVec2(centre.x + ImCos(a1) * radius, centre.y + ImSin(a1) * radius),
  1886. color_alpha(colorI, 1.f),
  1887. th * i);
  1888. }
  1889. const float ai_end = startI + (num_segments * angle_offset);
  1890. ImVec2 circle_i_center{centre.x + ImCos(ai_end) * radius, centre.y + ImSin(ai_end) * radius};
  1891. window->DrawList->AddCircleFilled(circle_i_center, thickness / 2.f, color_alpha(colorI, 1.f), num_segments);
  1892. const float rv = reverse ? -1.f : 1.f;
  1893. const float yang_radius = (radius - yang_detlta_r);
  1894. for (int i = 0; i < num_segments; i++)
  1895. {
  1896. const float a = startY + IM_PI + (i * angle_offset);
  1897. const float a1 = startY + IM_PI + ((i+1) * angle_offset);
  1898. window->DrawList->AddLine(ImVec2(centre.x + ImCos(a * rv) * yang_radius, centre.y + ImSin(a * rv) * yang_radius),
  1899. ImVec2(centre.x + ImCos(a1 * rv) * yang_radius, centre.y + ImSin(a1 * rv) * yang_radius),
  1900. color_alpha(colorY, 1.f),
  1901. th * i);
  1902. }
  1903. const float ay_end = startY + IM_PI + (num_segments * angle_offset);
  1904. ImVec2 circle_y_center{centre.x + ImCos(ay_end * rv) * yang_radius, centre.y + ImSin(ay_end * rv) * yang_radius};
  1905. window->DrawList->AddCircleFilled(circle_y_center, thickness / 2.f, color_alpha(colorY, 1.f), num_segments);
  1906. }
  1907. inline void SpinnerGooeyBalls(const char *label, float radius, const ImColor &color, float speed, int mode = 0)
  1908. {
  1909. SPINNER_HEADER(pos, size, centre, num_segments);
  1910. float start = ImFmod((float)ImGui::GetTime() * speed, IM_PI);
  1911. start = mode ? damped_spring(1, 10.f, 1.0f, ImSin(start), 1, 0) : start;
  1912. const float radius1 = (0.4f + 0.3f * ImSin(start)) * radius;
  1913. const float radius2 = radius - radius1;
  1914. window->DrawList->AddCircleFilled(ImVec2(centre.x - radius + radius1, centre.y), radius1, color_alpha(color, 1.f), num_segments);
  1915. window->DrawList->AddCircleFilled(ImVec2(centre.x - radius + radius1 * 1.2f + radius2, centre.y), radius2, color_alpha(color, 1.f), num_segments);
  1916. }
  1917. inline void SpinnerDotsLoading(const char *label, float radius, float thickness, const ImColor &color, const ImColor &bg, float speed)
  1918. {
  1919. SPINNER_HEADER(pos, size, centre, num_segments);
  1920. const float start = ImFmod((float)ImGui::GetTime() * speed, IM_PI);
  1921. const float radius1 = (2.f * ImSin(start)) * radius;
  1922. float startb = ImFmod(start, PI_DIV_2);
  1923. float lenb = startb < PI_DIV_2 ? ImAbs((0.5f * ImSin(start * 2)) * radius) : radius * 0.5f;
  1924. float radius2 = radius * 0.25f;
  1925. float deltae = thickness - ImMin(thickness, ImMax<float>(0, (2.f * radius - radius1 + thickness + lenb) * 0.25f));
  1926. float deltag = ImMin(thickness, ImAbs(centre.x - radius + radius1 + thickness + lenb - centre.x - radius) * 0.25f);
  1927. window->DrawList->AddCircleFilled(ImVec2(centre.x - radius, centre.y), radius2 + deltag, color_alpha(bg, 1.f), num_segments);
  1928. window->DrawList->AddCircleFilled(ImVec2(centre.x + radius + thickness, centre.y), radius2 + deltae, color_alpha(bg, 1.f), num_segments);
  1929. window->DrawList->AddRectFilled(ImVec2(centre.x - radius + radius1 - thickness - lenb, centre.y - thickness), ImVec2(centre.x - radius + radius1 + thickness + lenb, centre.y + thickness), color_alpha(color, 1.f), thickness);
  1930. }
  1931. inline void SpinnerRotateGooeyBalls(const char *label, float radius, float thickness, const ImColor &color, float speed, int balls)
  1932. {
  1933. SPINNER_HEADER(pos, size, centre, num_segments);
  1934. const float start = ImFmod((float)ImGui::GetTime(), IM_PI);
  1935. const float rstart = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  1936. const float radius1 = (0.2f + 0.3f * ImSin(start)) * radius;
  1937. const float angle_offset = PI_2 / balls;
  1938. for (int i = 0; i <= balls; i++)
  1939. {
  1940. const float a = rstart + (i * angle_offset);
  1941. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(a) * radius1, centre.y + ImSin(a) * radius1), thickness, color_alpha(color, 1.f), num_segments);
  1942. }
  1943. }
  1944. inline void SpinnerHerbertBalls(const char *label, float radius, float thickness, const ImColor &color, float speed, int balls)
  1945. {
  1946. SPINNER_HEADER(pos, size, centre, num_segments);
  1947. const float start = ImFmod((float)ImGui::GetTime(), IM_PI);
  1948. const float rstart = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  1949. const float radius1 = 0.3f * radius;
  1950. const float radius2 = 0.8f * radius;
  1951. const float angle_offset = PI_2 / balls;
  1952. for (int i = 0; i < balls; i++)
  1953. {
  1954. const float a = rstart + (i * angle_offset);
  1955. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(a) * radius1, centre.y + ImSin(a) * radius1), thickness, color_alpha(color, 1.f), num_segments);
  1956. }
  1957. for (int i = 0; i < balls * 2; i++)
  1958. {
  1959. const float a = -rstart + (i * angle_offset / 2.f);
  1960. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(a) * radius2, centre.y + ImSin(a) * radius2), thickness, color_alpha(color, 1.f), num_segments);
  1961. }
  1962. }
  1963. inline void SpinnerHerbertBalls3D(const char *label, float radius, float thickness, const ImColor &color, float speed)
  1964. {
  1965. SPINNER_HEADER(pos, size, centre, num_segments);
  1966. const float start = ImFmod((float)ImGui::GetTime(), IM_PI);
  1967. const float rstart = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  1968. const float radius1 = 0.3f * radius;
  1969. const float radius2 = 0.8f * radius;
  1970. const int balls = 2;
  1971. const float angle_offset = PI_2 / balls;
  1972. ImVec2 frontpos, backpos;
  1973. for (int i = 0; i < balls; i++)
  1974. {
  1975. const float a = rstart + (i * angle_offset);
  1976. const float t = (i == 1 ? 0.7f : 1.f) * thickness;
  1977. const ImVec2 pos = ImVec2(centre.x + ImCos(a) * radius1, centre.y + ImSin(a) * radius1);
  1978. window->DrawList->AddCircleFilled(pos, t, color_alpha(color, 1.f), num_segments);
  1979. if (i == 0) frontpos = pos; else backpos = pos;
  1980. }
  1981. ImVec2 lastpos;
  1982. for (int i = 0; i <= balls * 2; i++)
  1983. {
  1984. const float a = -rstart + (i * angle_offset / 2.f);
  1985. const ImVec2 pos = ImVec2(centre.x + ImCos(a) * radius2, centre.y + ImSin(a) * radius2);
  1986. float t = (float)sqrt(pow(pos.x - frontpos.x, 2) + pow(pos.y - frontpos.y, 2)) / (radius * 1.f) * thickness;
  1987. window->DrawList->AddCircleFilled(pos, t, color_alpha(color, 1.f), num_segments);
  1988. window->DrawList->AddLine(pos, backpos, color_alpha(color, 0.5f), ImMax(thickness / 2.f, 1.f));
  1989. if (i > 0) {
  1990. window->DrawList->AddLine(pos, lastpos, color_alpha(color, 1.f), ImMax(thickness / 2.f, 1.f));
  1991. }
  1992. window->DrawList->AddLine(pos, frontpos, color_alpha(color, 1.f), ImMax(thickness / 2.f, 1.f));
  1993. lastpos = pos;
  1994. }
  1995. }
  1996. inline void SpinnerRotateTriangles(const char *label, float radius, float thickness, const ImColor &color, float speed, int tris)
  1997. {
  1998. SPINNER_HEADER(pos, size, centre, num_segments);
  1999. const float start = ImFmod((float)ImGui::GetTime(), IM_PI);
  2000. const float rstart = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  2001. const float radius1 = radius / 2.5f + thickness;
  2002. const float angle_offset = PI_2 / tris;
  2003. for (int i = 0; i <= tris; i++)
  2004. {
  2005. const float a = rstart + (i * angle_offset);
  2006. ImVec2 tri_centre(centre.x + ImCos(a) * radius1, centre.y + ImSin(a) * radius1);
  2007. ImVec2 p1(tri_centre.x + ImCos(-a) * radius1, tri_centre.y + ImSin(-a) * radius1);
  2008. ImVec2 p2(tri_centre.x + ImCos(-a + PI_2 / 3.f) * radius1, tri_centre.y + ImSin(-a + PI_2 / 3.f) * radius1);
  2009. ImVec2 p3(tri_centre.x + ImCos(-a - PI_2 / 3.f) * radius1, tri_centre.y + ImSin(-a - PI_2 / 3.f) * radius1);
  2010. ImVec2 points[] = {p1, p2, p3};
  2011. window->DrawList->AddConvexPolyFilled(points, 3, color_alpha(color, 1.f));
  2012. }
  2013. }
  2014. inline void SpinnerRotateShapes(const char *label, float radius, float thickness, const ImColor &color, float speed, int shapes, int pnt)
  2015. {
  2016. SPINNER_HEADER(pos, size, centre, num_segments);
  2017. const float start = ImFmod((float)ImGui::GetTime(), IM_PI);
  2018. const float rstart = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  2019. const float radius1 = radius / 2.5f + thickness;
  2020. const float angle_offset = PI_2 / shapes;
  2021. std::vector<ImVec2> points(pnt);
  2022. const float begin_a = -IM_PI / ((pnt % 2 == 0) ? pnt : (pnt - 1));
  2023. for (int i = 0; i <= shapes; i++)
  2024. {
  2025. const float a = rstart + (i * angle_offset);
  2026. ImVec2 tri_centre(centre.x + ImCos(a) * radius1, centre.y + ImSin(a) * radius1);
  2027. for (int pi = 0; pi < pnt; ++pi) {
  2028. points[pi] = {tri_centre.x + ImCos(begin_a + pi * PI_2 / pnt) * radius1, tri_centre.y + ImSin(begin_a + pi * PI_2 / pnt) * radius1};
  2029. }
  2030. window->DrawList->AddConvexPolyFilled(points.data(), pnt, color_alpha(color, 1.f));
  2031. }
  2032. }
  2033. inline void SpinnerSinSquares(const char *label, float radius, float thickness, const ImColor &color, float speed)
  2034. {
  2035. SPINNER_HEADER(pos, size, centre, num_segments);
  2036. const float start = ImFmod((float)ImGui::GetTime(), IM_PI);
  2037. const float rstart = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  2038. const float radius1 = radius / 2.5f + thickness;
  2039. const float angle_offset = PI_DIV_2;
  2040. std::vector<ImVec2> points(4);
  2041. for (int i = 0; i <= 4; i++)
  2042. {
  2043. const float a = rstart + (i * angle_offset);
  2044. const float begin_a = a - PI_DIV_2;
  2045. const float roff = ImMax(ImSin(start) - 0.5f, 0.f) * (radius * 0.4f);
  2046. ImVec2 tri_centre(centre.x + ImCos(a) * (radius1 + roff), centre.y + ImSin(a) * (radius1 + roff));
  2047. for (int pi = 0; pi < 4; ++pi) {
  2048. points[pi] = {tri_centre.x + ImCos(begin_a+ pi * PI_DIV_2) * radius1, tri_centre.y + ImSin(begin_a + pi * PI_DIV_2) * radius1};
  2049. }
  2050. window->DrawList->AddConvexPolyFilled(points.data(), 4, color_alpha(color, 1.f));
  2051. }
  2052. }
  2053. inline void SpinnerMoonLine(const char *label, float radius, float thickness, const ImColor &color = white, const ImColor &bg = red, float speed = 2.8f, float angle = IM_PI)
  2054. {
  2055. SPINNER_HEADER(pos, size, centre, num_segments);
  2056. const float start = (float)ImGui::GetTime()* speed;
  2057. const float angle_offset = (angle * 0.5f) / num_segments;
  2058. const float th = thickness / num_segments;
  2059. window->DrawList->AddCircleFilled(centre, radius, bg, num_segments);
  2060. auto draw_gradient = [&] (const std::function<float (int)>& b, const std::function<float (int)>& e, const std::function<float (int)>& th) {
  2061. for (int i = 0; i < num_segments; i++)
  2062. {
  2063. window->DrawList->AddLine(ImVec2(centre.x + ImCos(start + b(i)) * radius, centre.y + ImSin(start + b(i)) * radius),
  2064. ImVec2(centre.x + ImCos(start + e(i)) * radius, centre.y + ImSin(start + e(i)) * radius),
  2065. color_alpha(color, 1.f),
  2066. th(i));
  2067. }
  2068. };
  2069. draw_gradient([&] (int i) { return (num_segments + i) * angle_offset; },
  2070. [&] (int i) { return (num_segments + i + 1) * angle_offset; },
  2071. [&] (int i) { return thickness - th * i; });
  2072. draw_gradient([&] (int i) { return (i) * angle_offset; },
  2073. [&] (int i) { return (i + 1) * angle_offset; },
  2074. [&] (int i) { return th * i; });
  2075. draw_gradient([&] (int i) { return (num_segments + i) * angle_offset; },
  2076. [&] (int i) { return (num_segments + i + 1) * angle_offset; },
  2077. [&] (int i) { return thickness - th * i; });
  2078. const float b_angle_offset = (PI_2 - angle) / num_segments;
  2079. draw_gradient([&] (int i) { return num_segments * angle_offset * 2.f + (i * b_angle_offset); },
  2080. [&] (int i) { return num_segments * angle_offset * 2.f + ((i + 1) * b_angle_offset); },
  2081. [] (int) { return 1.f; });
  2082. }
  2083. inline void SpinnerCircleDrop(const char *label, float radius, float thickness, float thickness_drop, const ImColor &color = white, const ImColor &bg = half_white, float speed = 2.8f, float angle = IM_PI)
  2084. {
  2085. SPINNER_HEADER(pos, size, centre, num_segments);
  2086. const float start = (float)ImGui::GetTime() * speed;
  2087. const float bg_angle_offset = PI_2 / num_segments;
  2088. const float angle_offset = angle / num_segments;
  2089. const float th = thickness_drop / num_segments;
  2090. const float drop_radius_th = thickness_drop / num_segments;
  2091. for (int i = 0; i < num_segments; i++)
  2092. {
  2093. const float a = start + (i * angle_offset);
  2094. const float a1 = start + ((i + 1) * angle_offset);
  2095. const float s_drop_radius = radius - thickness / 2.f - (drop_radius_th * i);
  2096. window->DrawList->AddLine(ImVec2(centre.x + ImCos(a) * s_drop_radius, centre.y + ImSin(a) * s_drop_radius),
  2097. ImVec2(centre.x + ImCos(a1) * s_drop_radius, centre.y + ImSin(a1) * s_drop_radius),
  2098. color_alpha(color, 1.f),
  2099. th * 2.f * i);
  2100. }
  2101. const float ai_end = start + (num_segments * angle_offset);
  2102. const float f_drop_radius = radius - thickness / 2.f - thickness_drop;
  2103. ImVec2 circle_i_center{centre.x + ImCos(ai_end) * f_drop_radius, centre.y + ImSin(ai_end) * f_drop_radius};
  2104. window->DrawList->AddCircleFilled(circle_i_center, thickness_drop, color_alpha(color, 1.f), num_segments);
  2105. window->DrawList->PathClear();
  2106. for (int i = 0; i <= num_segments; i++)
  2107. {
  2108. const float a = (i * bg_angle_offset);
  2109. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * radius, centre.y + ImSin(a) * radius));
  2110. }
  2111. window->DrawList->PathStroke(color_alpha(bg, 1.f), false, thickness);
  2112. }
  2113. inline void SpinnerSurroundedIndicator(const char *label, float radius, float thickness, const ImColor &color = white, const ImColor &bg = half_white, float speed = 2.8f)
  2114. {
  2115. SPINNER_HEADER(pos, size, centre, num_segments);
  2116. float lerp_koeff = (ImSin((float)ImGui::GetTime() * speed) + 1.f) * 0.5f;
  2117. window->DrawList->AddCircleFilled(centre, thickness, color_alpha(bg, 1.f), num_segments);
  2118. window->DrawList->AddCircleFilled(centre, thickness, color_alpha(color, ImMax(0.1f, ImMin(lerp_koeff, 1.f))), num_segments);
  2119. auto PathArc = [&] (const ImColor& c, float th) {
  2120. window->DrawList->PathClear();
  2121. const float bg_angle_offset = PI_2 / num_segments;
  2122. for (int i = 0; i <= num_segments; i++)
  2123. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(i * bg_angle_offset) * radius, centre.y + ImSin(i * bg_angle_offset) * radius));
  2124. window->DrawList->PathStroke(color_alpha(c, 1.f), false, th);
  2125. };
  2126. lerp_koeff = (ImSin((float)ImGui::GetTime() * speed * 1.6f) + 1.f) * 0.5f;
  2127. PathArc(bg, thickness);
  2128. PathArc(color_alpha(color, 1.f - ImMax(0.1f, ImMin(lerp_koeff, 1.f))), thickness);
  2129. }
  2130. inline void SpinnerWifiIndicator(const char *label, float radius, float thickness, const ImColor &color = red, const ImColor &bg = half_white, float speed = 2.8f, float cangle = 0.f, int dots = 3)
  2131. {
  2132. SPINNER_HEADER(pos, size, centre, num_segments);
  2133. float lerp_koeff = (ImSin((float)ImGui::GetTime() * speed) + 1.f) * 0.5f;
  2134. float start_ang = -cangle - PI_DIV_4 - PI_DIV_2;
  2135. ImVec2 pc(centre.x + ImSin(cangle) * radius, centre.y + ImCos(cangle) * radius);
  2136. window->DrawList->AddCircleFilled(pc, thickness, bg, num_segments);
  2137. window->DrawList->AddCircleFilled(pc, thickness, color_alpha(color, ImMax(0.1f, ImMin(lerp_koeff, 1.f))), num_segments);
  2138. auto PathArc = [&] (float as, const ImColor& c, float th, float r) {
  2139. window->DrawList->PathClear();
  2140. const float bg_angle_offset = PI_DIV(2) / num_segments;
  2141. for (int i = 0; i <= num_segments; i++)
  2142. window->DrawList->PathLineTo(ImVec2(pc.x + ImCos(as + i * bg_angle_offset) * r, pc.y + ImSin(as + i * bg_angle_offset) * r));
  2143. window->DrawList->PathStroke(color_alpha(c, 1.f), false, th);
  2144. };
  2145. const float interval = (size.x * 0.7f) / dots;
  2146. for (int i = 0; i < dots; ++i) {
  2147. float r = 1.5f * (i + 1) * interval;
  2148. lerp_koeff = (ImSin((float)ImGui::GetTime() * speed - (i+1) * (IM_PI / dots)) + 1.f) * 0.5f;
  2149. PathArc(start_ang, bg, thickness, r);
  2150. PathArc(start_ang, color_alpha(color, ImMax(0.1f, ImMin(lerp_koeff, 1.f))), thickness, r);
  2151. }
  2152. }
  2153. inline void SpinnerTrianglesSelector(const char *label, float radius, float thickness, const ImColor &color = white, const ImColor &bg = half_white, float speed = 2.8f, size_t bars = 8)
  2154. {
  2155. SPINNER_HEADER(pos, size, centre, num_segments);
  2156. float lerp_koeff = (ImSin((float)ImGui::GetTime() * speed) + 1.f) * 0.5f;
  2157. ImColor c = color_alpha(color, ImMax(0.1f, ImMin(lerp_koeff, 1.f)));
  2158. float dr = radius - thickness - 3;
  2159. window->DrawList->AddCircleFilled(centre, dr, bg, num_segments);
  2160. window->DrawList->AddCircleFilled(centre, dr, c, num_segments);
  2161. // Render
  2162. float start = (float)ImGui::GetTime() * speed;
  2163. float astart = ImFmod(start, PI_2 / bars);
  2164. start -= astart;
  2165. const float angle_offset = PI_2 / bars;
  2166. const float angle_offset_t = angle_offset * 0.3f;
  2167. bars = ImMin<size_t>(bars, 32);
  2168. const float rmin = radius - thickness;
  2169. auto get_points = [&] (float left, float right) -> std::array<ImVec2, 4> {
  2170. return {
  2171. ImVec2(centre.x + ImCos(left) * rmin, centre.y + ImSin(left) * rmin),
  2172. ImVec2(centre.x + ImCos(left) * radius, centre.y + ImSin(left) * radius),
  2173. ImVec2(centre.x + ImCos(right) * radius, centre.y + ImSin(right) * radius),
  2174. ImVec2(centre.x + ImCos(right) * rmin, centre.y + ImSin(right) * rmin)
  2175. };
  2176. };
  2177. auto draw_sectors = [&] (float s, const std::function<ImU32 (size_t)>& color_func) {
  2178. for (size_t i = 0; i <= bars; i++) {
  2179. float left = s + (i * angle_offset) - angle_offset_t;
  2180. float right = s + (i * angle_offset) + angle_offset_t;
  2181. auto points = get_points(left, right);
  2182. window->DrawList->AddConvexPolyFilled(points.data(), 4, color_func(i));
  2183. }
  2184. };
  2185. draw_sectors(0, [&] (size_t) { return color_alpha(bg, 0.1f); });
  2186. draw_sectors(start, [&] (size_t i) { return color_alpha(bg, (i / (float)bars) - 0.5f); });
  2187. }
  2188. using LeafColor = ImColor (int);
  2189. inline void SpinnerCamera(const char *label, float radius, float thickness, LeafColor *leaf_color, float speed = 2.8f, size_t bars = 8)
  2190. {
  2191. SPINNER_HEADER(pos, size, centre, num_segments);
  2192. const float start = (float)ImGui::GetTime() * speed;
  2193. const float angle_offset = PI_2 / bars;
  2194. const float angle_offset_t = angle_offset * 0.3f;
  2195. bars = ImMin<size_t>(bars, 32);
  2196. const float rmin = radius - thickness - 1;
  2197. auto get_points = [&] (float left, float right) -> std::array<ImVec2, 4> {
  2198. return {
  2199. ImVec2(centre.x + ImCos(left - 0.1f) * radius, centre.y + ImSin(left - 0.1f) * radius),
  2200. ImVec2(centre.x + ImCos(right + 0.15f) * radius, centre.y + ImSin(right + 0.15f) * radius),
  2201. ImVec2(centre.x + ImCos(right - 0.91f) * rmin, centre.y + ImSin(right - 0.91f) * rmin)
  2202. };
  2203. };
  2204. auto draw_sectors = [&] (float s, const std::function<ImU32 (int)>& color_func) {
  2205. for (size_t i = 0; i <= bars; i++) {
  2206. float left = s + (i * angle_offset) - angle_offset_t;
  2207. float right = s + (i * angle_offset) + angle_offset_t;
  2208. auto points = get_points(left, right);
  2209. window->DrawList->AddConvexPolyFilled(points.data(), 3, color_alpha(color_func((int)i), 1.f));
  2210. }
  2211. };
  2212. draw_sectors(start, leaf_color);
  2213. }
  2214. inline void SpinnerFlowingGradient(const char *label, float radius, float thickness, const ImColor &color = white, const ImColor &bg = red, float speed = 2.8f, float angle = IM_PI)
  2215. {
  2216. SPINNER_HEADER(pos, size, centre, num_segments);
  2217. const float start = (float)ImGui::GetTime()* speed;
  2218. const float angle_offset = (angle * 0.5f) / num_segments;
  2219. const float bg_angle_offset = (PI_2) / num_segments;
  2220. const float th = thickness / num_segments;
  2221. for (size_t i = 0; i <= num_segments; i++)
  2222. {
  2223. const float a = (i * bg_angle_offset);
  2224. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * radius, centre.y + ImSin(a) * radius));
  2225. }
  2226. window->DrawList->PathStroke(bg, false, thickness);
  2227. auto draw_gradient = [&] (const std::function<float (size_t)>& b, const std::function<float (size_t)>& e, const std::function<ImU32 (size_t)>& c) {
  2228. for (size_t i = 0; i < num_segments; i++)
  2229. {
  2230. window->DrawList->AddLine(ImVec2(centre.x + ImCos(start + b(i)) * radius, centre.y + ImSin(start + b(i)) * radius),
  2231. ImVec2(centre.x + ImCos(start + e(i)) * radius, centre.y + ImSin(start + e(i)) * radius),
  2232. c(i),
  2233. thickness);
  2234. }
  2235. };
  2236. draw_gradient([&] (size_t i) { return (i) * angle_offset; },
  2237. [&] (size_t i) { return (i + 1) * angle_offset; },
  2238. [&] (size_t i) { return color_alpha(color, (i / (float)num_segments)); });
  2239. draw_gradient([&] (size_t i) { return (num_segments + i) * angle_offset; },
  2240. [&] (size_t i) { return (num_segments + i + 1) * angle_offset; },
  2241. [&] (size_t i) { return color_alpha(color, 1.f - (i / (float)num_segments)); });
  2242. }
  2243. inline void SpinnerRotateSegments(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, size_t arcs = 4, size_t layers = 1)
  2244. {
  2245. SPINNER_HEADER(pos, size, centre, num_segments);
  2246. const float start = (float)ImGui::GetTime()* speed;
  2247. const float arc_angle = PI_2 / (float)arcs;
  2248. const float angle_offset = arc_angle / num_segments;
  2249. float r = radius;
  2250. float reverse = 1.f;
  2251. for (size_t layer = 0; layer < layers; layer++)
  2252. {
  2253. for (size_t arc_num = 0; arc_num < arcs; ++arc_num)
  2254. {
  2255. window->DrawList->PathClear();
  2256. for (size_t i = 2; i <= num_segments - 2; i++)
  2257. {
  2258. const float a = start * (1 + 0.1f * layer) + arc_angle * arc_num + (i * angle_offset);
  2259. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a * reverse) * r, centre.y + ImSin(a * reverse) * r));
  2260. }
  2261. window->DrawList->PathStroke(color_alpha(color, 1.f), false, thickness);
  2262. }
  2263. r -= (thickness + 1);
  2264. reverse *= -1.f;
  2265. }
  2266. }
  2267. inline void SpinnerLemniscate(const char* label, float radius, float thickness, const ImColor& color = white, float speed = 2.8f, float angle = IM_PI / 2.0f)
  2268. {
  2269. SPINNER_HEADER(pos, size, centre, num_segments);
  2270. const float start = (float)ImGui::GetTime() * speed;
  2271. const float a = radius;
  2272. const float t = start;
  2273. const float step = angle / num_segments;
  2274. const float th = thickness / num_segments;
  2275. auto get_coord = [&](float const& a, float const& t) -> std::pair<float, float> {
  2276. return std::make_pair((a * ImCos(t)) / (1 + (powf(ImSin(t), 2.0f))), (a * ImSin(t) * ImCos(t)) / (1 + (powf(ImSin(t), 2.0f))));
  2277. };
  2278. for (size_t i = 0; i < num_segments; i++)
  2279. {
  2280. const auto xy0 = get_coord(a, start + (i * step));
  2281. const auto xy1 = get_coord(a, start + ((i + 1) * step));
  2282. window->DrawList->AddLine(ImVec2(centre.x + xy0.first, centre.y + xy0.second),
  2283. ImVec2(centre.x + xy1.first, centre.y + xy1.second),
  2284. color_alpha(color, 1.f),
  2285. th * i);
  2286. }
  2287. }
  2288. inline void SpinnerRotateGear(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, size_t pins = 12)
  2289. {
  2290. SPINNER_HEADER(pos, size, centre, num_segments);
  2291. const float start = (float)ImGui::GetTime()* speed;
  2292. const float bg_angle_offset = PI_2 / num_segments;
  2293. const float bg_radius = radius - thickness;
  2294. window->DrawList->PathClear();
  2295. for (size_t i = 0; i <= num_segments; i++)
  2296. {
  2297. const float a = (i * bg_angle_offset);
  2298. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * bg_radius, centre.y + ImSin(a) * bg_radius));
  2299. }
  2300. window->DrawList->PathStroke(color_alpha(color, 1.f), false, bg_radius / 2);
  2301. const float rmin = bg_radius;
  2302. const float rmax = radius;
  2303. const float pin_angle_offset = PI_2 / pins;
  2304. for (size_t i = 0; i <= pins; i++)
  2305. {
  2306. float a = start + (i * pin_angle_offset);
  2307. window->DrawList->AddLine(ImVec2(centre.x + ImCos(a) * rmin, centre.y + ImSin(a) * rmin),
  2308. ImVec2(centre.x + ImCos(a) * rmax, centre.y + ImSin(a) * rmax),
  2309. color_alpha(color, 1.f), thickness);
  2310. }
  2311. }
  2312. inline void SpinnerRotateWheel(const char *label, float radius, float thickness, const ImColor &bg_color = white, const ImColor &color = white, float speed = 2.8f, size_t pins = 12)
  2313. {
  2314. SPINNER_HEADER(pos, size, centre, num_segments);
  2315. const float start = (float)ImGui::GetTime() * speed;
  2316. const float bg_radius = radius - thickness;
  2317. const float line_th = ImMax(radius / 8.f, 3.f);
  2318. auto draw_circle = [window, num_segments, centre] (float r, const ImColor &c, float th) {
  2319. const float bg_angle_offset = PI_2 / num_segments;
  2320. window->DrawList->PathClear();
  2321. for (size_t i = 0; i <= num_segments; i++)
  2322. {
  2323. const float a = (i * bg_angle_offset);
  2324. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * r, centre.y + ImSin(a) * r));
  2325. }
  2326. window->DrawList->PathStroke(color_alpha(c, 1.f), false, th);
  2327. };
  2328. auto draw_pins = [window, centre, pins, start] (float rmin, float rmax, const ImColor &c, float th) {
  2329. const float pin_angle_offset = PI_2 / pins;
  2330. for (size_t i = 0; i <= pins; i++) {
  2331. float a = start + (i * pin_angle_offset);
  2332. window->DrawList->AddLine(ImVec2(centre.x + ImCos(a) * rmin, centre.y + ImSin(a) * rmin),
  2333. ImVec2(centre.x + ImCos(a) * rmax, centre.y + ImSin(a) * rmax),
  2334. color_alpha(c, 1.f), th);
  2335. }
  2336. };
  2337. draw_circle(bg_radius, bg_color, line_th);
  2338. draw_pins(bg_radius, radius, bg_color, line_th);
  2339. draw_circle(radius, color, line_th);
  2340. }
  2341. inline void SpinnerAtom(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, int elipses = 3)
  2342. {
  2343. SPINNER_HEADER(pos, size, centre, num_segments);
  2344. const float start = (float)ImGui::GetTime()* speed;
  2345. elipses = std::min<int>(elipses, 3);
  2346. auto draw_rotated_ellipse = [&] (float alpha, float start) {
  2347. alpha = ImFmod(alpha, IM_PI);
  2348. float a = radius;
  2349. float b = radius / 2.f;
  2350. window->DrawList->PathClear();
  2351. for (int i = 0; i < num_segments; ++i) {
  2352. float anga = (i * (PI_2 / (num_segments - 1)));
  2353. float xx = a * ImCos(anga) * ImCos(alpha) + b * ImSin(anga) * ImSin(alpha) + centre.x;
  2354. float yy = b * ImSin(anga) * ImCos(alpha) - a * ImCos(anga) * ImSin(alpha) + centre.y;
  2355. window->DrawList->PathLineTo({xx, yy});
  2356. }
  2357. window->DrawList->PathStroke(color_alpha(color, 1.f), false, thickness);
  2358. float anga = ImFmod(start, PI_2);
  2359. float x = a * ImCos(anga) * ImCos(alpha) + b * ImSin(anga) * ImSin(alpha) + centre.x;
  2360. float y = b * ImSin(anga) * ImCos(alpha) - a * ImCos(anga) * ImSin(alpha) + centre.y;
  2361. return ImVec2{x, y};
  2362. };
  2363. ImVec2 ppos[3];
  2364. for (int i = 0; i < elipses; ++i) {
  2365. ppos[i % 3] = draw_rotated_ellipse((IM_PI * (float)i/ elipses), start * (1.f + 0.1f * i));
  2366. }
  2367. ImColor pcolors[3] = {ImColor(255, 0, 0), ImColor(0, 255, 0), ImColor(0, 0, 255)};
  2368. for (int i = 0; i < elipses; ++i) {
  2369. window->DrawList->AddCircleFilled(ppos[i], thickness * 2, color_alpha(pcolors[i], 1.f), int(num_segments / 3.f));
  2370. }
  2371. }
  2372. inline void SpinnerPatternRings(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, int elipses = 3)
  2373. {
  2374. SPINNER_HEADER(pos, size, centre, num_segments);
  2375. const float start = (float)ImGui::GetTime()* speed;
  2376. elipses = std::max<int>(elipses, 1);
  2377. auto draw_rotated_ellipse = [&] (float alpha, float tr, float y) {
  2378. alpha = ImFmod(alpha, IM_PI);
  2379. float a = radius;
  2380. float b = radius / 2.f;
  2381. const float bg_angle_offset = PI_2 / (num_segments - 1);
  2382. ImColor c = color_alpha(color, tr);
  2383. window->DrawList->PathClear();
  2384. for (int i = 0; i < num_segments; ++i) {
  2385. float anga = (i * bg_angle_offset);
  2386. float xx = a * ImCos(anga) * ImCos(alpha) + b * ImSin(anga) * ImSin(alpha) + centre.x;
  2387. float yy = b * ImSin(anga) * ImCos(alpha) - a * ImCos(anga) * ImSin(alpha) + centre.y + y;
  2388. window->DrawList->PathLineTo({xx, yy});
  2389. }
  2390. window->DrawList->PathStroke(c, false, thickness);
  2391. };
  2392. for (int i = 0; i < elipses; ++i)
  2393. {
  2394. const float h = (0.5f * ImSin(start + (IM_PI / elipses) * i));
  2395. draw_rotated_ellipse(0.f, 0.1f + (0.9f / elipses) * i, radius * h);
  2396. }
  2397. }
  2398. inline void SpinnerPatternEclipse(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, int elipses = 3, float delta_a = 2.f, float delta_y = 0.f)
  2399. {
  2400. SPINNER_HEADER(pos, size, centre, num_segments);
  2401. const float start = (float)ImGui::GetTime()* speed;
  2402. elipses = std::max<int>(elipses, 1);
  2403. auto draw_rotated_ellipse = [&] (const ImVec2 &pp, float alpha, float tr, float r, float x, float y) {
  2404. alpha = ImFmod(alpha, IM_PI);
  2405. float a = r;
  2406. float b = r / delta_a;
  2407. ImColor c = color_alpha(color, tr);
  2408. window->DrawList->PathClear();
  2409. for (int i = 0; i < num_segments; ++i) {
  2410. float anga = (i * PI_2 / (num_segments - 1));
  2411. float xx = a * ImCos(anga) * ImCos(alpha) + b * ImSin(anga) * ImSin(alpha) + pp.x + x;
  2412. float yy = b * ImSin(anga) * ImCos(alpha) - a * ImCos(anga) * ImSin(alpha) + pp.y + y;
  2413. window->DrawList->PathLineTo({xx, yy});
  2414. }
  2415. window->DrawList->PathStroke(c, false, thickness);
  2416. };
  2417. for (int i = 0; i < elipses; ++i)
  2418. {
  2419. const float rkoeff = (0.5f + 0.5f * ImSin(start + (IM_PI / elipses) * i));
  2420. const float h = ((1.f / elipses) * (i+1));
  2421. const float anga = start + (i * PI_DIV_2 / elipses);
  2422. const float yoff = ((1.f / elipses) * i) * delta_y;
  2423. float a = (radius * (1.f - h));
  2424. float b = (radius * (1.f - h)) / delta_a;
  2425. float xx = a * ImCos(anga) * ImCos(0) + b * ImSin(anga) * ImSin(0) + centre.x;
  2426. float yy = b * ImSin(anga) * ImCos(0) - a * ImCos(anga) * ImSin(0) + centre.y;
  2427. draw_rotated_ellipse(ImVec2(xx, yy), 0.f, 0.3f + (0.7f / elipses) * i, radius * h, 0.f, yoff * radius);
  2428. }
  2429. }
  2430. inline void SpinnerPatternSphere(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, int elipses = 3)
  2431. {
  2432. SPINNER_HEADER(pos, size, centre, num_segments);
  2433. const float start = ImFmod((float)ImGui::GetTime() * speed * 3.f, size.y);
  2434. elipses = std::max<int>(elipses, 1);
  2435. auto draw_rotated_ellipse = [&] (float alpha, float tr, float y, float r) {
  2436. alpha = ImFmod(alpha, IM_PI);
  2437. float a = r;
  2438. float b = r / 4.f;
  2439. ImColor c = color_alpha(color, tr);
  2440. window->DrawList->PathClear();
  2441. for (int i = 0; i < num_segments; ++i) {
  2442. float anga = (i * PI_2 / (num_segments - 1));
  2443. float xx = a * ImCos(anga) * ImCos(alpha) + b * ImSin(anga) * ImSin(alpha) + centre.x;
  2444. float yy = b * ImSin(anga) * ImCos(alpha) - a * ImCos(anga) * ImSin(alpha) + pos.y + y;
  2445. window->DrawList->PathLineTo({xx, yy});
  2446. }
  2447. window->DrawList->PathStroke(c, false, thickness);
  2448. };
  2449. float offset = 0;
  2450. float half_size = size.y * 0.5f;
  2451. for (size_t i = 0; i < elipses; i++)
  2452. {
  2453. offset = ImFmod(start + i * (size.y / elipses), size.y);
  2454. const float th = (offset > half_size)
  2455. ? 1.f - (offset - half_size) / half_size
  2456. : offset / half_size;
  2457. draw_rotated_ellipse(0.f, th, offset, ImSin(offset / size.y * IM_PI) * radius);
  2458. }
  2459. }
  2460. inline void SpinnerRingSynchronous(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, int elipses = 3)
  2461. {
  2462. SPINNER_HEADER(pos, size, centre, num_segments);
  2463. const float start = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  2464. num_segments *= 4;
  2465. const float aoffset = ImFmod((float)ImGui::GetTime(), PI_2);
  2466. const float bofsset = (aoffset > IM_PI) ? IM_PI : aoffset;
  2467. const float angle_offset = PI_2 / num_segments;
  2468. float ared_min = 0, ared = 0;
  2469. if (aoffset > IM_PI)
  2470. ared_min = aoffset - IM_PI;
  2471. auto draw_ellipse = [&] (float alpha, float y, float r) {
  2472. window->DrawList->PathClear();
  2473. for (size_t i = 0; i <= num_segments + 1; i++)
  2474. {
  2475. ared = start + (i * angle_offset);
  2476. if (i * angle_offset < ared_min * 2)
  2477. continue;
  2478. if (i * angle_offset > bofsset * 2.f)
  2479. break;
  2480. float a = r;
  2481. float b = r * 0.25f;
  2482. const float xx = a * ImCos(ared) * ImCos(alpha) + b * ImSin(ared) * ImSin(alpha) + centre.x;
  2483. const float yy = b * ImSin(ared) * ImCos(alpha) - a * ImCos(ared) * ImSin(alpha) + pos.y + y;
  2484. window->DrawList->PathLineTo(ImVec2(xx, yy));
  2485. }
  2486. window->DrawList->PathStroke(color_alpha(color, 1.f), false, thickness);
  2487. };
  2488. for (int i = 0; i < elipses; ++i)
  2489. {
  2490. float y = i * ((float)(size.y * 0.7f) / (float)elipses) + (size.y * 0.15f);
  2491. draw_ellipse(0, y, radius * ImSin((i + 1) * (IM_PI / (elipses + 1))));
  2492. }
  2493. }
  2494. inline void SpinnerRingWatermarks(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, int elipses = 3)
  2495. {
  2496. SPINNER_HEADER(pos, size, centre, num_segments);
  2497. const float start = (float)ImGui::GetTime() * speed;
  2498. num_segments *= 4;
  2499. const float angle_offset = PI_2 / num_segments;
  2500. auto draw_ellipse = [&] (float s, float alpha, float x, float y, float r) {
  2501. const float aoffset = ImFmod((float)s, PI_2);
  2502. const float bofsset = (aoffset > IM_PI) ? IM_PI : aoffset;
  2503. float ared_min = 0, ared = 0;
  2504. if (aoffset > IM_PI)
  2505. ared_min = aoffset - IM_PI;
  2506. window->DrawList->PathClear();
  2507. for (size_t i = 0; i <= num_segments + 1; i++)
  2508. {
  2509. ared = s + (i * angle_offset);
  2510. if (i * angle_offset < ared_min * 2)
  2511. continue;
  2512. if (i * angle_offset > bofsset * 2.f)
  2513. break;
  2514. float a = r;
  2515. float b = r * 0.25f;
  2516. const float xx = a * ImCos(ared) * ImCos(alpha) + b * ImSin(ared) * ImSin(alpha) + centre.x + x;
  2517. const float yy = b * ImSin(ared) * ImCos(alpha) - a * ImCos(ared) * ImSin(alpha) + pos.y + y;
  2518. window->DrawList->PathLineTo(ImVec2(xx, yy));
  2519. }
  2520. window->DrawList->PathStroke(color_alpha(color, 1.f), false, thickness);
  2521. };
  2522. for (int i = 0; i < elipses; ++i)
  2523. {
  2524. float y = i * ((float)(size.y * 0.7f) / (float)elipses) + (size.y * 0.15f);
  2525. float x = -i * (radius / elipses);
  2526. draw_ellipse(start + (i * IM_PI / (elipses * 2)), -PI_DIV_4, x, y, radius);
  2527. }
  2528. }
  2529. inline void SpinnerRotatedAtom(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, int elipses = 3)
  2530. {
  2531. SPINNER_HEADER(pos, size, centre, num_segments);
  2532. const float start = (float)ImGui::GetTime()* speed;
  2533. auto draw_rotated_ellipse = [&] (float alpha) {
  2534. std::array<ImVec2, 36> pts;
  2535. alpha = ImFmod(alpha, IM_PI);
  2536. float a = radius;
  2537. float b = radius / 2.f;
  2538. const float bg_angle_offset = PI_2 / num_segments;
  2539. for (size_t i = 0; i < num_segments; ++i) {
  2540. float anga = (i * bg_angle_offset);
  2541. pts[i].x = a * ImCos(anga) * ImCos(alpha) + b * ImSin(anga) * ImSin(alpha) + centre.x;
  2542. pts[i].y = b * ImSin(anga) * ImCos(alpha) - a * ImCos(anga) * ImSin(alpha) + centre.y;
  2543. }
  2544. for (size_t i = 1; i < num_segments; ++i) {
  2545. window->DrawList->AddLine(pts[i-1], pts[i], color_alpha(color, 1.f), thickness);
  2546. }
  2547. window->DrawList->AddLine(pts[num_segments-1], pts[0], color_alpha(color, 1.f), thickness);
  2548. };
  2549. for (int i = 0; i < elipses; ++i) {
  2550. draw_rotated_ellipse(start + (IM_PI * (float)i/ elipses));
  2551. }
  2552. }
  2553. inline void SpinnerRainbowBalls(const char *label, float radius, float thickness, const ImColor &color, float speed, int balls = 5)
  2554. {
  2555. SPINNER_HEADER(pos, size, centre, num_segments);
  2556. const float start = ImFmod((float)ImGui::GetTime() * speed * 3.f, IM_PI);
  2557. const float colorback = 0.3f + 0.2f * ImSin((float)ImGui::GetTime() * speed);
  2558. const float rstart = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  2559. const float radius1 = (0.8f + 0.2f * ImSin(start)) * radius;
  2560. const float angle_offset = PI_2 / balls;
  2561. const bool rainbow = ((ImU32)color.Value.w) == 0;
  2562. float out_h, out_s, out_v;
  2563. ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, out_h, out_s, out_v);
  2564. for (int i = 0; i <= balls; i++)
  2565. {
  2566. const float a = rstart + (i * angle_offset);
  2567. ImColor c = rainbow ? ImColor::HSV(out_h + i * (1.f / balls) + colorback, out_s, out_v) : color;
  2568. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(a) * radius1, centre.y + ImSin(a) * radius1), thickness, color_alpha(c, 1.f), num_segments);
  2569. }
  2570. }
  2571. inline void SpinnerRainbowShot(const char *label, float radius, float thickness, const ImColor &color, float speed, int balls = 5)
  2572. {
  2573. SPINNER_HEADER(pos, size, centre, num_segments);
  2574. const float start = ImFmod((float)ImGui::GetTime() * speed * 3.f, PI_2);
  2575. const float colorback = 0.3f + 0.2f * ImSin((float)ImGui::GetTime() * speed);
  2576. const float rstart = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  2577. const float angle_offset = PI_2 / balls;
  2578. const bool rainbow = ((ImU32)color.Value.w) == 0;
  2579. float out_h, out_s, out_v;
  2580. ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, out_h, out_s, out_v);
  2581. for (int i = 0; i <= balls; i++)
  2582. {
  2583. float centera = start - PI_DIV_2 + (i * angle_offset);
  2584. float rmul = ImMax(0.2f, 1.f - ImSin(centera));
  2585. const float radius1 = ImMin(radius * rmul, radius);
  2586. const float a = (i * angle_offset);
  2587. ImColor c = rainbow ? ImColor::HSV(out_h + i * (1.f / balls) + colorback, out_s, out_v) : color;
  2588. window->DrawList->AddLine(centre, ImVec2(centre.x + ImCos(a) * radius1, centre.y + ImSin(a) * radius1), color_alpha(c, 1.f), thickness);
  2589. }
  2590. }
  2591. inline void SpinnerSpiral(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, size_t arcs = 4)
  2592. {
  2593. SPINNER_HEADER(pos, size, centre, num_segments);
  2594. const float start = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  2595. float a = radius / num_segments;
  2596. float b = a;
  2597. ImVec2 last = centre;
  2598. for (size_t arc_num = 0; arc_num < (num_segments * arcs); ++arc_num)
  2599. {
  2600. float angle = (PI_2 / num_segments) * arc_num;
  2601. float x = centre.x + (a + b * angle) * ImCos(start + angle);
  2602. float y = centre.y + (a + b * angle) * ImSin(start + angle);
  2603. window->DrawList->AddLine(last, ImVec2(x, y), color_alpha(color, 1.f), thickness);
  2604. last = ImVec2(x, y);
  2605. }
  2606. }
  2607. inline void SpinnerSpiralEye(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f)
  2608. {
  2609. SPINNER_HEADER(pos, size, centre, num_segments);
  2610. const float start = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  2611. float a = (radius * 3.f) / num_segments;
  2612. float b = a;
  2613. num_segments *= 4;
  2614. auto half_eye = [&] (float side) {
  2615. for (size_t arc_num = 0; arc_num < num_segments; ++arc_num) {
  2616. float angle = (PI_2 / num_segments) * arc_num;
  2617. float x = centre.x + (a + b * angle) * ImCos((start + angle) * side);
  2618. float y = centre.y + (a + b * angle) * ImSin((start + angle) * side);
  2619. window->DrawList->AddCircleFilled(ImVec2(x, y), thickness, color_alpha(color, 1.f));
  2620. }
  2621. };
  2622. half_eye(1.f);
  2623. half_eye(-1.f);
  2624. }
  2625. inline void SpinnerBarChartSine(const char *label, float radius, float thickness, const ImColor &color, float speed, int bars = 5, int mode = 0)
  2626. {
  2627. SPINNER_HEADER(pos, size, centre, num_segments);
  2628. const ImGuiStyle &style = GImGui->Style;
  2629. const float nextItemKoeff = 1.5f;
  2630. const float yOffsetKoeftt = 0.8f;
  2631. const float heightSpeed = 0.8f;
  2632. const float start = (float)ImGui::GetTime() * speed;
  2633. const float offset = IM_PI / bars;
  2634. for (int i = 0; i < bars; i++)
  2635. {
  2636. const float angle = ImMax(PI_DIV_2, (1.f - i/(float)bars) * IM_PI);
  2637. float a = start + (IM_PI - i * offset);
  2638. ImColor c = color_alpha(color, ImMax(0.1f, ImSin(a * heightSpeed)));
  2639. float h = mode ? ImSin(a) * size.y / 2.f
  2640. : (0.6f + 0.4f * c.Value.w) * size.y;
  2641. float halfs = mode ? 0 : size.y / 2.f;
  2642. window->DrawList->AddRectFilled(ImVec2(pos.x + style.FramePadding.x + i * (thickness * nextItemKoeff) - thickness / 2, centre.y + halfs),
  2643. ImVec2(pos.x + style.FramePadding.x + i * (thickness * nextItemKoeff) + thickness / 2, centre.y + halfs - h * yOffsetKoeftt),
  2644. c);
  2645. }
  2646. }
  2647. inline void SpinnerBarChartAdvSine(const char *label, float radius, float thickness, const ImColor &color, float speed, int mode = 0)
  2648. {
  2649. SPINNER_HEADER(pos, size, centre, num_segments);
  2650. const float nextItemKoeff = 1.5f;
  2651. const float start = (float)ImGui::GetTime() * speed;
  2652. const int bars = (int)(radius * 2 / thickness);
  2653. const float offset = PI_DIV_2 / bars;
  2654. for (int i = 0; i < bars; i++)
  2655. {
  2656. float a = start + (PI_DIV_2 - i * offset);
  2657. float halfsx = thickness * ImSin(a);
  2658. float halfsy = (ImMax(0.1f, ImSin(a) + 1.f)) * radius * 0.5f;
  2659. window->DrawList->AddRectFilled(ImVec2(pos.x + i * (thickness * nextItemKoeff) - thickness / 2 + halfsx, centre.y + halfsy),
  2660. ImVec2(pos.x + i * (thickness * nextItemKoeff) + thickness / 2 + halfsx, centre.y - halfsy),
  2661. color);
  2662. }
  2663. }
  2664. inline void SpinnerBarChartAdvSineFade(const char *label, float radius, float thickness, const ImColor &color, float speed, int mode = 0)
  2665. {
  2666. SPINNER_HEADER(pos, size, centre, num_segments);
  2667. const float start = (float)ImGui::GetTime() * speed;
  2668. const int bars = (int)(radius * 2 / thickness);
  2669. const float offset = PI_DIV_2 / bars;
  2670. for (int i = 0; i < bars; i++)
  2671. {
  2672. float a = start - i * offset;
  2673. float halfsy = ImMax(0.1f, ImCos(a) + 1.f) * radius * 0.5f;
  2674. window->DrawList->AddRectFilled(ImVec2(pos.x + i * thickness - thickness / 2, centre.y + halfsy),
  2675. ImVec2(pos.x + i * thickness + thickness / 2, centre.y - halfsy),
  2676. color_alpha(color, ImMax(0.1f, halfsy / radius)));
  2677. }
  2678. }
  2679. inline void SpinnerBarChartRainbow(const char *label, float radius, float thickness, const ImColor &color, float speed, int bars = 5)
  2680. {
  2681. SPINNER_HEADER(pos, size, centre, num_segments);
  2682. const ImGuiStyle &style = GImGui->Style;
  2683. const float nextItemKoeff = 1.5f;
  2684. const float yOffsetKoeftt = 0.8f;
  2685. const float start = (float)ImGui::GetTime() * speed;
  2686. const float hspeed = 0.1f + ImSin((float)ImGui::GetTime() * 0.1f) * 0.05f;
  2687. constexpr float rkoeff[6] = {4.f, 13.f, 3.4f, 8.7f, 25.f, 11.f};
  2688. float out_h, out_s, out_v;
  2689. ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, out_h, out_s, out_v);
  2690. for (int i = 0; i < bars; i++)
  2691. {
  2692. ImColor c = ImColor::HSV(out_h + i * 0.1f, out_s, out_v);
  2693. float h = (0.6f + 0.4f * ImSin(start + (1.f + rkoeff[i % 6] * i * hspeed)) ) * size.y;
  2694. window->DrawList->AddRectFilled(ImVec2(pos.x + style.FramePadding.x + i * (thickness * nextItemKoeff) - thickness / 2, centre.y + size.y / 2.f),
  2695. ImVec2(pos.x + style.FramePadding.x + i * (thickness * nextItemKoeff) + thickness / 2, centre.y + size.y / 2.f - h * yOffsetKoeftt),
  2696. color_alpha(c, 1.f));
  2697. }
  2698. }
  2699. inline void SpinnerBlocks(const char *label, float radius, float thickness, const ImColor &bg, const ImColor &color, float speed)
  2700. {
  2701. SPINNER_HEADER(pos, size, centre, num_segments);
  2702. ImVec2 lt{centre.x - radius, centre.y - radius};
  2703. const float offset_block = radius * 2.f / 3.f;
  2704. int start = (int)ImFmod((float)ImGui::GetTime() * speed, 8.f);
  2705. const ImVec2ih poses[] = {{0, 0}, {1, 0}, {2, 0}, {2, 1}, {2, 2}, {1, 2}, {0, 2}, {0, 1}};
  2706. int ti = 0;
  2707. for (const auto &rpos: poses)
  2708. {
  2709. const ImColor &c = (ti == start) ? color : bg;
  2710. window->DrawList->AddRectFilled(ImVec2(lt.x + rpos.x * (offset_block), lt.y + rpos.y * offset_block),
  2711. ImVec2(lt.x + rpos.x * (offset_block) + thickness, lt.y + rpos.y * offset_block + thickness),
  2712. color_alpha(c, 1.f));
  2713. ti++;
  2714. }
  2715. }
  2716. inline void SpinnerTwinBlocks(const char *label, float radius, float thickness, const ImColor &bg, const ImColor &color, float speed)
  2717. {
  2718. SPINNER_HEADER(pos, size, centre, num_segments);
  2719. const float offset_block = radius * 2.f / 3.f;
  2720. ImVec2 lt{centre.x - radius - offset_block / 2.f, centre.y - radius - offset_block / 2.f};
  2721. int start = (int)ImFmod((float)ImGui::GetTime() * speed, 8.f);
  2722. const ImVec2ih poses[] = {{0, 0}, {1, 0}, {2, 0}, {2, 1}, {2, 2}, {1, 2}, {0, 2}, {0, 1}};
  2723. int ti = 0;
  2724. for (const auto &rpos: poses)
  2725. {
  2726. const ImColor &c = (ti == start) ? color : bg;
  2727. window->DrawList->AddRectFilled(ImVec2(lt.x + rpos.x * (offset_block), lt.y + rpos.y * offset_block),
  2728. ImVec2(lt.x + rpos.x * (offset_block) + thickness, lt.y + rpos.y * offset_block + thickness),
  2729. color_alpha(c, 1.f));
  2730. ti++;
  2731. }
  2732. lt = ImVec2{centre.x - radius + offset_block / 2.f, centre.y - radius + offset_block / 2.f};
  2733. ti = (int)std::size(poses) - 1;
  2734. start = (int)ImFmod((float)ImGui::GetTime() * speed * 1.1f, 8.f);
  2735. for (const auto &rpos: poses)
  2736. {
  2737. const ImColor &c = (ti == start) ? color : bg;
  2738. window->DrawList->AddRectFilled(ImVec2(lt.x + rpos.x * (offset_block), lt.y + rpos.y * offset_block),
  2739. ImVec2(lt.x + rpos.x * (offset_block) + thickness, lt.y + rpos.y * offset_block + thickness),
  2740. color_alpha(c, 1.f));
  2741. ti--;
  2742. }
  2743. }
  2744. inline void SpinnerSquareRandomDots(const char *label, float radius, float thickness, const ImColor &bg, const ImColor &color, float speed)
  2745. {
  2746. SPINNER_HEADER(pos, size, centre, num_segments);
  2747. const float offset_block = radius * 2.f / 3.f;
  2748. ImVec2 lt{centre.x - offset_block, centre.y - offset_block};
  2749. int start = (int)ImFmod((float)ImGui::GetTime() * speed, 9.f);
  2750. ImGuiStorage* storage = window->DC.StateStorage;
  2751. const ImGuiID vtimeId = window->GetID("##vtime");
  2752. const ImGuiID vvald = window->GetID("##vval");
  2753. int vtime = storage->GetInt(vtimeId, 0);
  2754. int vval = storage->GetInt(vvald, 0);
  2755. if (vtime != start) {
  2756. vval = rand() % 9;
  2757. storage->SetInt(vvald, vval);
  2758. storage->SetInt(vtimeId, start);
  2759. }
  2760. const ImVec2ih poses[] = {{0, 0}, {1, 0}, {2, 0}, {2, 1}, {2, 2}, {1, 2}, {0, 2}, {0, 1}, {1, 1}};
  2761. int ti = 0;
  2762. for (const auto &rpos: poses)
  2763. {
  2764. const ImColor &c = (ti == vval) ? color : bg;
  2765. window->DrawList->AddCircleFilled(ImVec2(lt.x + rpos.x * (offset_block), lt.y + rpos.y * offset_block), thickness,
  2766. color_alpha(c, 1.f));
  2767. ti++;
  2768. }
  2769. }
  2770. inline void SpinnerScaleBlocks(const char *label, float radius, float thickness, const ImColor &color, float speed, int mode = 0)
  2771. {
  2772. SPINNER_HEADER(pos, size, centre, num_segments);
  2773. ImVec2 lt{centre.x - radius, centre.y - radius};
  2774. const float offset_block = radius * 2.f / 3.f;
  2775. const ImVec2ih poses[] = {{0, 0}, {1, 0}, {2, 0}, {0, 1}, {1, 1}, {2, 1}, {0, 2}, {1, 2}, {2, 2}};
  2776. constexpr float rkoeff[9] = {0.1f, 0.15f, 0.17f, 0.25f, 0.6f, 0.15f, 0.1f, 0.12f, 0.22f};
  2777. int ti = 0;
  2778. float out_h, out_s, out_v;
  2779. ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, out_h, out_s, out_v);
  2780. for (const auto &rpos: poses)
  2781. {
  2782. ImColor c = ImColor::HSV(out_h + ti * 0.1f, out_s, out_v);
  2783. if (mode) {
  2784. float h = (0.1f + 0.4f * ImSin((float)ImGui::GetTime() * (speed * rkoeff[ti % 9])));
  2785. window->DrawList->AddCircleFilled(ImVec2(lt.x + rpos.x * (offset_block), lt.y + rpos.y * offset_block), std::max<float>(1.f, h * thickness),
  2786. color_alpha(c, 1.f));
  2787. } else {
  2788. float h = (0.8f + 0.4f * ImSin((float)ImGui::GetTime() * (speed * rkoeff[ti % 9])));
  2789. window->DrawList->AddRectFilled(ImVec2(lt.x + rpos.x * (offset_block), lt.y + rpos.y * offset_block),
  2790. ImVec2(lt.x + rpos.x * (offset_block) + h * thickness, lt.y + rpos.y * offset_block + h * thickness),
  2791. color_alpha(c, 1.f));
  2792. }
  2793. ti++;
  2794. }
  2795. }
  2796. inline void SpinnerScaleSquares(const char *label, float radius, float thikness, const ImColor &color, float speed)
  2797. {
  2798. SPINNER_HEADER(pos, size, centre, num_segments);
  2799. ImVec2 lt{centre.x - radius, centre.y - radius};
  2800. const float offset_block = radius * 2.f / 3.f;
  2801. const float hside = (thikness / 2.f);
  2802. const ImVec2ih poses[] = {{0, 0}, {1, 0}, {0, 1}, {2, 0}, {1, 1}, {0, 2}, {2, 1}, {1, 2}, {2, 2}};
  2803. const float offsets[] = {0.f, 0.8f, 0.8f, 1.6f, 1.6f, 1.6f, 2.4f, 2.4f, 3.2f};
  2804. int ti = 0;
  2805. float out_h, out_s, out_v;
  2806. ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, out_h, out_s, out_v);
  2807. for (const auto &rpos: poses)
  2808. {
  2809. const ImColor c = ImColor::HSV(out_h + offsets[ti], out_s, out_v);
  2810. const float strict = (0.5f + 0.5f * ImSin((float)-ImGui::GetTime() * speed + offsets[ti % 9]));
  2811. const float side = ImClamp<float>(strict + 0.1f, 0.1f, 1.f) * hside;
  2812. window->DrawList->AddRectFilled(ImVec2(lt.x + hside + (rpos.x * offset_block) - side, lt.y + hside + (rpos.y * offset_block) - side),
  2813. ImVec2(lt.x + hside + (rpos.x * offset_block) + side, lt.y + hside + (rpos.y * offset_block) + side),
  2814. color_alpha(c, 1.f));
  2815. ti++;
  2816. }
  2817. }
  2818. inline void SpinnerSquishSquare(const char *label, float radius, const ImColor &color, float speed)
  2819. {
  2820. SPINNER_HEADER(pos, size, centre, num_segments);
  2821. float start = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  2822. const float side = ImSin((float)-start) * radius;
  2823. bool type = (start > IM_PI) ? 1 : 0;
  2824. if (type) {
  2825. if (start > IM_PI && start < IM_PI + PI_DIV_2) {
  2826. window->DrawList->AddRectFilled(ImVec2(centre.x - side, centre.y - radius), ImVec2(centre.x + side, centre.y + radius), color_alpha(color, 1.f));
  2827. } else {
  2828. window->DrawList->AddRectFilled(ImVec2(centre.x - radius, centre.y - side), ImVec2(centre.x + radius, centre.y + side), color_alpha(color, 1.f));
  2829. }
  2830. } else {
  2831. if (start < PI_DIV_2) {
  2832. window->DrawList->AddRectFilled(ImVec2(centre.x - radius, centre.y - side), ImVec2(centre.x + radius, centre.y + side), color_alpha(color, 1.f));
  2833. } else {
  2834. window->DrawList->AddRectFilled(ImVec2(centre.x - side, centre.y - radius), ImVec2(centre.x + side, centre.y + radius), color_alpha(color, 1.f));
  2835. }
  2836. }
  2837. }
  2838. inline void SpinnerFluid(const char *label, float radius, const ImColor &color, float speed, int bars = 3)
  2839. {
  2840. SPINNER_HEADER(pos, size, centre, num_segments);
  2841. const ImGuiStyle &style = GImGui->Style;
  2842. const float hspeed = 0.1f + ImSin((float)ImGui::GetTime() * 0.1f) * 0.05f;
  2843. constexpr float rkoeff[6][3] = {{0.15f, 0.1f, 0.1f}, {0.033f, 0.15f, 0.8f}, {0.017f, 0.25f, 0.6f}, {0.037f, 0.1f, 0.4f}, {0.25f, 0.1f, 0.3f}, {0.11f, 0.1f, 0.2f}};
  2844. const float j_k = radius * 2.f / num_segments;
  2845. float out_h, out_s, out_v;
  2846. ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, out_h, out_s, out_v);
  2847. for (int i = 0; i < bars; i++)
  2848. {
  2849. ImColor c = color_alpha(ImColor::HSV(out_h - i * 0.1f, out_s, out_v), rkoeff[i % 6][1]);
  2850. for (int j = 0; j < num_segments; ++j) {
  2851. float h = (0.6f + 0.3f * ImSin((float)ImGui::GetTime() * (speed * rkoeff[i % 6][2] * 2.f) + (2.f * rkoeff[i % 6][0] * j * j_k))) * (radius * 2.f * rkoeff[i % 6][2]);
  2852. window->DrawList->AddRectFilled(ImVec2(pos.x + style.FramePadding.x + j * j_k, centre.y + size.y / 2.f),
  2853. ImVec2(pos.x + style.FramePadding.x + (j + 1) * (j_k), centre.y + size.y / 2.f - h),
  2854. c);
  2855. }
  2856. }
  2857. }
  2858. inline void SpinnerFluidPoints(const char *label, float radius, float thickness, const ImColor &color, float speed, size_t dots = 6, float delta = 0.35f)
  2859. {
  2860. SPINNER_HEADER(pos, size, centre, num_segments);
  2861. const ImGuiStyle &style = GImGui->Style;
  2862. const float rkoeff[3] = {0.033f, 0.3f, 0.8f};
  2863. const float hspeed = 0.1f + ImSin((float)ImGui::GetTime() * 0.1f) * 0.05f;
  2864. const float j_k = radius * 2.f / num_segments;
  2865. float out_h, out_s, out_v;
  2866. ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, out_h, out_s, out_v);
  2867. for (int j = 0; j < num_segments; ++j) {
  2868. float h = (0.6f + delta * ImSin((float)ImGui::GetTime() * (speed * rkoeff[2] * 2.f) + (2.f * rkoeff[0] * j * j_k))) * (radius * 2.f * rkoeff[2]);
  2869. for (int i = 0; i < dots; i++) {
  2870. ImColor c = color_alpha(ImColor::HSV(out_h - i * 0.1f, out_s, out_v), 1.f);
  2871. window->DrawList->AddCircleFilled(ImVec2(pos.x + style.FramePadding.x + j * j_k, centre.y + size.y / 2.f - (h / dots) * i), thickness, c);
  2872. }
  2873. }
  2874. }
  2875. inline void SpinnerArcPolarFade(const char *label, float radius, const ImColor &color = white, float speed = 2.8f, size_t arcs = 4)
  2876. {
  2877. SPINNER_HEADER(pos, size, centre, num_segments);
  2878. float arc_angle = PI_2 / (float)arcs;
  2879. const float angle_offset = arc_angle / num_segments;
  2880. constexpr float rkoeff[6][3] = {{0.15f, 0.1f, 0.1f}, {0.033f, 0.15f, 0.8f}, {0.017f, 0.25f, 0.6f}, {0.037f, 0.1f, 0.4f}, {0.25f, 0.1f, 0.3f}, {0.11f, 0.1f, 0.2f}};
  2881. for (size_t arc_num = 0; arc_num < arcs; ++arc_num)
  2882. {
  2883. const float b = arc_angle * arc_num - PI_DIV_2 - PI_DIV_4;
  2884. const float e = arc_angle * arc_num + arc_angle - PI_DIV_2 - PI_DIV_4;
  2885. const float a = arc_angle * arc_num;
  2886. float h = (0.6f + 0.3f * ImSin((float)ImGui::GetTime() * (speed * rkoeff[arc_num % 6][2] * 2.f) + (2 * rkoeff[arc_num % 6][0])));
  2887. ImColor c = color_alpha(color, h);
  2888. window->DrawList->PathClear();
  2889. window->DrawList->PathLineTo(centre);
  2890. for (size_t i = 0; i <= num_segments + 1; i++)
  2891. {
  2892. const float ar = arc_angle * arc_num + (i * angle_offset) - PI_DIV_2 - PI_DIV_4;
  2893. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(ar) * radius, centre.y + ImSin(ar) * radius));
  2894. }
  2895. window->DrawList->PathFillConvex(c);
  2896. }
  2897. }
  2898. inline void SpinnerArcPolarRadius(const char *label, float radius, const ImColor &color = white, float speed = 2.8f, size_t arcs = 4)
  2899. {
  2900. SPINNER_HEADER(pos, size, centre, num_segments);
  2901. float arc_angle = PI_2 / (float)arcs;
  2902. const float angle_offset = arc_angle / num_segments;
  2903. constexpr float rkoeff[6][3] = {{0.15f, 0.1f, 0.41f}, {0.033f, 0.15f, 0.8f}, {0.017f, 0.25f, 0.6f}, {0.037f, 0.1f, 0.4f}, {0.25f, 0.1f, 0.3f}, {0.11f, 0.1f, 0.2f}};
  2904. float out_h, out_s, out_v;
  2905. ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, out_h, out_s, out_v);
  2906. for (size_t arc_num = 0; arc_num < arcs; ++arc_num)
  2907. {
  2908. const float b = arc_angle * arc_num - PI_DIV_2 - PI_DIV_4;
  2909. const float e = arc_angle * arc_num + arc_angle - PI_DIV_2 - PI_DIV_4;
  2910. const float a = arc_angle * arc_num;
  2911. float r = (0.6f + 0.3f * ImSin((float)ImGui::GetTime() * (speed * rkoeff[arc_num % 6][2] * 2.f) + (2.f * rkoeff[arc_num % 6][0])));
  2912. window->DrawList->PathClear();
  2913. window->DrawList->PathLineTo(centre);
  2914. ImColor c = ImColor::HSV(out_h + arc_num * 0.31f, out_s, out_v);
  2915. for (size_t i = 0; i <= num_segments + 1; i++)
  2916. {
  2917. const float ar = arc_angle * arc_num + (i * angle_offset) - PI_DIV_2 - PI_DIV_4;
  2918. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(ar) * (radius * r), centre.y + ImSin(ar) * (radius * r)));
  2919. }
  2920. window->DrawList->PathFillConvex(color_alpha(c, 1.f));
  2921. }
  2922. }
  2923. inline void SpinnerCaleidoscope(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, size_t arcs = 6, int mode = 0)
  2924. {
  2925. SPINNER_HEADER(pos, size, centre, num_segments);
  2926. float start = (float)ImGui::GetTime() * speed;
  2927. float astart = ImFmod(start, PI_2 / arcs);
  2928. start -= astart;
  2929. const float angle_offset = PI_2 / arcs;
  2930. const float angle_offset_t = angle_offset * 0.3f;
  2931. arcs = ImMin<size_t>(arcs, 32);
  2932. auto get_points = [&] (float left, float right, float r) -> std::array<ImVec2, 4> {
  2933. const float rmin = r - thickness;
  2934. return {
  2935. ImVec2(centre.x + ImCos(left) * rmin, centre.y + ImSin(left) * rmin),
  2936. ImVec2(centre.x + ImCos(left) * r, centre.y + ImSin(left) * r),
  2937. ImVec2(centre.x + ImCos(right) * r, centre.y + ImSin(right) * r),
  2938. ImVec2(centre.x + ImCos(right) * rmin, centre.y + ImSin(right) * rmin)
  2939. };
  2940. };
  2941. auto draw_sectors = [&] (float s, const std::function<ImColor (size_t)>& color_func, float r) {
  2942. for (size_t i = 0; i <= arcs; i++) {
  2943. float left = s + (i * angle_offset) - angle_offset_t;
  2944. float right = s + (i * angle_offset) + angle_offset_t;
  2945. auto points = get_points(left, right, r);
  2946. window->DrawList->AddConvexPolyFilled(points.data(), 4, color_alpha(color_func(i), 1.f));
  2947. }
  2948. };
  2949. float out_h, out_s, out_v;
  2950. ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, out_h, out_s, out_v);
  2951. draw_sectors(start, [&] (size_t i) { return ImColor::HSV(out_h + i * 0.31f, out_s, out_v); }, radius);
  2952. switch (mode) {
  2953. case 0: draw_sectors(-start * 0.78f, [&] (size_t i) { return ImColor::HSV(out_h + i * 0.31f, out_s, out_v); }, radius - thickness - 2); break;
  2954. case 1:
  2955. {
  2956. ImColor c = color;
  2957. float lerp_koeff = (ImSin((float)ImGui::GetTime() * speed) + 1.f) * 0.5f;
  2958. c.Value.w = ImMax(0.1f, ImMin(lerp_koeff, 1.f));
  2959. float dr = radius - thickness - 3;
  2960. window->DrawList->AddCircleFilled(centre, dr, c, num_segments);
  2961. }
  2962. break;
  2963. }
  2964. }
  2965. // spinner idea by nitz 'Chris Dailey'
  2966. inline void SpinnerHboDots(const char *label, float radius, float thickness, const ImColor &color = white, float minfade = 0.0f, float ryk = 0.f, float speed = 1.1f, size_t dots = 6)
  2967. {
  2968. SPINNER_HEADER(pos, size, centre, num_segments);
  2969. const float start = (float)ImGui::GetTime() * speed;
  2970. for (size_t i = 0; i < dots; i++)
  2971. {
  2972. const float astart = start + PI_2_DIV(dots) * i;
  2973. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImSin(astart) * radius, centre.y + ryk * ImCos(astart) * radius), thickness,
  2974. color_alpha(color, ImMax(minfade, ImSin(astart + PI_DIV_2))),
  2975. 8);
  2976. }
  2977. }
  2978. inline void SpinnerMoonDots(const char *label, float radius, float thickness, const ImColor &first, const ImColor &second, float speed = 1.1f)
  2979. {
  2980. SPINNER_HEADER(pos, size, centre, num_segments);
  2981. const float start = (float)ImGui::GetTime() * speed;
  2982. const float astart = ImFmod(start, IM_PI * 2.f);
  2983. const float bstart = astart + IM_PI;
  2984. const float sina = ImSin(astart);
  2985. const float sinb = ImSin(bstart);
  2986. if (astart < PI_DIV_2 || astart > IM_PI + PI_DIV_2) {
  2987. window->DrawList->AddCircleFilled(ImVec2(centre.x + sina * thickness, centre.y), thickness, color_alpha(first, 1.f), 16);
  2988. window->DrawList->AddCircleFilled(ImVec2(centre.x + sinb * thickness, centre.y), thickness, color_alpha(second, 1.f), 16);
  2989. window->DrawList->AddCircle(ImVec2(centre.x + sinb * thickness, centre.y), thickness, color_alpha(first, 1.f), 16);
  2990. } else {
  2991. window->DrawList->AddCircleFilled(ImVec2(centre.x + sinb * thickness, centre.y), thickness, color_alpha(second, 1.f), 16);
  2992. window->DrawList->AddCircle(ImVec2(centre.x + sinb * thickness, centre.y), thickness, color_alpha(first, 1.f), 16);
  2993. window->DrawList->AddCircleFilled(ImVec2(centre.x + sina * thickness, centre.y), thickness, color_alpha(first, 1.f), 16);
  2994. }
  2995. }
  2996. inline void SpinnerTwinHboDots(const char *label, float radius, float thickness, const ImColor &color = white, float minfade = 0.0f, float ryk = 0.f, float speed = 1.1f, size_t dots = 6, float delta = 0.f)
  2997. {
  2998. SPINNER_HEADER(pos, size, centre, num_segments);
  2999. const float start = (float)ImGui::GetTime() * speed;
  3000. for (size_t i = 0; i < dots; i++)
  3001. {
  3002. const float astart = start + PI_2_DIV(dots) * i;
  3003. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImSin(astart) * radius, centre.y + ryk * ImCos(astart) * radius + radius * delta), thickness,
  3004. color_alpha(color, ImMax(minfade, ImSin(astart + PI_DIV_2))),
  3005. 8);
  3006. }
  3007. for (size_t i = 0; i < dots; i++)
  3008. {
  3009. const float astart = start + PI_2_DIV(dots) * i;
  3010. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImSin(astart) * radius, centre.y - ryk * ImCos(astart) * radius - radius * delta), thickness,
  3011. color_alpha(color, ImMax(minfade, ImSin(astart + PI_DIV_2))),
  3012. 8);
  3013. }
  3014. }
  3015. inline void SpinnerThreeDotsStar(const char *label, float radius, float thickness, const ImColor &color = white, float minfade = 0.0f, float ryk = 0.f, float speed = 1.1f, float delta = 0.f)
  3016. {
  3017. SPINNER_HEADER(pos, size, centre, num_segments);
  3018. const float start = (float)ImGui::GetTime() * speed;
  3019. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImSin(-start) * radius, centre.y - ryk * ImCos(-start) * radius + radius * delta), thickness, color_alpha(color, ImMax(minfade, ImSin(-start + PI_DIV_2))), 8);
  3020. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImSin(start) * radius, centre.y - ryk * ImCos(start) * radius - radius * delta), thickness, color_alpha(color, ImMax(minfade, ImSin(start + PI_DIV_2))), 8);
  3021. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImSin(start + PI_DIV_4) * radius, centre.y - ryk * ImCos(start + PI_DIV_4) * radius - radius * delta), thickness, color_alpha(color, ImMax(minfade, ImSin(start + PI_DIV_4 + PI_DIV_2))), 8);
  3022. }
  3023. inline void SpinnerSineArcs(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f)
  3024. {
  3025. SPINNER_HEADER(pos, size, centre, num_segments);
  3026. float start = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  3027. float length = ImFmod(start, IM_PI);
  3028. const float dangle = ImSin(length) * IM_PI * 0.35f;
  3029. const float angle_offset = IM_PI / num_segments;
  3030. auto draw_spring = [&] (float k) {
  3031. float arc = 0.f;
  3032. window->DrawList->PathClear();
  3033. for (size_t i = 0; i < num_segments; i++) {
  3034. float a = start + (i * angle_offset);
  3035. if (ImSin(a) < 0.f)
  3036. a *= -1;
  3037. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * radius, centre.y + k * ImSin(a) * radius));
  3038. arc += angle_offset;
  3039. if (arc > dangle)
  3040. break;
  3041. }
  3042. window->DrawList->PathStroke(color_alpha(color, 1.f), false, thickness);
  3043. };
  3044. draw_spring(1);
  3045. draw_spring(-1);
  3046. }
  3047. inline void SpinnerTrianglesShift(const char *label, float radius, float thickness, const ImColor &color = white, const ImColor &bg = half_white, float speed = 2.8f, size_t bars = 8)
  3048. {
  3049. SPINNER_HEADER(pos, size, centre, num_segments);
  3050. ImColor c = color;
  3051. float lerp_koeff = (ImSin((float)ImGui::GetTime() * speed) + 1.f) * 0.5f;
  3052. c.Value.w = ImMax(0.1f, ImMin(lerp_koeff, 1.f));
  3053. const float angle_offset = PI_2 / bars;
  3054. float start = (float)ImGui::GetTime() * speed;
  3055. const float astart = ImFmod(start, angle_offset);
  3056. const float save_start = start;
  3057. start -= astart;
  3058. const float angle_offset_t = angle_offset * 0.3f;
  3059. bars = ImMin<size_t>(bars, 32);
  3060. const float rmin = radius - thickness;
  3061. auto get_points = [&] (float left, float right, float r1, float r2) -> std::array<ImVec2, 4> {
  3062. return {
  3063. ImVec2(centre.x + ImCos(left) * r1, centre.y + ImSin(left) * r1),
  3064. ImVec2(centre.x + ImCos(left) * r2, centre.y + ImSin(left) * r2),
  3065. ImVec2(centre.x + ImCos(right) * r2, centre.y + ImSin(right) * r2),
  3066. ImVec2(centre.x + ImCos(right) * r1, centre.y + ImSin(right) * r1)
  3067. };
  3068. };
  3069. ImColor rc = bg;
  3070. for (size_t i = 0; i < bars; i++) {
  3071. float left = start + (i * angle_offset) - angle_offset_t;
  3072. float right = start + (i * angle_offset) + angle_offset_t;
  3073. float centera = start - PI_DIV_2 + (i * angle_offset);
  3074. float rmul = 1.f - ImClamp(ImAbs(centera - save_start), 0.f, PI_DIV_2) / PI_DIV_2;
  3075. rc.Value.w = ImMax(rmul, 0.1f);
  3076. rmul *= 1.5f;
  3077. rmul = ImMax(0.5f, rmul);
  3078. const float r1 = ImMax(rmin * rmul, rmin);
  3079. const float r2 = ImMax(radius * rmul, radius);
  3080. auto points = get_points(left, right, r1, r2);
  3081. window->DrawList->AddConvexPolyFilled(points.data(), 4, color_alpha(rc, 1.f));
  3082. }
  3083. }
  3084. inline void SpinnerPointsShift(const char *label, float radius, float thickness, const ImColor &color = white, const ImColor &bg = half_white, float speed = 2.8f, size_t bars = 8)
  3085. {
  3086. SPINNER_HEADER(pos, size, centre, num_segments);
  3087. ImColor c = color;
  3088. float lerp_koeff = (ImSin((float)ImGui::GetTime() * speed) + 1.f) * 0.5f;
  3089. c.Value.w = ImMax(0.1f, ImMin(lerp_koeff, 1.f));
  3090. const float angle_offset = PI_2 / bars;
  3091. float start = (float)ImGui::GetTime() * speed;
  3092. const float astart = ImFmod(start, angle_offset);
  3093. const float save_start = start;
  3094. start -= astart;
  3095. const float angle_offset_t = angle_offset * 0.3f;
  3096. bars = ImMin<size_t>(bars, 32);
  3097. const float rmin = radius - thickness;
  3098. ImColor rc = bg;
  3099. for (size_t i = 0; i < bars; i++) {
  3100. float left = start + (i * angle_offset) - angle_offset_t;
  3101. float centera = start - PI_DIV_2 + (i * angle_offset);
  3102. float rmul = 1.f - ImClamp(ImAbs(centera - save_start), 0.f, PI_DIV_2) / PI_DIV_2;
  3103. rc.Value.w = ImMax(rmul, 0.1f);
  3104. rmul *= 1.f + ImSin(rmul * IM_PI);
  3105. const float r = ImMax(radius * rmul, radius);
  3106. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(left) * r, centre.y + ImSin(left) * r), thickness, color_alpha(rc, 1.f), num_segments);
  3107. }
  3108. }
  3109. inline void SpinnerSwingDots(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f)
  3110. {
  3111. SPINNER_HEADER(pos, size, centre, num_segments);
  3112. const float start = (float)ImGui::GetTime() * speed;
  3113. constexpr int elipses = 2;
  3114. auto get_rotated_ellipse_pos = [&] (float alpha, float start) {
  3115. std::array<ImVec2, 36> pts;
  3116. alpha = ImFmod(alpha, IM_PI);
  3117. float a = radius;
  3118. float b = radius / 10.f;
  3119. float anga = ImFmod(start, PI_2);
  3120. float x = a * ImCos(anga) * ImCos(alpha) + b * ImSin(anga) * ImSin(alpha) + centre.x;
  3121. float y = b * ImSin(anga) * ImCos(alpha) - a * ImCos(anga) * ImSin(alpha) + centre.y;
  3122. return ImVec2{x, y};
  3123. };
  3124. float out_h, out_s, out_v;
  3125. ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, out_h, out_s, out_v);
  3126. for (int i = 0; i < elipses; ++i) {
  3127. ImVec2 ppos = get_rotated_ellipse_pos((IM_PI * (float)i/ elipses) + PI_DIV_4, start + PI_DIV_2 * i);
  3128. const float y_delta = ImAbs(centre.y - ppos.y);
  3129. float th_koeff = ImMax((y_delta / size.y) * 4.f, 0.5f);
  3130. window->DrawList->AddCircleFilled(ppos, th_koeff * thickness, color_alpha(ImColor::HSV(out_h + i * 0.5f, out_s, out_v), 1.f), num_segments);
  3131. }
  3132. }
  3133. inline void SpinnerCircularPoints(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 1.8f, int lines = 8)
  3134. {
  3135. SPINNER_HEADER(pos, size, centre, num_segments);
  3136. const float start = ImFmod((float)ImGui::GetTime() * speed, radius);
  3137. const float bg_angle_offset = (PI_2) / lines;
  3138. for (size_t j = 0; j < 3; ++j)
  3139. {
  3140. const float start_offset = j * radius / 3.f;
  3141. const float rmax = ImFmod((start + start_offset), radius);
  3142. ImColor c = color_alpha(color, ImSin((radius - rmax) / radius * IM_PI));
  3143. for (size_t i = 0; i < lines; i++)
  3144. {
  3145. float a = (i * bg_angle_offset);
  3146. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(a) * rmax, centre.y + ImSin(a) * rmax), thickness, c, num_segments);
  3147. }
  3148. }
  3149. }
  3150. inline void SpinnerCurvedCircle(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, size_t circles = 1)
  3151. {
  3152. SPINNER_HEADER(pos, size, centre, num_segments);
  3153. const float start = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  3154. const float bg_angle_offset = PI_2 / num_segments;
  3155. float out_h, out_s, out_v;
  3156. ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, out_h, out_s, out_v);
  3157. for (int j = 0; j < circles; j++)
  3158. {
  3159. window->DrawList->PathClear();
  3160. const float rr = radius - ((radius * 0.5f) / circles) * j;
  3161. const float start_a = start * (1.1f * (j+1));
  3162. for (size_t i = 0; i <= num_segments; i++)
  3163. {
  3164. const float a = start_a + (i * bg_angle_offset);
  3165. const float r = rr - (0.2f * (i % 2)) * rr;
  3166. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a) * r, centre.y + ImSin(a) * r));
  3167. }
  3168. window->DrawList->PathStroke(color_alpha(ImColor::HSV(out_h + (j * 1.f / circles), out_s, out_v), 1.f), false, thickness);
  3169. }
  3170. }
  3171. inline void SpinnerModCircle(const char *label, float radius, float thickness, const ImColor &color = white, float ang_min = 1.f, float ang_max = 1.f, float speed = 2.8f)
  3172. {
  3173. SPINNER_HEADER(pos, size, centre, num_segments);
  3174. float start = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  3175. window->DrawList->PathClear();
  3176. for (size_t i = 0; i <= 90; i++)
  3177. {
  3178. const float ax = ((i / 90.f) * PI_2 * ang_min);
  3179. const float ay = ((i / 90.f) * PI_2 * ang_max);
  3180. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(ax) * radius, centre.y + ImSin(ay) * radius));
  3181. }
  3182. window->DrawList->PathStroke(color_alpha(color, 1.f), false, thickness);
  3183. start = (start < IM_PI) ? (start * 2.f) : (PI_2 - start) * 2.f;
  3184. window->DrawList->AddCircleFilled(ImVec2(centre.x + ImCos(start * ang_min) * radius, centre.y + ImSin(start * ang_max) * radius), thickness * 4.f, color_alpha(color, 1.f), num_segments);
  3185. }
  3186. inline void SpinnerDnaDots(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, int lt = 8, float delta = 0.5f, bool mode = 0)
  3187. {
  3188. SPINNER_HEADER(pos, size, centre, num_segments);
  3189. const float nextItemKoeff = 2.5f;
  3190. const float dots = (size.x / (thickness * nextItemKoeff));
  3191. const float start = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  3192. float out_h, out_s, out_v;
  3193. ImGui::ColorConvertRGBtoHSV(color.Value.x, color.Value.y, color.Value.z, out_h, out_s, out_v);
  3194. auto draw_point = [&] (float angle, int i) {
  3195. float a = angle + start + (IM_PI - i * PI_DIV(dots));
  3196. float th_koeff = 1.f + ImSin(a + PI_DIV_2) * 0.5f;
  3197. float pp = mode ? centre.x + ImSin(a) * size.x * delta
  3198. : centre.y + ImSin(a) * size.y * delta;
  3199. ImColor c = ImColor::HSV(out_h + i * (1.f / dots * 2.f), out_s, out_v);
  3200. ImVec2 p = mode ? ImVec2(pp, centre.y - (size.y * 0.5f) + i * thickness * nextItemKoeff)
  3201. : ImVec2(centre.x - (size.x * 0.5f) + i * thickness * nextItemKoeff, pp);
  3202. window->DrawList->AddCircleFilled(p, thickness * th_koeff, color_alpha(c, 1.f), lt);
  3203. return p;
  3204. };
  3205. for (int i = 0; i < dots; i++) {
  3206. ImVec2 p1 = draw_point(0, i);
  3207. ImVec2 p2 = draw_point(IM_PI, i);
  3208. window->DrawList->AddLine(p1, p2, color_alpha(color, 1.f), thickness * 0.5f);
  3209. }
  3210. }
  3211. inline void Spinner3SmuggleDots(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 4.8f, int lt = 8, float delta = 0.5f, bool mode = 0) {
  3212. SPINNER_HEADER(pos, size, centre, num_segments);
  3213. const float nextItemKoeff = 2.5f;
  3214. const float dots = 2;// (size.x / (thickness * nextItemKoeff));
  3215. const float start = ImFmod((float)ImGui::GetTime() * speed, PI_2);
  3216. auto draw_point = [&] (float angle, int i, float k) {
  3217. float a = angle + k * start + k * (IM_PI - i * PI_DIV(dots));
  3218. float th_koeff = 1.f + ImSin(a + PI_DIV_2) * 0.3f;
  3219. float pp = mode ? centre.x + ImSin(a) * size.x * delta
  3220. : centre.y + ImSin(a) * size.y * delta;
  3221. ImVec2 p = mode ? ImVec2(pp, centre.y - (size.y * 0.5f) + i * thickness * nextItemKoeff)
  3222. : ImVec2(centre.x - (size.x * 0.5f) + i * thickness * nextItemKoeff, pp);
  3223. window->DrawList->AddCircleFilled(p, thickness * th_koeff, color_alpha(color, 1.f), lt);
  3224. return p;
  3225. };
  3226. {
  3227. ImVec2 p1 = draw_point(0, 1, -1);
  3228. ImVec2 p2 = draw_point(IM_PI, 2, 1);
  3229. //window->DrawList->AddLine(p1, p2, color_alpha(color, 1.f), thickness * 0.5f);
  3230. ImVec2 p3 = draw_point(PI_DIV_2, 3, -1);
  3231. //window->DrawList->AddLine(p2, p3, color_alpha(color, 1.f), thickness * 0.5f);
  3232. }
  3233. }
  3234. inline void SpinnerRotateSegmentsPulsar(const char *label, float radius, float thickness, const ImColor &color = white, float speed = 2.8f, size_t arcs = 4, size_t layers = 1)
  3235. {
  3236. SPINNER_HEADER(pos, size, centre, num_segments);
  3237. const float arc_angle = PI_2 / (float)arcs;
  3238. const float angle_offset = arc_angle / num_segments;
  3239. float r = radius;
  3240. float reverse = 1.f;
  3241. const float bg_angle_offset = PI_2_DIV(num_segments);
  3242. const float koeff = PI_DIV(2 * layers);
  3243. float start = (float)ImGui::GetTime() * speed;
  3244. for (int num_ring = 0; num_ring < layers; ++num_ring) {
  3245. float radius_k = ImSin(ImFmod(start + (num_ring * koeff), PI_DIV_2));
  3246. ImColor c = color_alpha(color, (radius_k > 0.5f) ? (2.f - (radius_k * 2.f)) : color.Value.w);
  3247. for (size_t arc_num = 0; arc_num < arcs; ++arc_num)
  3248. {
  3249. window->DrawList->PathClear();
  3250. for (size_t i = 2; i <= num_segments - 2; i++)
  3251. {
  3252. const float a = start * (1.f + 0.1f * num_ring) + arc_angle * arc_num + (i * angle_offset);
  3253. window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a * reverse) * (r * radius_k), centre.y + ImSin(a * reverse) * (r * radius_k)));
  3254. }
  3255. window->DrawList->PathStroke(c, false, thickness);
  3256. }
  3257. }
  3258. }
  3259. namespace detail {
  3260. static struct SpinnerDraw { SpinnerTypeT type; void (*func)(const char *, const detail::SpinnerConfig &); } spinner_draw_funcs[e_st_count] = {
  3261. { e_st_rainbow, [] (const char *label, const detail::SpinnerConfig &c) { SpinnerRainbow(label, c.m_Radius, c.m_Thickness, c.m_Color, c.m_Speed, c.m_AngleMin, c.m_AngleMax); } },
  3262. { e_st_angle, [] (const char *label, const detail::SpinnerConfig &c) { SpinnerAng(label, c.m_Radius, c.m_Thickness, c.m_Color, c.m_BgColor, c.m_Speed, c.m_Angle); } },
  3263. { e_st_dots, [] (const char *label, const detail::SpinnerConfig &c) { SpinnerDots(label, c.m_FloatPtr, c.m_Radius, c.m_Thickness, c.m_Color, c.m_Speed, c.m_Dots, c.m_MinThickness); } },
  3264. { e_st_ang, [] (const char *label, const detail::SpinnerConfig &c) { SpinnerAng(label, c.m_Radius, c.m_Thickness, c.m_Color, c.m_BgColor, c.m_Speed, c.m_Angle); } },
  3265. { e_st_vdots, [] (const char *label, const detail::SpinnerConfig &c) { SpinnerVDots(label, c.m_Radius, c.m_Thickness, c.m_Color, c.m_BgColor, c.m_Speed, c.m_Dots); } },
  3266. { e_st_bounce_ball, [] (const char *label,const detail::SpinnerConfig &c) { SpinnerBounceBall(label, c.m_Radius, c.m_Thickness, c.m_Color, c.m_Speed, c.m_Dots); } },
  3267. { e_st_eclipse, [] (const char *label, const detail::SpinnerConfig &c) { SpinnerAngEclipse(label , c.m_Radius, c.m_Thickness, c.m_Color, c.m_Speed); } },
  3268. { e_st_ingyang, [] (const char *label, const detail::SpinnerConfig &c) { SpinnerIngYang(label, c.m_Radius, c.m_Thickness, c.m_Reverse, c.m_Delta, c.m_AltColor, c.m_Color, c.m_Speed, c.m_Angle); } }
  3269. };
  3270. }
  3271. inline void Spinner(const char *label, const detail::SpinnerConfig& config)
  3272. {
  3273. if (config.m_SpinnerType < sizeof(detail::spinner_draw_funcs))
  3274. detail::spinner_draw_funcs[config.m_SpinnerType].func(label, config);
  3275. }
  3276. template<SpinnerTypeT Type, typename... Args>
  3277. inline void Spinner(const char *label, const Args&... args)
  3278. {
  3279. detail::SpinnerConfig config(SpinnerType{Type}, args...);
  3280. Spinner(label, config);
  3281. }
  3282. #ifdef IMSPINNER_DEMO
  3283. inline void demoSpinners() {
  3284. static int hue = 0;
  3285. static float nextdot = 0, nextdot2;
  3286. static bool show_number = false;
  3287. nextdot -= 0.07f;
  3288. static float velocity = 1.f;
  3289. static float widget_size = 50.f;
  3290. static int selected_idx = 0;
  3291. static ImColor spinner_filling_meb_bg;
  3292. constexpr int num_spinners = 200;
  3293. static int cci = 0, last_cci = 0;
  3294. static std::map<int, const char*> __nn; auto Name = [] (const char* v) { if (!__nn.count(cci)) { __nn[cci] = v; }; return __nn[cci]; };
  3295. static std::map<int, float> __rr; auto R = [] (float v) { if (!__rr.count(cci)) { __rr[cci] = v; }; return __rr[cci]; };
  3296. static std::map<int, float> __tt; auto T = [] (float v) { if (!__tt.count(cci)) { __tt[cci] = v; }; return __tt[cci]; };
  3297. static std::map<int, ImColor> __cc; auto C = [] (ImColor v) { if (!__cc.count(cci)) { __cc[cci] = v; }; return __cc[cci]; };
  3298. static std::map<int, ImColor> __cb; auto CB = [] (ImColor v) { if (!__cb.count(cci)) { __cb[cci] = v; }; return __cb[cci]; };
  3299. static std::map<int, bool> __hc; auto HC = [] (bool v) { if (!__hc.count(cci)) { __hc[cci] = v; }; return __hc[cci]; };
  3300. static std::map<int, bool> __hcb; auto HCB = [] (bool v) { if (!__hcb.count(cci)) { __hcb[cci] = v; }; return __hcb[cci]; };
  3301. static std::map<int, float> __ss; auto S = [] (float v) { if (!__ss.count(cci)) { __ss[cci] = v; }; return __ss[cci]; };
  3302. static std::map<int, float> __aa; auto A = [] (float v) { if (!__aa.count(cci)) { __aa[cci] = v; }; return __aa[cci]; };
  3303. static std::map<int, float> __amn; auto AMN = [] (float v) { if (!__amn.count(cci)) { __amn[cci] = v; }; return __amn[cci]; };
  3304. static std::map<int, float> __amx; auto AMX = [] (float v) { if (!__amx.count(cci)) { __amx[cci] = v; }; return __amx[cci]; };
  3305. static std::map<int, int> __dt; auto DT = [] (int v) { if (!__dt.count(cci)) { __dt[cci] = v; }; return __dt[cci]; };
  3306. static std::map<int, int> __mdt; auto MDT = [] (int v) { if (!__mdt.count(cci)) { __mdt[cci] = v; }; return __mdt[cci]; };
  3307. static std::map<int, float> __dd; auto D = [] (float v) { if (!__dd.count(cci)) { __dd[cci] = v; }; return __dd[cci]; };
  3308. const auto draw_spinner = [&](int spinner_idx, float widget_size)
  3309. {
  3310. const ImVec2 curpos_begin = ImGui::GetCursorPos();
  3311. ImGui::PushID(spinner_idx);
  3312. {
  3313. if (show_number) {
  3314. ImGui::Text("%04u", spinner_idx);
  3315. }
  3316. const bool is_selected = (selected_idx == spinner_idx);
  3317. if (ImGui::Selectable("", is_selected, 0, ImVec2(widget_size, widget_size))) {
  3318. selected_idx = spinner_idx;
  3319. last_cci = spinner_idx;
  3320. }
  3321. // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
  3322. if (is_selected) {
  3323. ImGui::SetItemDefaultFocus();
  3324. }
  3325. const float sp_radius = __rr.count(spinner_idx) ? __rr[spinner_idx] : 16.f;
  3326. const float sp_offset = (widget_size - sp_radius * 2.f ) / 2.f;
  3327. ImGui::SetCursorPos({curpos_begin.x + sp_offset, curpos_begin.y + sp_offset});
  3328. #define $(i) i: cci = i;
  3329. switch (spinner_idx) {
  3330. case $( 0) ImSpinner::Spinner<e_st_rainbow> (Name("Spinner"),
  3331. Radius{R(16)}, Thickness{T(2)}, Color{ImColor::HSV(++hue * 0.005f, 0.8f, 0.8f)}, Speed{S(8) * velocity}, AngleMin{AMN(0.f)}, AngleMax{AMX(PI_2)}); break;
  3332. case $( 1) ImSpinner::Spinner<e_st_angle> (Name("SpinnerAng"),
  3333. Radius{R(16)}, Thickness{T(2)}, Color{C(white)}, BgColor{CB(ImColor(255, 255, 255, 128))}, Speed{S(8) * velocity}, Angle{A(IM_PI)}); break;
  3334. case $( 2) ImSpinner::Spinner<e_st_dots> (Name("SpinnerDots"),
  3335. Radius{R(16)}, Thickness{T(4)}, Color{C(white)}, FloatPtr{&nextdot}, Speed{S(1) * velocity}, Dots{DT(12)}, MinThickness{-1.f}); break;
  3336. case $( 3) ImSpinner::Spinner<e_st_ang> (Name("SpinnerAngNoBg"),
  3337. Radius{R(16)}, Thickness{T(2)}, Color{C(white)}, BgColor{CB(ImColor(255, 255, 255, 0))}, Speed{S(6) * velocity}, Angle{A(IM_PI)}); break;
  3338. case $( 4) ImSpinner::Spinner<e_st_ang> (Name("SpinnerAng270"),
  3339. Radius{R(16)}, Thickness{T(2)}, Color{C(white)}, BgColor{CB(ImColor(255, 255, 255, 128))}, Speed{S(6) * velocity}, Angle{A(0.75f * PI_2)}); break;
  3340. case $( 5) ImSpinner::Spinner<e_st_ang> (Name("SpinnerAng270NoBg"),
  3341. Radius{R(16)}, Thickness{T(2)}, Color{C(white)}, BgColor{CB(ImColor(255, 255, 255, 0))}, Speed{S(6) * velocity}, Angle{A(0.75f * PI_2)}); break;
  3342. case $( 6) ImSpinner::Spinner<e_st_vdots> (Name("SpinnerVDots"),
  3343. Radius{R(16)}, Thickness{T(4)}, Color{C(white)}, BgColor{CB(ImColor::HSV(hue * 0.0011f, 0.8f, 0.8f))}, Speed{S(2.7f) * velocity}, Dots{DT(12)}, MiddleDots{6}); break;
  3344. case $( 7) ImSpinner::Spinner<e_st_bounce_ball>(Name("SpinnerBounceBall"),
  3345. Radius{R(16)}, Thickness{T(6)}, Color{C(white)}, Speed{S(4) * velocity}, Dots{DT(1)}); break;
  3346. case $( 8) ImSpinner::Spinner<e_st_eclipse> (Name("SpinnerAngEclipse"),
  3347. Radius{R(16)}, Thickness{T(5)}, Color{C(white)}, Speed{S(6) * velocity}); break;
  3348. case $( 9) ImSpinner::Spinner<e_st_ingyang> (Name("SpinnerIngYang"),
  3349. Radius{R(16)}, Thickness{T(5)}, Reverse{false}, Delta{D(0.f)}, Color{C(white)}, AltColor{ImColor(255, 0, 0)}, Speed{S(4) * velocity}, Angle{A(IM_PI * 0.8f)}); break;
  3350. case $(10) ImSpinner::SpinnerBarChartSine (Name("SpinnerBarChartSine"),
  3351. R(16), 4, C(white), S(6.8f) * velocity, 4, 0); break;
  3352. case $(11) ImSpinner::SpinnerBounceDots (Name("SpinnerBounceDots"), R(16),
  3353. T(6), C(white), S(6) * velocity, DT(3)); break;
  3354. case $(12) ImSpinner::SpinnerFadeDots (Name("SpinnerFadeDots"), R(16),
  3355. T(6), C(white), S(8) * velocity, DT(8)); break;
  3356. case $(13) ImSpinner::SpinnerScaleDots (Name("SpinnerScaleDots"), R(16),
  3357. T(6), C(white), S(7) * velocity, DT(8)); break;
  3358. case $(14) ImSpinner::SpinnerMovingDots (Name("SpinnerMovingDots"), R(16),
  3359. T(6), C(white), S(30) * velocity, DT(3)); break;
  3360. case $(15) ImSpinner::SpinnerRotateDots (Name("SpinnerRotateDots"),
  3361. R(16), T(6), C(white), S(4) * velocity, DT(2)); break;
  3362. case $(16) ImSpinner::SpinnerTwinAng (Name("SpinnerTwinAng"),
  3363. R(16), 16, T(6), C(white), CB(ImColor(255, 0, 0)), S(4) * velocity, A(IM_PI)); break;
  3364. case $(17) ImSpinner::SpinnerClock (Name("SpinnerClock"),
  3365. R(16), T(2), C(ImColor(255, 0, 0)), CB(white), S(4) * velocity); break;
  3366. case $(18) ImSpinner::SpinnerIngYang (Name("SpinnerIngYangR"),
  3367. R(16), T(5), true, 0.1f, C(white), CB(ImColor(255, 0, 0)), S(4) * velocity, A(IM_PI * 0.8f)); break;
  3368. case $(19) ImSpinner::SpinnerBarChartSine (Name("SpinnerBarChartSine2"),
  3369. R(16), T(4), ImColor::HSV(hue * 0.005f, 0.8f, 0.8f), S(4.8f) * velocity, 4, 1); break;
  3370. case $(20) ImSpinner::SpinnerTwinAng180 (Name("SpinnerTwinAng"),
  3371. R(16), 12, T(4), C(white), CB(ImColor(255, 0, 0)), S(4) * velocity); break;
  3372. case $(21) ImSpinner::SpinnerTwinAng360 (Name("SpinnerTwinAng360"),
  3373. R(16), 11, T(4), C(white), CB(ImColor(255, 0, 0)), S(4) * velocity); break;
  3374. case $(22) ImSpinner::SpinnerIncDots (Name("SpinnerIncDots"),
  3375. R(16), T(4), C(white), S(5.6f) * velocity, 6); break;
  3376. case $(23) nextdot2 -= 0.2f * velocity;
  3377. ImSpinner::SpinnerDots (Name("SpinnerDotsWoBg"),
  3378. &nextdot2, R(16), T(4), C(white), S(0.3f) * velocity, 12, 0.f); break;
  3379. case $(24) ImSpinner::SpinnerIncScaleDots (Name("SpinnerIncScaleDots"),
  3380. R(16), T(4), C(white), S(6.6f) * velocity, 6); break;
  3381. case $(25) ImSpinner::SpinnerAng (Name("SpinnerAng90"),
  3382. R(16), T(6), C(white), CB(ImColor(255, 255, 255, 128)), S(8.f) * velocity, A(PI_DIV_2)); break;
  3383. case $(26) ImSpinner::SpinnerAng (Name("SpinnerAng90"),
  3384. R(16), 6, C(white), CB(ImColor(255, 255, 255, 0)), S(8.5f) * velocity, A(PI_DIV_2)); break;
  3385. case $(27) ImSpinner::SpinnerFadeBars (Name("SpinnerFadeBars"),
  3386. 10, C(white), S(4.8f) * velocity, 3); break;
  3387. case $(28) ImSpinner::SpinnerPulsar (Name("SpinnerPulsar"),
  3388. R(16), T(2), C(white), S(1) * velocity); break;
  3389. case $(29) ImSpinner::SpinnerIngYang (Name("SpinnerIngYangR2"),
  3390. R(16), T(5), true, 3.f, C(white), CB(ImColor(255, 0, 0)), S(4) * velocity, A(IM_PI * 0.8f)); break;
  3391. case $(30) ImSpinner::SpinnerBarChartRainbow (Name("SpinnerBarChartRainbow"),
  3392. R(16), T(4), ImColor::HSV(hue * 0.005f, 0.8f, 0.8f), S(6.8f) * velocity, 4); break;
  3393. case $(31) ImSpinner::SpinnerBarsRotateFade (Name("SpinnerBarsRotateFade"),
  3394. 8, 18, T(4), C(white), S(7.6f) * velocity, 6); break;
  3395. case $(32) ImSpinner::SpinnerFadeBars (Name("SpinnerFadeScaleBars"),
  3396. 10, C(white), S(6.8f) * velocity, 3, true); break;
  3397. case $(33) ImSpinner::SpinnerBarsScaleMiddle (Name("SpinnerBarsScaleMiddle"),
  3398. 6, C(white), S(8.8f) * velocity, 3); break;
  3399. case $(34) ImSpinner::SpinnerAngTwin (Name("SpinnerAngTwin1"),
  3400. R(16), 13, T(2), C(ImColor(255, 0, 0)), CB(white), S(6) * velocity, A(PI_DIV_2)); break;
  3401. case $(35) ImSpinner::SpinnerAngTwin (Name("SpinnerAngTwin2"),
  3402. 13, 16, T(2), C(ImColor(255, 0, 0)), CB(white), S(6) * velocity, A(PI_DIV_2)); break;
  3403. case $(36) ImSpinner::SpinnerAngTwin (Name("SpinnerAngTwin3"),
  3404. 13, 16, T(2), C(ImColor(255, 0, 0)), CB(white), S(6) * velocity, A(PI_DIV_2), 2); break;
  3405. case $(37) ImSpinner::SpinnerAngTwin (Name("SpinnerAngTwin4"),
  3406. R(16), 13, T(2), C(ImColor(255, 0, 0)), CB(white), S(6) * velocity, A(PI_DIV_2), 2); break;
  3407. case $(38) ImSpinner::SpinnerTwinPulsar (Name("SpinnerTwinPulsar"),
  3408. R(16), T(2), C(white), S(0.5f) * velocity, 2); break;
  3409. case $(39) ImSpinner::SpinnerAngTwin (Name("SpinnerAngTwin4"),
  3410. R(14), 13, T(3), C(ImColor(255, 0, 0)), CB(ImColor(0, 0, 0, 0)), S(5) * velocity, A(IM_PI / 1.5f), 2); break;
  3411. case $(40) ImSpinner::SpinnerBlocks (Name("SpinnerBlocks"),
  3412. R(16), T(7), C(ImColor(255, 255, 255, 30)), CB(ImColor::HSV(hue * 0.005f, 0.8f, 0.8f)), S(5) * velocity); break;
  3413. case $(41) ImSpinner::SpinnerTwinBall (Name("SpinnerTwinBall"),
  3414. R(16), 11, T(2), 2.5f, C(ImColor(255, 0, 0)), CB(white), S(6) * velocity, 2); break;
  3415. case $(42) ImSpinner::SpinnerTwinBall (Name("SpinnerTwinBall2"),
  3416. R(15), 19, T(2), 2.f, C(ImColor(255, 0, 0)), CB(white), S(6) * velocity, 3); break;
  3417. case $(43) ImSpinner::SpinnerTwinBall (Name("SpinnerTwinBall2"),
  3418. 16, 16, T(2), 5.f, C(ImColor(255, 0, 0)), CB(white), S(5) * velocity, 1); break;
  3419. case $(44) ImSpinner::SpinnerAngTriple (Name("SpinnerAngTriple"),
  3420. 16, 13, 10, T(1.3f), C(white), ImColor(255, 0, 0), white, S(5) * velocity, A(1.5f * IM_PI)); break;
  3421. case $(45) ImSpinner::SpinnerIncFullDots (Name("SpinnerIncFullDots"),
  3422. R(16), T(4), C(white), S(5.6f) * velocity, 4); break;
  3423. case $(46) ImSpinner::SpinnerGooeyBalls (Name("SpinnerGooeyBalls"),
  3424. R(16), C(white), S(2.f) * velocity); break;
  3425. case $(47) ImSpinner::SpinnerRotateGooeyBalls (Name("SpinnerRotateGooeyBalls2"),
  3426. R(16), T(5), C(white), S(6.f) * velocity, 2); break;
  3427. case $(48) ImSpinner::SpinnerRotateGooeyBalls (Name("SpinnerRotateGooeyBalls3"),
  3428. R(16), T(5), C(white), S(6.f) * velocity, 3); break;
  3429. case $(49) ImSpinner::SpinnerMoonLine (Name("SpinnerMoonLine"),
  3430. R(16), T(3), C(ImColor(200, 80, 0)), ImColor(80, 80, 80), S(5) * velocity); break;
  3431. case $(50) ImSpinner::SpinnerArcRotation (Name("SpinnerArcRotation"),
  3432. R(13), T(5), C(white), S(3) * velocity, DT(4)); break;
  3433. case $(51) ImSpinner::SpinnerFluid (Name("SpinnerFluid"),
  3434. R(16), C(ImColor(0, 0, 255)), S(3.8f) * velocity, 4); break;
  3435. case $(52) ImSpinner::SpinnerArcFade (Name("SpinnerArcFade"),
  3436. R(13), T(5), C(white), S(3) * velocity, 4); break;
  3437. case $(53) ImSpinner::SpinnerFilling (Name("SpinnerFilling"),
  3438. R(16), T(6), C(white), CB(ImColor(255, 0, 0)), S(4) * velocity); break;
  3439. case $(54) ImSpinner::SpinnerTopup (Name("SpinnerTopup"),
  3440. R(16), 12, C(ImColor(255, 0, 0)), ImColor(80, 80, 80), CB(white), S(1) * velocity); break;
  3441. case $(55) ImSpinner::SpinnerFadePulsar (Name("SpinnerFadePulsar"),
  3442. R(16), C(white), S(1.5f) * velocity, 1); break;
  3443. case $(56) ImSpinner::SpinnerFadePulsar (Name("SpinnerFadePulsar2"),
  3444. R(16), C(white), S(0.9f) * velocity, 2); break;
  3445. case $(57) ImSpinner::SpinnerPulsar (Name("SpinnerPulsar"),
  3446. R(16), T(2), C(white), S(1) * velocity, false); break;
  3447. case $(58) ImSpinner::SpinnerDoubleFadePulsar (Name("SpinnerDoubleFadePulsar"),
  3448. R(16), T(2), C(white), S(2) * velocity); break;
  3449. case $(59) ImSpinner::SpinnerFilledArcFade (Name("SpinnerFilledArcFade"),
  3450. R(16), C(white), S(4) * velocity, 4); break;
  3451. case $(60) ImSpinner::SpinnerFilledArcFade (Name("SpinnerFilledArcFade6"),
  3452. R(16), C(white), S(6) * velocity, 6); break;
  3453. case $(61) ImSpinner::SpinnerFilledArcFade (Name("SpinnerFilledArcFade6"),
  3454. R(16), C(white), S(8) * velocity, 12); break;
  3455. case $(62) ImSpinner::SpinnerFilledArcColor (Name("SpinnerFilledArcColor"),
  3456. R(16), C(ImColor(255, 0, 0)), CB(white), S(2.8f) * velocity, 4); break;
  3457. case $(63) ImSpinner::SpinnerCircleDrop (Name("SpinnerCircleDrop"),
  3458. R(16), T(1.5f), 4.f, C(ImColor(255, 0, 0)), CB(white), S(2.8f) * velocity, A(IM_PI)); break;
  3459. case $(64) ImSpinner::SpinnerSurroundedIndicator(Name("SpinnerSurroundedIndicator"),
  3460. R(16), T(5), C(ImColor(0, 0, 0)), CB(white), S(7.8f) * velocity); break;
  3461. case $(65) ImSpinner::SpinnerTrianglesSelector (Name("SpinnerTrianglesSelector"),
  3462. R(16), T(8), C(ImColor(0, 0, 0)), CB(white), S(4.8f) * velocity, 8); break;
  3463. case $(66) ImSpinner::SpinnerFlowingGradient (Name("SpinnerFlowingFradient"),
  3464. R(16), T(6), C(ImColor(200, 80, 0)), CB(ImColor(80, 80, 80)), S(5) * velocity, A(PI_2)); break;
  3465. case $(67) ImSpinner::SpinnerRotateSegments (Name("SpinnerRotateSegments"),
  3466. R(16), T(4), C(white), S(3) * velocity, 4); break;
  3467. case $(68) ImSpinner::SpinnerRotateSegments (Name("SpinnerRotateSegments2"),
  3468. R(16), T(3), C(white), S(2.4f) * velocity, 4, 2); break;
  3469. case $(69) ImSpinner::SpinnerRotateSegments (Name("SpinnerRotateSegments3"),
  3470. R(16), T(2), C(white), S(2.1f) * velocity, 4, 3); break;
  3471. case $(70) ImSpinner::SpinnerLemniscate (Name("SpinnerLemniscate"),
  3472. R(20), T(3), C(white), S(2.1f) * velocity, 3); break;
  3473. case $(71) ImSpinner::SpinnerRotateGear (Name("SpinnerRotateGear"),
  3474. R(16), T(6), C(white), S(2.1f) * velocity, 8); break;
  3475. case $(72) ImSpinner::SpinnerRotatedAtom (Name("SpinnerRotatedAtom"),
  3476. R(16), T(2), C(white), S(2.1f) * velocity, 3); break;
  3477. case $(73) ImSpinner::SpinnerAtom (Name("SpinnerAtom"),
  3478. R(16), T(2), C(white), S(4.1f) * velocity, 3); break;
  3479. case $(74) ImSpinner::SpinnerRainbowBalls (Name("SpinnerRainbowBalls"),
  3480. R(16.0f), T(4.0f), ImColor::HSV(0.25f, 0.8f, 0.8f, 0.f), S(1.5f) * velocity, (int)D(5.0f)); break;
  3481. case $(75) ImSpinner::SpinnerCamera (Name("SpinnerCamera"),
  3482. R(16), T(8), [] (int i) { return ImColor::HSV(i * 0.25f, 0.8f, 0.8f); }, S(4.8f) * velocity, 8); break;
  3483. case $(76) ImSpinner::SpinnerArcPolarFade (Name("SpinnerArcPolarFade"),
  3484. R(16), C(white), S(6) * velocity, 6); break;
  3485. case $(77) ImSpinner::SpinnerArcPolarRadius (Name("SpinnerArcPolarRadius"),
  3486. R(16), C(ImColor::HSV(0.25f, 0.8f, 0.8f)), S(6.f) * velocity, 6); break;
  3487. case $(78) ImSpinner::SpinnerCaleidoscope (Name("SpinnerArcPolarPies"),
  3488. R(16), T(4), C(ImColor::HSV(0.25f, 0.8f, 0.8f)), S(2.6f) * velocity, 10, 0); break;
  3489. case $(79) ImSpinner::SpinnerCaleidoscope (Name("SpinnerArcPolarPies2"),
  3490. R(16), T(4), C(ImColor::HSV(0.35f, 0.8f, 0.8f)), S(3.2f) * velocity, 10, 1); break;
  3491. case $(80) ImSpinner::SpinnerScaleBlocks (Name("SpinnerScaleBlocks"),
  3492. R(16), T(8), ImColor::HSV(hue * 0.005f, 0.8f, 0.8f), S(5) * velocity); break;
  3493. case $(81) ImSpinner::SpinnerRotateTriangles (Name("SpinnerRotateTriangles"),
  3494. R(16), T(2), C(white), S(6.f) * velocity, 3); break;
  3495. case $(82) ImSpinner::SpinnerArcWedges (Name("SpinnerArcWedges"),
  3496. R(16), C(ImColor::HSV(0.3f, 0.8f, 0.8f)), S(2.8f) * velocity, 4); break;
  3497. case $(83) ImSpinner::SpinnerScaleSquares (Name("SpinnerScaleSquares"),
  3498. R(16), T(8), ImColor::HSV(hue * 0.005f, 0.8f, 0.8f), S(5) * velocity); break;
  3499. case $(84) ImSpinner::SpinnerHboDots (Name("SpinnerHboDots"), R(16),
  3500. T(4), C(white), 0.f, 0.f, S(1.1f) * velocity, DT(6)); break;
  3501. case $(85) ImSpinner::SpinnerHboDots (Name("SpinnerHboDots2"), R(16),
  3502. T(4), C(white), 0.1f, 0.5f, S(1.1f) * velocity, DT(6)); break;
  3503. case $(86) ImSpinner::Spinner<e_st_bounce_ball>(Name("SpinnerBounceBall3"),
  3504. Radius{R(16)}, Thickness{T(4)}, Color{C(white)}, Speed{S(3.2f) * velocity}, Dots{DT(5)}); break;
  3505. case $(87) ImSpinner::SpinnerBounceBall (Name("SpinnerBounceBallShadow"),
  3506. R(16), T(4), C(white), S(2.2f) * velocity, DT(1), true); break;
  3507. case $(88) ImSpinner::SpinnerBounceBall (Name("SpinnerBounceBall5Shadow"),
  3508. R(16), T(4), C(white), S(3.6f) * velocity, DT(5), true); break;
  3509. case $(89) ImSpinner::SpinnerSquareStrokeFade (Name("SpinnerSquareStrokeFade"),
  3510. R(13), T(5), C(white), S(3) * velocity); break;
  3511. case $(90) ImSpinner::SpinnerSquareStrokeFill (Name("SpinnerSquareStrokeFill"),
  3512. R(13), T(5), C(white), S(3) * velocity); break;
  3513. case $(91) ImSpinner::SpinnerSwingDots (Name("SpinnerSwingDots"),
  3514. R(16), T(6), C(ImColor(255, 0, 0)), S(4.1f) * velocity); break;
  3515. case $(92) ImSpinner::SpinnerRotateWheel (Name("SpinnerRotateWheel"),
  3516. R(16), T(10), C(ImColor(255, 255, 0)), CB(white), S(2.1f) * velocity, 8); break;
  3517. case $(93) ImSpinner::SpinnerWaveDots (Name("SpinnerWaveDots"), R(16),
  3518. T(3), C(white), S(6) * velocity, DT(8)); break;
  3519. case $(94) ImSpinner::SpinnerRotateShapes (Name("SpinnerRotateShapes"),
  3520. R(16), T(2), C(white), S(6.f) * velocity, DT(4), MDT(4)); break;
  3521. case $(95) ImSpinner::SpinnerSquareStrokeLoading(Name("SpinnerSquareStrokeLoanding"),
  3522. R(13), T(5), C(white), S(3) * velocity); break;
  3523. case $(96) ImSpinner::SpinnerSinSquares (Name("SpinnerSinSquares"),
  3524. R(16), T(2), C(white), S(1.f) * velocity); break;
  3525. case $(97) ImSpinner::SpinnerZipDots (Name("SpinnerZipDots"), R(16),
  3526. T(3), C(white), S(6) * velocity, DT(5)); break;
  3527. case $(98) ImSpinner::SpinnerDotsToBar (Name("SpinnerDotsToBar"), R(16),
  3528. T(3), D(0.5f), C(ImColor::HSV(0.31f, 0.8f, 0.8f)), S(5) * velocity, DT(5)); break;
  3529. case $(99) ImSpinner::SpinnerSineArcs (Name("SpinnerSineArcs"), R(16),
  3530. T(1), C(white), S(3) * velocity);
  3531. case $(100) ImSpinner::SpinnerTrianglesShift (Name("SpinnerTrianglesShift"),
  3532. R(16), T(8), C(ImColor(0, 0, 0)), CB(white), S(1.8f) * velocity, DT(8)); break;
  3533. case $(101) ImSpinner::SpinnerCircularLines (Name("SpinnerCircularLines"),
  3534. R(16), C(white), S(1.5f) * velocity, DT(8)); break;
  3535. case $(102) ImSpinner::SpinnerLoadingRing (Name("SpinnerLoadingRing"),
  3536. R(16), T(6), C(red), CB(ImColor(255, 255, 255, 128)), S(1.f) * velocity, DT(5)); break;
  3537. case $(103) ImSpinner::SpinnerPatternRings (Name("SpinnerPatternRings"),
  3538. R(16), T(2), C(white), S(4.1f) * velocity, DT(3)); break;
  3539. case $(104) ImSpinner::SpinnerPatternSphere (Name("SpinnerPatternSphere"),
  3540. R(16), T(2), C(white), S(2.1f) * velocity, DT(6)); break;
  3541. case $(105) ImSpinner::SpinnerRingSynchronous (Name("SpinnerRingSnchronous"),
  3542. R(16), T(2), C(white), S(2.1f) * velocity, DT(3)); break;
  3543. case $(106) ImSpinner::SpinnerRingWatermarks (Name("SpinnerRingWatermarks"),
  3544. R(16), T(2), C(white), S(2.1f) * velocity, DT(3)); break;
  3545. case $(107) ImSpinner::SpinnerFilledArcRing (Name("SpinnerFilledArcRing"),
  3546. R(16), T(6), C(red), CB(white), S(2.8f) * velocity, DT(8)); break;
  3547. case $(108) ImSpinner::SpinnerPointsShift (Name("SpinnerPointsShift"),
  3548. R(16), T(3), C(ImColor(0, 0, 0)), CB(white), S(1.8f) * velocity, DT(10)); break;
  3549. case $(109) ImSpinner::SpinnerCircularPoints (Name("SpinnerCircularPoints"),
  3550. R(16), T(1.2f), C(white), S(10.f) * velocity, DT(7)); break;
  3551. case $(110) ImSpinner::SpinnerCurvedCircle (Name("SpinnerCurvedCircle"),
  3552. R(16), T(1.2f), C(white), S(1.f) * velocity, DT(3)); break;
  3553. case $(111) ImSpinner::SpinnerModCircle (Name("SpinnerModCirclre"),
  3554. R(16), T(1.2f), C(white), AMN(1.f), AMX(2.f), S(3.f) * velocity); break;
  3555. case $(112) ImSpinner::SpinnerModCircle (Name("SpinnerModCirclre2"),
  3556. R(16), T(1.2f), C(white), AMN(1.11f), AMX(3.33f), S(3.f) * velocity); break;
  3557. case $(113) ImSpinner::SpinnerPatternEclipse (Name("SpinnerPatternEclipse"),
  3558. R(16), T(2), C(white), S(4.1f) * velocity, DT(5), AMN(2.f), AMX(0.f)); break;
  3559. case $(114) ImSpinner::SpinnerPatternEclipse (Name("SpinnerPatternEclipse2"),
  3560. R(16), T(2), C(white), S(4.1f) * velocity, DT(9), AMN(4.f), AMX(1.f)); break;
  3561. case $(115) ImSpinner::SpinnerMultiFadeDots (Name("SpinnerMultiFadeDots"), R(16),
  3562. T(2), C(white), S(8) * velocity, DT(8)); break;
  3563. case $(116) ImSpinner::SpinnerRainbowShot (Name("SpinnerRainbowShot"),
  3564. R(16), T(4), ImColor::HSV(0.25f, 0.8f, 0.8f, 0.f), S(1.5f) * velocity, DT(5)); break;
  3565. case $(117) ImSpinner::SpinnerSpiral (Name("SpinnerSpiral"),
  3566. R(16), T(2), C(white), S(6) * velocity, DT(5)); break;
  3567. case $(118) ImSpinner::SpinnerSpiralEye (Name("SpinnerSpiralEye"),
  3568. R(16), T(1), C(white), S(3) * velocity); break;
  3569. case $(119) ImSpinner::SpinnerWifiIndicator (Name("SpinnerWifiIndicator"),
  3570. R(16), T(1.5f), C(ImColor(0, 0, 0)), CB(white), S(7.8f) * velocity, AMN(5.52f), DT(3)); break;
  3571. case $(120) ImSpinner::SpinnerHboDots (Name("SpinnerHboDots"), R(16),
  3572. T(2), C(white), 0.f, 0.f, S(1.1f) * velocity, DT(10)); break;
  3573. case $(121) ImSpinner::SpinnerHboDots (Name("SpinnerHboDots2"), R(16),
  3574. T(4), C(white), 0.1f, 0.5f, S(1.1f) * velocity, DT(2)); break;
  3575. case $(122) ImSpinner::SpinnerHboDots (Name("SpinnerHboDots4"), R(16),
  3576. T(4), C(white), 0.1f, 0.5f, S(1.1f) * velocity, DT(3)); break;
  3577. case $(123) ImSpinner::SpinnerDnaDots (Name("SpinnerDnaDotsH"), R(16),
  3578. T(3), C(white), S(2) * velocity, DT(8), D(0.25f)); break;
  3579. case $(124) ImSpinner::SpinnerDnaDots (Name("SpinnerDnaDotsV"), R(16),
  3580. T(3), C(white), S(2) * velocity, DT(8), D(0.25f), true); break;
  3581. case $(125) ImSpinner::SpinnerRotateDots (Name("SpinnerRotateDots2"),
  3582. R(16), T(6), C(white), S(4) * velocity, ImMax<int>(int(ImSin((float)ImGui::GetTime() * 0.5f) * 8), 3)); break;
  3583. case $(126) ImSpinner::SpinnerSevenSegments (Name("SpinnerSevenSegments"), "012345679ABCDEF",
  3584. R(16), T(2), C(white), S(4) * velocity); break;
  3585. case $(127) ImSpinner::SpinnerSolarBalls (Name("SpinnerSolarBalls"),
  3586. R(16), T(4), C(red), CB(white), S(5) * velocity, DT(4)); break;
  3587. case $(128) ImSpinner::SpinnerSolarArcs (Name("SpinnerSolarArcs"),
  3588. R(16), T(4), C(red), CB(white), S(5) * velocity, DT(4)); break;
  3589. case $(129) ImSpinner::SpinnerRainbow (Name("Spinner"),
  3590. R(16), T(2), ImColor::HSV(++hue * 0.005f, 0.8f, 0.8f), S(8) * velocity, AMN(0.f), AMX(PI_2), DT(3)); break;
  3591. case $(130) ImSpinner::SpinnerRotatingHeart (Name("SpinnerRotatedHeart"),
  3592. R(16), T(2), C(red), S(8) * velocity, AMN(0.f)); break;
  3593. case $(131) ImSpinner::SpinnerSolarScaleBalls (Name("SpinnerSolarScaleBalls"),
  3594. R(16), T(1.3f), C(red), S(1) * velocity, DT(36)); break;
  3595. case $(132) ImSpinner::SpinnerOrionDots (Name("SpinnerOrionDots"),
  3596. R(16), T(1.3f), C(white), S(4) * velocity, DT(12)); break;
  3597. case $(133) ImSpinner::SpinnerGalaxyDots (Name("SpinnerGalaxyDots"),
  3598. R(16), T(1.3f), C(white), S(0.2f) * velocity, DT(6)); break;
  3599. case $(134) ImSpinner::SpinnerAsciiSymbolPoints(Name("SpinnerAsciiSymbolPoints"), "012345679ABCDEF",
  3600. R(16), T(2), C(white), S(4) * velocity); break;
  3601. case $(135) ImSpinner::SpinnerRainbowCircle (Name("SpinnerRainbowCircle"),
  3602. R(16), T(4), C(ImColor::HSV(0.25f, 0.8f, 0.8f)), S(1) * velocity, DT(4)); break;
  3603. case $(136) ImSpinner::SpinnerRainbowCircle (Name("SpinnerRainbowCircle2"),
  3604. R(16), T(2), ImColor::HSV(hue * 0.001f, 0.8f, 0.8f), S(2) * velocity, DT(8), D(0)); break;
  3605. case $(137) ImSpinner::Spinner<e_st_vdots> (Name("SpinnerVDots2"),
  3606. Radius{R(16)}, Thickness{T(4)}, Color{C(white)}, BgColor{CB(ImColor::HSV(hue * 0.0011f, 0.8f, 0.8f))}, Speed{S(2.1f) * velocity}, Dots{DT(2)}, MiddleDots{6}); break;
  3607. case $(138) ImSpinner::Spinner<e_st_vdots> (Name("SpinnerVDots3"),
  3608. Radius{R(16)}, Thickness{T(4)}, Color{C(white)}, BgColor{CB(ImColor::HSV(hue * 0.0011f, 0.8f, 0.8f))}, Speed{S(2.9f) * velocity}, Dots{DT(3)}, MiddleDots{6}); break;
  3609. case $(139) ImSpinner::SpinnerSquareRandomDots(Name("SpinnerSquareRandomDots"),
  3610. R(16), T(2.8f), C(ImColor(255, 255, 255, 30)), CB(ImColor::HSV(hue * 0.005f, 0.8f, 0.8f)), S(5) * velocity); break;
  3611. case $(140) ImSpinner::SpinnerFluidPoints (Name("SpinnerFluidPoints"),
  3612. R(16), T(2.8f), C(ImColor(0, 0, 255)), S(3.8f) * velocity, Dots{DT(4)}, D(0.45f)); break;
  3613. case $(141) ImSpinner::SpinnerDotsLoading (Name("SpinnerDotsLoading"),
  3614. R(16), T(4.f), C(white), CB(white), S(2.f) * velocity); break;
  3615. case $(142) ImSpinner::SpinnerDotsToPoints (Name("SpinnerDotsToPoints"), R(16),
  3616. T(3), D(0.5f), C(ImColor::HSV(0.31f, 0.8f, 0.8f)), S(1.8f) * velocity, DT(5)); break;
  3617. case $(143) ImSpinner::SpinnerThreeDots (Name("SpinnerThreeDots"), R(16),
  3618. T(6), C(white), S(4) * velocity, DT(8)); break;
  3619. case $(144) ImSpinner::Spinner4Caleidospcope (Name("Spinner4Caleidospcope"), R(16),
  3620. T(6), ImColor::HSV(hue * 0.0031f, 0.8f, 0.8f), S(4.0f) * velocity, DT(8)); break;
  3621. case $(145) ImSpinner::SpinnerFiveDots (Name("SpinnerSixDots"), R(16),
  3622. T(6), C(white), S(4) * velocity, DT(8)); break;
  3623. case $(146) ImSpinner::SpinnerFillingMem (Name("SpinnerFillingMem"),
  3624. R(16), T(6), ImColor::HSV(hue * 0.001f, 0.8f, 0.8f), spinner_filling_meb_bg, S(4) * velocity); break;
  3625. case $(147) ImSpinner::SpinnerHerbertBalls (Name("SpinnerHerbertBalls"),
  3626. R(16), T(2.3f), C(white), S(2.0f) * velocity, DT(4)); break;
  3627. case $(148) ImSpinner::SpinnerHerbertBalls3D (Name("SpinnerHerbertBalls3D"),
  3628. R(16), T(3.f), C(white), S(1.4f) * velocity); break;
  3629. case $(149) ImSpinner::SpinnerSquareLoading (Name("SpinnerSquareLoanding"),
  3630. R(16), T(2.0f), C(white), S(3.0f) * velocity); break;
  3631. case $(150) ImSpinner::SpinnerTextFading (Name("SpinnerTextFading"), "Loading",
  3632. R(16), T(15.0f), C(ImColor::HSV(hue * 0.0011f, 0.8f, 0.8f)), S(4) * velocity); break;
  3633. case $(151) ImSpinner::SpinnerBarChartAdvSine (Name("SpinnerBarChartAdvSine"),
  3634. R(16), T(5.0f), C(white), S(4.8f) * velocity, 0); break;
  3635. case $(152) ImSpinner::SpinnerBarChartAdvSineFade(Name("SpinnerBarChartAdvSineFade"),
  3636. R(16), T(5.0f), C(white), S(4.8f) * velocity, 0); break;
  3637. case $(153) ImSpinner::SpinnerMovingArcs (Name("SpinnerMovingArcs"),
  3638. R(16), T(4.0f), C(white), S(2.0f) * velocity, DT(4)); break;
  3639. case $(154) ImSpinner::SpinnerFadeTris (Name("SpinnerFadeTris"),
  3640. R(20), C(white), S(5.f) * velocity, DT(2)); break;
  3641. case $(155) ImSpinner::SpinnerBounceDots (Name("SpinnerBounceDots"), R(16),
  3642. T(2.5f), C(white), S(3.0f) * velocity, DT(6), 1); break;
  3643. case $(156) ImSpinner::SpinnerRotateDots (Name("SpinnerRotateDots"),
  3644. R(16), T(2), C(white), S(4) * velocity, DT(16), 1); break;
  3645. case $(157) ImSpinner::SpinnerTwinAng360 (Name("SpinnerTwinAng360"),
  3646. R(16), 11, T(2), C(white), CB(ImColor(255, 0, 0)), 2.4f, 2.1f, 1); break;
  3647. case $(158) ImSpinner::SpinnerAngTwin (Name("SpinnerAngTwin1"),
  3648. R(18), 13, T(2), C(ImColor(255, 0, 0)), CB(white), S(3) * velocity, A(1.3f), DT(3), 1); break;
  3649. case $(159) ImSpinner::SpinnerGooeyBalls (Name("SpinnerGooeyBalls"),
  3650. R(16), C(white), S(2.f) * velocity, 1); break;
  3651. case $(160) ImSpinner::SpinnerArcRotation (Name("SpinnerArcRotation"),
  3652. R(13), T(2.5), C(white), S(3) * velocity, DT(15), 1); break;
  3653. case $(161) ImSpinner::SpinnerAng (Name("SpinnerAng90Gravity"),
  3654. R(16), T(1), C(white), CB(ImColor(255, 255, 255, 128)), S(8.f) * velocity, A(PI_DIV_2), 1); break;
  3655. case $(162) ImSpinner::SpinnerAng (Name("SpinnerAng90SinRad"),
  3656. R(16), T(1), C(white), CB(ImColor(255, 255, 255, 0)), S(8.f) * velocity, A(0.75f * PI_2), 2); break;
  3657. case $(163) ImSpinner::SpinnerSquishSquare (Name("SpinnerSquishSquare"),
  3658. R(16), C(white), S(8.f) * velocity); break;
  3659. case $(164) ImSpinner::SpinnerPulsarBall (Name("SpinnerBounceBall"),
  3660. R(16), T(2), C(white), S(4) * velocity, DT(1)); break;
  3661. case $(165) ImSpinner::SpinnerRainbowMix (Name("Spinner"),
  3662. R(16), T(2), ImColor::HSV(0.005f, 0.8f, 0.8f), S(8) * velocity, AMN(0.f), AMX(PI_2), DT(5), 1); break;
  3663. case $(166) ImSpinner::SpinnerAngMix (Name("SpinnerAngMix"),
  3664. R(16), T(1), C(white), S(8.f) * velocity, A(IM_PI), DT(4), 0); break;
  3665. case $(167) ImSpinner::SpinnerAngMix (Name("SpinnerAngMixGravity"),
  3666. R(16), T(1), C(white), S(8.f) * velocity, A(PI_DIV_2), DT(6), 1); break;
  3667. case $(168) ImSpinner::SpinnerScaleBlocks (Name("SpinnerScaleBlocks"),
  3668. R(16), T(8), ImColor::HSV(hue * 0.005f, 0.8f, 0.8f), S(5) * velocity, 1); break;
  3669. case $(169) ImSpinner::SpinnerFadeDots (Name("SpinnerFadeDots3"), R(16),
  3670. T(6), C(white), S(8) * velocity, DT(4), 1); break;
  3671. case $(170) ImSpinner::SpinnerFadeDots (Name("SpinnerFadeDots6"), R(16),
  3672. T(3), C(white), S(8) * velocity, DT(4), 1); break;
  3673. case $(171) ImSpinner::SpinnerFadeDots (Name("SpinnerFadeDots2"), R(16),
  3674. T(2), C(white), S(5) * velocity, DT(8)); break;
  3675. case $(172) ImSpinner::SpinnerScaleDots (Name("SpinnerScaleDots2"), R(16),
  3676. T(2), C(white), S(4) * velocity, DT(8)); break;
  3677. case $(173) ImSpinner::Spinner3SmuggleDots (Name("Spinner3SmuggleDots"), R(16),
  3678. T(3), C(white), S(4) * velocity, DT(8), D(0.25f), true); break;
  3679. case $(174) ImSpinner::SpinnerSimpleArcFade (Name("SpinnerSimpleArcFade"),
  3680. R(13), T(2), C(white), S(4) * velocity); break;
  3681. case $(175) ImSpinner::SpinnerTwinHboDots (Name("SpinnerTwinHboDots"), R(16),
  3682. T(4), C(white), 0.1f, 0.5f, S(1.1f) * velocity, DT(6), D(0.f)); break;
  3683. case $(176) ImSpinner::SpinnerTwinHboDots (Name("SpinnerTwinHboDots2"), R(16),
  3684. T(4), C(white), 0.1f, 0.5f, S(3.1f) * velocity, DT(3), D(-0.5f)); break;
  3685. case $(177) ImSpinner::SpinnerThreeDotsStar (Name("SpinnerThreeDotsStar"), R(16),
  3686. T(4), C(white), 0.1f, 0.5f, S(5.1f) * velocity, D(-0.2f)); break;
  3687. case $(178) ImSpinner::SpinnerSquareSpins (Name("SpinnerSquareSpins"), R(16),
  3688. T(6), C(white), S(2) * velocity); break;
  3689. case $(179) ImSpinner::SpinnerMoonDots (Name("SpinnerMoonDots"), R(16),
  3690. T(8), C(white), CB(ImColor(0, 0, 0)), S(1.1f) * velocity); break;
  3691. case $(180) ImSpinner::SpinnerFilledArcFade (Name("SpinnerFilledArcFade7"),
  3692. R(16), C(white), S(6) * velocity, DT(6), 1); break;
  3693. case $(181) ImSpinner::SpinnerRotateSegmentsPulsar(Name("SpinnerRotateSegmentsPulsar"),
  3694. R(16), T(2), C(white), S(1.1f) * velocity, DT(4), MDT(2)); break;
  3695. case $(182) ImSpinner::SpinnerRotateSegmentsPulsar(Name("SpinnerRotateSegmentsPulsar2"),
  3696. R(16), T(2), C(white), S(1.1f) * velocity, DT(1), MDT(3)); break;
  3697. case $(183) ImSpinner::SpinnerRotateSegmentsPulsar(Name("SpinnerRotateSegmentsPulsar3"),
  3698. R(16), T(2), C(white), S(1.1f) * velocity, DT(3), MDT(3)); break;
  3699. case $(184) ImSpinner::SpinnerPointsArcBounce (Name("SpinnerPointsArcBounce"),
  3700. R(16), T(2), C(white), S(3) * velocity, DT(12), 1, 0.f); break;
  3701. case $(185) ImSpinner::SpinnerSomeScaleDots (Name("SpinnerSomeScaleDots0"),
  3702. R(16), T(4), C(white), S(5.6f) * velocity, 6, 0); break;
  3703. case $(186) ImSpinner::SpinnerSomeScaleDots (Name("SpinnerSomeScaleDots1"),
  3704. R(16), T(4), C(white), S(6.6f) * velocity, 6, 1); break;
  3705. case $(187) ImSpinner::SpinnerPointsArcBounce (Name("SpinnerPointsArcBounce2"),
  3706. R(16), T(2), C(white), S(3) * velocity, DT(12), 1, 0.5f); break;
  3707. case $(188) ImSpinner::SpinnerPointsArcBounce (Name("SpinnerPointsArcBounce3"),
  3708. R(16), T(2), C(white), S(3) * velocity, DT(12), 2, 0.3f); break;
  3709. case $(189) ImSpinner::SpinnerPointsArcBounce (Name("SpinnerPointsArcBounce4"),
  3710. R(16), T(2), C(white), S(3) * velocity, DT(12), 3, 0.3f); break;
  3711. case $(190) ImSpinner::SpinnerTwinBlocks (Name("SpinnerTwinBlocks"),
  3712. R(16), T(7), C(ImColor(255, 255, 255, 30)), CB(ImColor::HSV(hue * 0.005f, 0.8f, 0.8f)), S(5) * velocity); break;
  3713. }
  3714. #undef $
  3715. }
  3716. ImGui::PopID();
  3717. };
  3718. if( ImGui::BeginTable("Demo table", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersInnerV) )
  3719. {
  3720. ImGui::TableNextColumn(); // Grid
  3721. {
  3722. // Extra 'Child region' needed here, to make scrollable-area
  3723. if(ImGui::BeginChild("Grid"))
  3724. {
  3725. ImGuiStyle& style = ImGui::GetStyle();
  3726. // Store previous Item spacing & Window padding (to restore it later)
  3727. const ImVec2 prevSpacing = style.ItemSpacing;
  3728. const ImVec2 prevPadding = style.WindowPadding;
  3729. // Set Item spacing & Window padding as zero
  3730. style.ItemSpacing = style.WindowPadding = {0.f, 0.f};
  3731. // -----------------------------------------------------------------
  3732. // For drawing spinners used 'Row-wrap' layout, same as in
  3733. // Dear ImGui Demo > Layout > Basic Horizontal Layout > Manual wrapping:
  3734. // https://github.com/ocornut/imgui/blob/1029f57b8aa9118d08413d1d8a6dd9d32cf0d5f1/imgui_demo.cpp#L2866-L2878
  3735. const float region_visible_x2 = ImGui::GetWindowPos().x + ImGui::GetColumnWidth();
  3736. const ImVec2 item_size = ImVec2(widget_size, widget_size);
  3737. for(int current_spi = 0; current_spi < num_spinners; current_spi++)
  3738. {
  3739. // BeginChild here needed to restrict item width&height by specific size
  3740. if( ImGui::BeginChild(100 + current_spi, item_size, false, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NavFlattened) )
  3741. {
  3742. draw_spinner(current_spi, widget_size);
  3743. }
  3744. ImGui::EndChild();
  3745. // Show tooltip over spinner
  3746. if( ImGui::IsItemHovered() )
  3747. {
  3748. //if( )
  3749. ImGui::BeginTooltip();
  3750. {
  3751. // Number
  3752. ImGui::TextDisabled("%04u", current_spi);
  3753. // Spinner name
  3754. if(__nn.count(current_spi)) {
  3755. ImGui::SameLine();
  3756. ImGui::Text(" - %s", __nn[current_spi] );
  3757. }
  3758. ImGui::EndTooltip();
  3759. }
  3760. }
  3761. // -------------------------------------------------------------
  3762. const float last_item_x2 = ImGui::GetItemRectMax().x;
  3763. const float next_item_x2 = last_item_x2 + style.ItemSpacing.x + item_size.x; // Expected position if next item was on same line
  3764. if ((current_spi + 1 < num_spinners) && (next_item_x2 < region_visible_x2)) {
  3765. ImGui::SameLine();
  3766. }
  3767. }
  3768. // -----------------------------------------------------------------
  3769. // Restore previous Item spacing & Window padding
  3770. style.ItemSpacing = prevSpacing;
  3771. style.WindowPadding = prevPadding;
  3772. }
  3773. ImGui::EndChild();
  3774. }
  3775. // ---------------------------------------------------------------------
  3776. ImGui::TableNextColumn(); // Options
  3777. {
  3778. ImGui::SliderFloat("Velocity", &velocity, 0.0f, 10.0f, "velocity = %.2f");
  3779. ImGui::Checkbox("Show Numbers", &show_number);
  3780. ImGui::SliderFloat("Grid size", &widget_size, 0.0f, 100.0f, "size = %.2f");
  3781. // -----------------------------------------------------------------
  3782. // Spinner-related parameters
  3783. constexpr ImGuiColorEditFlags COLOR_EDIT_FLAGS =
  3784. ImGuiColorEditFlags_PickerHueWheel |
  3785. ImGuiColorEditFlags_NoSidePreview |
  3786. ImGuiColorEditFlags_NoInputs |
  3787. ImGuiColorEditFlags_NoAlpha;
  3788. if(__nn.count(last_cci)) ImGui::Separator();
  3789. if (__rr.count(last_cci)) ImGui::SliderFloat("Radius", &__rr[last_cci], 0.0f, 100.0f, "radius = %.2f");
  3790. if (__tt.count(last_cci)) ImGui::SliderFloat("Thickness", &__tt[last_cci], 0.0f, 100.0f, "thickness = %.2f");
  3791. if (__cc.count(last_cci)) {
  3792. ImGui::Checkbox("Change Color", &__hc[last_cci]);
  3793. if (__hc[last_cci]) { __cc[last_cci] = ImColor::HSV(hue * 0.005f, 0.8f, 0.8f); }
  3794. else {
  3795. ImGui::SameLine(); ImGui::SetNextItemWidth(120);
  3796. ImGui::ColorPicker3("##MyColor", (float *)&__cc[last_cci], COLOR_EDIT_FLAGS);
  3797. }
  3798. }
  3799. if (__cb.count(last_cci)) {
  3800. ImGui::Checkbox("Change Bg Color", &__hcb[last_cci]);
  3801. if (__hcb[last_cci]) { __cb[last_cci] = ImColor::HSV(hue * 0.008f, 0.8f, 0.8f); }
  3802. else {
  3803. ImGui::SameLine(); ImGui::SetNextItemWidth(120);
  3804. ImGui::ColorPicker3("##MyBgColor", (float *)&__cb[last_cci], COLOR_EDIT_FLAGS);
  3805. }
  3806. }
  3807. if (__ss.count(last_cci)) ImGui::SliderFloat("Speed", &__ss[last_cci], 0.0f, 100.0f, "speed = %.2f");
  3808. if (__aa.count(last_cci)) ImGui::SliderFloat("Angle", &__aa[last_cci], 0.0f, PI_2, "angle = %.2f");
  3809. if (__amn.count(last_cci)) ImGui::SliderFloat("Angle Min", &__amn[last_cci], 0.0f, PI_2, "angle min = %.2f");
  3810. if (__amx.count(last_cci)) ImGui::SliderFloat("Angle Max", &__amx[last_cci], 0.0f, PI_2, "angle max = %.2f");
  3811. if (__dt.count(last_cci)) ImGui::SliderInt("Dots", &__dt[last_cci], 1, 100, "dots = %u");
  3812. if (__mdt.count(last_cci)) ImGui::SliderInt("MidDots", &__mdt[last_cci], 1, 100, "mid dots = %u");
  3813. if (__dd.count(last_cci)) ImGui::SliderFloat("Delta", &__dd[last_cci], -1.f, 1.f, "delta = %f");
  3814. }
  3815. ImGui::EndTable();
  3816. }
  3817. }
  3818. #endif // IMSPINNER_DEMO
  3819. }
  3820. #endif // _IMSPINNER_H_