| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453 | /** LaGUI: A graphical application framework.* Copyright (C) 2022-2023 Wu Yiming** This program is free software: you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation, either version 3 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program.  If not, see <http://www.gnu.org/licenses/>.*/#if defined(LA_USE_GLES) || defined(LAGUI_ANDROID)#define NANOVG_GLES3_IMPLEMENTATION#else#define NANOVG_GL3_IMPLEMENTATION#endif#include "la_5.h"#include <stdio.h>#include <stdlib.h>#include <math.h>#include <time.h>#ifdef LA_LINUX#include <execinfo.h>#include <signal.h>#include <sys/time.h>#include <X11/Xlib.h>#include <X11/Xutil.h>#include <X11/Xos.h>#include <X11/keysymdef.h>#include <X11/XKBlib.h>#include <X11/extensions/XInput.h>#include <X11/extensions/XInput2.h>#include <X11/extensions/Xfixes.h>#include <X11/extensions/Xrandr.h>#include <X11/Xcursor/Xcursor.h>#include <X11/cursorfont.h>#include <GL/glx.h>#endif#ifdef _WIN32#include <GL/wglew.h>#include <GL/wgl.h>#include <shellscalingapi.h>#endif#ifdef LAGUI_ANDROID#include <GLES3/gl32.h>#include <jni.h>#include <android/log.h>#include <android/native_activity.h>#include <android/native_window.h>#include <android/native_window_jni.h>#include <android_native_app_glue.h>#include <android/window.h>#include <android/asset_manager.h>#include <android/input.h>#include <android/keycodes.h> FILE *funopen(const void *cookie, int (*readfn)(void *, char *, int), int (*writefn)(void *, const char *, int),              fpos_t (*seekfn)(void *, fpos_t, int), int (*closefn)(void *));static int android_read(void *cookie, char *buf, int size);static int android_write(void *cookie, const char *buf, int size);static fpos_t android_seek(void *cookie, fpos_t offset, int whence);static int android_close(void *cookie);void la_InitAndroidPlatform(struct android_app *app);static void la_AndroidCommandCallback(struct android_app *app, int32_t cmd);static int32_t la_AndroidInputCallback(struct android_app *app, AInputEvent *event);void la_InitAndroidPlatform(struct android_app *app);#endifLA MAIN={0};extern tnsMain *T;int deb = 0;laOperator *DEB;laColumn *DEBUG_C;#ifdef _WIN32#define LA_GUI_WNDCLASS_NAME L"NUL4_GUI_CLASS"#else#define LA_GUI_WNDCLASS_NAME "NUL4_GUI_CLASS"#endif#ifdef LA_LINUXtypedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);\typedef void (*glXSwapIntervalEXTProc)(Display *dpy, GLXDrawable drawable, int interval);glXCreateContextAttribsARBProc glXCreateContextAttribsF;glXSwapIntervalEXTProc glXSwapIntervalEXTF;#endif#ifdef LA_LINUXstatic void la_PrintWacomValuators(Display *display, XIAnyClassInfo **classes, int num_classes){    int i;    for (i = 0; i < num_classes; i++) {        if (classes[i]->type == XIValuatorClass) {            XIValuatorClassInfo *v = (XIValuatorClassInfo*)classes[i];            logPrint("        Valuator %d: '%s'\n", v->number, (v->label) ?  XGetAtomName(display, v->label) : "No label");            logPrint("            Range: %f - %f\n", v->min, v->max);            logPrint("            Resolution: %d units/m\n", v->resolution);            logPrint("            Mode: %s\n", v->mode == XIModeAbsolute ? "absolute": "relative");            if (v->mode == XIModeAbsolute) logPrint("            Current value: %f\n", v->value);        }    }}static void la_RegisterWacomEventMasks(Display *display, int deviceid, real* max_pressure) {	XIDeviceInfo *info, *dev;	int i, ndevices;	dev = XIQueryDevice(display, deviceid, &ndevices);    XIEventMask *mask=memAcquireSimple(sizeof(XIEventMask));    mask->deviceid = deviceid;    mask->mask_len = XIMaskLen(XI_RawMotion);    mask->mask=memAcquireSimple(mask->mask_len);    memset(mask->mask, 0, mask->mask_len);	XISetMask(mask->mask, XI_RawMotion);    XISelectEvents(display, DefaultRootWindow(display), mask, 1);    int FoundMax=0;    for (i = 0; i < dev->num_classes; i++) {        if (dev->classes[i]->type == XIValuatorClass) {            XIValuatorClassInfo *v = (XIValuatorClassInfo*)dev->classes[i];            if(v->number==2){ *max_pressure=v->max; FoundMax=1; break; }        }    }    if(!FoundMax){*max_pressure=65535;}	logPrint("    Device Name: '%s' (%d)\n", dev->name, dev->deviceid);	//la_PrintWacomValuators(display, dev->classes, dev->num_classes);    XIFreeDeviceInfo(dev);}int la_DeviceProbablyHasPressure(XIDeviceInfo* dev){    int axis=0;    for (int i = 0; i < dev->num_classes; i++) {        if (dev->classes[i]->type == XIValuatorClass){ axis++; }    }    return axis>=3;}#define LA_G_STYLUS(dev) \    (la_DeviceProbablyHasPressure(dev)&&(!MAIN.WacomDeviceStylus))#define LA_G_ERASER \    (!MAIN.WacomDeviceEraser)void la_ScanWacomDevices(Display *display, int deviceid){    XIDeviceInfo *info, *dev;    int ndevices;    int i; char * word;    int LikelyPen=-1,LikelyEraser=-1;    int _event, _error;    if (!XQueryExtension(MAIN.dpy, "XInputExtension", &MAIN.xi_opcode, &_event, &_error)) {        logPrint("X Input extension not available, wacom pressure events are not available.\n"); return;    }    info = XIQueryDevice(display, deviceid, &ndevices);    for(i = 0; i < ndevices; i++) {        dev = &info[i]; strToLower(dev->name);        if (strstr(dev->name, "pen pen")){ if(LA_G_STYLUS(dev)) MAIN.WacomDeviceStylus = dev->deviceid; } // some wacom tablets "wacom bamboo connect pen pen"        elif (strstr(dev->name, "stylus pen")){ if(LA_G_STYLUS(dev)) MAIN.WacomDeviceStylus = dev->deviceid; } // some huion ones "HUION 256C PEN STYLUS Pen"        int is_ipts=0; if(strstr(dev->name, "ipts")){ is_ipts=1; }        word = strtok (dev->name," ");        while (1) {            word = strtok (NULL, " "); if (!word) break;            if (strstr("stylus", word)){ if(LA_G_STYLUS(dev)) MAIN.WacomDeviceStylus = dev->deviceid; }// wacom            elif (strstr("eraser", word)){ if(LA_G_ERASER) MAIN.WacomDeviceEraser = dev->deviceid; }// wacom            elif (is_ipts && strcmp("pen", word) == 0){ if(LA_G_STYLUS(dev)) MAIN.WacomDeviceStylus = dev->deviceid; }// surface ipts            elif (is_ipts && strcmp("eraser", word) == 0){ if(LA_G_ERASER) MAIN.WacomDeviceEraser = dev->deviceid; }// surface ipts            elif (strstr("pen", word)){ if(LA_G_STYLUS(dev)) MAIN.WacomDeviceStylus = dev->deviceid; }// generic pen        }    }    if(!MAIN.WacomDeviceStylus){        for(i = 0; i < ndevices; i++) {            dev = &info[i]; strToLower(dev->name);            if (strstr(dev->name, "stylus")){ if(LA_G_STYLUS(dev)) MAIN.WacomDeviceStylus = dev->deviceid; } // xwayland reports "stylus:10" etc        }    }    if(!MAIN.WacomDeviceStylus){        for(i = 0; i < ndevices; i++) { dev = &info[i];            if(la_DeviceProbablyHasPressure(dev)){ MAIN.WacomDeviceStylus=dev->deviceid; break; } // generic stylus with unknown name        }    }    if(!MAIN.WacomDeviceEraser){        if (strstr(dev->name, "eraser")){ if(LA_G_ERASER) MAIN.WacomDeviceEraser = dev->deviceid; } // xwayland reports "eraser:10" etc    }    if(!MAIN.WacomDeviceEraser){        for(i = 0; i < ndevices; i++) { dev = &info[i]; if(MAIN.WacomDeviceStylus == dev->deviceid) continue;            if(la_DeviceProbablyHasPressure(dev)){ MAIN.WacomDeviceStylus=dev->deviceid;  break; } // generic eraser with unknown name        }    }    if(MAIN.WacomDeviceStylus || MAIN.WacomDeviceEraser){        logPrintNew("Found wacom devices:\n");        if(MAIN.WacomDeviceStylus) la_RegisterWacomEventMasks(display, MAIN.WacomDeviceStylus,&MAIN.StylusMaxPressure);        if(MAIN.WacomDeviceEraser) la_RegisterWacomEventMasks(display, MAIN.WacomDeviceEraser,&MAIN.EraserMaxPressure);	}else{        logPrintNew("No wacom pen device connected.\n");	}    XIFreeDeviceInfo(info);}void laHideCursor(){#ifdef NDEBUG    if(!MAIN.CurrentWindow) return; XFixesHideCursor(MAIN.dpy, MAIN.CurrentWindow->win);#endif}void laShowCursor(){#ifdef NDEBUG    if(!MAIN.CurrentWindow) return; XFixesShowCursor(MAIN.dpy, MAIN.CurrentWindow->win);#endif}int la_XErrorHandler(Display *display, XErrorEvent *event){    char buf[512];    XGetErrorText(display, event->error_code, buf, sizeof(buf));    printf("X Error:\n%s\n",buf);    return 0;}SYSWINDOW la_CreateWindowX11(int x, int y, int w, int h, char *title, int SyncToVBlank, GLXContext* r_glc, void* egl_surf){    XSetWindowAttributes swa;    XWindowAttributes wa;    swa.event_mask =         KeyPressMask|KeyReleaseMask|StructureNotifyMask|SubstructureNotifyMask|        ButtonMotionMask|ButtonPressMask|ButtonReleaseMask|ExposureMask|PointerMotionMask;    swa.colormap = MAIN.cmap;    SYSWINDOW root = DefaultRootWindow(MAIN.dpy);    SYSWINDOW win = XCreateWindow(MAIN.dpy, root, x,y, w, h, 0, MAIN.xvi->depth, InputOutput, MAIN.xvi->visual, CWColormap | CWEventMask, &swa);    XSetWMProtocols(MAIN.dpy , win, &MAIN.MsgDelWindow, 1);    if(x>0||y>0){        XSizeHints    my_hints = {0};        my_hints.flags = PPosition;        my_hints.x = x; my_hints.y = y;        XSetNormalHints(MAIN.dpy, win, &my_hints);    }    XStoreName(MAIN.dpy, win, title);#ifdef LA_USE_GLES    static const EGLint ctx_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE };    (*r_glc)=eglCreateContext(MAIN.egl_dpy, MAIN.BestFBC, MAIN.glc, ctx_attribs );    if (!(*r_glc)){ printf("\n\tcannot create gl context\n\n"); exit(0); }    EGLSurface* surf=egl_surf;    (*surf)=eglCreateWindowSurface(MAIN.egl_dpy, MAIN.BestFBC, win, NULL);    if (!(*surf)) { printf("Error: eglCreateWindowSurface failed %d\n",eglGetError()); exit(1); }    tnsContextMakeCurrent((*r_glc),win,(*surf));#else    int attribs[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, MAIN.GLMajor, GLX_CONTEXT_MINOR_VERSION_ARB, MAIN.GLMinor, 0};    if (((*r_glc) = glXCreateContextAttribsF(MAIN.dpy, MAIN.BestFBC, MAIN.glc, GL_TRUE, attribs)) == NULL){        printf("\n\tcannot create gl context\n\n"); exit(0);    }    tnsContextMakeCurrent((*r_glc),win,0);    int sync=SyncToVBlank?1:0; glXSwapIntervalEXTF(MAIN.dpy, win, sync);#endif    XSetLocaleModifiers("");    MAIN.im = XOpenIM(MAIN.dpy, NULL, NULL, NULL);    if(!MAIN.im){        XSetLocaleModifiers("@im=local");        MAIN.im = XOpenIM(MAIN.dpy, NULL, NULL, NULL);    }    if(!MAIN.im){        XSetLocaleModifiers("@im=none");        MAIN.im = XOpenIM(MAIN.dpy, NULL, NULL, NULL);    }    if(!MAIN.im){        XSetLocaleModifiers("@im=");        MAIN.im = XOpenIM(MAIN.dpy, NULL, NULL, NULL);    }    if(!MAIN.im){        logPrint("Can't open a input method.\n");    }    if(MAIN.im){        MAIN.ic = XCreateIC(MAIN.im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, win, NULL);        XSetICFocus(MAIN.ic);    }    XClassHint ch; ch.res_name = "LAGUI_WINDOW"; ch.res_class = "LAGUI_WINDOW";    XSetClassHint(MAIN.dpy, win, &ch);#define _NET_WM_STATE_ADD 1    if(w<0&&h<0){        XEvent xev;        Atom wm_state  =  XInternAtom(MAIN.dpy, "_NET_WM_STATE", False);        Atom max_horz  =  XInternAtom(MAIN.dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", False);        Atom max_vert  =  XInternAtom(MAIN.dpy, "_NET_WM_STATE_MAXIMIZED_VERT", False);        memset(&xev, 0, sizeof(xev));        xev.type = ClientMessage;        xev.xclient.window = win;        xev.xclient.message_type = wm_state;        xev.xclient.format = 32;        xev.xclient.data.l[0] = _NET_WM_STATE_ADD;        xev.xclient.data.l[1] = max_horz;        xev.xclient.data.l[2] = max_vert;        XSendEvent(MAIN.dpy, DefaultRootWindow(MAIN.dpy), False, SubstructureNotifyMask, &xev);    }    return win;};void la_DestroySystemWindowX11(laWindow* w) {    tnsContextMakeCurrent(0,0,0);    tnsDeleteContext(w->glc);#ifdef LA_USE_GLES    eglDestroySurface(MAIN.egl_dpy, w->egl_surf);#endif    XDestroyWindow(MAIN.dpy, w->win);};#endif //linux#ifdef _WIN32#include <msgdef.h>#include <wintab.h>#include <wintab_utils.h>#define PACKETDATA	(PK_X | PK_Y | PK_Z | PK_STATUS | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION | PK_TIME | PK_CURSOR)#define PACKETMODE	PK_BUTTONS#include <pktdef.h>void la_OpenWacomWinTab(HWND hwnd){    if((!MAIN.WinTabAvailable)||(MAIN.WinTabOpened)) return;    static LOGCONTEXT glogContext = { 0 };    HCTX hctx = NULL;	UINT wDevice = 0; UINT wExtX = 0; UINT wExtY = 0;	UINT wWTInfoRetVal = 0; AXIS TabletX = { 0 }; AXIS TabletY = { 0 }; AXIS TabletZ = { 0 };	glogContext.lcOptions |= CXO_SYSTEM;	wWTInfoRetVal = gpWTInfoA(WTI_DEFSYSCTX, 0, &glogContext);	assert(wWTInfoRetVal == sizeof(LOGCONTEXT));	assert(glogContext.lcOptions & CXO_SYSTEM);	wsprintf(glogContext.lcName, "PrsTest Digitizing %p", MAIN.hinstance);	glogContext.lcOptions |= CXO_MESSAGES|CXO_CSRMESSAGES;	glogContext.lcPktData = PACKETDATA;	glogContext.lcPktMode = PACKETMODE;	glogContext.lcMoveMask = PACKETDATA;	glogContext.lcBtnUpMask = glogContext.lcBtnDnMask;	wWTInfoRetVal = gpWTInfoA(WTI_DEVICES + 0, DVC_X, &TabletX);	assert(wWTInfoRetVal == sizeof(AXIS));	wWTInfoRetVal = gpWTInfoA(WTI_DEVICES, DVC_Y, &TabletY);	assert(wWTInfoRetVal == sizeof(AXIS));    wWTInfoRetVal = gpWTInfoA(WTI_DEVICES, DVC_Z, &TabletZ);    if (wWTInfoRetVal) {        assert(wWTInfoRetVal == sizeof(AXIS));        MAIN.WinTabMaxHover = TabletZ.axMax;    }    AXIS tabletPressure = { 0 };    gpWTInfoA(WTI_DEVICES, DVC_NPRESSURE, &tabletPressure); MAIN.WinTabMaxPenPressure = tabletPressure.axMax + 1;    //glogContext.lcInOrgX = 0;	//glogContext.lcInOrgY = 0;	//glogContext.lcInExtX = TabletX.axMax;	//glogContext.lcInExtY = TabletY.axMax;    gpWTInfoA(WTI_DEFSYSCTX, CTX_INORGX, &glogContext.lcInOrgX);    gpWTInfoA(WTI_DEFSYSCTX, CTX_INORGY, &glogContext.lcInOrgY);    gpWTInfoA(WTI_DEFSYSCTX, CTX_INEXTX, &glogContext.lcInExtX);    gpWTInfoA(WTI_DEFSYSCTX, CTX_INEXTY, &glogContext.lcInExtY);    gpWTInfoA(WTI_DEFSYSCTX, CTX_OUTORGX, &glogContext.lcOutOrgX);    gpWTInfoA(WTI_DEFSYSCTX, CTX_OUTORGY, &glogContext.lcOutOrgY);    gpWTInfoA(WTI_DEFSYSCTX, CTX_OUTEXTX, &glogContext.lcOutExtX);    gpWTInfoA(WTI_DEFSYSCTX, CTX_OUTEXTY, &glogContext.lcOutExtY);    gpWTInfoA(WTI_DEFSYSCTX, CTX_SYSORGX, &glogContext.lcSysOrgX);    gpWTInfoA(WTI_DEFSYSCTX, CTX_SYSORGY, &glogContext.lcSysOrgY);    gpWTInfoA(WTI_DEFSYSCTX, CTX_SYSEXTX, &glogContext.lcSysExtX);    gpWTInfoA(WTI_DEFSYSCTX, CTX_SYSEXTY, &glogContext.lcSysExtY);    //printf("%d %d\n", glogContext.lcInOrgX, glogContext.lcInOrgY);    //printf("%d %d\n", glogContext.lcInExtX, glogContext.lcInExtY);    //printf("%d %d\n", glogContext.lcOutOrgX, glogContext.lcOutOrgY);    //printf("%d %d\n", glogContext.lcOutExtX, glogContext.lcOutExtY);    //printf("%d %d\n", glogContext.lcSysOrgX, glogContext.lcSysOrgY);    //printf("%d %d\n", glogContext.lcSysExtX, glogContext.lcSysExtY);    glogContext.lcOutOrgX = GetSystemMetrics(SM_XVIRTUALSCREEN);	glogContext.lcOutOrgY = GetSystemMetrics(SM_YVIRTUALSCREEN);	glogContext.lcOutExtX = GetSystemMetrics(SM_CXVIRTUALSCREEN); //SM_CXSCREEN);	glogContext.lcOutExtY = -GetSystemMetrics(SM_CYVIRTUALSCREEN);	// lower left to upper left. SM_CYSCREEN);    //printf("%d %d\n", glogContext.lcOutOrgX, glogContext.lcOutOrgY);    //printf("%d %d\n", glogContext.lcOutExtX, glogContext.lcOutExtY);	hctx = gpWTOpenA(hwnd, &glogContext, FALSE);    if (!hctx)return;    gpWTEnable(hctx, 1); MAIN.WinTabOpened = 1;    logPrintNew("Successfully opened Wacom input device via WinTab.\n");}void laHideCursor() {    if (!MAIN.CurrentWindow) return; //impl}void laShowCursor() {    if (!MAIN.CurrentWindow) return; //impl}static PIXELFORMATDESCRIPTOR cpfd = {    sizeof(PIXELFORMATDESCRIPTOR),1,    PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_SWAP_COPY | PFD_DOUBLEBUFFER,    PFD_TYPE_RGBA,    8,    0, 0, 0, 0, 0, 0,    0, 0, 0,    0, 0, 0, 0,    32,    8, 0,    0,    0, 0, 0, 0};void la_SetupPxlFormat(HDC hdc, int* nRegularFormat, int* nMSFormat) {    int nBestMS = 0;    int i;    int iResults[9];    int iAttributes[9] = { WGL_SUPPORT_OPENGL_ARB, // 0        WGL_ACCELERATION_ARB,   // 1        WGL_DRAW_TO_WINDOW_ARB, // 2        WGL_DOUBLE_BUFFER_ARB,  // 3        WGL_PIXEL_TYPE_ARB,     // 4        WGL_DEPTH_BITS_ARB,     // 5        WGL_STENCIL_BITS_ARB,   // 6        WGL_SAMPLE_BUFFERS_ARB, // 7        WGL_SAMPLES_ARB };      // 8    // How many pixelformats are there?    int nFormatCount[] = { 0 };    int attrib[] = { WGL_NUMBER_PIXEL_FORMATS_ARB };    if (!wglGetPixelFormatAttribivARB)        wglGetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)        wglGetProcAddress("wglGetPixelFormatAttribivARB");    wglGetPixelFormatAttribivARB(hdc, 1, 0, 1, attrib, nFormatCount);    for (i = 0; i < nFormatCount[0]; i++){        wglGetPixelFormatAttribivARB(hdc, i + 1, 0, 9, iAttributes, iResults);        if (iResults[0] == 1 && iResults[1] == WGL_FULL_ACCELERATION_ARB && iResults[2] == 1)            if (iResults[3] == 1)                    // Double buffered                if (iResults[4] == WGL_TYPE_RGBA_ARB)    // Full Color                    if (iResults[5] >= 24)                   // Any Depth greater than 16                        if (iResults[6] > 0) { *nRegularFormat = i; break; }    }    SetPixelFormat(hdc, *nRegularFormat, &cpfd);};void la_SetupGLEnviornment(laWindow* window, HWND hwnd, int Sync) {    GLint Attrib[] = { WGL_CONTEXT_MAJOR_VERSION_ARB, MAIN.GLMajor,                  WGL_CONTEXT_MINOR_VERSION_ARB, MAIN.GLMinor,        WGL_CONTEXT_PROFILE_MASK_ARB,WGL_CONTEXT_CORE_PROFILE_BIT_ARB,        //WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, GL_TRUE,        0 };    HGLRC hglrc = 0;    HDC hdc = 0;    int a, b;    hdc = GetDC(hwnd);    la_SetupPxlFormat(hdc, &a, &b);    hglrc = wglCreateContextAttribsARB(hdc, MAIN.glc, Attrib);    if (!hglrc) SEND_PANIC_ERROR("Can't Create Opengl Context!\n");    tnsContextMakeCurrent(hglrc, hdc,0);    //int sync = Sync ? 1 : 0; wglSwapIntervalEXT(sync);    wglSwapIntervalEXT(-1);    window->win = hwnd; window->glc = hglrc; window->hdc = hdc;};SYSWINDOW la_CreateWindowWin32(int x, int y, int w, int h, char* title, int SyncToVBlank, SYSGLCONTEXT* r_glc) {    HINSTANCE* inst = &MAIN.hinstance;    HWND hwnd = CreateWindow(LA_GUI_WNDCLASS_NAME, title, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,        x, y, w, h, 0, 0, *inst, 0);    if (!hwnd) { int a = GetLastError(); printf("%d", a); return 0; }    if (!MAIN.WinTabOpened) { la_OpenWacomWinTab(hwnd); }    return hwnd;};void la_DestroySystemWindowWin32(laWindow* w) {    tnsContextMakeCurrent(0,0,0);    tnsDeleteContext(w->glc);    ReleaseDC(w->win, w->hdc);    DestroyWindow(w->win);};#endif#ifdef LAGUI_ANDROIDSYSWINDOW la_CreateWindowAndroid(){    return 0;};void laShowCursor(){}void laHideCursor(){}#endif#ifdef LA_LINUXvoid la_HandlerSIGSEGV(int sig) {    void *array[30];    size_t sz;    sz = backtrace(array, 30);    fprintf(stdout, "LaGUI recieved error signal %d:\n The program terminated unexpectedly.\n", sig);    backtrace_symbols_fd(array, sz, STDERR_FILENO);    exit(1);}#endifvoid la_glDebugOutput(GLenum source, GLenum type, unsigned int id,    GLenum severity, GLsizei length, const char* message, const void* userParam) {//#ifndef LAGUI_ANDROID    // ignore non-significant error/warning codes    if (id==131169 || id==131185 || id==131218 || id==131204 || id==131076 || id==7||id==8) return;    logPrint("GL %d: %s\n", id, message);    char* strsource="",*strtype="",*strseverity="";    switch (source) {    case GL_DEBUG_SOURCE_API:             strsource = "API"; break;    case GL_DEBUG_SOURCE_WINDOW_SYSTEM:   strsource = "Window System"; break;    case GL_DEBUG_SOURCE_SHADER_COMPILER: strsource = "Shader Compiler"; break;    case GL_DEBUG_SOURCE_THIRD_PARTY:     strsource = "Third Party"; break;    case GL_DEBUG_SOURCE_APPLICATION:     strsource = "Application"; break;    case GL_DEBUG_SOURCE_OTHER:           strsource = "Other"; break;    }    switch (type) {    case GL_DEBUG_TYPE_ERROR:               strtype = "Error"; break;    case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: strtype = "Deprecated Behaviour"; break;    case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:  strtype = "Undefined Behaviour"; break;    case GL_DEBUG_TYPE_PORTABILITY:         strtype = "Portability"; break;    case GL_DEBUG_TYPE_PERFORMANCE:         strtype = "Performance"; break;    case GL_DEBUG_TYPE_MARKER:              strtype = "Marker"; break;    case GL_DEBUG_TYPE_PUSH_GROUP:          strtype = "Push Group"; break;    case GL_DEBUG_TYPE_POP_GROUP:           strtype = "Pop Group"; break;    case GL_DEBUG_TYPE_OTHER:               strtype = "Other"; break;    }    switch (severity) {    case GL_DEBUG_SEVERITY_HIGH:         strseverity = "High"; break;    case GL_DEBUG_SEVERITY_MEDIUM:       strseverity = "Medium"; break;    case GL_DEBUG_SEVERITY_LOW:          strseverity = "Low"; break;    case GL_DEBUG_SEVERITY_NOTIFICATION: strseverity = "Notification"; break;    }    logPrint("%s | %s | %s\n\n", strsource,strtype,strseverity);//#endif}static void la_SetCurrentGLContextDebug(){//#ifndef LAGUI_ANDROID    int force=MAIN.InitArgs.GLDebug;    if(MAIN.EnableGLDebug || force){ glEnable(GL_DEBUG_OUTPUT); }else{ glDisable(GL_DEBUG_OUTPUT); }    if(MAIN.GLDebugSync || force){ glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); }else{ glDisable(GL_DEBUG_OUTPUT_SYNCHRONOUS); }    glDebugMessageCallback(la_glDebugOutput, 0);    int sev=GL_DONT_CARE;    if(!force){        switch(MAIN.GLDebugLevel){         default: sev=GL_DONT_CARE; break;        case 1: sev=GL_DEBUG_SEVERITY_NOTIFICATION; break;        case 2: sev=GL_DEBUG_SEVERITY_LOW; break;        case 3: sev=GL_DEBUG_SEVERITY_MEDIUM; break;        case 4: sev=GL_DEBUG_SEVERITY_HIGH; break;        }    }    glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, sev, 0, 0, GL_TRUE);//#endif}void la_NotifyGLDebugChanges(){    MAIN.GLDebugNeedsUpdate=1; for(laWindow* w=MAIN.Windows.pFirst;w;w=w->Item.pNext){ w->GLDebugNeedsUpdate=1; }}void la_SetupWindowGLStates(laWindow* w){    tnsBindVertexArray(w->vao); tnsUnbindTexture(); tnsUseImmShader(); tnsEnableShaderv(T->immShader);    if(w->GLDebugNeedsUpdate){        tnsContextMakeWindowCurrent(w);        la_SetCurrentGLContextDebug(); w->GLDebugNeedsUpdate=0;    }}int la_CreateSystemWindow(laWindow *window, int SyncToVBlank){    SYSGLCONTEXT glc;#ifdef LA_LINUX    void* egl_surf=0;#ifdef LA_USE_GLES    egl_surf=&window->egl_surf;#endif    SYSWINDOW hwnd = la_CreateWindowX11(window->X, window->Y, window->W, window->H, window->Title->Ptr, SyncToVBlank, &glc, egl_surf);#endif#ifdef _WIN32    SYSWINDOW hwnd = la_CreateWindowWin32(window->X, window->Y, window->W, window->H, window->Title->Ptr, SyncToVBlank, &glc);#endif#ifdef LAGUI_ANDROID    la_CreateWindowAndroid();    window->win = 1;    window->glc = MAIN.glc;#else    window->win = hwnd;    window->glc = glc;#endif#ifdef _WIN32    la_SetupGLEnviornment(window, hwnd, SyncToVBlank);    RECT rc; GetClientRect(window->win, &rc);    window->CW = rc.right - rc.left;    window->CH = rc.bottom - rc.top;    window->himc = ImmCreateContext();#endif#ifdef LA_LINUX    XWindowAttributes attr;    XGetWindowAttributes(MAIN.dpy, window->win, &attr);    window->CW =attr.width;    window->CH = attr.height;#endif    la_SetCurrentGLContextDebug();    glGenVertexArrays(1,&window->vao); tnsBindVertexArray(window->vao);    la_SetupWindowGLStates(window);#if defined(LA_USE_GLES) || defined(LAGUI_ANDROID)    window->nvg=nvgCreateGLES3(NVG_STENCIL_STROKES|NVG_DEBUG|NVG_ANTIALIAS);#else    window->nvg=nvgCreateGL3(NVG_STENCIL_STROKES|NVG_DEBUG|NVG_ANTIALIAS);#endif    window->OutputShowStripes=0; window->Redraw=1;    window->GLDebugNeedsUpdate=1;    window->UseComposing=0; window->ComposingGamma=1.0; window->ComposingBlackpoint=0.0;    return 1;};void la_DestroySystemWindow(laWindow* wnd){#if defined(LA_USE_GLES) || defined(LAGUI_ANDROID)    nvgDeleteGLES3(wnd->nvg);#else    nvgDeleteGL3(wnd->nvg);#endif#ifdef LA_LINUX    la_DestroySystemWindowX11(wnd);#endif#ifdef _WIN32    la_DestroySystemWindowWin32(wnd);#endif}void la_DestroyWindow(laWindow *wnd){    laLayout *l; laPanel *p; if (!wnd) return;        tnsSwitchToCurrentWindowContext(wnd);    tnsBindVertexArray(0); glDeleteVertexArrays(1,&wnd->vao);    la_StopAllOperators();    strSafeDestroy(&wnd->Title);    //la_PrintUserList(wnd);    //printf("----\n");    while (p = lstPopItem(&wnd->Panels)){ laDestroySinglePanel(p,1); }    while (l = lstPopItem(&wnd->Layouts)){        laDestroyBlocksRecursive(l->FirstBlock);        //la_PrintUserList(l);        //printf("%x %s\n", l, l->ID->Ptr);        strSafeDestroy(&l->ID);        memFree(l);        //la_PrintUserList(wnd);        //printf("----\n");    }    //printf("----\n%x\n",wnd);    //la_PrintUserList(wnd);    la_DestroySystemWindow(wnd);    lstRemoveItem(&MAIN.Windows, wnd);    memFree(wnd);    MAIN.CurrentWindow=MAIN.Windows.pFirst;}void laRenameWindow(laWindow* wnd, char* name){    if((!wnd)||MAIN.ReadingUDF) return;    strSafeSet(&wnd->Title, name);    if(!wnd->win) return;#ifdef LA_LINUX    XStoreName(MAIN.dpy, wnd->win, name);#endif#ifdef _WIN32    int wlen=strlen(name)+1;    int unisize=MultiByteToWideChar(CP_UTF8, 0, name, -1, 0, 0);    WCHAR *unistr=malloc(wlen*sizeof(WCHAR));    MultiByteToWideChar(CP_UTF8, 0, name, -1, unistr, unisize);    int bufsize=WideCharToMultiByte(CP_ACP, 0, unistr, -1, 0, 0, 0, 0);    char* acpstr = malloc(bufsize);    WideCharToMultiByte(CP_ACP, 0, unistr, -1, acpstr, bufsize, 0, 0);    SetWindowText(wnd->win, acpstr);    free(unistr); free(acpstr);#endif}#ifdef LA_LINUXconst char* la_ConvertCursorID(int id){    switch (id) {    case LA_ARROW: return "arrow";    case LA_CROSS: return "cross";    case LA_LEFT_AND_RIGHT: return "sb_h_double_arrow";    case LA_UP_AND_DOWN: return "sb_v_double_arrow";    case LA_MOVE: return "diamond_cross";    case LA_HAND: return "hand1";    case LA_CORNER: return "bottom_right_corner";    }    return "arrow";}#endif#ifdef _WIN32HCURSOR la_ConvertCursorID(int id){    switch (id){    case LA_ARROW: return LoadCursor(0,IDC_ARROW);    case LA_CROSS: return LoadCursor(0,IDC_CROSS);    case LA_LEFT_AND_RIGHT: return LoadCursor(0,IDC_SIZEWE);    case LA_UP_AND_DOWN: return LoadCursor(0, IDC_SIZENS);    case LA_MOVE: return LoadCursor(0, IDC_SIZEALL);    case LA_HAND: return LoadCursor(0, IDC_HAND);    case LA_CORNER: return LoadCursor(0, IDC_SIZENWSE);    }    return LoadCursor(0, IDC_ARROW);;}#endifvoid la_InitThreadEnviornment(){    //pthread_spin_init(&MAIN.csNotifier, //pthread_PROCESS_PRIVATE);}laLogEntry* logEnsure(int Create){    if(!MAIN.Logs.pFirst || Create){        laLogEntry* le=memAcquireSimple(sizeof(laLogEntry));        lstAppendItem(&MAIN.Logs, le);    }    return MAIN.Logs.pLast;}void logPrintTV(int Continued, char* format, va_list v){    if(!format || !format[0]) return;    laLogEntry* le=logEnsure(Continued);    if(MAIN.EnableLogStdOut){ va_list v1; va_copy(v1,v); vprintf(format,v1); }    strSafePrintV(&le->Content, format, v);#ifdef LAGUI_ANDROID    __android_log_print(ANDROID_LOG_DEBUG, "LAGUI", "%s",SSTR(le->Content));#endif    laNotifyUsers("la.logs");}void logPrintT(int Continued, char* format, ...){    if(!format || !format[0]) return;    laLogEntry* le=logEnsure(Continued);    va_list aptr; va_start(aptr, format);    strSafePrint(&le->Content, format, aptr);    va_end(aptr);#ifdef LAGUI_ANDROID    __android_log_print(ANDROID_LOG_DEBUG, "LAGUI", "%s",SSTR(le->Content));#endif    laNotifyUsers("la.logs");}void logPrint(char* format, ...){    va_list aptr; va_start(aptr, format);    logPrintTV(0, format, aptr);    va_end(aptr);}void logPrintNew(char* format, ...){    logEnsure(1);    va_list aptr; va_start(aptr, format);    logPrintTV(0, format, aptr);    va_end(aptr);}void logClear(){    laLogEntry*l;    while(l=lstPopItem(&MAIN.Logs)){ strSafeDestroy(&l->Content); memFree(l); }    laNotifyUsers("la.logs");}laSafeString** la_PerfEnsure(){    MAIN.NextPerfCounter++;    if(MAIN.NextPerfCounter>=32){ MAIN.NextPerfCounter=0; }    return &MAIN.PerfLogs[MAIN.NextPerfCounter];}void la_PerfClear(){    if(!MAIN.ShowPerf){ return; }    MAIN.NextPerfCounter=0; MAIN.NextPerfGroup++; if(MAIN.NextPerfGroup>=32){ MAIN.NextPerfGroup=0; }    memset(&MAIN.PerfCounter[MAIN.NextPerfGroup],0,32*sizeof(real));    for(int i=0;i<32;i++){ strSafeDestroy(&MAIN.PerfLogs[i]); }}void laPerfRecordV(char* format, va_list v){    if(!format || !format[0]) return;    laSafeString** ss=la_PerfEnsure();    strSafePrintV(ss, format, v);    laTimeRecorder tm; laRecordTime(&tm);    MAIN.PerfCounter[MAIN.NextPerfGroup][MAIN.NextPerfCounter] = laTimeElapsedSecondsf(&tm, &MAIN.FrameStartTime);}void laPerfRecord(char* format, ...){    if(!format || !format[0]) return;    laSafeString** ss=la_PerfEnsure();    va_list aptr; va_start(aptr, format);    strSafePrintV(ss, format, aptr);    va_end(aptr);    laTimeRecorder tm; laRecordTime(&tm);    MAIN.PerfCounter[MAIN.NextPerfGroup][MAIN.NextPerfCounter] = laTimeElapsedSecondsf(&tm, &MAIN.FrameStartTime);}void la_PerfDraw(){    tnsScale3d(0.75,0.75,0.75);    int sy=0; laBoxedTheme* bt=_LA_THEME_LABEL; real* color=laThemeColor(bt,LA_BT_TEXT);    int sl=LA_RH*4; char buf[16]; real totval=0; real vals[32];    for(int i=0;i<32;i++){        if(MAIN.PerfLogs[i]){            real value = MAIN.PerfCounter[MAIN.NextPerfGroup][i]-(i>0?MAIN.PerfCounter[MAIN.NextPerfGroup][i-1]:0);            sprintf(buf,"%0.2lf",value*1000); totval+=value; vals[i]=value;            tnsDrawStringAuto(buf,color,0,10000,sy,LA_TEXT_SHADOW);            tnsDrawStringAuto(SSTR(MAIN.PerfLogs[i]),color,sl,10000,sy,LA_TEXT_SHADOW);            sy+=LA_RH;        }    }    real SL=LA_RH*2,SR=LA_RH*3.5; sy=0; tnsColor4dv(color); tnsUseNoTexture();    for(int i=0;i<32;i++){        if(MAIN.PerfLogs[i]){            real r=vals[i]/totval; real use_r=tnsInterpolate(SL,SR,r);            tnsVertex2d(SL,sy); tnsVertex2d(SL,sy+LA_RH); tnsVertex2d(use_r,sy+LA_RH); tnsVertex2d(use_r,sy);            tnsPackAs(GL_TRIANGLE_FAN);            sy+=LA_RH;        }    }    tnsFlush();}laScreen* la_EnsureScreen(char* Name, int mmw, int mmh, int x, int y, int w, int h,int dpi){ if(!Name || !Name[0]) return 0;    laScreen* uses=0;    for(laScreen* s=MAIN.Screens.pFirst;s;s=s->Item.pNext){        if(strSame(SSTR(s->Name),Name)){ s->x=x;s->y=y;s->w=w;s->h=h; uses=s; break; }    }    if(!uses){ uses=memAcquire(sizeof(laScreen)); lstAppendItem(&MAIN.Screens,uses); }    strSafeSet(&uses->Name,Name); strSafeDestroy(&uses->Description);    strSafePrint(&uses->Description,"%dmm x %dmm with %dx%d ~%ddpi",mmw,mmh,w,h,dpi); uses->RoughDPI=dpi;    uses->x=x;uses->y=y;uses->w=w;uses->h=h;    laNotifyUsers("la.user_preferences.screens");    return uses;}void la_RemoveScreen(laScreen*s){    strSafeDestroy(&s->Description); strSafeDestroy(&s->Name);    lstRemoveItem(&MAIN.Screens,s); memFree(s);}void la_RemoveDuplicatedScreenConf(){    laScreen* NextS;    for(laScreen* s=MAIN.Screens.pFirst;s;s=NextS){        NextS = s->Item.pNext;        for(laScreen* fs=s->Item.pNext;fs;fs=fs->Item.pNext){            if(strSame(SSTR(fs->Name),SSTR(s->Name))){ fs->x=s->x;fs->y=s->y;fs->w=s->w;fs->h=s->h; la_RemoveScreen(s); break; }        }    }}laScreen* laGetWindowScreen(laWindow* w){    int l,r,u,b; int area=-1; laScreen* maxs=0;    for(laScreen* s=MAIN.Screens.pFirst;s;s=s->Item.pNext){        l=TNS_MAX2(s->x,w->X); r=TNS_MIN2(s->x+s->w,w->X+w->W);        u=TNS_MAX2(s->y,w->Y); b=TNS_MIN2(s->y+s->h,w->Y+w->H);        int w=(r-l); if(w<0){w=0;} int h=(b-u); if(h<0){h=0;}        int a=w*h; if(a>area){ maxs = s; area = a; }    }    return maxs;}void la_EnsureScreenColorMatrix(laScreen* s){    real* usemat; tnsMatrix44d mat,matinv;    if(s->whitepoint[0]==0.0f || s->primaries[0]==0.0f || s->gamma==0.0f){        logPrint("    Fallback to sRGB configurations\n");        s->gamma=2.2;        static const tnsMatrix44d srgbmat={3.2404542,-1.5371385,-0.4985314,                                           -0.9692660,1.8760108,0.0415560,                                           0.0556434,-0.2040259,1.0572252};        usemat=srgbmat;    }else{        tnsComputeMatrixRGB2XYZ(mat,&s->primaries[0],&s->primaries[2],&s->primaries[4],s->whitepoint);        tnsInverse33d(matinv,mat); usemat=matinv;    }    for(int i=0;i<9;i++){ s->xyz2rgb[i]=usemat[i]; }}void la_UseWindowColorCorrection(laWindow* w){    if(w->OutputColorSpace==255){        if(!w->WhichScreen){ memAssignRef(w,&w->WhichScreen,laGetWindowScreen(w)); }        if(w->WhichScreen){            tnsUniformOutputColorCorrection(T->immShader,w->WhichScreen->gamma, w->WhichScreen->xyz2rgb);        }else{ w->OutputColorSpace=0; }    }}#define EDID_MAX_SIZE 256#ifdef LA_LINUXvoid la_TryGettingEDIDColors(XRROutputInfo* output, laScreen* s){    if(s->gamma!=0){ return; }    Atom edid_atom = XInternAtom(MAIN.dpy, "EDID", True);    if (edid_atom != None) {        unsigned char *edid_data = NULL;        Atom actual_type;        int actual_format;        unsigned long nitems, bytes_after;        if (XRRGetOutputProperty(MAIN.dpy, output, edid_atom, 0, EDID_MAX_SIZE,                                False, False, AnyPropertyType, &actual_type, &actual_format,                                &nitems, &bytes_after, &edid_data) == Success &&            edid_data && nitems > 0) {            logPrint("    %d bytes of EDID data is available\n",nitems);            real gamma = edid_data[23]==255?0.0f:((real)(edid_data[23]+100))/100.0f;            uint8_t rx_low = (edid_data[0x19] >> 6) & 0x03;            uint8_t ry_low = (edid_data[0x19] >> 4) & 0x03;            uint8_t gx_low = (edid_data[0x19] >> 2) & 0x03;            uint8_t gy_low = edid_data[0x19] & 0x03;            uint8_t bx_low = (edid_data[0x1A] >> 6) & 0x03;            uint8_t by_low = (edid_data[0x1A] >> 4) & 0x03;            uint8_t wx_low = (edid_data[0x1A] >> 2) & 0x03;            uint8_t wy_low = edid_data[0x1A] & 0x03;            double red_x   = ((edid_data[0x1B] << 2) | rx_low) / 1024.0;            double red_y   = ((edid_data[0x1C] << 2) | ry_low) / 1024.0;            double green_x = ((edid_data[0x1D] << 2) | gx_low) / 1024.0;            double green_y = ((edid_data[0x1E] << 2) | gy_low) / 1024.0;            double blue_x  = ((edid_data[0x1F] << 2) | bx_low) / 1024.0;            double blue_y  = ((edid_data[0x20] << 2) | by_low) / 1024.0;            double white_x = ((edid_data[0x21] << 2) | wx_low) / 1024.0;            double white_y = ((edid_data[0x22] << 2) | wy_low) / 1024.0;            s->gamma=gamma;            s->primaries[0]=red_x;    s->primaries[1]=red_y;            s->primaries[2]=green_x;  s->primaries[3]=green_y;            s->primaries[4]=blue_x;   s->primaries[5]=blue_y;            s->whitepoint[0]=white_x; s->whitepoint[1]=white_y;            laSafeString* additional=0; strSafePrint(&additional,"\n"                "    Gamma: %0.4f\n"                "    Primaries:\n"                "        (%04lf, %04lf)\n"                "        (%04lf, %04lf)\n"                "        (%04lf, %04lf)\n"                "    White point:\n"                "        (%04lf, %04lf)\n", gamma, LA_COLOR3(s->primaries),LA_COLOR3(&s->primaries[3]),s->whitepoint[0],s->whitepoint[1]);            //strSafeAppend(&s->Description,SSTR(additional));            logPrint("Color calibration info:%s",SSTR(additional));            strSafeDestroy(&additional);            XFree(edid_data);            la_EnsureScreenColorMatrix(s);        }    }}int la_GetDPI(Window* root_win){    XRRScreenResources *screen;    XRROutputInfo *info;    XRRCrtcInfo *crtc_info;    XRRCrtcInfo *crtc;    int iscres, icrtc, dpi=0;    screen=XRRGetScreenResources(MAIN.dpy, root_win);    for(iscres=0;iscres<screen->noutput;iscres++){        info=XRRGetOutputInfo(MAIN.dpy,screen,screen->outputs[iscres]);        if(!info->mm_width || !info->mm_height || info->connection!=RR_Connected){ continue; }        logPrint("    Output size: %dmm x %dmm\n",info->mm_width,info->mm_height);        crtc=XRRGetCrtcInfo(MAIN.dpy,screen,info->crtc);        dpi=(real)crtc->width/(real)info->mm_width*25.4;        logPrint("    CRTC: %d x %d, around %ddpi\n",crtc->width,crtc->height,dpi);        laScreen* s=la_EnsureScreen(info->name,info->mm_width,info->mm_height,crtc->x,crtc->y,crtc->width,crtc->height,dpi);        la_TryGettingEDIDColors(screen->outputs[iscres],s);        XRRFreeCrtcInfo(crtc);        //if(info->connection==RR_Connected){        //    for (icrtc=0;icrtc<info->ncrtc;icrtc++) {        //        crtc_info=XRRGetCrtcInfo(MAIN.dpy,screen,screen->crtcs[icrtc]);        //        printf("==> %d,%d + %dx%d\n", crtc_info->x, crtc_info->y, crtc_info->width, crtc_info->height);        //        XRRFreeCrtcInfo(crtc_info);        //    }        //}        XRRFreeOutputInfo(info);                //real primaries[6]={0.64, 0.33, 0.3, 0.6, 0.15, 0.06};        //real white[2]={0.3127, 0.3290};        //tnsMatrix44d mat;        //tnsComputeMatrixRGB2XYZ(mat,&primaries[0],&primaries[2],&primaries[4],white);        //for(int i=0;i<9;i++){ printf("%lf ",mat[i]); } printf("\n");    }    XRRFreeScreenResources(screen);    return dpi;}#endif#ifdef _WIN32typedef struct laWin32MonitorEnumData {    int id;}laWin32MonitorEnumData;static BOOL CALLBACK la_Win32MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData){    laWin32MonitorEnumData* data = pData; char str[32]; sprintf(str, "Display %d", data->id); data->id++;    laScreen* s = la_EnsureScreen(str, 0,0, lprcMonitor->left, lprcMonitor->top, lprcMonitor->right-lprcMonitor->left, lprcMonitor->bottom-lprcMonitor->top, 0);    return TRUE;}int la_GetDPI(HWND win){    laWin32MonitorEnumData data = { 0 };    EnumDisplayMonitors(0, 0, la_Win32MonitorEnum, (LPARAM)&data);    if(win) return GetDpiForWindow(win);    return 144;}#endif#define PROGRESSW (LA_RH*15)void laShowProgress(real p1, real p2){    laSpinLock(&MAIN.OpsLock);    laBoxedTheme *bt = _LA_THEME_TAB; real* fg=laThemeColor(bt,LA_BT_TEXT); real* bg=laThemeColor(bt,LA_BT_NORMAL);    if(!MAIN.Progress.Called){        laRecordTime(&MAIN.Progress.TimeCalled); MAIN.Progress.Called=1;    }        laTimeRecorder tm; laRecordTime(&tm);        real t=laTimeElapsedSecondsf(&tm,&MAIN.Progress.TimeCalled); if(t<0.1){ laSpinUnlock(&MAIN.OpsLock); return; }        memcpy(&MAIN.Progress.TimeCalled,&tm,sizeof(laTimeRecorder));        if((!MAIN.Progress.Shown) && MAIN.Progress.Called){            int ww=PROGRESSW+LA_RH*2;#ifdef LA_LINUX            int w=XDisplayWidth(MAIN.dpy, 0),h=XDisplayHeight(MAIN.dpy, 0);            XMoveResizeWindow(MAIN.dpy,MAIN.Progress.w,w/2-ww/2,h/2-LA_RH*2/2,ww,LA_RH*2);            long a=LA_COLOR3_TO_HEX(bg);            XSetForeground(MAIN.dpy,MAIN.Progress.gc,LA_COLOR3_TO_HEX(fg));            XSetBackground(MAIN.dpy,MAIN.Progress.gc,LA_COLOR3_TO_HEX(bg));            XSetWindowBackground(MAIN.dpy,MAIN.Progress.w,LA_COLOR3_TO_HEX(bg));            if(MAIN.CurrentWindow) XSetTransientForHint(MAIN.dpy,MAIN.Progress.w,MAIN.CurrentWindow->win);            XMapWindow(MAIN.dpy,MAIN.Progress.w);            XSync(MAIN.dpy, 1); XFlush(MAIN.dpy);#endif#ifdef _WIN32            ShowWindow(MAIN.Progress.w, SW_NORMAL);#endif            MAIN.Progress.Shown = 1;        }    if(p1>=0) MAIN.Progress.p1=p1; if(p2>=0) MAIN.Progress.p2=p2;#ifdef LA_LINUX    XClearWindow(MAIN.dpy,MAIN.Progress.w);    XFillRectangle(MAIN.dpy,MAIN.Progress.w,MAIN.Progress.gc,LA_RH*2,0,PROGRESSW*MAIN.Progress.p1,LA_RH);    XFillRectangle(MAIN.dpy,MAIN.Progress.w,MAIN.Progress.gc,LA_RH*2,LA_RH,PROGRESSW*MAIN.Progress.p2,LA_RH);    tnsDrawLCD7_ProgressSystem(LA_RH*1.5,0,MAIN.Progress.p1);    tnsDrawLCD7_ProgressSystem(LA_RH*1.5,LA_RH,MAIN.Progress.p2);    XSync(MAIN.dpy, 1); XFlush(MAIN.dpy);#endif#ifdef _WIN32    PostMessage(MAIN.Progress.w, LA_PROGRESS_REPAINT_MESSAGE, 0, 0);#endif#ifdef LAGUI_ANDROID    laWindow* window=MAIN.CurrentWindow; int pw=window->CW;    eglMakeCurrent(MAIN.egl_dpy, MAIN.egl_surf, MAIN.egl_surf, MAIN.glc);    tnsViewportWithScissor(0,0,window->CW,window->CH);    tnsOrtho(0,window->CW,-window->CH+LA_2RH,LA_2RH,-100,100);    tnsClearColorv(bg); tnsClearAll(); tnsUseNoTexture(); tnsColor4dv(fg);    tnsVertex2d(0,0);tnsVertex2d(pw*MAIN.Progress.p2,0);tnsVertex2d(pw*MAIN.Progress.p2,LA_RH);tnsVertex2d(0,LA_RH);    tnsPackAs(GL_TRIANGLE_FAN);    tnsVertex2d(0,LA_RH);tnsVertex2d(pw*MAIN.Progress.p1,LA_RH);tnsVertex2d(pw*MAIN.Progress.p1,LA_2RH);tnsVertex2d(0,LA_2RH);    tnsPackAs(GL_TRIANGLE_FAN);    tnsFlush();    eglSwapBuffers(MAIN.egl_dpy, MAIN.egl_surf);    eglMakeCurrent(MAIN.egl_dpy,0,0,0);#endif    laSpinUnlock(&MAIN.OpsLock);}void laHideProgress(){    laSpinLock(&MAIN.OpsLock);    if(!MAIN.Progress.Shown){        MAIN.Progress.Called=0; laSpinUnlock(&MAIN.OpsLock); return;    }    laTimeRecorder tm; laRecordTime(&tm);    real t=laTimeElapsedSecondsf(&tm,&MAIN.Progress.TimeCalled);    if(t<0.2){ usleep((TNS_MIN2(0.2-t,0.2))*1000000); }    MAIN.Progress.Called = MAIN.Progress.Shown = 0;#ifdef LA_LINUX    XUnmapWindow(MAIN.dpy,MAIN.Progress.w); XSync(MAIN.dpy, 1); XFlush(MAIN.dpy);#endif#ifdef _WIN32    ShowWindow(MAIN.Progress.w,SW_HIDE);    if(MAIN.CurrentWindow) UpdateWindow(MAIN.CurrentWindow->win);#endif#ifdef LAGUI_ANDROID    laRedrawAllWindows();#endif    laSpinUnlock(&MAIN.OpsLock);}//=======================#ifdef _WIN32void la_Win32ProgressWindowThread(void* unused) {    laSpinLock(&MAIN.OpsLock);    WNDCLASSW wc;    wc.hInstance = MAIN.hinstance;    wc.lpfnWndProc = LA_ProgressWindowProc;    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);    wc.hCursor = LoadCursor(NULL, IDC_ARROW);    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);    wc.cbWndExtra = 0;    wc.cbClsExtra = 0;    wc.lpszClassName = L"_LAGUIPROGRESS";    wc.lpszMenuName = NULL;    wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;    if (!RegisterClassW(&wc)) { return; }    MAIN.Progress.w = CreateWindowW(L"_LAGUIPROGRESS", L"Progress", WS_POPUP, 0, 0, PROGRESSW + LA_RH * 2, LA_RH * 2, 0, 0, MAIN.hinstance, 0);    laSpinUnlock(&MAIN.OpsLock);    MSG msg;    while (GetMessage(&msg, MAIN.Progress.w, 0, 0)) {        TranslateMessage(&msg); DispatchMessage(&msg);    }}#endifvoid la_InitProgressWindow(){#ifdef LA_LINUX    MAIN.Progress.w=XCreateSimpleWindow(MAIN.dpy, RootWindow(MAIN.dpy, 0), 0, 0, PROGRESSW+LA_RH*2, LA_RH*2, 0, BlackPixel(MAIN.dpy, 0), WhitePixel(MAIN.dpy, 0));    if(!MAIN.Progress.w) return;    Atom window_type = XInternAtom(MAIN.dpy, "_NET_WM_WINDOW_TYPE", False); long value = XInternAtom(MAIN.dpy, "_NET_WM_WINDOW_TYPE_DOCK", False);    XChangeProperty(MAIN.dpy, MAIN.Progress.w, window_type,XA_ATOM, 32, PropModeReplace, (unsigned char *) &value,1 );    MAIN.Progress.gc=XCreateGC(MAIN.dpy,MAIN.Progress.w,0,&MAIN.Progress.gc_values);    if(MAIN.Progress.gc<0) return;    XSetFillStyle(MAIN.dpy, MAIN.Progress.gc, FillSolid);    XSetLineAttributes(MAIN.dpy, MAIN.Progress.gc, 2, LineSolid, CapButt, JoinBevel);    XSync(MAIN.dpy,0);#endif#ifdef _WIN32    thrd_create(&MAIN.Progress.th, la_Win32ProgressWindowThread, 0);    //MAIN.Progress.hdc=GetDC(MAIN.Progress.w);#endif}void la_InitProofingLut(){}void laSetFontFolderPath(char* absolute){    strcpy(MAIN.SysFontDir,absolute); int len=strlen(MAIN.SysFontDir);    if(MAIN.SysFontDir[len-1]!='/'){ MAIN.SysFontDir[len]='/'; MAIN.SysFontDir[len+1]=0; }}void laSetDefaultInitArguments(laInitArguments* ia){    ia->GLMajor=3; ia->GLMinor=3; ia->BufferSamples=0;    ia->UseColorManagement=0;    ia->HasWorldObjects=0;    ia->HasAction=0;    ia->HasTextureInspector=0;    ia->HasHistories=0;    ia->HasTerminal=1;    ia->HasAudio=0;}void laSetCompleteInitArguments(laInitArguments* ia){    ia->GLMajor=3; ia->GLMinor=3; ia->BufferSamples=0;    ia->GLESMajor=3; ia->GLESMinor=0;    ia->UseColorManagement=1;    ia->HasWorldObjects=1;    ia->HasAction=1;    ia->HasTextureInspector=1;    ia->HasHistories=1;    ia->HasTerminal=1;    ia->HasAudio=1;}void laProcessInitArguments(int argc, char* argv[],laInitArguments* ia) {    MAIN.GLMajor=MAIN.GLMinor=-1;    char* arg = 0;    printf("Initializing LaGUI...\n",argc);    for(int i=0;i<argc;i++){        if(strstr(argv[i], "--gl-version=")==argv[i]){ arg=&argv[i][strlen(argv[i])-3];            if(arg[0]>='2'&&arg[0]<='4'&&arg[1]=='.'&&arg[2]>='0'&&arg[2]<='9'){                ia->GLMajor=arg[0]-'0'; ia->GLMinor=arg[2]-'0';                printf("Set gl-version = %d.%d\n",ia->GLMajor,ia->GLMinor);            }            continue;        }        if(strSame(argv[i], "--gl-debug")){ ia->GLDebug=1; printf("Enabled OpenGL Debug.\n"); }        if(strSame(argv[i], "--log")){ ia->EnableLogStdOut=1; printf("Enabled log output to stdout.\n"); }    }}int laGetReadyWith(laInitArguments* ia){#ifdef LA_LINUX    //signal(SIGSEGV,la_HandlerSIGSEGV);#endif    laSpinInit(&MAIN.MemLock);    laSpinInit(&MAIN.OpsLock);    memcpy(&MAIN.InitArgs,ia,sizeof(laInitArguments));    if(MAIN.InitArgs.GLMajor>4||MAIN.InitArgs.GLMajor<1){ MAIN.InitArgs.GLMajor=3; }    if(MAIN.InitArgs.GLMinor<1){ MAIN.InitArgs.GLMinor=3; }    if(MAIN.InitArgs.GLESMajor>3||MAIN.InitArgs.GLESMajor<2){ MAIN.InitArgs.GLESMajor=3; }    if(MAIN.InitArgs.GLESMinor<0){ MAIN.InitArgs.GLESMinor=0; }    if(MAIN.BufferSamples==1){ MAIN.BufferSamples=0; }    la_GetWorkingDirectoryInternal();    tnsInit();#ifdef LA_LINUX    SYSWINDOW root, win;    GLint att[] = {GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None};    XSetWindowAttributes swa={0};    XWindowAttributes wa={0};    XEvent xev;    logPrintNew("Initializing LaGUI...\n");    setlocale(LC_CTYPE, "zh_CN.utf8");    XSetErrorHandler(la_XErrorHandler);    int i;    if ((MAIN.dpy = XOpenDisplay(NULL)) == NULL){        printf("\n\tcannot connect to x server\n\n");        exit(0);    }    la_ScanWacomDevices(MAIN.dpy,XIAllDevices);        MAIN.GLMajor=MAIN.InitArgs.GLMajor; MAIN.GLMinor=MAIN.InitArgs.GLMinor; MAIN.BufferSamples=MAIN.InitArgs.BufferSamples;    MAIN.GLESMajor=MAIN.InitArgs.GLESMajor; MAIN.GLESMinor=MAIN.InitArgs.GLESMinor;#ifdef LA_USE_GLES    logPrint("Chosen OpenGL version %d.%d\n",MAIN.GLESMajor,MAIN.GLESMinor);#else    logPrint("Chosen OpenGL version %d.%d\n",MAIN.GLMajor,MAIN.GLMinor);#endif#ifdef LA_USE_GLES    MAIN.egl_dpy=eglGetDisplay(MAIN.dpy);    if(!MAIN.egl_dpy){ printf("Error: eglGetDisplay() failed\n"); exit(1); }    EGLint egl_major, egl_minor;    if (!eglInitialize(MAIN.egl_dpy, &egl_major, &egl_minor)) {        printf("Error: eglInitialize() failed\n"); return -1;    }    int scrnum;    XSetWindowAttributes attr;    XVisualInfo *visInfo, visTemplate;    int num_visuals;    EGLContext ctx;    EGLint num_configs;    EGLint vid;    static const EGLint attribs[] = {        EGL_RED_SIZE, 8,        EGL_GREEN_SIZE, 8,        EGL_BLUE_SIZE, 8,        EGL_DEPTH_SIZE, 1,        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,        EGL_NONE    };    if (!eglChooseConfig(MAIN.egl_dpy, attribs, &MAIN.BestFBC, 1, &num_configs)) {        printf("Error: couldn't get an EGL visual config\n"); exit(1);    }    if (!eglGetConfigAttrib(MAIN.egl_dpy, MAIN.BestFBC, EGL_NATIVE_VISUAL_ID, &vid)) {        printf("Error: eglGetConfigAttrib() failed\n"); exit(1);    }    visTemplate.visualid = vid;    visInfo = XGetVisualInfo(MAIN.dpy, VisualIDMask, &visTemplate, &num_visuals);    if (!visInfo) {        printf("Error: couldn't get X visual\n"); exit(1);    }    MAIN.xvi=visInfo;    root = DefaultRootWindow(MAIN.dpy);    if ((MAIN.cmap = XCreateColormap(MAIN.dpy, root, MAIN.xvi->visual, AllocNone)) == 0){        printf("\n\tcannot create colormap\n\n"); exit(1);    }    eglBindAPI(EGL_OPENGL_ES_API);    EGLint ctx_attribs[] = {        EGL_CONTEXT_CLIENT_VERSION, MAIN.GLESMajor,        EGL_CONTEXT_MINOR_VERSION, MAIN.GLESMinor,        EGL_NONE    };    MAIN.glc = eglCreateContext(MAIN.egl_dpy, MAIN.BestFBC, EGL_NO_CONTEXT, ctx_attribs);    if (!MAIN.glc) {        printf("Error: eglCreateContext failed\n"); exit(1);    }    eglMakeCurrent(MAIN.egl_dpy,EGL_NO_SURFACE,EGL_NO_SURFACE,MAIN.glc);#else    int visual_attribs[] = {        GLX_X_RENDERABLE    , True,        GLX_DRAWABLE_TYPE   , GLX_WINDOW_BIT,        GLX_RENDER_TYPE     , GLX_RGBA_BIT,        GLX_X_VISUAL_TYPE   , GLX_TRUE_COLOR,        GLX_RED_SIZE        , 8,        GLX_GREEN_SIZE      , 8,        GLX_BLUE_SIZE       , 8,        GLX_ALPHA_SIZE      , 8,        GLX_DEPTH_SIZE      , 24,        //GLX_STENCIL_SIZE    , 8,        GLX_DOUBLEBUFFER    , True,        GLX_SAMPLE_BUFFERS  , MAIN.BufferSamples?1:0,        GLX_SAMPLES         , MAIN.BufferSamples?MAIN.BufferSamples:0,        None    };    int fbcount = -1;    GLXFBConfig* fbconfig = glXChooseFBConfig(MAIN.dpy, DefaultScreen(MAIN.dpy), visual_attribs, &fbcount );    logPrint("glXChooseFBConfig matched %d\n",fbcount);    if (!fbcount){ printf("\n\tno matching visual\n\n"); exit(0); }    MAIN.BestFBC = fbconfig[0];    int sample_buf,samples;    glXGetFBConfigAttrib(MAIN.dpy, MAIN.BestFBC, GLX_SAMPLE_BUFFERS, &sample_buf);    glXGetFBConfigAttrib(MAIN.dpy, MAIN.BestFBC, GLX_SAMPLES, &samples);    logPrint("    Chosen framebuffer with: %s %d samples\n",sample_buf?"Multisample":"-",samples);    MAIN.xvi=glXGetVisualFromFBConfig(MAIN.dpy, MAIN.BestFBC);    free(fbconfig);    root = DefaultRootWindow(MAIN.dpy);    if ((MAIN.cmap = XCreateColormap(MAIN.dpy, root, MAIN.xvi->visual, AllocNone)) == 0){        printf("\n\tcannot create colormap\n\n"); exit(0);    }    swa.colormap = MAIN.cmap;    root = DefaultRootWindow(MAIN.dpy);    win = XCreateWindow(MAIN.dpy, root, 0, 0, 100, 100, 0, MAIN.xvi->depth, InputOutput, MAIN.xvi->visual, CWBackPixel | CWBorderPixel|CWColormap | CWEventMask, &swa);    MAIN.win=win;    int attribs[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, MAIN.GLMajor, GLX_CONTEXT_MINOR_VERSION_ARB, MAIN.GLMinor, 0};    glXCreateContextAttribsF = (glXCreateContextAttribsARBProc) glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" );    if ((MAIN.glc = glXCreateContextAttribsF(MAIN.dpy, MAIN.BestFBC, NULL, GL_TRUE, attribs)) == NULL){        printf("\n\tcannot create gl context\n\n"); exit(0);    }    glXSwapIntervalEXTF = (glXSwapIntervalEXTProc) glXGetProcAddressARB( (const GLubyte *) "glXSwapIntervalEXT" );    tnsContextMakeCurrent(MAIN.glc,win,0);    int major,minor; glGetIntegerv(GL_MAJOR_VERSION, &major); glGetIntegerv(GL_MINOR_VERSION, &minor);    logPrint("    OpenGL Version: %d.%d\n",major,minor);    logPrint("    OpenGL Renderer: %s\n",glGetString(GL_RENDERER));    int err=0;    if((err=glewInit())!=GLEW_OK){        printf("%d\n",err); printf("%s\n",glewGetErrorString(err));    };#endif /* gles or glx */    glGenVertexArrays(1,&MAIN.TempVAO); tnsBindVertexArray(MAIN.TempVAO);    la_SetCurrentGLContextDebug();    MAIN.MsgDelWindow = XInternAtom(MAIN.dpy, "WM_DELETE_WINDOW", 0);    MAIN.bufid =  XInternAtom(MAIN.dpy, "CLIPBOARD", False),    MAIN.fmtid =  XInternAtom(MAIN.dpy, "UTF8_STRING", False),    MAIN.propid = XInternAtom(MAIN.dpy, "XSEL_DATA", False),    MAIN.incrid = XInternAtom(MAIN.dpy, "INCR", False);    MAIN.targets_atom = XInternAtom(MAIN.dpy, "TARGETS",0);    MAIN.text_atom =    XInternAtom(MAIN.dpy, "TEXT", 0);    MAIN.UTF8 =         XInternAtom(MAIN.dpy, "UTF8_STRING", 1);    MAIN.selection =    XInternAtom(MAIN.dpy, "CLIPBOARD", 0);	if(MAIN.UTF8 == None) MAIN.UTF8 = XA_STRING;    MAIN.wmstate=XInternAtom(MAIN.dpy,"_NET_WM_STATE",1);    MAIN.wmfullscr=XInternAtom(MAIN.dpy,"_NET_WM_STATE_FULLSCREEN",0);    MAIN.wmfullscroff=XInternAtom(MAIN.dpy,"_NET_WM_STATE_FULLSCREEN",0);#endif //linux#ifdef _WIN32    logPrintNew("Initializing LaGUI...\n");    SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);    setlocale(LC_ALL, "zh_CN.utf8");    MAIN.hinstance = GetModuleHandle(NULL);    HINSTANCE* hInst = &MAIN.hinstance;    WNDCLASSEXW wt;    wt.cbSize = sizeof(WNDCLASSEXW);    wt.cbClsExtra = 0;    wt.cbWndExtra = 0;    wt.hbrBackground = 0;    wt.hCursor = LoadCursor(0, IDC_ARROW);    wt.hIcon = LoadIcon(*hInst, IDI_WINLOGO);    wt.hIconSm = LoadIcon(*hInst, IDI_WINLOGO);    wt.hInstance = *hInst;    wt.lpfnWndProc = LA_WindowProc;    wt.lpszClassName = LA_GUI_WNDCLASS_NAME;    wt.lpszMenuName = 0;    wt.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;    if (!RegisterClassEx(&wt)) return 0;        MAIN.GLMajor=MAIN.InitArgs.GLMajor; MAIN.GLMinor=MAIN.InitArgs.GLMinor; MAIN.BufferSamples=MAIN.InitArgs.BufferSamples;    logPrint("Chosen OpenGL version %d.%d\n", MAIN.GLMajor, MAIN.GLMinor);    SetProcessDPIAware();    GLenum err;    PIXELFORMATDESCRIPTOR pfd;    HINSTANCE* hinst = &MAIN.hinstance;    HWND hwnd = CreateWindowEx(WS_EX_ACCEPTFILES, LA_GUI_WNDCLASS_NAME,        "Temp Window For Accessing GLEW!",        WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, 100, 100,        0, 0, *hinst, 0);    HDC hdc = GetDC(hwnd);    HGLRC hglrc = 0;    SetPixelFormat(hdc, 1, &cpfd);    hglrc = wglCreateContext(hdc);    tnsContextMakeCurrent(hglrc, hdc,0);    //MAIN.hdc = hdc;   // MAIN.tWND = hwnd;    MAIN.glc = hglrc;    int major, minor; glGetIntegerv(GL_MAJOR_VERSION, &major); glGetIntegerv(GL_MINOR_VERSION, &minor);    logPrint("    OpenGL Version: %d.%d\n", major, minor);    logPrint("    OpenGL Renderer: %s\n", glGetString(GL_RENDERER));    if (err = glewInit()) {        printf("Init Glew Failed\n");        printf("glewGetErrorString: %s\n", glewGetErrorString(err));        return 0;    }    logPrint("Trying to load WinTab for stylus input...\n"); int WtAvailable=1;    if (!LoadWintab()){ logPrint("WinTab not available.\n"); WtAvailable=0; }	elif (!gpWTInfoA(0, 0, NULL)){ logPrint("WinTab service is not available. (gpWTInfoA() returns 0).\n"); WtAvailable=0; }    if (WtAvailable){ MAIN.WinTabAvailable=1; logPrint("WinTab service is available.\n"); }#endif    MAIN.SavePreferenceOnExit=1;        MAIN.FontSize = 0.6;    int dpi=64;#ifdef _WIN32    dpi=la_GetDPI(hwnd);#endif#ifdef LA_LINUX    dpi = la_GetDPI(DefaultRootWindow(MAIN.dpy));#endif#ifdef LAGUI_ANDROID    dpi = 72;    #endif    if((!dpi) || dpi<144){ dpi=144; } if(dpi>300){ dpi=300; }    int UiSize=(int)(tnsLinearItp(16.0f,24.0f,tnsGetRatiod(96,144,dpi))+0.5);    MAIN.UiRowHeight = MAIN.ScaledUiRowHeight = UiSize;    MAIN.UiScale=1;    MAIN.MarginSize = 1;    MAIN.ColorPickerGamma=1.5;    MAIN.EnableColorManagement=MAIN.InitArgs.UseColorManagement;    MAIN.ViewportHalftoneFactor=0.5;    MAIN.ViewportHalftoneSize=3.7;    tnsInitRenderKernel(64);    tnsInitBuiltinShaders();    tnsSetuptnsFontManager();#define LOAD_FONT(font) \    if(!tnsLoadSystemFont(MAIN.SysFontDir, font)) printf("Can't load font \"" font "\"\n");    LOAD_FONT("NotoSansCJK-Regular.ttc");    LOAD_FONT("NotoEmoji-Regular.ttf");    LOAD_FONT("NotoSansSymbols-Regular.ttf");    LOAD_FONT("NotoSansSymbols2-Regular.ttf");    LOAD_FONT("NotoSansMath-Regular.ttf");    //LOAD_FONT("NotoMusic-Regular.ttf");    //LOAD_FONT("NotoSansEgyptianHieroglyphs-Regular.ttf);    if(!tnsLoadSystemFontMono(MAIN.SysFontDir, "NotoSansMono-Regular.ttf")) logPrintNew("Can't load font \"NotoSansMono-Regular.ttf\"\n");;    arrEnsureLength(&MAIN.InputBuf,0,&MAIN.InputBufMax,sizeof(char));    arrEnsureLength(&MAIN.InputBufU,0,&MAIN.InputBufUMax,sizeof(uint32_t));    arrEnsureLength(&MAIN.NodeTypes,0,&MAIN.NodeTypeMax,sizeof(laBaseNode*));        MAIN.InputMapping=memAcquire(sizeof(laInputMappingBundle));    MAIN.Animation=memAcquire(sizeof(laAnimation));    MAIN.Audio=memAcquire(sizeof(laAudio));#ifdef LA_WITH_LUAJIT    // starting lua    logPrint("Starting luajit...\n");    MAIN.L = lua_open();    la_luaLoadLibs(MAIN.L);    la_luaPrintStatus(MAIN.L);    tnsLuaInit(MAIN.L);#endif        //interactions:    MAIN.TopFramerate = 60;    MAIN.ValuatorThreshold = 8;    MAIN.ScrollingSpeed = 3;    MAIN.AnimationSpeed = 0.4;    MAIN.PanelAnimationSpeed = 0.4;    MAIN.ZoomSpeed2D = 0.01;    MAIN.IdleTime = 0.75;    MAIN.TooltipCloseDistance = 30;    MAIN.InkOrWinTab = 1; /* Default use wacom wintab input. */    //display:    MAIN.FloatingAlpha = 0.35;    MAIN.SolidShadowLength = 20;    MAIN.WireColorSlices = 16;    MAIN.WireThickness = 5;    MAIN.WireSaggyness = 0.5;    MAIN.ManagerFilterInstances = 1;    laSetMenuBarTemplates(laui_DefaultMenuButtons, laui_DefaultMenuExtras, "🧩LaGUI 2022");    laAddExtraExtension(LA_FILETYPE_UDF,"udf",0ll);    la_InitProgressWindow();    la_MakeTranslations_es_ES();    la_MakeTranslations_zh_hans();    //tns_RegisterResourcesForSoftwareRender();    la_RegisterDefaultSignals();    la_RegisterGeneralProps();    la_RegisterBuiltinTemplates();    la_RegisterMainThemes();    la_RegisterMainOperators();    la_RegisterMainUiTypes();    la_RegisterInternalProps();    la_RegisterAnimationResources();    la_RegisterWindowKeys();    if(MAIN.InitArgs.HasWorldObjects){        la_RegisterModellingOperators();        la_RegisterShapeOperators();    }    if(MAIN.InitArgs.HasAudio) laInitAudio();    laFinalizeUiTemplates();    laFinalizeOperators();    la_RegisterControllerProps();    la_RefreshControllers();        la_RegisterBasicNodes();    tns_RegisterNodes();    la_InitThreadEnviornment();    laSetRootInstance(&MAIN);    if(!MAIN.DBInstMemLeft){ hsh65536Init(&MAIN.DBInstMemLeft); }    laPushDifferences(0, 0);    la_MakeDummyManagedUDF();    la_RegenerateWireColors();    laAnimationRegisterHolderPath("tns.world.root_objects_as_root");    if(MAIN.InitArgs.EnableLogStdOut){ MAIN.EnableLogStdOut=1; }    logPrintNew("Initialization Completed\n");    MAIN.InitDone=1;#ifdef LAGUI_ANDROID    MAIN.AutoSwitchColorSpace = 0;    MAIN.GotFilePermission = la_check_permission("android.permission.WRITE_EXTERNAL_STORAGE");#else    MAIN.AutoSwitchColorSpace = 1;#endif    return 1;}int laGetReady(){    laInitArguments ia={0}; laSetDefaultInitArguments(&ia);    return laGetReadyWith(&ia);}void la_DestroyUiType(laUiType* uit);void la_FreeKeyMapItem(laKeyMapItem* kmi);void laShutoff(int SavePrefereces){    if(MAIN.SavePreferenceOnExit && SavePrefereces){ laSaveUserPreferences(); }    //for(laPropContainer* pc=MAIN.PropContainers.pFirst;pc;pc=pc->Item.pNext){    //     transLate(pc->Description);    //    for(laProp* p=pc->Props.pFirst;p;p=p->Item.pNext){    //         transLate(p->Description);    //    }    //}#ifdef _WIN32    laSpinLock(&MAIN.OpsLock);    PostMessage(MAIN.Progress.w, WM_QUIT, 0, 0);    laSpinUnlock(&MAIN.OpsLock);    thrd_join(MAIN.Progress.th, 0);#endif    transDumpMissMatchRecord("TranslationDump.txt");    if(MAIN.Cleanup) MAIN.Cleanup();    if(MAIN.InitArgs.HasAudio) laDeinitAudio();    strSafeDestroy(&MAIN.WorkingDirectory);    strSafeDestroy(&MAIN.example_string);    la_NoLongerRecordUndo(); //XXX: it's not reliable yet, we need to only remove steps that are consistent with current data structure    // (Must undo/redo to desired position or delete from back/front without moving target head. This can be done but this is of lower priority. )    laWindow* wi; while(wi=lstPopItem(&MAIN.Windows)){ la_DestroyWindow(wi); }    laUiTemplate* uit; while(uit=lstPopItem(&MAIN.PanelTemplates)){ la_DestroyUiTemplate(uit); }    laCanvasTemplate* u2t; while(u2t=lstPopItem(&MAIN.View2DTemplates)){ la_DestroyCanvasTemplate(u2t); }    laUiType* uit1; while(uit1=lstPopItem(&MAIN.UiTypes)){ la_DestroyUiType(uit1); }    laOperatorType* at; for(int i=0;i<256;i++){ while(at=lstPopItem(&MAIN.OperatorTypeHash.Entries[i])) la_DestroyOperatorType(at); }    laSharedTypeItem* sti; while(sti=lstPopItem(&MAIN.SharedTypePointerSync)){ memFree(sti); }    laKeyMapItem* kmi; while(kmi=lstPopItem(&MAIN.KeyMap.Items)){ la_FreeKeyMapItem(kmi); }    laTheme* t; while(t=lstPopItem(&MAIN.Themes)){ la_DestroyTheme(t); }    arrFree(&MAIN.InputBuf,&MAIN.InputBufNext);    arrFree(&MAIN.InputBufU,&MAIN.InputBufUNext);    strSafeDestroy(&MAIN.CopyPending);    la_ClearUDFRegistryAndFolders();    laClearManagedUDF();    laClearSaveProp();    logClear();    tnsBindVertexArray(0); glDeleteVertexArrays(1,&MAIN.TempVAO);#ifdef LA_LINUX    tnsContextMakeCurrent(0,0,0);    tnsDeleteContext(MAIN.glc);    #ifdef LA_USE_GLES        eglTerminate(MAIN.egl_dpy);    #endif#endif#ifdef _WIN32    tnsContextMakeCurrent(0,0,0);    tnsDeleteContext(MAIN.glc);    UnloadWintab();#endif    tnsQuit();    laPropContainer* pc; while(pc=lstPopItem(&MAIN.PropContainers)){ la_FreePropertyContainer(pc); }    //laPanel* p; while(p=lstPopItem(&MAIN.WastedPanels)){ memFree(p); }    strSafeDump();    hshFree(&MAIN.DBInstMemLeft);    memNoLonger();    laSpinDestroy(&MAIN.MemLock);    laSpinDestroy(&MAIN.OpsLock);#ifdef LA_WITH_LUAJIT    lua_close(MAIN.L);#endif    printf("LaGUI has cleaned up.\n");}int laRestoreFactorySettings(){    char path[1024];#ifdef LAGUI_ANDROID    sprintf(path,"%s/%s",MAIN.InternalDataPath,"preferences.udf");    logPrintNew("%s", path);    if(!remove(path)){ return 1; }    sprintf(path,"%s/%s",MAIN.ExternalDataPath,"preferences.udf");    logPrintNew("%s", path);    if(!remove(path)){ return 1; }    return 0;#else    sprintf(path,"%s%s",SSTR(MAIN.WorkingDirectory),"preferences.udf");#endif    if(remove(path)){ return 0; }    return 1;}void laSaveUserPreferences(){    char path[1024];#ifdef LAGUI_ANDROID    sprintf(path,"%s","preferences.udf");#else    sprintf(path,"%s%s",SSTR(MAIN.WorkingDirectory),"preferences.udf");#endif    laUDF* udf=laPrepareUDF(path);    laWriteProp(udf,"la.windows");    laWriteProp(udf,"la.themes");    laWriteProp(udf,"la.user_preferences");    laWriteProp(udf,"la.input_mapping");    laWriteProp(udf,"la.controllers");    for(laListItemPointer* lip=MAIN.ExtraPreferencePaths.pFirst;lip;lip=lip->pNext){        laWriteProp(udf,lip->p);    }    laPackUDF(udf,0,0);}void laEnsureUserPreferences(){    //laLoadHyperResources("LATHEME");    char path[1024];#ifdef LAGUI_ANDROID    sprintf(path,"%s/%s",MAIN.InternalDataPath,"preferences.udf");#else    sprintf(path,"%s%s",SSTR(MAIN.WorkingDirectory),"preferences.udf");#endif    laUDFRegistry* r=laFindUDFRegistry(path);    if(!r){ laSaveUserPreferences(); return; }    laUDF* udf=laOpenUDF(SSTR(r->Path),1,0,0); if(!udf){ logPrint("Can't read preferences on %s. Using default settings.",SSTR(r->Path)); return; }    laClearUDFRegistries();    while(MAIN.ResourceFolders.pFirst){ laRemoveResourceFolder(MAIN.ResourceFolders.pFirst); }    while(MAIN.InputMapping->InputMappings.pFirst){ laRemoveInputMapping(MAIN.InputMapping->InputMappings.pFirst); }    laExtractUDF(udf,0,LA_UDF_MODE_OVERWRITE);    laCloseUDF(udf);    la_RemoveDuplicatedScreenConf();    la_RemoveDuplicatedControllers();    laRefreshUDFRegistries();    //restore forced settings    if(MAIN.InitArgs.EnableLogStdOut){ MAIN.EnableLogStdOut=1; }}void laAddExtraExtension(int FileType, ...){    va_list list; va_start(list,FileType);    char* ext;    logPrint("Enabling extra extensions: ");    while(ext=va_arg(list,char*)){ if(!ext) break;        laExtensionType* et=memAcquireSimple(sizeof(laExtensionType));        et->FileType=FileType; et->Extension=ext;        lstAppendItem(&MAIN.ExtraExtensions, et);        logPrint("%s ",ext);    }    logPrint("\n");    va_end(list);}void laAddExtraPreferencePath(const char* path){    if(!path) return;    lstAppendPointer(&MAIN.ExtraPreferencePaths, path);}void laAddExtraPreferencePage(const char* name, laUiDefineFunc Func){    if(!name || !Func) return;    laExtraPreferencePage*epp=memAcquireSimple(sizeof(laExtraPreferencePage));    epp->Name=name; epp->Func=Func; lstAppendItem(&MAIN.ExtraPreferencePages,epp);}void laSetMenuBarTemplates(laUiDefineFunc MenuButtons, laUiDefineFunc MenuExtras, const char* ProgramName){    MAIN.MenuButtons=MenuButtons; MAIN.MenuExtras=MenuExtras; MAIN.MenuProgramName=ProgramName;}void laSetAboutTemplates(laUiDefineFunc AboutContent, laUiDefineFunc AboutVersion, laUiDefineFunc AboutAuthor){    MAIN.AboutAuthor=AboutAuthor; MAIN.AboutVersion=AboutVersion; MAIN.AboutContent=AboutContent;}void laSetPreferenceTemplates(laUiDefineFunc PreferencePageDisplay, laUiDefineFunc PreferencePageInput, laUiDefineFunc PreferencePageResource, laUiDefineFunc PreferencePageTheme){    MAIN.PreferencePageDisplay=PreferencePageDisplay; MAIN.PreferencePageInput=PreferencePageInput;    MAIN.PreferencePageResource=PreferencePageResource; MAIN.PreferencePageTheme=PreferencePageTheme;}void la_InputMappingGetKeyName(int key, int special, char* name){    char *_next=name; name[0]=0;    if(special&LA_KEY_CTRL){ strcat(name,"Ctrl+"); }    if(special&LA_KEY_SHIFT){ strcat(name,"Shift+"); }    if(special&LA_KEY_ALT){ strcat(name,"Alt+"); }    switch(key){    case ' ': strcat(name,"Space"); break;    case LA_KEY_BACKSPACE: strcat(name,"Backspace"); break;    case LA_KEY_ESCAPE: strcat(name,"Escape"); break;    case LA_KEY_ENTER: strcat(name,"Enter"); break;    case LA_KEY_ARRLEFT: strcat(name,"Left"); break;    case LA_KEY_ARRRIGHT: strcat(name,"Right"); break;    case LA_KEY_ARRUP: strcat(name,"Up"); break;    case LA_KEY_ARRDOWN: strcat(name,"Down"); break;    case LA_KEY_SHIFT: case LA_KEY_CTRL: case LA_KEY_ALT: break;    case LA_KEY_DELETE: strcat(name,"Delete"); break;    case LA_KEY_TAB: strcat(name,"Tab"); break;    case LA_KEY_NUM1: strcat(name,"Num1"); break;    case LA_KEY_NUM2: strcat(name,"Num2"); break;    case LA_KEY_NUM3: strcat(name,"Num3"); break;    case LA_KEY_NUM4: strcat(name,"Num4"); break;    case LA_KEY_NUM5: strcat(name,"Num5"); break;    case LA_KEY_NUM6: strcat(name,"Num6"); break;    case LA_KEY_NUM7: strcat(name,"Num7"); break;    case LA_KEY_NUM8: strcat(name,"Num8"); break;    case LA_KEY_NUM9: strcat(name,"Num9"); break;    case LA_KEY_NUM0: strcat(name,"Num0"); break;    case LA_KEY_NUMPLUS: strcat(name,"NumPlus"); break;    case LA_KEY_NUMMINUS: strcat(name,"NumMinus"); break;    case LA_KEY_NUMMULT: strcat(name,"NumMult"); break;    case LA_KEY_NUMDIVIDE: strcat(name,"NumDivide"); break;    case LA_KEY_NUMDOT: strcat(name,"NumDot"); break;    case LA_KEY_NUMENTER: strcat(name,"NumEnter"); break;    case LA_KEY_F1: strcat(name,"F1"); break;    case LA_KEY_F2: strcat(name,"F2"); break;    case LA_KEY_F3: strcat(name,"F3"); break;    case LA_KEY_F4: strcat(name,"F4"); break;    case LA_KEY_F5: strcat(name,"F5"); break;    case LA_KEY_F6: strcat(name,"F6"); break;    case LA_KEY_F7: strcat(name,"F7"); break;    case LA_KEY_F8: strcat(name,"F8"); break;    case LA_KEY_F9: strcat(name,"F9"); break;    case LA_KEY_F10: strcat(name,"F10"); break;    case LA_KEY_F11: strcat(name,"F11"); break;    case LA_KEY_F12: strcat(name,"F12"); break;    case LA_KEY_MOUSE_LEFT: strcat(name,"Mouse1"); break;    case LA_KEY_MOUSE_MIDDLE: strcat(name,"Mouse2"); break;    case LA_KEY_MOUSE_RIGHT: strcat(name,"Mouse3"); break;    case LA_KEY_MOUSE_SCROLL|LA_STATE_UP: strcat(name,"MouseWheelUp"); break;    case LA_KEY_MOUSE_SCROLL|LA_STATE_DOWN: strcat(name,"MouseWheelDown"); break;    default:        name = name+strlen(name); _next=name;        laToUTF8(key,name,&_next); *_next=0; break;    }}int la_InputMappingGetKeyFromName(char* name, int* special){    if(!name ||name[0]==0){ *special=0; return 0; }    *special=0;    if(strstr(name,"Ctrl")) *special|=LA_KEY_CTRL;    if(strstr(name,"Shift")) *special|=LA_KEY_SHIFT;    if(strstr(name,"Alt")) *special|=LA_KEY_ALT;    char* p=name+strlen(name)-1;    while(*p!='+'){ p--; if(p<=name){p=name; break;} }    while(*p=='+' || *p==' '){ p++; }    if(strSame(p,"Space")) return ' ';    if(strSame(p,"Backspace")) return LA_KEY_BACKSPACE;    if(strSame(p,"Escape")) return LA_KEY_ESCAPE;    if(strSame(p,"Enter")) return LA_KEY_ENTER;    if(strSame(p,"Left")) return LA_KEY_ARRLEFT;    if(strSame(p,"Right")) return LA_KEY_ARRRIGHT;    if(strSame(p,"Up")) return LA_KEY_ARRUP;    if(strSame(p,"Down")) return LA_KEY_ARRDOWN;    if(strSame(p,"Delete")) return LA_KEY_DELETE;    if(strSame(p,"Tab")) return LA_KEY_TAB;    if(strSame(p,"Num1")) return LA_KEY_NUM1;    if(strSame(p,"Num2")) return LA_KEY_NUM2;    if(strSame(p,"Num3")) return LA_KEY_NUM3;    if(strSame(p,"Num4")) return LA_KEY_NUM4;    if(strSame(p,"Num5")) return LA_KEY_NUM5;    if(strSame(p,"Num6")) return LA_KEY_NUM6;    if(strSame(p,"Num7")) return LA_KEY_NUM7;    if(strSame(p,"Num8")) return LA_KEY_NUM8;    if(strSame(p,"Num9")) return LA_KEY_NUM9;    if(strSame(p,"Num0")) return LA_KEY_NUM0;    if(strSame(p,"NumPlus")) return LA_KEY_NUMPLUS;    if(strSame(p,"NumMinus")) return LA_KEY_NUMMINUS;    if(strSame(p,"NumMult")) return LA_KEY_NUMMULT;    if(strSame(p,"NumDivide")) return LA_KEY_NUMDIVIDE;    if(strSame(p,"NumDot")) return LA_KEY_NUMDOT;    if(strSame(p,"NumEnter")) return LA_KEY_NUMENTER;    if(strSame(p,"F1")) return LA_KEY_F1;    if(strSame(p,"F2")) return LA_KEY_F2;    if(strSame(p,"F3")) return LA_KEY_F3;    if(strSame(p,"F4")) return LA_KEY_F4;    if(strSame(p,"F5")) return LA_KEY_F5;    if(strSame(p,"F6")) return LA_KEY_F6;    if(strSame(p,"F7")) return LA_KEY_F7;    if(strSame(p,"F8")) return LA_KEY_F8;    if(strSame(p,"F9")) return LA_KEY_F9;    if(strSame(p,"F10")) return LA_KEY_F10;    if(strSame(p,"F11")) return LA_KEY_F11;    if(strSame(p,"F12")) return LA_KEY_F12;    if(strSame(p,"Mouse1")) return LA_KEY_MOUSE_LEFT;    if(strSame(p,"Mouse2")) return LA_KEY_MOUSE_MIDDLE;    if(strSame(p,"Mouse3")) return LA_KEY_MOUSE_RIGHT;    if(strSame(p,"MouseWheelUp")) return LA_KEY_MOUSE_SCROLL|LA_STATE_UP;    if(strSame(p,"MouseWheelDown")) return LA_KEY_MOUSE_SCROLL|LA_STATE_DOWN;    int adv;    return laToUnicode(p,&adv);}laCustomSignal* laFindSignal(char* Name){    for(laCustomSignal* cs=MAIN.CustomSignals.pFirst;cs;cs=cs->Item.pNext){ if(strSame(SSTR(cs->Name),Name)) return cs; }    return 0;}laCustomSignal* laFindSignalByID(int ID){    for(laCustomSignal* cs=MAIN.CustomSignals.pFirst;cs;cs=cs->Item.pNext){ if(ID==cs->Signal) return cs; }    return 0;}void laInputMappingUpdateSignal(laInputMappingEntry* ime){    if(ime->DeviceType == LA_INPUT_DEVICE_KEYBOARD || ime->DeviceType==LA_INPUT_DEVICE_MOUSE){ char* str=SSTR(ime->Key);        if(str&&str[0]){ int adv; ime->KeyValue=la_InputMappingGetKeyFromName(str,&ime->SpecialKeyBits); }else{ ime->KeyValue=0; }    }    elif(ime->DeviceType == LA_INPUT_DEVICE_JOYSTICK){ int key=0; sscanf(SSTR(ime->Key),"%d",&key); ime->KeyValue=key; }    char* signal = SSTR(ime->Signal);    laCustomSignal *cs=laFindSignal(signal); if(cs){ ime->SignalValue=cs->Signal; }else{ ime->SignalValue=0;}}laInputMapping* laFindToolbox(char* Name){    for(laInputMapping* im=MAIN.InputMapping->Toolboxes.pFirst;im;im=im->Item.pNext){        if(strSame(Name,SSTR(im->Name))) return im;    }    return 0;}laInputMapping* laNewInputMapping(char* Name){    laInputMapping* im=memAcquireHyper(sizeof(laInputMapping)); lstAppendItem(&MAIN.InputMapping->InputMappings,im);    memAssignRef(MAIN.InputMapping,&MAIN.InputMapping->CurrentInputMapping,im);    strSafeSet(&im->Name,Name);    return im;}laInputMappingEntry* laNewInputMappingEntry(laInputMapping* im, int DeviceType, int JoystickDevice, char* Key, int SpecialKeyBit, char* Signal){    laInputMappingEntry* e=memAcquire(sizeof(laInputMappingEntry)); lstAppendItem(&im->Entries,e);    e->DeviceType = DeviceType; e->JoystickDevice=JoystickDevice; e->SpecialKeyBits=SpecialKeyBit;    memAssignRef(e,&e->Parent,im);    if(Signal){ strSafeSet(&e->Signal,Signal); } if(Key){ strSafeSet(&e->Key,Key); }    laInputMappingUpdateSignal(e);    e->SpecialKeyBits=SpecialKeyBit;    char buf[64],*_next=buf;    la_InputMappingGetKeyName(e->KeyValue,e->SpecialKeyBits,buf); strSafeSet(&e->Key,buf);    return e;}laInputMappingEntry* laNewInputMappingEntryP(laInputMapping* im, int DeviceType, int JoystickDevice, char* Key, int SpecialKeyBit, int Signal){    laCustomSignal* cs; if(!(cs=laFindSignalByID(Signal))) return 0;    return laNewInputMappingEntry(im,DeviceType,JoystickDevice,Key,SpecialKeyBit,SSTR(cs->Name));}laInputMappingEntry* laNewInputMappingMouseEntryP(laInputMapping* im, int MouseEventType, int SpecialKeyBit, int Signal){    laCustomSignal* cs; if(!(cs=laFindSignalByID(Signal))) return 0;    char* Key="Mouse2";    if(MouseEventType&LA_KEY_MOUSE_LEFT){ Key="Mouse1"; }    elif(MouseEventType&LA_KEY_MOUSE_MIDDLE){ Key="Mouse2"; }    elif(MouseEventType&LA_KEY_MOUSE_RIGHT){ Key="Mouse3"; }    elif((MouseEventType&LA_KEY_MOUSE_SCROLL) && (MouseEventType&LA_STATE_UP)){ Key="MouseWheelUp"; }    elif((MouseEventType&LA_KEY_MOUSE_SCROLL) && (MouseEventType&LA_STATE_DOWN)){ Key="MouseWheelDown"; }    return laNewInputMappingEntry(im,LA_INPUT_DEVICE_MOUSE,0,Key,SpecialKeyBit,SSTR(cs->Name));}void laRemoveInputMappingEntry(laInputMapping* im, laInputMappingEntry* e){    memAssignRef(e,&e->Parent,0); lstRemoveItem(&im->Entries,e); strSafeDestroy(&e->Signal); strSafeDestroy(&e->Key); memFree(e);}void laRemoveInputMapping(laInputMapping* im){    laInputMappingEntry* e; while(e=im->Entries.pFirst){ laRemoveInputMappingEntry(im,e); }    laInputMapping* use=im->Item.pNext?im->Item.pNext:im->Item.pPrev;    memAssignRef(MAIN.InputMapping,&MAIN.InputMapping->CurrentInputMapping,use);    lstRemoveItem(&MAIN.InputMapping->InputMappings,im); strSafeDestroy(&im->Name); memFree(im);}laInputMapping* laNewToolbox(char* Name){    laInputMapping* im=memAcquireHyper(sizeof(laInputMapping)); lstAppendItem(&MAIN.InputMapping->Toolboxes,im);    memAssignRef(MAIN.InputMapping,&MAIN.InputMapping->CurrentToolbox,im);    strSafeSet(&im->Name,Name);    return im;}void laRemoveToolbox(laInputMapping* im){    laInputMappingEntry* e; while(e=im->Entries.pFirst){ laRemoveInputMappingEntry(im,e); }    laInputMapping* use=im->Item.pNext?im->Item.pNext:im->Item.pPrev;    memAssignRef(MAIN.InputMapping,&MAIN.InputMapping->CurrentToolbox,use);    lstRemoveItem(&MAIN.InputMapping->Toolboxes,im); strSafeDestroy(&im->Name); memFree(im);}laCustomSignal* laNewCustomSignal(char* Name, int Signal){    laCustomSignal* cs=memAcquire(sizeof(laCustomSignal)); lstAppendItem(&MAIN.CustomSignals,cs);    strSafeSet(&cs->Name,Name); cs->Signal = Signal;    return cs;}void laRemoveCustomSignal(laCustomSignal* cs){    strSafeDestroy(&cs->Name); lstRemoveItem(&MAIN.CustomSignals,cs); memFree(cs);}void la_SendSignalEvent(SYSWINDOW* hwnd, int signal);void la_SendOperatorEvent(SYSWINDOW* hwnd, laOperatorType* at, int use_base, char* instructions);void la_SendInputMappingSignalsAuto(SYSWINDOW* hwnd, laInputMappingEntry* ime){    if(ime->UseOperator){ la_SendOperatorEvent(hwnd, ime->OperatorType, ime->OperatorBase, SSTR(ime->OperatorArguments)); }    else{ la_SendSignalEvent(hwnd, ime->SignalValue); }}void la_SendSignalsFromEvent(laEvent* e){    laInputMapping* im = MAIN.InputMapping->CurrentInputMapping;    if(!im){return;}    for(laInputMappingEntry* ime = im->Entries.pFirst;ime;ime=ime->Item.pNext){        if(ime->Disabled) continue;        if(e->type==LA_KEY_DOWN && ime->DeviceType == LA_INPUT_DEVICE_KEYBOARD){            if(e->key == ime->KeyValue && e->SpecialKeyBit == ime->SpecialKeyBits){                la_SendInputMappingSignalsAuto(e->window->win,ime);            }        }elif((e->type&LA_MOUSE_EVENT) && ime->DeviceType == LA_INPUT_DEVICE_MOUSE){            int matchkey; if(!(e->type&LA_KEY_MOUSE_SCROLL)){ matchkey = ((e->type&ime->KeyValue) && (e->type&LA_STATE_DOWN)); }            else{ matchkey = (e->type==(ime->KeyValue&LA_MOUSE_EVENT)); }            if(e->SpecialKeyBit == ime->SpecialKeyBits && matchkey){                la_SendInputMappingSignalsAuto(e->window->win,ime);            }        }    }}//MSG====================================================int la_IsThisSysWindow(laWindow *wnd, SYSWINDOW hwnd){    if (wnd->win == hwnd) return 1;    else return 0;};void la_EnsurePanelSnapping(laPanel *p, int CW, int CH){    if (p->SL){ int s=p->SL<0?0:p->SL;        if (p->TX != s) laRecalcPanel(p);        p->TX = s;    }    if (p->SR){ int s=p->SR<0?0:p->SR;        if (p->TW != CW - p->TX - s) laRecalcPanel(p);        p->TW = CW - p->TX - s;    }    if (p->ST){ int s=p->ST<0?0:p->ST;        if (p->TY != s) laRecalcPanel(p);        p->TY = s;    }    if (p->SB){ int s=p->SB<0?0:p->SB;        if (p->TH != CH - p->TY - s) laRecalcPanel(p);        p->TH = CH - p->TY - s;    }}void la_RecalcBlockRecursive(laBlock *b, int X, int Y, int W, int H){    laPanel *p = 0;    b->X = X;    b->Y = Y;    b->W = W;    b->H = H;    if (b->B1){        int SplitWidth;        if (b->Vertical){            SplitWidth = H * b->SplitRatio;            la_RecalcBlockRecursive(b->B1, X, Y, W, SplitWidth);            la_RecalcBlockRecursive(b->B2, X, Y + SplitWidth, W, H - SplitWidth);        }else{            SplitWidth = W * b->SplitRatio;            la_RecalcBlockRecursive(b->B1, X, Y, SplitWidth, H);            la_RecalcBlockRecursive(b->B2, X + SplitWidth, Y, W - SplitWidth, H);        }    }    //if (!b->CurrentPanel)b->CurrentPanel = b->Panels.pFirst;    for(p=b->Panels.pFirst;p;p=p->Item.pNext){        p->TitleWidth = tnsStringGetWidth(transLate(p->Title->Ptr), 0, 0);    }    if (p = b->CurrentPanel){        int TitleGap=b->Folded?0:LA_RH;        p->X = X + LA_SEAM_W; p->Y = Y + LA_SEAM_W + TitleGap;        p->TX = X + LA_SEAM_W; p->TY = Y + LA_SEAM_W + TitleGap;        p->TW = W - LA_SEAM_W*2; p->TH = H - LA_SEAM_W*2 - TitleGap;        laRecalcPanel(p);    }}void la_UpdateUiPlacement(laWindow *w){    laLayout *l;    laPanel *p;    int CW = w->CW;    int CH = w->CH;    laBoxedTheme* bt = _LA_THEME_FLOATING_PANEL;    int MenuHeight=(LA_M+LA_M)*2+LA_RH;    if(w->MaximizedUi && w->MaximizedUiPanel){        laRecalcPanel(w->MaximizedUiPanel);    }elif(w->MaximizedBlock){        la_RecalcBlockRecursive(w->MaximizedBlock, -LA_SEAM_W, MenuHeight, CW+LA_SEAM_W*2, CH-MenuHeight+LA_SEAM_W);    }else{        for (l = w->Layouts.pFirst; l; l = l->Item.pNext){            la_RecalcBlockRecursive(l->FirstBlock, -LA_SEAM_W, MenuHeight, CW+LA_SEAM_W*2, CH-MenuHeight+LA_SEAM_W);        }    }    for (p = w->Panels.pFirst; p; p = p->Item.pNext){        if(p->IsMenuPanel){            p->TH=p->H=MenuHeight;        }        la_EnsurePanelSnapping(p, CW, CH);        laRecalcPanel(p);    }}void la_CommandResizeWindow(SYSWINDOW hwnd, int x, int y, int w, int h){    laWindow *window;#ifdef LAGUI_ANDROID    window = MAIN.Windows.pFirst; if (!window) return;    window->X=x;window->Y=y;window->W=w;window->H=h;    window->CW=w;window->CH=h;    la_UpdateUiPlacement(window); return;#endif    window = lstFindItem(hwnd, la_IsThisSysWindow, &MAIN.Windows);    if (!window) return;#ifdef _WIN32    RECT rcc; GetClientRect(window->win, &rcc);    RECT rcw; GetWindowRect(window->win, &rcw);    window->CW = rcc.right - rcc.left;    window->CH = rcc.bottom - rcc.top;    window->W = rcw.right - rcw.left;    window->H = rcw.bottom - rcw.top;    window->X = rcw.left; window->Y = rcw.top;    if (MAIN.AutoSwitchColorSpace || window->OutputColorSpace==255) {        memAssignRef(window,&window->WhichScreen, laGetWindowScreen(window));        if (window->WhichScreen && MAIN.AutoSwitchColorSpace) { window->OutputColorSpace = window->WhichScreen->ColorSpace; }    }#endif#ifdef LA_LINUX    XWindowAttributes attr;    XGetWindowAttributes(MAIN.dpy, window->win, &attr);    window->CW = w; window->CH = h;    window->W = w; window->H = h;    window->X = x; window->Y = y;    if(MAIN.AutoSwitchColorSpace || window->OutputColorSpace==255){        memAssignRef(window,&window->WhichScreen, laGetWindowScreen(window));        if(window->WhichScreen && MAIN.AutoSwitchColorSpace){ window->OutputColorSpace = window->WhichScreen->ColorSpace; }    }#endif    la_UpdateUiPlacement(window);}int la_OnWindowDestroy(SYSWINDOW wnd){    laListHandle *hlst = &MAIN.Windows;    laWindow *w = lstFindItem(wnd, la_IsThisSysWindow, hlst);    if (!w) return 0;    if (MAIN.Windows.pFirst==MAIN.Windows.pLast){        int empty=0; int mod=laRegisterModifications(1,1,&empty,0);        if(mod || empty){ laInvoke(0, "LA_managed_save", 0,0,"on_exit=true;",0); return 0; }        laShutoff(1);        return 1;    }    laListHandle h={0};laLayout*l=0;    while(l=lstPopItem(&w->Layouts)){ lstAppendItem(&h, l); }    la_DestroyWindow(w);    int done=0; for(laWindow* w=MAIN.Windows.pFirst;w;w=w->Item.pNext){#ifdef LA_LINUX        if(done) glXSwapIntervalEXTF(MAIN.dpy, w->win, 0);        else { glXSwapIntervalEXTF(MAIN.dpy, w->win, 1); done = 1; }#endif        while (l = lstPopItem(&h)) { lstAppendItem(&w->Layouts, l); }    }    return 0;}void la_MakeSpecialKeyBit(SYSWINDOW hwnd,laWindow*wnd,laEvent *e,int use_last_pos){    laListHandle *el = &wnd->EventList;    laEvent* last_e=el->pLast;    SYSWINDOW root_ret, win_ret; int rrx=0,rry=0,rx=e->x,ry=e->y,rmask=0;#ifdef LA_LINUX    XQueryPointer(MAIN.dpy, wnd->win, &root_ret,&win_ret,&rrx,&rry,&rx,&ry,&rmask);    e->SpecialKeyBit = ((rmask&ShiftMask)?LA_KEY_SHIFT:0)|((rmask&ControlMask)?LA_KEY_CTRL:0)|((rmask&Mod1Mask)?LA_KEY_ALT:0);#endif#ifdef _WIN32    e->SpecialKeyBit = ((GetKeyState(VK_SHIFT)&0x8000)?LA_KEY_SHIFT:0)|((GetKeyState(VK_CONTROL)&0x8000)?LA_KEY_CTRL:0)|((GetKeyState(VK_MENU)&0x8000)?LA_KEY_ALT:0);#endif}void la_SaveEvent(SYSWINDOW hwnd, laEvent *e, int use_last_pos){    laListHandle *wl = &MAIN.Windows;    laWindow* wnd;#ifdef LAGUI_ANDROID    wnd = MAIN.Windows.pFirst;#else    wnd = lstFindItem(hwnd, la_IsThisSysWindow, wl);#endif    if (!wnd){ memFree(e); return; }    laListHandle *el = &wnd->EventList;    la_MakeSpecialKeyBit(hwnd,wnd,e,use_last_pos);    if(use_last_pos){ e->x=MAIN.evLastX; e->y=MAIN.evLastY; }    e->window = wnd;    e->Twist=MAIN.StylusTwist; e->HasTwist = MAIN.StylusHasTwist;    e->Pressure=MAIN.IsPen?(MAIN.PointerIsEraser?MAIN.EraserPressure:MAIN.StylusPressure):0.5f;    e->Orientation=MAIN.PointerIsEraser?MAIN.EraserOrientation:MAIN.StylusOrientation;    e->Deviation=MAIN.PointerIsEraser?MAIN.EraserDeviation:MAIN.StylusDeviation;    e->IsEraser=MAIN.PointerIsEraser; e->Hover=MAIN.StylusHover;    e->GoodPressure=MAIN.IsPen;    lstAppendItem(el, (laListItem *)e);    laMappingRequestEval();};void la_SendKeyboardEvent(SYSWINDOW hwnd, int type, int key){    laEvent *e = memAcquireSimple(sizeof(laEvent)); e->type = type; e->key = tolowerGuarded(key);    la_SaveEvent(hwnd, e, 1);};void la_SendInputEvent(SYSWINDOW hwnd, uint32_t Input){    laEvent *e = memAcquireSimple(sizeof(laEvent));    e->type = LA_INPUT; e->Input=Input;    la_SaveEvent(hwnd, e, 1);}void la_SendEmptyEvent(SYSWINDOW hwnd){    laEvent *e = memAcquireSimple(sizeof(laEvent));    e->type = LA_EMPTY;    la_SaveEvent(hwnd, e, 1);}void laSendOperatorTriggerEvent(){    if (MAIN.ReTriggerOperators) la_SendEmptyEvent(MAIN.CurrentWindow->win);    MAIN.ReTriggerOperators = 0;}int la_TranslateSpecialKey(int keysym){#ifdef LA_LINUX    switch(keysym){    case XK_Return:    return LA_KEY_ENTER;    case XK_BackSpace: return LA_KEY_BACKSPACE;    case XK_Delete:    return LA_KEY_DELETE;    case XK_Escape:    return LA_KEY_ESCAPE;    case XK_Tab:       return LA_KEY_TAB;    case XK_Left:      return LA_KEY_ARRLEFT;    case XK_Right:     return LA_KEY_ARRRIGHT;    case XK_Up:        return LA_KEY_ARRUP;    case XK_Down:      return LA_KEY_ARRDOWN;    case XK_Control_L: return LA_KEY_CTRL;    case XK_Control_R: return LA_KEY_CTRL;    case XK_Shift_L:   return LA_KEY_SHIFT;    case XK_Shift_R:   return LA_KEY_SHIFT;    case XK_Alt_L:     return LA_KEY_ALT;    case XK_Alt_R:     return LA_KEY_ALT;    case XK_KP_1:      return LA_KEY_NUM1;    case XK_KP_2:      return LA_KEY_NUM2;    case XK_KP_3:      return LA_KEY_NUM3;    case XK_KP_4:      return LA_KEY_NUM4;    case XK_KP_5:      return LA_KEY_NUM5;    case XK_KP_6:      return LA_KEY_NUM6;    case XK_KP_7:      return LA_KEY_NUM7;    case XK_KP_8:      return LA_KEY_NUM8;    case XK_KP_9:      return LA_KEY_NUM9;    case XK_KP_0:      return LA_KEY_NUM0;    case XK_KP_Add: return LA_KEY_NUMPLUS;    case XK_KP_Subtract: return LA_KEY_NUMMINUS;    case XK_KP_Divide: return LA_KEY_NUMDIVIDE;    case XK_KP_Multiply: return LA_KEY_NUMMULT;    case XK_KP_Decimal: return LA_KEY_NUMDOT;    case XK_KP_Enter:  return LA_KEY_NUMENTER;    default:           return keysym;    }#endif#ifdef _WIN32    switch (keysym) {    case VK_RETURN:    return LA_KEY_ENTER;    case VK_ESCAPE:    return LA_KEY_ESCAPE;    case VK_TAB:       return LA_KEY_TAB;    case VK_LEFT:      return LA_KEY_ARRLEFT;    case VK_RIGHT:     return LA_KEY_ARRRIGHT;    case VK_UP:        return LA_KEY_ARRUP;    case VK_DOWN:      return LA_KEY_ARRDOWN;    case VK_CONTROL:   return LA_KEY_CTRL;    case VK_SHIFT:     return LA_KEY_SHIFT;    case VK_MENU:      return LA_KEY_ALT;    case VK_F1:        return LA_KEY_F1;    case VK_F2:        return LA_KEY_F2;    case VK_F3:        return LA_KEY_F3;    case VK_F4:        return LA_KEY_F4;    case VK_F5:        return LA_KEY_F5;    case VK_F6:        return LA_KEY_F6;    case VK_F7:        return LA_KEY_F7;    case VK_F8:        return LA_KEY_F8;    case VK_F9:        return LA_KEY_F9;    case VK_F10:       return LA_KEY_F10;    case VK_F11:       return LA_KEY_F11;    case VK_F12:       return LA_KEY_F12;    case VK_NUMPAD0:   return LA_KEY_NUM0;    case VK_NUMPAD1:   return LA_KEY_NUM1;    case VK_NUMPAD2:   return LA_KEY_NUM2;    case VK_NUMPAD3:   return LA_KEY_NUM3;    case VK_NUMPAD4:   return LA_KEY_NUM4;    case VK_NUMPAD5:   return LA_KEY_NUM5;    case VK_NUMPAD6:   return LA_KEY_NUM6;    case VK_NUMPAD7:   return LA_KEY_NUM7;    case VK_NUMPAD8:   return LA_KEY_NUM8;    case VK_NUMPAD9:   return LA_KEY_NUM9;    case VK_MULTIPLY:   return LA_KEY_NUMMULT;    case VK_DIVIDE:   return LA_KEY_NUMDIVIDE;    case VK_ADD:   return LA_KEY_NUMPLUS;    case VK_SUBTRACT:   return LA_KEY_NUMMINUS;    case VK_DECIMAL:   return LA_KEY_NUMDOT;    case VK_OEM_1:     return ';';    case VK_OEM_2:     return '/';    case VK_OEM_3:     return '`';    case VK_OEM_4:     return '[';    case VK_OEM_5:     return '\\';    case VK_OEM_6:     return ']';    case VK_OEM_7:     return '\'';    case VK_OEM_COMMA: return ',';    case VK_OEM_PERIOD: return '.';    case VK_OEM_PLUS:  return '+';    case VK_OEM_MINUS: return '-';    default:           return keysym;    }#endif}void la_SendMouseEvent(SYSWINDOW hwnd, int type, int x, int y){    //if((type&LA_STATE_DOWN)&&(x!=MAIN.evLastX || y!=MAIN.evLastY)){    //    laEvent *e = memAcquireSimple(sizeof(laEvent));    //    e->Type = LA_MOUSEMOVE; e->x = x; e->y = y;    //    la_SaveEvent(hwnd, e, 0);    //}    laEvent *e = memAcquireSimple(sizeof(laEvent));    e->type = type; e->x = x; e->y = y;    la_SaveEvent(hwnd, e, 0);    MAIN.evLastX=x; MAIN.evLastY=y;};void la_SendTimerEvent(SYSWINDOW hwnd, int type){    laEvent *e = memAcquireSimple(sizeof(laEvent));    e->type = type;    la_SaveEvent(hwnd, e, 1);};void la_SendSignalEvent(SYSWINDOW* hwnd, int signal){    laEvent *e = memAcquireSimple(sizeof(laEvent));    e->type = LA_SIGNAL_EVENT;    e->key = signal;    la_SaveEvent(hwnd, e, 1);};void la_SendPasteEvent(SYSWINDOW* hwnd) {    laEvent* e = memAcquireSimple(sizeof(laEvent));    e->type = LA_PASTE;    la_SaveEvent(hwnd, e, 1);};void la_SendOperatorEvent(SYSWINDOW* hwnd, laOperatorType* at, int use_base, char* instructions){    if(!at){ return; }    laEvent *e = memAcquireSimple(sizeof(laEvent));    e->type = LA_OPERATOR_EVENT;    e->Operator = at; e->OperatorBase = use_base; e->OperatorInstructions = instructions;    la_SaveEvent(hwnd, e, 1);};void laRetriggerOperators(){    MAIN.ReTriggerOperators = 1;}void laSetFrameCallbacks(laPreFrameF PreFrame, laPreDrawF PreDraw, laPostFrameF PostFrame){    MAIN.PreFrame=PreFrame; MAIN.PreDraw=PreDraw; MAIN.PostFrame=PostFrame;}void laSetCleanupCallback(laCleanupF Cleanup){    MAIN.Cleanup=Cleanup;}void laSetInputProcessCallback(laInputProcessF InputProcess){    MAIN.InputProcess=InputProcess;}//====================================================================================================laTheme *laDuplicateTheme(laTheme* from){    laTheme *t = memAcquireHyper(sizeof(laTheme));    strSafePrint(&t->Name, "~%s", SSTR(from->Name));    lstPushItem(&MAIN.Themes, t);    MAIN.CurrentTheme = t;    char buf[32]; sprintf(buf,"LATHEME_%.22s",SSTR(t->Name));    laset_InstanceUID(t, buf);    tnsVectorSet3v(t->Color,from->Color);    tnsVectorSet3v(t->ColorB,from->ColorB);    tnsVectorSet3v(t->ColorC,from->ColorC);    tnsVectorSet3v(t->AccentColor,from->AccentColor);    tnsVectorSet3v(t->WarningColor,from->WarningColor);    t->InactiveMix=from->InactiveMix;    t->InactiveSaturation=from->InactiveSaturation;    t->CursorAlpha=from->CursorAlpha;    t->SelectionAlpha=from->SelectionAlpha;    t->ShadowAlpha=from->ShadowAlpha; t->TextShadowAlpha=from->TextShadowAlpha;    t->WireBrightness=from->WireBrightness;    t->WireSaturation=from->WireSaturation;    t->WireTransparency=from->WireTransparency;    t->EdgeBrightness=from->EdgeBrightness;    t->EdgeTransparency=from->EdgeTransparency;    t->VertexBrightness=from->VertexBrightness;    t->VertexTransparency=from->VertexTransparency;    t->SelectedFaceTransparency=from->SelectedFaceTransparency;    t->SelectedEdgeTransparency=from->SelectedEdgeTransparency;    t->SelectedVertexTransparency=from->SelectedVertexTransparency;        for(laBoxedTheme* bt=from->BoxedThemes.pFirst;bt;bt=bt->Item.pNext){        laBoxedTheme* new_bt = laDesignBoxedTheme(t,SSTR(bt->Name),bt->BackRef,bt->ColorSelection,            bt->NormalY,bt->ActiveY,bt->BorderY,bt->TextY,bt->TextActiveY,bt->Alpha,bt->BoxStyle,bt->TextShadow);    }    la_RefreshThemeColor(t);    la_RegenerateWireColors();    return t;}void la_DestroyTheme(laTheme* t){    MAIN.CurrentTheme = t->Item.pPrev?t->Item.pPrev:t->Item.pNext;    lstRemoveItem(&MAIN.Themes, t);    laBoxedTheme*bt; while(bt=lstPopItem(&t->BoxedThemes)){ strSafeDestroy(&bt->Name); *bt->BackRef=0; memFree(bt); }    strSafeDestroy(&t->Name);    memFree(t);}laTheme *laDesignTheme(const char *Name){    laTheme *t = memAcquireHyper(sizeof(laTheme));    strSafeSet(&t->Name, Name);    lstPushItem(&MAIN.Themes, t);    MAIN.CurrentTheme = t;    char buf[32]; sprintf(buf,"LATHEME_%.22s",Name);    laset_InstanceUID(t, buf);    return t;}laBoxedTheme *laDesignBoxedTheme(laTheme *t, const char *Name, laBoxedTheme** BackRef, int ColorSelection,                                 real NormalY,real ActiveY,real BorderY,real TextY,real TextActiveY, real Alpha,                                 int BoxStyle, int TextShadow){    laBoxedTheme *bt = memAcquire(sizeof(laBoxedTheme));    strSafeSet(&bt->Name, Name);    bt->ColorSelection = ColorSelection;    bt->NormalY=NormalY; bt->ActiveY=ActiveY; bt->BorderY=BorderY;    bt->TextY=TextY; bt->TextActiveY=TextActiveY; bt->Alpha = Alpha;    bt->BoxStyle = BoxStyle; bt->TextShadow = TextShadow;    bt->BackRef = BackRef;    memAssignRef(bt, &bt->Parent, t);    lstAppendItem(&t->BoxedThemes, bt);    return bt;}laTheme *laGetTheme(const char *ThemeName){    laTheme *t = MAIN.Themes.pFirst;    for (t; t; t = t->Item.pNext){        if (strSame(t->Name->Ptr, ThemeName)) return t;    }    return 0;}laBoxedTheme *laGetBoxedTheme(const char *ThemeName, const char *BoxName){    laTheme *t = MAIN.Themes.pFirst;    for (t; t; t = t->Item.pNext){        laBoxedTheme *bt;        if (!strSame(t->Name->Ptr, ThemeName)) continue;        bt = t->BoxedThemes.pFirst;        for (bt; bt; bt = bt->Item.pNext){            if (strSame(bt->Name->Ptr, BoxName)) return bt;        }    }    return 0;}real* laThemeColor(laBoxedTheme* bt, int which){    switch(which){        default:        case LA_BT_NORMAL: return bt->Normal;        case LA_UI_EDITING:        case LA_BT_ACTIVE: return bt->Active;        case LA_BT_BORDER: return bt->Border;        case LA_BT_TEXT|LA_BT_NO_DECAL: return bt->TextInvert;        case LA_BT_TEXT:   return bt->Text;        case LA_BT_TEXT|LA_UI_EDITING:        case LA_BT_TEXT_ACTIVE: return bt->TextActive;        case LA_BT_DISABLED: return bt->Inactive;        case LA_BT_DISABLED|LA_BT_TEXT: return bt->TextInactive;    }    return bt->Normal;}real* laAccentColor(int which){    switch(which){        default:        case LA_BT_NORMAL: case LA_UI_EDITING: case LA_BT_ACTIVE: return MAIN.CurrentTheme->SelectionColor;        case LA_BT_WARNING: return MAIN.CurrentTheme->WarningColor;        case LA_BT_BORDER: case LA_BT_TEXT: case LA_BT_TEXT_ACTIVE: return MAIN.CurrentTheme->CursorColor;        case LA_BT_VERTEX: return MAIN.CurrentTheme->VertexColor;        case LA_BT_FACE:        case LA_BT_EDGE: return MAIN.CurrentTheme->EdgeColor;        case LA_BT_SVERTEX: return MAIN.CurrentTheme->SVertexColor;        case LA_BT_SEDGE: return MAIN.CurrentTheme->SEdgeColor;        case LA_BT_SFACE: return MAIN.CurrentTheme->SFaceColor;        case LA_BT_SHADOW: return MAIN.CurrentTheme->ShadowColor;        case LA_BT_SHADOW|LA_BT_TEXT: return MAIN.CurrentTheme->TextShadowColor;    }    return MAIN.CurrentTheme->SelectionColor;}void la_RefreshBoxedThemeColor(laBoxedTheme* bt){    real hcy[3]; if(!bt->Parent){ return; }    laTheme* th = bt->Parent; real* color = bt->ColorSelection==2?th->ColorC:(bt->ColorSelection==1?th->ColorB:th->Color);    tnsRGB2HCY(color,hcy);    hcy[2]=bt->NormalY; tnsHCY2RGB(hcy, bt->Normal); bt->Normal[3]=bt->Alpha;    hcy[2]=bt->ActiveY; tnsHCY2RGB(hcy, bt->Active); bt->Active[3]=bt->Alpha;    hcy[2]=bt->BorderY; tnsHCY2RGB(hcy, bt->Border); bt->Border[3]=1;    hcy[2]=bt->TextY;   tnsHCY2RGB(hcy, bt->Text); bt->Text[3]=1;    hcy[2]=bt->TextActiveY; tnsHCY2RGB(hcy, bt->TextActive); bt->TextActive[3]=1;    if(bt->NoDecalInvert){ hcy[2]=bt->NormalY/(bt->TextY/bt->NormalY);TNS_CLAMP(hcy[2],0,1); tnsHCY2RGB(hcy, bt->TextInvert); bt->TextInvert[3]=1.0f; }    else{ tnsVectorSet4v(bt->TextInvert,bt->Text); }}void la_RefreshThemeColorSelf(laTheme* th){    if((!th) || (!th->BoxedThemes.pFirst)) return;    tnsVectorCopy3d(th->AccentColor, th->CursorColor);   th->CursorColor[3]=th->CursorAlpha;    tnsVectorCopy3d(th->AccentColor, th->SelectionColor);th->SelectionColor[3]=th->SelectionAlpha; th->WarningColor[3]=th->SelectionAlpha;    real hcy[3], usehcy[3];    tnsRGB2HCY(th->Color,hcy); tnsVectorCopy3d(hcy,usehcy);    usehcy[2]=th->VertexBrightness; tnsHCY2RGB(usehcy, th->VertexColor); th->VertexColor[3]=th->VertexTransparency;    usehcy[2]=th->EdgeBrightness;   tnsHCY2RGB(usehcy, th->EdgeColor);   th->EdgeColor[3]=th->EdgeTransparency;    tnsVectorCopy3d(th->AccentColor, th->SVertexColor); th->SVertexColor[3]=th->SelectedVertexTransparency;    tnsVectorCopy3d(th->AccentColor, th->SEdgeColor); th->SEdgeColor[3]=th->SelectedEdgeTransparency;    tnsVectorCopy3d(th->AccentColor, th->SFaceColor); th->SFaceColor[3]=th->SelectedFaceTransparency;    //tnsVectorCopy3d(th->Color, th->ShadowColor); th->ShadowColor[3]=th->CursorAlpha;    tnsVectorSet4(th->ShadowColor,0,0,0,th->ShadowAlpha);    tnsVectorSet4(th->TextShadowColor,0,0,0,th->TextShadowAlpha);}void la_RefreshThemeColor(laTheme* th){    if(!th) return;    real hcy[3], usehcy[3], normalhcy[3];    la_RefreshThemeColorSelf(th);    for(laBoxedTheme* bt = th->BoxedThemes.pFirst;bt;bt=bt->Item.pNext){        la_RefreshBoxedThemeColor(bt);        (*bt->BackRef) = bt;        tnsRGB2HCY(bt->Text, usehcy); usehcy[1]*=th->InactiveSaturation;        tnsHCY2RGB(usehcy, bt->TextInactive); bt->TextInactive[3]=th->InactiveMix;        tnsRGB2HCY(bt->Normal, normalhcy); normalhcy[1]*=th->InactiveSaturation;        tnsHCY2RGB(normalhcy, bt->Inactive); bt->Inactive[3]=bt->Alpha*th->InactiveMix;    }}void laSetProofingLut(laProofingLUT* pl){    MAIN.CurrentProofingLUT = pl;    MAIN.LutNeedsRefreshing=1;}void la_RefreshProofingLut(){    if(!MAIN.CurrentWindow) return;    int table = MAIN.CurrentWindow->OutputColorSpace;    if(!MAIN.LutNeedsRefreshing) return;    tnsEnableShaderv(T->immShader);    tnsShader* s = T->immShader;    if(!MAIN.CurrentProofingLUT){ MAIN.CurrentProofingLUT=MAIN.ProofingLUTs.pFirst; }    if(!MAIN.CurrentProofingLUT || !MAIN.CurrentWindow->OutputProofing){ MAIN.CurrentWindow->OutputProofing=0; return; }    char* tabledata=0;    switch(table){        default:        case 0: tabledata=MAIN.CurrentProofingLUT->TablesRGB; break;        case 1: tabledata=MAIN.CurrentProofingLUT->TableClay; break;        case 2: tabledata=MAIN.CurrentProofingLUT->TableD65P3; break;    }    if(!tabledata){ MAIN.CurrentWindow->OutputProofing=0; return; }    if(!MAIN.LutTexture) glGenTextures(1, &MAIN.LutTexture);    tnsActiveTexture(GL_TEXTURE3);    glBindTexture(GL_TEXTURE_3D, MAIN.LutTexture);    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);    glTexImage3D(GL_TEXTURE_3D,0,GL_RGB,LA_LUT_PRECISION,LA_LUT_PRECISION,LA_LUT_PRECISION,0,GL_RGB, GL_UNSIGNED_BYTE,tabledata);    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);    //glBindTexture(GL_TEXTURE_3D,0);    tnsActiveTexture(GL_TEXTURE0);    MAIN.LutNeedsRefreshing=0;}//I FUCKING HATE THIS STUPID FUNCTIONint la_SetUpUiListMatrix(laUiListDraw *uild, laUiList *Target, int _L, int _R, int LimH, int PanelH){    laUiListDrawItem *uildi = memAcquireSimple(sizeof(laUiListDrawItem));    laUiListDrawItem *last = uild->Items.pFirst;    int LimW=_R-_L;    int SL, SR, SU, SB;    int Target__B = Target->B;    int Target__R = Target->R;    uildi->Target = Target;    // uildi->    //   XP,YP total pan    //   LRUB border after previous pan    //   SLRUB border after clamping    //   DifXY clamped distance    //       // why we still need this line    if (Target__B - Target->U > LimH) Target__B = Target->U + LimH;    //if (Target__R - Target->L > LimW) Target__R = Target->L + LimW;    uildi->XP = last ? last->XP + Target->PanX : Target->PanX;    uildi->YP = last ? last->YP + Target->PanY : Target->PanY;    uildi->L = last ? Target->L - last->XP : Target->L;    uildi->R = last ? Target__R - last->XP : Target__R;    uildi->U = last ? Target->U - last->YP : Target->U;    uildi->B = last ? Target__B - last->YP : Target__B;    if (uildi->B - uildi->U > LimH) uildi->B = Target->U + LimH;    SL = last ? (uildi->L < last->L ? last->L : uildi->L) : uildi->L;    SR = last ? (uildi->R > last->R ? last->R : uildi->R) : uildi->R;    SU = last ? (uildi->U < last->U ? last->U : uildi->U) : uildi->U;    SB = last ? (uildi->B > last->B ? last->B : uildi->B) : uildi->B;    if(SL<_L) SL=_L;    if(SR>_R) SR=_R;    uildi->DifX = SL - uildi->L;    uildi->DifY = SU - uildi->U;    uildi->L = SL;    uildi->R = SR;    uildi->U = SU;    uildi->B = SB;    if(uildi->B-SU>LimH){ uildi->B=SU+LimH; }    if(uildi->R - uildi->L<=0 || uildi->B - uildi->U<=0){        memFree(uildi);        return 0;    }    int Pad=2;    tnsViewportWithScissor(uildi->L-Pad, PanelH - uildi->B-Pad, uildi->R - uildi->L+Pad*2, uildi->B - uildi->U+Pad*2);    tnsOrtho(Target->L + Target->PanX + uildi->DifX-Pad,             Target->L + Target->PanX + uildi->DifX+Pad+ (uildi->R - uildi->L),             Target->U + Target->PanY + uildi->DifY+Pad+ (uildi->B - uildi->U),             Target->U + Target->PanY + uildi->DifY-Pad,             -100, 100);    lstPushItem(&uild->Items, uildi);    return 1;}void la_SetUpUiListMatrixInLine(laUiListDraw *uild, int L, int R, int U, int B, int PanX, int PanY, int LimH, int PanelH){    laUiListDrawItem *uildi = memAcquireSimple(sizeof(laUiListDrawItem));    laUiListDrawItem *last = uild->Items.pFirst;    int SL, SR, SU, SB;    if (B - U > LimH) B = U + LimH;    uildi->XP = last ? last->XP + PanX : PanX;    uildi->YP = last ? last->YP + PanY : PanY;    uildi->L = last ? L - last->XP : L;    uildi->R = last ? R - last->XP : R;    uildi->U = last ? U - last->YP : U;    uildi->B = last ? B - last->YP : B;    SL = last ? (uildi->L < last->L ? last->L : uildi->L) : uildi->L;    SR = last ? (uildi->R > last->R ? last->R : uildi->R) : uildi->R;    SU = last ? (uildi->U < last->U ? last->U : uildi->U) : uildi->U;    SB = last ? (uildi->B > last->B ? last->B : uildi->B) : uildi->B;    uildi->DifX = SL - uildi->L;    uildi->DifY = SU - uildi->U;    uildi->L = SL;    uildi->R = SR;    uildi->U = SU;    uildi->B = SB;    tnsViewportWithScissor(uildi->L, PanelH - uildi->B, uildi->R - uildi->L, uildi->B - uildi->U);    tnsOrtho(L + PanX + uildi->DifX,             L + PanX + uildi->DifX + (uildi->R - uildi->L),             U + PanY + uildi->DifY + (uildi->B - uildi->U),             U + PanY + uildi->DifY,             -100, 100);    lstPushItem(&uild->Items, uildi);}void la_DoUiScissor(laUiItem* ui, int* savex, int* savey, int* savew, int* saveh,    int* savel, int* saver, int* saveu, int* saveb){    laPanel* panel=MAIN.PropMatcherContextP; int PW=panel->W, PH=panel->H;    *savex=T->vsx;*savey=T->vsy;*savew=T->vsw;*saveh=T->vsh;    *savel=T->vol;*saver=T->vor;*saveu=T->vou;*saveb=T->vob;    real p[3]={0}, tp[3]={0}; tnsMatrix44d m; tnsGetMVPMatrix(m);    real x,y,w,h;    x=TNS_MAX2(ui->L,T->vsx); y=TNS_MAX2(PH-ui->B,T->vsy);    w=TNS_MIN2(ui->R-ui->L,T->vsw); h=TNS_MIN2(ui->B-ui->U,T->vsh);    tnsViewportWithScissor(x,y,w,h); tnsOrtho(ui->L,ui->R,ui->B,ui->U,-100,100);}void la_RebuildCurrentUiListMatrix(laUiListDraw *uild, laUiList *Target, int LimH, int PanelH){    laUiListDrawItem *uildi = uild->Items.pFirst;    tnsViewportWithScissor(uildi->L-1, PanelH - uildi->B-1, uildi->R - uildi->L+2, uildi->B - uildi->U+2);    tnsOrtho(Target->L + Target->PanX + uildi->DifX -1,             Target->L + Target->PanX + uildi->DifX +1 + (uildi->R - uildi->L),             Target->U + Target->PanY + uildi->DifY +1 + (uildi->B - uildi->U),             Target->U + Target->PanY + uildi->DifY -1,             -100, 100);}void la_RestoreLastUiListMatrix(laUiListDraw *uild, int PanelH){    laUiListDrawItem *uildi = lstPopItem(uild);    laUiList *Target;    memFree(uildi);    uildi = uild->Items.pFirst;    if (!uildi || !uildi->Target){        if (uild->Items.pFirst) la_RestoreLastUiListMatrix(uild, PanelH);        return;    }    Target = uildi->Target;    tnsViewportWithScissor(uildi->L-1, PanelH - uildi->B-1, uildi->R - uildi->L+2, uildi->B - uildi->U+2);    tnsOrtho(Target->L + Target->PanX + uildi->DifX -1,             Target->L + Target->PanX + uildi->DifX +1 + (uildi->R - uildi->L),             Target->U + Target->PanY + uildi->DifY +1 + (uildi->B - uildi->U),             Target->U + Target->PanY + uildi->DifY -1,             -100, 100);}void la_SetupUiListLimitMatrix(laUiListDraw *uild, int L, int R, int U, int B, int PanelH){    laUiListDrawItem *uildi = memAcquireSimple(sizeof(laUiListDrawItem));    uildi->L = L;    uildi->R = R;    uildi->U = U;    uildi->B = B;    tnsViewportWithScissor(uildi->L, PanelH - uildi->B, uildi->R - uildi->L, uildi->B - uildi->U);    tnsOrtho(L, R, B, U, -100, 100);    lstPushItem(&uild->Items, uildi);}void la_ClearUiListMatrix(laUiListDraw *uild){    laUiListDrawItem *uildi;    while (uildi = lstPopItem(uild)){        memFree(uildi);    }}int la_UpdateUiListRecursive(laUiList *uil, int U, int L, int R, int B, int Fast, laPanel *ParentPanel);int la_DrawUiListRecursive(laUiListDraw *uild, laUiList *uil, int L, int R, int U, int B, int LimH, int ConditionStackLevel, int RegisterNodes);void la_DestroyUiList(laUiList *uil, int NoFree, int RemoveUsers, int OnlyRemoveUser);void la_DrawUiListScrollerV(laUiList *uil, int DisplayOffset, int TotalH, int DisplayedH, int UiR, int BarTop, int BarBottom);int la_TestUiListMinumWidth(laUiList *uil);void la_PanelValidateWidth(laPanel *p, laUiList *ui){    if (ui){        if (p->MaxW && p->TW > p->MaxW) p->TW = p->MaxW;        if (p->MinW && p->TW < p->MinW) p->TW = p->MinW;        la_EnsurePanelSnapping(p, MAIN.CurrentWindow->CW, MAIN.CurrentWindow->CH);        p->X = p->TX; p->Y = p->TY;        p->W = p->TW;    }}void laEnsurePanelInBound(laPanel *p, laUiList *uil){    int cw = MAIN.CurrentWindow->CW;    int ch = MAIN.CurrentWindow->CH;    int PH = p->TH;    laBoxedTheme*bt = *p->BT;    int uih=uil->B + LA_M;    if (p->BoundUi && !(p->SB||p->ST)) PH = TNS_MAX2(uih, p->MinH);    if (p->MaxH && PH > p->MaxH) p->TH = p->MaxH;    else if (p->MinH && PH < p->MinH) p->TH = p->MinH;    else p->TH = PH;    p->H = p->TH;    if(p->BoundUi){        if ((p->X + p->W) > cw) p->X -= (p->X + p->W - cw);        if ((p->Y + p->H) > ch) p->Y -= (p->Y + p->H - ch);        if (p->X < 0) p->X = 0;        if (p->Y < 0) p->Y = 0;        if ((p->X + p->W) > cw){ p->W -= (p->X + p->W - cw); }        if ((p->Y + p->H) > ch){ p->H -= (p->Y + p->H - ch); }    }else{        if (p->Y < 0) p->Y = 0;        if ((!p->Block)&&(!p->IsMenuPanel)){            int cw2=cw-LA_RH*2,ch2=ch-LA_RH*2;            if (p->X + p->W < LA_RH * 5) p->X = LA_RH * 5 - +p->W;            if (p->X > cw2){ p->X = cw2; } if (p->Y > ch2){ p->Y = ch2; }            if (p->W > cw2){ p->W = cw2; } if (p->H > ch2){ p->H = ch2; }        }    }    if((!p->IsMenuPanel) && (p->Mode!=LA_PANEL_FLOATING_PASSIVE) && (!p->Block)){        if(p->W<LA_RH*3) p->W=LA_RH*3;        if(p->H<LA_RH*2) p->H=LA_RH*2;    }    if (p->ST) p->TY = p->ST;    if (p->SB && p->TH != ch - p->TY - p->SB) laRecalcPanel(p);    if (p->SB) p->TH = ch - p->TY - p->SB;    if(p->CloseWhenMovedOut==2){ p->X=(cw-p->W)/2; p->Y=(ch-p->H)/2; }    p->TX = p->X; p->TY = p->Y;    p->TW = p->W; p->TH = p->H;}void laPlacePanelForCreation(laPanel *p){    int cw = MAIN.CurrentWindow->CW; int ch = MAIN.CurrentWindow->CH; int PH = p->TH;    if ((!p->Block)&&(!p->IsMenuPanel)&&(!p->Parent)){        if (p->X+p->W > cw-LA_RH){ p->X = cw-LA_RH-p->W; }        if (p->Y+p->H > ch-LA_RH){ p->Y = ch-LA_RH-p->H; }        if (p->X < LA_RH){ p->X = LA_RH; } if (p->Y < LA_RH){ p->Y = LA_RH; }        p->TX=p->X; p->TY=p->Y;    }}void la_SetPanelMatrix(laPanel *p, laBoxedTheme *bt){    tnsDrawToOffscreen(p->OffScr, 1, 0);    tnsViewportWithScissor(0, 0, p->W, p->H);    //tnsMatrixMode(TNS_PROJECTION_MATRIX);    tnsOrtho(0, p->W, p->H, 0, -100, 100);}void la_SetPanelMatrixDrawWindow(laPanel *p, laBoxedTheme *bt){    tnsDrawToScreen();    tnsViewportWithScissor(p->X, MAIN.CurrentWindow->CH - p->H - p->Y, p->W, p->H);    tnsOrtho(0, p->W, p->H, 0, -100, 100);}void la_SetPanelMatrixLRTB(int PW, int PH, int LPadding, int RPadding, int TPadding, int BPadding, int XOffset, int YOffset){    tnsViewportWithScissor(LPadding, BPadding, PW - LPadding - RPadding, PH - TPadding - BPadding);    tnsOrtho(XOffset, XOffset + PW - LPadding - RPadding, YOffset + PH - BPadding, YOffset + TPadding, -100, 100);}void la_PanelBackgroundInit(laPanel *p, laBoxedTheme *bt){    real* color=laThemeColor(bt,LA_BT_NORMAL);    glClearColor(LA_COLOR3(color), p->Block?1.0f:color[3]);    tnsClearAll();    if(bt->BoxStyle==-1){ tnsUseNoTexture(); tnsColor4dv(laAccentColor(LA_BT_SHADOW)); la_DrawInnerShadow(0,p->W,0,p->H); }}void la_PanelDrawDescendBorder(laPanel* Panel, laBoxedTheme* bt);void la_PanelDrawToWindow(laPanel *p, laWindow *w){    real Color[] = {1, 1, 1, 1};    real L, W, U, H;    tnsUseImmShader(); tnsEnableShaderv(T->immShader);    if(MAIN.EnableColorManagement){        la_UseWindowColorCorrection(w);        tnsUniformOutputColorSpace(T->immShader,w->OutputColorSpace);        tnsUniformShowColorOverflowStripes(T->immShader,w->OutputShowStripes);        tnsUniformColorComposing(T->immShader,w->UseComposing,w->ComposingGamma,w->ComposingBlackpoint,w->OutputProofing);    }else{        tnsUniformOutputColorSpace(T->immShader,0);        tnsUniformShowColorOverflowStripes(T->immShader,0);        tnsUniformColorComposing(T->immShader,0,0,0,0);    }    if (p->Mode && (!p->AnimationMode || (p->AnimationMode && p->AnimationRatio > 0.99) || p->AnimationMode==LA_PANEL_ANIMATION_FLASH)){        tnsUseNoTexture();        if (!p->IsMenuPanel){            la_PanelDrawDescendBorder(p, (*p->BT));        }        tnsFlush();    }    if(p->ParentOperator){        tnsUseNoTexture();        tnsColor4d(LA_COLOR3(MAIN.CurrentTheme->Color),0.7*(p->AnimationMode==LA_PANEL_ANIMATION_FLASH?1.0f:p->AnimationRatio));        tnsVertex2d(0,0); tnsVertex2d(w->CW,0); tnsVertex2d(w->CW,w->CH); tnsVertex2d(0,w->CH);        tnsPackAs(GL_TRIANGLE_FAN); tnsFlush();    }    switch (p->AnimationMode){    case 0: /* and */    case LA_PANEL_ANIMATION_FLASH:        tnsDraw2DTextureDirectly(p->OffScr->pColor[0], p->X, p->Y, p->W, p->H);        if(!(p->SR || p->SB || p->Parent || p->Block || p->IsMenuPanel)){            real* color=laThemeColor(_LA_THEME_PANEL,LA_BT_TEXT); tnsColor4d(LA_COLOR3(color),color[3]*(p->ShowCorner?1:0.8));            int len=LA_RH/(p->ShowCorner?1:2); tnsUseNoTexture(); int px=p->X+p->W,py=p->Y+p->H;            tnsVertex2d(px,py); tnsVertex2d(px-len,py); tnsVertex2d(px,py-len);            tnsPackAs(GL_TRIANGLES);            tnsColor4dv(laThemeColor(_LA_THEME_PANEL,LA_BT_NORMAL)); tnsVertex2d(px-len,py); tnsVertex2d(px,py-len);            tnsLineWidth(2); tnsPackAs(GL_LINES); tnsLineWidth(1);        }        if(p->AnimationMode==LA_PANEL_ANIMATION_FLASH){            p->AnimationRatio += MAIN.PanelAnimationSpeed * 0.1 * MAIN.LastFrameTime * 60;            if((int)(p->AnimationRatio*6)%2){                tnsUseNoTexture();                tnsColor4dv(laAccentColor(LA_BT_SELECTED));                tnsVertex2d(p->X,p->Y); tnsVertex2d(p->X+p->W,p->Y); tnsVertex2d(p->X+p->W,p->Y+p->H); tnsVertex2d(p->X,p->Y+p->H);                 tnsPackAs(GL_TRIANGLE_FAN); tnsFlush();            }            if (p->AnimationRatio > 0.99) p->AnimationMode = 0; laRefreshWindow();        }        break;    case LA_PANEL_ANIMATION_DROP_DOWN:        tnsVectorMultiSelf4d(Color, p->AnimationRatio);        tnsDraw2DTextureArg(            p->OffScr->pColor[0],            p->X, p->Y, p->W, p->H * p->AnimationRatio,            Color,            0, 0, 1 - p->AnimationRatio, 0);        p->AnimationRatio += (1 - p->AnimationRatio) * MAIN.PanelAnimationSpeed * MAIN.LastFrameTime * 60;        if (p->AnimationRatio > 0.99) p->AnimationMode = 0; laRefreshWindow();        break;    case LA_PANEL_ANIMATION_EXPAND:        L = tnsLinearItp(p->X, p->X + p->W, 0.3);        U = tnsLinearItp(p->Y, p->Y + p->H, 0.3);        W = tnsLinearItp(0, p->W, 0.4);        H = tnsLinearItp(0, p->H, 0.4);        tnsVectorMultiSelf4d(Color, p->AnimationRatio);        tnsDraw2DTextureArg(            p->OffScr->pColor[0],            tnsLinearItp(L, p->X, p->AnimationRatio), tnsLinearItp(U, p->Y, p->AnimationRatio),            tnsLinearItp(W, p->W, p->AnimationRatio), tnsLinearItp(H, p->H, p->AnimationRatio),            Color,            0, 0, 0, 0);        p->AnimationRatio += (1 - p->AnimationRatio) * MAIN.PanelAnimationSpeed * MAIN.LastFrameTime * 60;        if (p->AnimationRatio > 0.99) p->AnimationMode = 0; laRefreshWindow();        break;    case LA_PANEL_ANIMATION_DISSOVE:        L = tnsLinearItp(p->X, p->X + p->W, -0.2);        U = tnsLinearItp(p->Y, p->Y + p->H, -0.2);        W = tnsLinearItp(0, p->W, 1.4);        H = tnsLinearItp(0, p->H, 1.4);        tnsVectorMultiSelf4d(Color, (p->AnimationRatio));        if (p->OffScr) tnsDraw2DTextureArg(                p->OffScr->pColor[0],                tnsLinearItp(L, p->X, p->AnimationRatio), tnsLinearItp(U, p->Y, p->AnimationRatio),                tnsLinearItp(W, p->W, p->AnimationRatio), tnsLinearItp(H, p->H, p->AnimationRatio),                Color,                0, 0, 0, 0);        p->AnimationRatio -= (p->AnimationRatio) * MAIN.PanelAnimationSpeed * MAIN.LastFrameTime * 60;        if (p->AnimationRatio < 0.01) p->AnimationMode = 0; laRefreshWindow();        break;    case LA_PANEL_ANIMATION_COLLAPSE:        L = tnsLinearItp(p->X, p->X + p->W, 0.3);        U = tnsLinearItp(p->Y, p->Y + p->H, 0.3);        W = tnsLinearItp(0, p->W, 0.4);        H = tnsLinearItp(0, p->H, 0.4);        tnsVectorMultiSelf4d(Color, p->AnimationRatio);        if (p->OffScr) tnsDraw2DTextureArg(                p->OffScr->pColor[0],                tnsLinearItp(L, p->X, p->AnimationRatio), tnsLinearItp(U, p->Y, p->AnimationRatio),                tnsLinearItp(W, p->W, p->AnimationRatio), tnsLinearItp(H, p->H, p->AnimationRatio),                Color,                0, 0, 0, 0);        p->AnimationRatio -= p->AnimationRatio * MAIN.PanelAnimationSpeed * MAIN.LastFrameTime * 60;        if (p->AnimationRatio < 0.01) p->AnimationMode = 0; laRefreshWindow();        break;    case LA_PANEL_ANIMATION_MINIMIZE:        L = tnsLinearItp(0, p->X, 0.3);        U = tnsLinearItp(w->H, p->Y + p->H, 0.3);        W = tnsLinearItp(0, p->W, 0.4);        H = tnsLinearItp(0, p->H, 0.4);        tnsVectorMultiSelf4d(Color, p->AnimationRatio);        tnsDraw2DTextureArg(            p->OffScr->pColor[0],            tnsLinearItp(L, p->X, p->AnimationRatio), tnsLinearItp(U, p->Y, p->AnimationRatio),            tnsLinearItp(W, p->W, p->AnimationRatio), tnsLinearItp(H, p->H, p->AnimationRatio),            Color,            0, 0, 0, 0);        p->AnimationRatio -= p->AnimationRatio * MAIN.PanelAnimationSpeed * MAIN.LastFrameTime * 60;        if (p->AnimationRatio < 0.01) p->AnimationMode = 0; laRefreshWindow();        break;    }    tnsFlush();    tnsUniformOutputColorSpace(T->immShader,0);    tnsUniformShowColorOverflowStripes(T->immShader,0);    tnsUniformColorComposing(T->immShader,0,0,0,0);}void la_PanelDrawToOffsceen(laPanel *p, laUiList *uil){    if (p->OffScr){ tnsEnsureOffscreenStatus(p->OffScr, p->W,p->H); }    else{        int GLFormat=(p->PanelTemplate&&p->PanelTemplate->DefaultGLFormat)?p->PanelTemplate->DefaultGLFormat:LA_PANEL_DEFAULT_GL_FORMAT;        if(p->MenuRefer && (p->MenuRefer->Flags&LA_UI_FLAGS_MENU_FLOAT16)){ GLFormat=GL_RGBA16F; }        p->OffScr = tnsCreate2DOffscreen(GLFormat, p->W, p->H, MAIN.PanelMultisample, 0,0);    }    tnsDrawToOffscreen(p->OffScr, 1, 0);}void la_PanelRefreshDetachedProp(laPanel *panel){    laProp *p;    for (p = panel->PropLinkContainer->Props.pFirst; p; p = p->Item.pNext){        la_StepPropPack(&p->DetachedPP);        la_UsePropPack(&p->DetachedPP, 0);        //if (p->DetachedPP.LastPs && p->DetachedPP.LastPs->p->Container ? p->DetachedPP.LastPs->p->Container->Hyper : 0){        //    laUseDataBlock(        //        p->DetachedPP.LastPs->UseInstance,        //        p->DetachedPP.LastPs->p,        //        MAIN.PropMatcherContextP->FrameDistinguish,        //        MAIN.PropMatcherContextP,        //        la_PropPanelUserRemover, 0);        //}    }}void la_PanelDrawDescendBorder(laPanel *Panel, laBoxedTheme *bt){    real* color=laThemeColor(bt,LA_BT_BORDER);    real* shadow=laAccentColor(LA_BT_SHADOW);    int sw=LA_SHADOW_W;    tnsColor4d(LA_COLOR3(shadow),shadow[3]);    la_DrawOuterShadowLength(Panel->X,Panel->X+Panel->W,Panel->Y,Panel->Y+Panel->H,sw*2);    tnsColor4d(LA_COLOR3(shadow),shadow[3]*0.5);    la_DrawOuterShadowLength(Panel->X+sw*2,Panel->X+Panel->W+sw*2,Panel->Y+sw*2,Panel->Y+Panel->H+sw*2,sw*2);    tnsColor4d(LA_COLOR3(shadow),shadow[3]*0.25);    la_DrawOuterShadowLength(Panel->X+sw*4,Panel->X+Panel->W+sw*4,Panel->Y+sw*4,Panel->Y+Panel->H+sw*4,sw*2);    tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));    tnsVertex2d(Panel->X-1, Panel->Y-1);    tnsVertex2d(Panel->X-1, Panel->Y + Panel->H+1);    tnsVertex2d(Panel->X+1 + Panel->W, Panel->Y + Panel->H+1);    tnsVertex2d(Panel->X+1 + Panel->W, Panel->Y-1);    tnsLineWidth(2.0); tnsPackAs(GL_LINE_LOOP); tnsLineWidth(1.0);}int la_AnimateUiListRecursive(laUiList *uil);void la_PanelDefDraw(laWindow *w, laPanel *p, laBoxedTheme *bt){    int DrawState_ = 0;    laUiListDraw uild = {0}; int orig_refresh=p->Refresh;    if (p->Show){        la_SetPropMathcerContext(p);        MAIN.CurrentPanel = p;        if (p->Refresh & LA_TAG_RECALC){            laRecalcPanelImmediate(p);        }        if (!p->MenuRefer){            if(!p->OffScr){ la_PanelDrawToOffsceen(p,&p->UI); p->Refresh|=LA_TAG_REDRAW; laRefreshWindow(); }            if (p->Refresh || !p->OffScr){                la_PanelDrawToOffsceen(p, &p->UI);                la_SetupUiListLimitMatrix(&uild, 0, p->W, 0, p->H, p->H);                la_PanelBackgroundInit(p, bt);                tnsUseImmShader(); tnsEnableShaderv(T->immShader);                tnsUniformOutputColorSpace(T->immShader,0);                tnsUniformShowColorOverflowStripes(T->immShader,0);                tnsUniformColorComposing(T->immShader,0,0,0,0);                int extrap=(p->Mode && (!p->IsMenuPanel))?p->TitleBar.B:0;                la_DrawUiListScrollerV(&p->UI, p->UI.PanY, p->UI.B-p->UI.U, p->H-extrap, p->W, p->UI.U+LA_M,p->H-LA_M*2);                tnsFlush();                if(((p->UI.B>p->H) && (!p->UI.ScrollerShownV))||                    ((p->UI.B<=p->H) && p->UI.ScrollerShownV)){                    p->UI.ScrollerShownV=!p->UI.ScrollerShownV;                    DrawState_++;                }                if(p->UI.PanY && p->UI.B-p->UI.PanY < p->H - LA_M){                    p->UI.PanY = (p->UI.B-p->H+LA_M);                    if(p->UI.PanY<0){p->UI.PanY=0;}                    DrawState_++;                }                if(p->Refresh&LA_TAG_RECALC_SCROLLER) DrawState_++;                if (!la_AnimateUiListRecursive(&p->TitleBar)) p->Refresh = 0;                else { p->Refresh = LA_TAG_ANIMATION; laRefreshWindow(); }                if (!la_AnimateUiListRecursive(&p->UI)){ p->Refresh = p->Refresh; if(p->Refresh){ laRefreshWindow(); } }                else { p->Refresh = LA_TAG_ANIMATION; laRefreshWindow(); }                DrawState_ += la_DrawUiListRecursive(&uild, &p->TitleBar, 0, p->W, 0, p->H, 10000, -1, 0);                if(p!=w->MaximizedUiPanel){                    DrawState_ += la_DrawUiListRecursive(&uild, &p->UI, 0, p->W, 0, p->H, 10000, -1, 0);                }else{                    tnsViewportWithScissor(0,0,p->W,p->H); tnsOrtho(0,p->W,p->H,0,-100,100);                    tnsDrawStringAutoM("Canvas is maximized",0,laThemeColor(bt,LA_BT_TEXT),                        LA_M,p->W-LA_M,(p->H - p->TitleBar.B)/2+LA_RH2,LA_TEXT_ALIGN_CENTER|LA_TEXT_LINE_WRAP);                    tnsFlush();                }                if (DrawState_){ p->Refresh = LA_TAG_RECALC; laRefreshWindow(); }            }        }else{            if (p->Refresh || !p->OffScr){                la_PanelDrawToOffsceen(p, p->MenuRefer);                la_SetupUiListLimitMatrix(&uild, 0, p->W, 0, p->H, p->H);                la_PanelBackgroundInit(p, bt);                la_DrawUiListScrollerV(p->MenuRefer, p->MenuRefer->PanY,                    p->MenuRefer->B-p->MenuRefer->U-LA_M*2, p->H-LA_M*3, p->W, p->MenuRefer->U+LA_M,p->H-LA_M*2);                tnsFlush();                if(((p->MenuRefer->TB>p->H-LA_M) && (!p->MenuRefer->ScrollerShownV))||                    ((p->MenuRefer->TB<=p->H-LA_M) && p->MenuRefer->ScrollerShownV)){                    p->MenuRefer->ScrollerShownV=!p->MenuRefer->ScrollerShownV;                    DrawState_++;                }                if(p->UI.PanY && p->MenuRefer->B-p->MenuRefer->PanY<p->H-LA_M){                    p->MenuRefer->PanY = (p->MenuRefer->B-p->H-LA_M);                    if(p->MenuRefer->PanY<0){p->MenuRefer->PanY=0;}                    DrawState_++;                }                if(p->Refresh&LA_TAG_RECALC_SCROLLER) DrawState_++;                if (!la_AnimateUiListRecursive(p->MenuRefer)) p->Refresh = 0;                else { p->Refresh = LA_TAG_ANIMATION; laRefreshWindow(); }                DrawState_ += la_DrawUiListRecursive(&uild, p->MenuRefer, 0, p->W, 0, p->H, 10000, -1, 0);                if (DrawState_){ p->Refresh = LA_TAG_RECALC; laRefreshWindow(); }            }        }        tnsDrawToScreen();        tnsViewportWithScissor(0, 0, w->CW, w->CH);        tnsOrtho(0, w->CW, w->CH, 0, -100, 100);        la_PanelDrawToWindow(p, w);    }elif (p->AnimationMode){        la_PanelDrawToWindow(p, w);    }    laPerfRecord("%s [%s]",(orig_refresh&LA_TAG_RECALC)?"🌑":                           ((orig_refresh&LA_TAG_REDRAW)?"🌓":                           ((orig_refresh&LA_TAG_ANIMATION)?"🌔":"🌕")), SSTR(p->Title));}void la_AttachedPanelDefDraw(laWindow* w, laPanel* p, laBoxedTheme* bt){    if(!p->Show && p!=w->MaximizedUiPanel) return;    if (p->SubPanels.pLast && (p->LaterDestroy ? !p->AnimationMode : 1)){        laPanel *pi, *PrevPI;        for (pi = p->SubPanels.pLast; pi; pi = PrevPI){            PrevPI = pi->Item.pPrev;            if (pi->AnimationMode && pi->LaterDestroy){                lstRemoveItem(&p->SubPanels, pi);                lstAppendItem(&MAIN.CurrentWindow->FadingPanels, pi);                continue;            }            la_PanelDefDraw(w, pi, _LA_THEME_FLOATING_PANEL);            la_AttachedPanelDefDraw(w,pi,bt);        }    }}void la_BlockDrawDropLocations(laBlock *b, int CH, real *BorderColor4dV, real *FillColor4dv){    real PanelSquare[] = {        b->X + 2, CH - (b->Y + 2 + LA_RH),        b->X + 2, CH - (b->Y + b->H - 4),        b->X + b->W - 4, CH - (b->Y + b->H - 4),        b->X + b->W - 4, CH - (b->Y + 2 + LA_RH)};    real Center[] = {        tnsLinearItp(PanelSquare[0], PanelSquare[4], 0.5), tnsLinearItp(PanelSquare[1], PanelSquare[5], 0.5)};    real DraggingPlot[] = {        tnsLinearItp(PanelSquare[0], Center[0], 0.5),        tnsLinearItp(PanelSquare[1], Center[1], 0.5),        PanelSquare[0],        PanelSquare[1],        tnsLinearItp(PanelSquare[2], Center[0], 0.5),        tnsLinearItp(PanelSquare[3], Center[1], 0.5),        PanelSquare[2],        PanelSquare[3],        tnsLinearItp(PanelSquare[4], Center[0], 0.5),        tnsLinearItp(PanelSquare[5], Center[1], 0.5),        PanelSquare[4],        PanelSquare[5],        tnsLinearItp(PanelSquare[6], Center[0], 0.5),        tnsLinearItp(PanelSquare[7], Center[1], 0.5),        PanelSquare[6],        PanelSquare[7],    };    real Square[] = {        tnsLinearItp(PanelSquare[0], Center[0], 0.5),        tnsLinearItp(PanelSquare[1], Center[1], 0.5),        tnsLinearItp(PanelSquare[2], Center[0], 0.5),        tnsLinearItp(PanelSquare[3], Center[1], 0.5),        tnsLinearItp(PanelSquare[4], Center[0], 0.5),        tnsLinearItp(PanelSquare[5], Center[1], 0.5),        tnsLinearItp(PanelSquare[6], Center[0], 0.5),        tnsLinearItp(PanelSquare[7], Center[1], 0.5),    };    real PlotColor[] = {LA_COLOR3(BorderColor4dV), 0.8,        LA_COLOR3(BorderColor4dV), 0,        LA_COLOR3(BorderColor4dV), 0.8,        LA_COLOR3(BorderColor4dV), 0,        LA_COLOR3(BorderColor4dV), 0.8,        LA_COLOR3(BorderColor4dV), 0,        LA_COLOR3(BorderColor4dV), 0.8,        LA_COLOR3(BorderColor4dV), 0,    };    real FillColor[] = {LA_COLOR3(FillColor4dv), 0.8,        LA_COLOR3(FillColor4dv), 0,        LA_COLOR3(FillColor4dv), 0.8,        LA_COLOR3(FillColor4dv), 0,        LA_COLOR3(FillColor4dv), 0.8,        LA_COLOR3(FillColor4dv), 0,        LA_COLOR3(FillColor4dv), 0.8,        LA_COLOR3(FillColor4dv), 0,    };    tnsUseNoTexture();    tnsLineWidth(LA_SEAM_W);    if (MAIN.CurrentWindow->CurrentLayout->DropToBlock == b){        int Index[4];        tnsVertexArray2d(DraggingPlot, 8);        tnsColorArray4d(FillColor, 8);        switch (MAIN.CurrentWindow->CurrentLayout->DropLocation){        case 0:            Index[0] = 0; Index[1] = 2; Index[2] = 4; Index[3] = 6;            break;        case LA_BLOCK_DROP_LOCATION_L:            Index[0] = 0; Index[1] = 1; Index[2] = 3; Index[3] = 2;            break;        case LA_BLOCK_DROP_LOCATION_R:            Index[0] = 4; Index[1] = 5; Index[2] = 7; Index[3] = 6;            break;        case LA_BLOCK_DROP_LOCATION_U:            Index[0] = 0; Index[1] = 1; Index[2] = 7; Index[3] = 6;            break;        case LA_BLOCK_DROP_LOCATION_B:            Index[0] = 4; Index[1] = 5; Index[2] = 3; Index[3] = 2;            break;        }        //glDisable(GL_CULL_FACE);        tnsIndexArray(Index, 4);        tnsPackAs(GL_TRIANGLE_FAN);        //tnsFlush();    }    tnsVertexArray2d(DraggingPlot, 8);    tnsColorArray4d(PlotColor, 8);    tnsPackAs(GL_LINES);    tnsVertexArray2d(Square, 4);    tnsColor4dv(BorderColor4dV);    tnsPackAs(GL_LINE_LOOP);    tnsFlush();    tnsLineWidth(1);}void la_BlockDefDrawSelf(laBlock *b, int CH){    laBoxedTheme *bt = _LA_THEME_TAB;    laPanel *p;    real v[] = {        b->X, CH - b->Y,        b->X + LA_SEAM_W, CH - b->Y ,        b->X, CH - (b->Y + b->H),        b->X + LA_SEAM_W, CH - (b->Y + b->H - LA_SEAM_W),        b->X + b->W, CH - (b->Y + b->H),        b->X + b->W - LA_SEAM_W, CH - (b->Y + b->H - LA_SEAM_W),        b->X + b->W, CH - b->Y,        b->X + b->W - LA_SEAM_W, CH - b->Y};    real ratio = 1.0001f;    int tw = 0;    int L = LA_RH+LA_SEAM_W;    tnsUseImmShader(); tnsEnableShaderv(T->immShader);    if(MAIN.EnableColorManagement){        laWindow* w=MAIN.CurrentWindow;        la_UseWindowColorCorrection(w);        tnsUniformOutputColorSpace(T->immShader,w->OutputColorSpace);        tnsUniformColorComposing(T->immShader,w->UseComposing,w->ComposingGamma,w->ComposingBlackpoint,w->OutputProofing);    }else{        tnsUniformOutputColorSpace(T->immShader,0);        tnsUniformColorComposing(T->immShader,0,0,0,0);    }    for (p = b->Panels.pFirst; p; p = p->Item.pNext){        tw += p->TitleWidth + LA_SEAM_W*2;    }    if (tw > b->W - LA_SEAM_W*2 - LA_RH) ratio = (real)(b->W - LA_SEAM_W*2 - LA_RH) / (real)tw;    real* cactive=laThemeColor(bt,LA_BT_ACTIVE);    real* cborder=laThemeColor(bt,LA_BT_BORDER);    tnsUseNoTexture();    tnsColor4d(LA_COLOR3(cactive),1);    tnsVertexArray2d(v, 8);    tnsPackAs(GL_TRIANGLE_STRIP);    int TitleGap=b->Folded?0:LA_RH;    tnsColor4d(LA_COLOR3(cactive),1);    la_DrawBox(b->X, b->X+b->W, CH-b->Y, CH-b->Y-TitleGap);        tnsColor4d(LA_COLOR3(cborder),1);    la_DrawBox(b->X+LA_SEAM_W, b->X+b->W-LA_SEAM_W, CH-b->Y-TitleGap, CH-b->Y-TitleGap-LA_SEAM_W);    if(b->Folded){ return;  }    int LT=0,RT=0;    for (p = b->Panels.pFirst; p; p = p->Item.pNext){        RT = LT + p->TitleWidth + LA_SEAM_W*2;        if (p == b->CurrentPanel){            tnsUseNoTexture();            tnsColor4d(LA_COLOR3(cborder),1);            la_DrawBox(b->X+L+LT*ratio, b->X+L+RT*ratio, CH-b->Y, CH-b->Y-LA_RH);            tnsDrawStringAuto(transLate(p->Title->Ptr), laThemeColor(bt,LA_BT_TEXT_ACTIVE), b->X+L+LT*ratio+LA_SEAM_W, b->X+L+RT*ratio, CH-b->Y, LA_TEXT_REVERT_Y);        }else{            tnsDrawStringAuto(transLate(p->Title->Ptr), laThemeColor(bt,LA_BT_TEXT), b->X+L+LT*ratio+LA_SEAM_W, b->X+L+RT*ratio, CH-b->Y, LA_TEXT_REVERT_Y);        }        LT =RT;    }    tnsDrawStringAuto("🔻",laThemeColor(bt,LA_BT_BORDER), b->X+LA_SEAM_W,b->X+b->W, CH-b->Y, LA_TEXT_REVERT_Y);    tnsFlush();    tnsUniformOutputColorSpace(T->immShader,0);    tnsUniformColorComposing(T->immShader,0,0,0,0);}void la_BlockDefDrawSelfEmpty(laBlock *b, int CH){    laBoxedTheme *bt = _LA_THEME_PANEL;    real tv[8];    tnsUseImmShader(); tnsEnableShaderv(T->immShader);    if(MAIN.EnableColorManagement){        laWindow* w=MAIN.CurrentWindow;        la_UseWindowColorCorrection(w);        tnsUniformOutputColorSpace(T->immShader,w->OutputColorSpace);        tnsUniformColorComposing(T->immShader,w->UseComposing,w->ComposingGamma,w->ComposingBlackpoint,w->OutputProofing);    }else{        tnsUniformOutputColorSpace(T->immShader,0);        tnsUniformColorComposing(T->immShader,0,0,0,0);    }        tnsUseNoTexture();    tnsMakeQuad2d(tv, b->X, (CH - b->Y),                      b->X + b->W, (CH - b->Y),                      b->X + b->W, (CH - b->Y-b->H),                      b->X, (CH - b->Y-b->H));    tnsVertexArray2d(tv, 4);    tnsColor4dv(laThemeColor(bt,LA_BT_NORMAL));    tnsPackAs(GL_TRIANGLE_FAN);    tnsDrawStringAuto(transLate("Dock some panels here."), laThemeColor(bt,LA_BT_TEXT), b->X+LA_SEAM_W,b->X+b->W-LA_SEAM_W, CH-b->Y-b->H/2+LA_RH2,        LA_TEXT_ALIGN_CENTER|LA_TEXT_REVERT_Y|LA_TEXT_USE_NEWLINE|LA_TEXT_LINE_WRAP);    tnsFlush();    tnsUniformOutputColorSpace(T->immShader,0);    tnsUniformColorComposing(T->immShader,0,0,0,0);}void la_BlockDefDrawRecursive(laWindow *w, laBoxedTheme *bt, laBlock *b){    if (b->B1){        la_BlockDefDrawRecursive(w, bt, b->B1);        la_BlockDefDrawRecursive(w, bt, b->B2);    }elif (b->CurrentPanel /*&& b->CurrentPanel->Refresh*/){        if (!b->CurrentPanel->BT) b->CurrentPanel->BT = &_LA_THEME_PANEL;        la_PanelDefDraw(w, b->CurrentPanel, *b->CurrentPanel->BT);        tnsViewportWithScissor(0, 0, w->CW, w->CH);        tnsOrtho(0, w->CW, 0, w->CH, -100, 100);        la_BlockDefDrawSelf(b, w->CH);    }else{        tnsViewportWithScissor(0, 0, w->CW, w->CH);        tnsOrtho(0, w->CW, 0, w->CH, -100, 100);        la_BlockDefDrawSelfEmpty(b, w->CH);    }    laLayout* l=MAIN.CurrentWindow->CurrentLayout;    if(b==l->HeaderBlock){        tnsUseNoTexture(); real tv[8]; int YOffset=0;        laBoxedTheme* bt = _LA_THEME_FLOATING_PANEL; int MenuHeight=(LA_M+LA_M)*2+LA_RH;        if(b->Y<MenuHeight+LA_SEAM_W){ YOffset=LA_SEAM_W; }        tnsMakeQuad2d(tv, b->X, (w->CH-(b->Y-LA_SEAM_W))-YOffset,                          b->X+b->W, (w->CH-(b->Y-LA_SEAM_W))-YOffset,                          b->X+b->W, (w->CH-(b->Y+LA_SEAM_W))-YOffset,                          b->X, (w->CH-(b->Y+LA_SEAM_W))-YOffset);        tnsColor4dv(laThemeColor(_LA_THEME_TAB,LA_BT_BORDER));        tnsVertexArray2d(tv, 4);        tnsPackAs(GL_TRIANGLE_FAN);        if(l->IsBlockHeaderClicked && (!l->IsMoving)){            char* Hint=transLate("Double-click to expand 🖱");            int Width = tnsStringGetWidth(Hint,0,0)+LA_M*2;            int UseL=l->LastX-Width-LA_RH; UseL=TNS_MAX2(UseL,b->X);            tnsMakeQuad2d(tv, UseL, w->CH-b->Y,                              UseL+Width, w->CH-b->Y,                              UseL+Width, w->CH-b->Y-LA_RH,                              UseL, w->CH-b->Y-LA_RH);            tnsColor4dv(laThemeColor(_LA_THEME_TAB,LA_BT_BORDER));            tnsVertexArray2d(tv, 4);            tnsPackAs(GL_TRIANGLE_FAN);            tnsDrawStringAuto(Hint,laThemeColor(_LA_THEME_TAB,LA_BT_TEXT_ACTIVE),UseL+LA_M,UseL+Width,w->CH-b->Y,LA_TEXT_REVERT_Y);        }    }elif(b==l->MovingBlock){        tnsUseNoTexture();        int at; real tv[8];        if (b->Vertical){            at = b->H * b->SplitRatio + b->Y;            tnsMakeQuad2d(tv,b->X, (w->CH - at + LA_SEAM_W),                            b->X + b->W, (w->CH - at + LA_SEAM_W),                            b->X + b->W, (w->CH - at - LA_SEAM_W),                            b->X, (w->CH - at - LA_SEAM_W));        }else{            at = b->X + b->W * b->SplitRatio;            tnsMakeQuad2d(tv,at+ LA_SEAM_W, (w->CH - b->Y),                            at- LA_SEAM_W, (w->CH - b->Y),                            at- LA_SEAM_W, (w->CH - b->Y - b->H),                            at+ LA_SEAM_W, (w->CH - b->Y - b->H));        }        tnsColor4dv(laThemeColor(_LA_THEME_TAB,LA_BT_BORDER));        tnsVertexArray2d(tv, 4);        tnsPackAs(GL_TRIANGLE_FAN);    }    //la_SetPanelMatrixDrawWindow(b->CurrentPanel, *b->CurrentPanel->BT);    tnsFlush();}void la_BlockDefDrawAttachedRecursive(laWindow *w, laBoxedTheme *bt, laBlock *b){    if (b->B1){        la_BlockDefDrawAttachedRecursive(w, bt, b->B1);        la_BlockDefDrawAttachedRecursive(w, bt, b->B2);    }elif (b->CurrentPanel /*&& b->CurrentPanel->Refresh*/){        la_AttachedPanelDefDraw(w,b->CurrentPanel,*b->CurrentPanel->BT);    }    tnsFlush();}void la_ClearBlockFramebuffersRecursive(laBlock* b, int AlsoClearCurrent){    if(b->B1)la_ClearBlockFramebuffersRecursive(b->B1,AlsoClearCurrent);    if(b->B2)la_ClearBlockFramebuffersRecursive(b->B2,AlsoClearCurrent);    for(laPanel* p=b->Panels.pFirst;p;p=p->Item.pNext){        if(!AlsoClearCurrent && p==b->CurrentPanel) continue;        if(p->OffScr){            tnsDelete2DOffscreen(p->OffScr); p->OffScr=0;        }    }}void la_ClearUnusedFramebuffers(laWindow* w){    for(laLayout* l = w->Layouts.pFirst;l;l=l->Item.pNext){        la_ClearBlockFramebuffersRecursive(l->FirstBlock, l!=w->CurrentLayout);    }    for(laPanel* p=w->Panels.pFirst;p;p=p->Item.pNext){        if(p->Show || p->AnimationMode) continue;        if(p->OffScr){            tnsDelete2DOffscreen(p->OffScr); p->OffScr=0;        }    }}void laDeferredDestroyPanel(laPanel* p, int immediate);void la_WindowDefDraw(laWindow *w, laBoxedTheme *bt){    laPanel *p, *NextP;    laLayout *l = w->CurrentLayout;    if (!w->CH || !w->CW) return;    la_ClearUnusedFramebuffers(w);    tnsDrawToScreen();    la_RefreshProofingLut();    tnsViewportWithScissor(0, 0, w->CW, w->CH);    glClearColor(0.2, 0.2, 0.3, 1.0);    tnsClearAll();    tnsUseNoTexture();    if (l->Draw) l->Draw(w, l);    tnsResetModelMatrix();tnsResetProjectionMatrix();tnsResetViewMatrix();    glEnable(GL_BLEND);    //lBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);    glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,GL_ONE,GL_ONE_MINUS_SRC_ALPHA);    laUiItem* ui;    if((ui=w->MaximizedUi) && w->MaximizedUiPanel && ui->Type->Draw && ui->CanvasTemplate->SecondDraw){        MAIN.CurrentPanel=w->MaximizedUiPanel; laPanel* p=w->MaximizedUiPanel; int DrawState_=0;        la_SetPropMathcerContext(p);        if(p->Refresh){            if (!p->BT) p->BT = &_LA_THEME_PANEL;            tnsUseShader(T->immShader);tnsEnableShaderv(T->immShader);            if(MAIN.EnableColorManagement){                la_UseWindowColorCorrection(w);                tnsUniformOutputColorSpace(T->immShader,w->OutputColorSpace);                tnsUniformColorComposing(T->immShader,w->UseComposing,w->ComposingGamma,w->ComposingBlackpoint,w->OutputProofing);            }else{                tnsUniformOutputColorSpace(T->immShader,0);                tnsUniformColorComposing(T->immShader,0,0,0,0);            }            if(p->Refresh&LA_TAG_RECALC){                laRecalcPanelImmediate(p);            }            ui->Type->Draw(ui, LA_RH); tnsFlush();            if (!la_AnimateUiListRecursive(&p->UI)) p->Refresh = 0;            else { p->Refresh|=LA_TAG_ANIMATION; laRefreshWindow(); }        }        tnsDrawToScreen();        tnsResetViewMatrix();        tnsViewportWithScissor(0, 0, w->CW, w->CH);        tnsOrtho(0, w->CW, w->CH, 0, -100, 100);        ui->CanvasTemplate->SecondDraw(ui, LA_RH);        tnsFlush();        if(!(ui->Flags&LA_UI_FLAGS_NO_OVERLAY)){            laUiListDraw uild = {0}; for (laUiList* sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){                tnsFlush();                DrawState_+=la_DrawUiListRecursive(&uild, sub, ui->L, ui->R, ui->U, ui->B, 10000, 0, 0);            }        }        if (DrawState_){ p->Refresh = LA_TAG_RECALC; laRefreshWindow(); }        la_AttachedPanelDefDraw(w,p,*p->BT);    }else{        laBlock* RootBlock= w->MaximizedBlock?w->MaximizedBlock:l->FirstBlock;        la_BlockDefDrawRecursive(w, bt, RootBlock);        la_BlockDefDrawAttachedRecursive(w,bt, RootBlock);    }    for (p = w->Panels.pLast; p; p = NextP){        NextP = p->Item.pPrev;        if (!p->BT) p->BT = &_LA_THEME_FLOATING_PANEL;        if (p->AnimationMode && p->LaterDestroy){            lstRemoveItem(&w->Panels, p);            lstAppendItem(&MAIN.CurrentWindow->FadingPanels, p);            continue;        }        la_PanelDefDraw(w, p, *p->BT);    }    for(laPanel* p=w->Panels.pFirst;p;p=p->Item.pNext){        la_AttachedPanelDefDraw(w,p,*p->BT);    }    if (MAIN.CurrentWindow->CurrentLayout->DropToBlock){        laBoxedTheme* ubt=_LA_THEME_TAB;tnsUseNoTexture();        tnsViewportWithScissor(0, 0, w->CW, w->CH); tnsOrtho(0, w->CW, 0, w->CH, -100, 100);        la_BlockDrawDropLocations(MAIN.CurrentWindow->CurrentLayout->DropToBlock,            MAIN.CurrentWindow->CH, laThemeColor(ubt,LA_BT_ACTIVE), laThemeColor(ubt,LA_BT_BORDER));        tnsFlush();    }    for (p = w->FadingPanels.pLast; p; p = NextP){        NextP = p->Item.pPrev;        if (!p->AnimationMode){            lstRemoveItem(&w->FadingPanels, p);            p->AnimationMode = LA_PANEL_ANIMATION_DESTROY; laRefreshWindow();            laDeferredDestroyPanel(p, 0);        }else            la_PanelDrawToWindow(p, w);    }    if(MAIN.ShowPerf){        la_PerfDraw();    }}void laStartWindow(laWindow *w){#ifdef LA_LINUX    XMapWindow(MAIN.dpy,w->win);    tnsContextMakeWindowCurrent(w);#endif#ifdef _WIN32    ShowWindow(w->win, SW_SHOWNORMAL);#endif    MAIN.CurrentWindow = w;    if(!w->CurrentLayout){        if(!w->Layouts.pFirst){laDesignLayout(w, "Empty Layout");}        memAssignRef(w, &w->CurrentLayout, w->Layouts.pFirst);    }    laRedrawCurrentWindow();    laInvokeUi(0, "LA_window_operator", 0, w, 0, 0);    w->Shown = 1;}void la_AssignWindowPP(laWindow* w){    w->PP.EndInstance = w;    w->PP.LastPs = &w->FakePS;    w->PP.LastPs->p = _LA_PROP_WINDOW;    w->PP.LastPs->UseInstance = w;    w->PP.LastPs->Type = U'.';}laWindow *laDesignWindow(int X, int Y, int W, int H){#ifdef LAGUI_ANDROID    if(MAIN.Windows.pFirst){ return MAIN.Windows.pFirst; }#endif    laWindow *n = memAcquire(sizeof(laWindow));    strSafeSet(&n->Title, "Empty SYSWINDOW");    n->X = X; n->Y = Y; n->W = W; n->H = H;#ifdef LAGUI_ANDROID    n->X=0; n->Y=0; n->W=MAIN.AppWidth; n->H=MAIN.AppHeight;#endif    la_CreateSystemWindow(n, MAIN.Windows.pFirst!=0);    lstAppendItem(&MAIN.Windows, n);    MAIN.CurrentWindow = n;    la_AssignWindowPP(n);    laui_DefaultMenuBar(n);    return n;}void laSetWindowCursor(int id){    MAIN.CurrentCursor = id;#ifdef LA_LINUX    Cursor c = XcursorLibraryLoadCursor(MAIN.dpy, la_ConvertCursorID(id));    XDefineCursor(MAIN.dpy, MAIN.CurrentWindow->win, c);#endif#ifdef _WIN32    SetCursor(la_ConvertCursorID(id));#endif};void la_AssignBlockPP(laBlock* b){    b->PP.EndInstance = b;    b->PP.LastPs = &b->FakePS;    b->PP.LastPs->p = _LA_PROP_BLOCK;    b->PP.LastPs->UseInstance = b;    b->PP.LastPs->Type = U'.';}void laDestroyLayout(laWindow *w, laLayout* l){    if((!l->Item.pPrev) && (!l->Item.pNext)) return;    laDestroyBlocksRecursive(l->FirstBlock);    strSafeDestroy(&l->ID);    if(w->CurrentLayout==l){ memAssignRef(w, &w->CurrentLayout, l->Item.pPrev?l->Item.pPrev:l->Item.pNext); }    lstRemoveItem(&w->Layouts,l); memFree(l);}laLayout *laDesignLayout(laWindow *w, char *Title){    laLayout *l = memAcquire(sizeof(laLayout));    l->FirstBlock = memAcquire(sizeof(laBlock));    la_AssignBlockPP(l->FirstBlock);    lstAppendItem(&w->Layouts, l);    strSafeSet(&l->ID, Title);    memAssignRef(w, &w->CurrentLayout, l);    laRenameWindow(w, Title);    return l;}void laFoldBlockTitle(laBlock* b){ if(b->B1) return; b->Folded=1; la_RecalcBlockRecursive(b,b->X,b->Y,b->W,b->H); }void laUnfoldBlockTitle(laBlock* b){ if(b->B1) return; b->Folded=0; la_RecalcBlockRecursive(b,b->X,b->Y,b->W,b->H); }void laMaximizeBlock(laBlock* b){ if(b->B1) return; laWindow* w=MAIN.CurrentWindow;    if(w->MaximizedBlock==b){laRestoreToLayout(); return;} w->MaximizedBlock=b; la_UpdateUiPlacement(w);    laNotifyUsers("la.windows.maximized_block"); }void laRestoreToLayout(){ laWindow* w=MAIN.CurrentWindow; if(!w->MaximizedBlock) return;  w->MaximizedBlock=0; la_UpdateUiPlacement(w);    laNotifyUsers("la.windows.maximized_block"); }void laMaximizeCanvasUI(laUiItem* ui, laPanel* UiParentPanel){    laRestoreCanvasUI();    if(!ui->Type||(!(ui->Type->Tag&LA_UI_TAG_IS_OFFSCREEN))||!UiParentPanel) return;    la_StopUiOperatorService(UiParentPanel); la_StopUiOperatorService(ui); laRetriggerOperators();    laWindow* w=MAIN.CurrentWindow; w->MaximizedUi=ui; w->MaximizedUiPanel=UiParentPanel; laRecalcPanel(UiParentPanel);    UiParentPanel->Show=0;    laNotifyUsers("la.windows.maximized_ui"); laHideMenuBar();}void laRestoreCanvasUI(){    laWindow* w=MAIN.CurrentWindow; if(!w->MaximizedUi || !w->MaximizedUiPanel) return;    la_StopUiOperatorService(w->MaximizedUi); laRetriggerOperators(); w->MaximizedUiPanel->Show=1;    laRecalcPanel(w->MaximizedUiPanel); w->MaximizedUi=0; w->MaximizedUiPanel=0; la_UpdateUiPlacement(w);    laNotifyUsers("la.windows.maximized_ui"); laShowMenuBar();}void laHideMenuBar(){ laWindow* w=MAIN.CurrentWindow; if(!w->MaximizedUi || !w->MaximizedUiPanel) return;    for(laPanel* p=MAIN.CurrentWindow->Panels.pFirst;p;p=p->Item.pNext){ if(p->IsMenuPanel){ p->Show=0; laRefreshWindow(); break; } }}void laShowMenuBar(){ for(laPanel* p=MAIN.CurrentWindow->Panels.pFirst;p;p=p->Item.pNext){ if(p->IsMenuPanel){ p->Show=1; laRefreshWindow(); break; } } }void laSplitBlockHorizon(laBlock *b, real Percentage){    laPanel *p;    b->SplitRatio = Percentage;    b->Vertical = 0;    b->B1 = memAcquire(sizeof(laBlock)); la_AssignBlockPP(b->B1); b->B1->Folded=b->Folded;    b->B2 = memAcquire(sizeof(laBlock)); la_AssignBlockPP(b->B2);    for (p = b->Panels.pFirst; p; p = p->Item.pNext){        p->Block = b->B1;    }    b->B1->Panels.pFirst = b->Panels.pFirst;    b->B1->Panels.pLast = b->Panels.pLast;    b->B1->CurrentPanel = b->CurrentPanel;    b->B1->parent = b->B2->parent=b;    b->Panels.pFirst = 0;    b->Panels.pLast = 0;    b->CurrentPanel = 0;    la_RecalcBlockRecursive(b, b->X, b->Y, b->W, b->H);}void laSplitBlockVertical(laBlock *b, real Percentage){    laPanel *p;    b->SplitRatio = Percentage;    b->Vertical = 1;    b->B1 = memAcquire(sizeof(laBlock)); la_AssignBlockPP(b->B1); b->B1->Folded=b->Folded;    b->B2 = memAcquire(sizeof(laBlock)); la_AssignBlockPP(b->B2);    for (p = b->Panels.pFirst; p; p = p->Item.pNext){        p->Block = b->B1;    }    b->B1->Panels.pFirst = b->Panels.pFirst;    b->B1->Panels.pLast = b->Panels.pLast;    b->B1->CurrentPanel = b->CurrentPanel;    b->B1->parent = b->B2->parent=b;    b->Panels.pFirst = 0;    b->Panels.pLast = 0;    b->CurrentPanel = 0;    la_RecalcBlockRecursive(b, b->X, b->Y, b->W, b->H);}void laCombineChildBlocks(laBlock *b){    laPanel *p; if(!b) return;    if (!b->B1->B1 && !b->B2->B1){        lstCombineLists(&b->Panels, &b->B1->Panels);        lstCombineLists(&b->Panels, &b->B2->Panels);        for (p = b->Panels.pFirst; p; p = p->Item.pNext){            p->Block = b;        }        b->CurrentPanel = b->B1->CurrentPanel?b->B1->CurrentPanel:b->B2->CurrentPanel;        memFree(b->B1);        memFree(b->B2);        b->B1 = 0;        b->B2 = 0;        la_RecalcBlockRecursive(b, b->X, b->Y, b->W, b->H);    }elif(!b->B1->B1){        laBlock* b1 = b->B2->B1; laBlock* b2 = b->B2->B2;        b->Vertical = b->B2->Vertical;        for (p = b->B1->Panels.pFirst; p; p = p->Item.pNext){            p->Block = b1;        }        lstCombineLists(&b1->Panels, &b->B1->Panels);        memFree(b->B1); memFree(b->B2);        b->B1 = b1; b->B2 = b2;        b1->parent = b; b2->parent = b;        la_RecalcBlockRecursive(b, b->X, b->Y, b->W, b->H);    }elif(!b->B2->B1){        laBlock* b1 = b->B1->B1;laBlock* b2 = b->B1->B2;        b->Vertical = b->B1->Vertical;        for (p = b->B2->Panels.pFirst; p; p = p->Item.pNext){            p->Block = b1;        }        lstCombineLists(&b1->Panels, &b->B2->Panels);        memFree(b->B1); memFree(b->B2);        b->B1 = b1; b->B2 = b2;        b1->parent = b; b2->parent = b;        la_RecalcBlockRecursive(b, b->X, b->Y, b->W, b->H);    }}laBlock *laBlock1(laBlock *b){    return b->B1;}laBlock *laBlock2(laBlock *b){    return b->B2;}void laSwapSubBlocks(laBlock *b){    laBlock *tB;    tB = b->B2;    b->B2 = b->B1;    b->B1 = tB;    b->SplitRatio = 1 - b->SplitRatio;    la_RecalcBlockRecursive(b, b->X, b->Y, b->W, b->H);}void laDestroyBlocksRecursive(laBlock *Root){    laPanel *p;    if (Root->B1){        laDestroyBlocksRecursive(Root->B1);        laDestroyBlocksRecursive(Root->B2);    }else{        while (p = lstPopItem(&Root->Panels)){ laDestroySinglePanel(p, 1); }    }    memFree(Root);}laPanel* laTearOffPanel(laBlock* b, laPanel* p_if_set){    if(!b->CurrentPanel ) return 0;    laPanel* p = p_if_set?p_if_set:b->CurrentPanel;    b->CurrentPanel = p->Item.pNext?p->Item.pNext:p->Item.pPrev;    lstRemoveItem(&b->Panels, p);    if(!b->CurrentPanel && b->parent){ b=b->parent; laCombineChildBlocks(b); }    if((!p->TitleBar.UiItems.pFirst) && p->PanelTemplate &&(!(p->PanelTemplate->Flags&LA_TEMPLATE_FLAGS_NO_DECORATION))){        laui_DefaultPanelTitleBar(&p->TitleBar, &p->PP, &p->PropLinkPP, p->PanelTemplate?p->PanelTemplate->Header:0);    }    p->Mode = LA_PANEL_FLOATING_TOP;    p->TY-=LA_RH; p->TH+=LA_RH;    p->W=p->TW=(p->PanelTemplate?p->PanelTemplate->DefaultW_RH:20)*LA_RH;    p->W=p->TH=(p->PanelTemplate?p->PanelTemplate->DefaultH_RH:20)*LA_RH;    p->Block = 0;    laEnsurePanelInBound(p,&p->UI); laPlacePanelForCreation(p);    laRecalcPanel(p);    la_RecalcBlockRecursive(b, b->X,b->Y,b->W,b->H);    p->BT = &_LA_THEME_FLOATING_PANEL;    lstPushItem(&MAIN.CurrentWindow->Panels, p);    laNotifyUsers("la.windows.panels");    return b->CurrentPanel;}void laDockPanel(laWindow* from, laBlock* b, laPanel* p){    if(!b||!p||p->Mode!=LA_PANEL_FLOATING_TOP||b->B1||b->B2) return;    lstRemoveItem(&from->Panels, p);    la_DestroyUiList(&p->TitleBar, 1, 1, 0);    p->Mode = LA_PANEL_NORMAL;    p->Block=b;    b->CurrentPanel = p;    b->Folded = 0;    lstPushItem(&b->Panels, p);    laRecalcPanel(p);    p->BT = &_LA_THEME_PANEL;    la_RecalcBlockRecursive(b, b->X,b->Y,b->W,b->H);    tnsFlush();    laNotifyUsers("la.windows.panels");}void laPopPanel(laPanel *p){    if (p->Mode == LA_PANEL_FLOATING_PASSIVE){        lstRemoveItem(&p->Parent->SubPanels, p);        lstPushItem(&p->Parent->SubPanels, p);    }else if (p->Mode == LA_PANEL_FLOATING_TOP){        lstRemoveItem(&MAIN.CurrentWindow->Panels, p);        lstPushItem(&MAIN.CurrentWindow->Panels, p);        laNotifyUsers("la.windows.panels");    }}void la_EnsurePanelExtras(laPanel *p){    laUiTemplate* uit=p->PanelTemplate;    p->PropLinkContainer = memAcquire(sizeof(laPropContainer));    p->PropLinkFakeProp = memAcquire(sizeof(laSubProp));    p->PropLinkFakeProp->Base.Identifier = "LA_UI_FAKE_PROP_PLACEHOLDER";    p->PropLinkFakeProp->Base.PropertyType = LA_PROP_SUB;    p->PropLinkFakeProp->Base.SubProp = p->PropLinkContainer;    p->PropLinkFakeProp->Base.Offset = 0;    p->PropLinkFakeProp->Base.OffsetIsPointer = 1;    p->PropLinkPP.EndInstance = p;    p->PropLinkPP.LastPs = &p->PropLinkFakePS;    p->PropLinkPP.LastPs->Type = U'.';    p->PropLinkFakePS.p = p->PropLinkFakeProp;}laPanel* la_GivePanelNode(){    laPanel* p; if(p=lstPopItem(&MAIN.WastedPanels)) return p;    return memAcquire(sizeof(laPanel));}void la_ReturnPanelNode(laPanel* p){    memset(p,0,sizeof(laPanel));    lstRemovePointer(&MAIN.DeferredRedrawList,p);    lstAppendItem(&MAIN.WastedPanels, p);}laPanel *la_NewPanel(laUiTemplate* uit, int X, int Y, int W, int H, int MaxW, int MaxH, int MinW, int MinH, int SnapL, int SnapR, int SnapT, int SnapB){    laPanel *p = la_GivePanelNode();    int CW = MAIN.CurrentWindow->CW;    int CH = MAIN.CurrentWindow->CH;    p->PanelTemplate = uit;    if((!W) && uit)W=uit->DefaultW_RH*LA_RH;    if((!H) && uit)H=uit->DefaultH_RH*LA_RH;    if (!MaxW) MaxW = 10000;    if (!MaxH) MaxH = 10000;    if (W > MaxW) W = MaxW;    if (H > MaxH) H = MaxH;    if (W < MinW) W = MinW;    if (H < MinH) H = MinH;    if(uit) { strSafeSet(&p->Title, uit->Title->Ptr); }    p->X = p->TX = (X < 0 ? 0 : X);    p->Y = p->TY = (Y < 0 ? 0 : Y);    p->W = p->TW = (W < 0 ? CW + W - p->X : W);    p->H = p->TH = (H < 0 ? CH + H - p->Y : H);    p->MaxW = MaxW; p->MaxH = MaxH;    p->MinW = MinW; p->MinH = MinH;    p->SL = SnapL; p->ST = SnapT;    p->SR = SnapR; p->SB = SnapB;    if (p->SR) p->X = CW - p->W - p->SR;    if (p->SB) p->Y = CH - p->H - p->SB;    la_EnsurePanelSnapping(p, CW, CH);    p->Show = 1;    p->PP.EndInstance = p;    p->PP.LastPs = &p->FakePS;    p->PP.LastPs->p = _LA_PROP_PANEL;    p->PP.LastPs->UseInstance = p;    p->PP.LastPs->Type = U'.';    la_EnsurePanelExtras(p);    laRecalcPanel(p);    p->FrameDistinguish = 100; //greater than 1 is ok    if(uit&&uit->PropFunc){ uit->PropFunc(p); }    if(uit){uit->Define(&p->UI, &p->PP, &p->PropLinkPP, 0, 0);}    return p;}laPanel *laCreatePanelT(laBlock *b, laUiTemplate* uit){    if(!uit) return 0;    laPanel *p = memAcquireHyper(sizeof(laPanel));    strSafeSet(&p->Title, uit->Title->Ptr);    p->PanelTemplate = uit;    p->Show = 1;    p->PP.EndInstance = p;    p->PP.LastPs = &p->FakePS;    p->PP.LastPs->p = _LA_PROP_PANEL;    p->PP.LastPs->UseInstance = p;    p->PP.LastPs->Type = U'.';    la_EnsurePanelExtras(p);        laRecalcPanel(p);    p->FrameDistinguish = 100; //greater than 1 is ok    p->TitleWidth = tnsStringGetWidth(transLate(SSTR(p->Title)), 0, 0);    while (b->B1){ b = b->B1; } lstPushItem(&b->Panels, p);    p->Block = b; b->CurrentPanel = p;    if(uit->PropFunc){ uit->PropFunc(p); }    uit->Define(&p->UI, &p->PP, &p->PropLinkPP, 0, 0);    laNotifyUsers("la.windows.panels");    return p;}laPanel *laCreatePanel(laBlock *b, char *template_id){    laUiTemplate* uit=laFindUiTemplate(template_id);    return laCreatePanelT(b, uit);}laPanel *laCreateTopPanel(laWindow *w, char *template_id, int X, int Y, int W, int H, int MaxW, int MaxH, int MinW, int MinH, int SnapL, int SnapR, int SnapT, int SnapB){    laUiTemplate* uit=0;    if(template_id) uit=laFindUiTemplate(template_id);    laPanel *p = la_NewPanel(uit, X, Y, W, H, MaxW, MaxH, MinW, MinH, SnapL, SnapR, SnapT, SnapB);    p->Mode = LA_PANEL_FLOATING_TOP;    laPlacePanelForCreation(p);    if(uit && (!(uit->Flags&LA_TEMPLATE_FLAGS_NO_DECORATION))){        laui_DefaultPanelTitleBar(&p->TitleBar, &p->PP, &p->PropLinkPP, p->PanelTemplate->Header);    }    if (w) lstPushItem(&w->Panels, p);    return p;}void laShowPanel(laPanel *p){    p->Show = 1; laNotifyUsers("la.windows.panels_hidden");}void laShowPanelWithDropDownEffect(laPanel *p){    laShowPanel(p);    p->AnimationMode = LA_PANEL_ANIMATION_DROP_DOWN; laRefreshWindow();    p->AnimationRatio = 0;}void laShowPanelWithExpandEffect(laPanel *p){    laShowPanel(p);    p->AnimationMode = LA_PANEL_ANIMATION_EXPAND; laRefreshWindow();    p->AnimationRatio = 0;}void laHidePanel(laPanel *p){    if (!p->Mode) return;    p->Show = 0;    laNotifyUsers("la.windows.panels_hidden");}void laHidePanelWithDissoveEffect(laPanel *p){    if (!p->Mode) return;    laHidePanel(p);    p->AnimationMode = LA_PANEL_ANIMATION_DISSOVE; laRefreshWindow();    p->AnimationRatio = 1;}void laHidePanelWithCollapseEffect(laPanel *p){    if (!p->Mode) return;    laHidePanel(p);    p->AnimationMode = LA_PANEL_ANIMATION_COLLAPSE; laRefreshWindow();    p->AnimationRatio = 1;}void laHidePanelWithMinimizeEffect(laPanel *p){    if (!p->Mode) return;    laHidePanel(p);    p->AnimationMode = LA_PANEL_ANIMATION_MINIMIZE; laRefreshWindow();    p->AnimationRatio = 1;}void laActivatePanel(char* TemplateID, int x, int y){    laUiTemplate* uit = laFindUiTemplate(TemplateID);    laPanel *p = la_FindFreePanelByTemplate(MAIN.CurrentWindow, uit);    if (!p){ p=laCreateTopPanel(MAIN.CurrentWindow, TemplateID, x, y, 0,0, 0, 0, 0, 0, 0, 0, 0, 0); }    laShowPanelWithExpandEffect(p); laPopPanel(p);}void laPanPanel(laPanel *p, int DeltaX, int DeltaY){    p->UI.PanX += DeltaX;    p->UI.PanY += DeltaY;}void laPanUiListFree(laUiList *uil, int X, int Y){    uil->PanX+=X; uil->PanY+=Y;}int laPanUiList(laUiList *uil, int X, int Y, int L, int R, int U, int B){    if(uil->ScrollerShownH && !uil->ScrollerShownV){        if(Y){X+=Y;Y=0;}    }    if (Y > 0){        if (uil->B - uil->PanY <= B) return 0;        else{            uil->PanY += Y;            if (uil->B - uil->PanY <= B){                uil->PanY = uil->B - B;                return 1;            }        }    }    if (Y < 0){        if (uil->U - uil->PanY >= U) return 0;        else{            uil->PanY += Y;            if (uil->U - uil->PanY >= U){                uil->PanY = uil->U - U;                return 1;            }        }    }    if(uil->AllowScale){        laPanUiListFree(uil, X, 0);    }else{        if (X > 0){            if (uil->R - uil->PanX <= R) return 0;            else{                uil->PanX += X;                if (uil->R - uil->PanX <= R){                    uil->PanX = uil->R - R;                    return 1;                }            }        }        if (X < 0){            if (uil->L - uil->PanX >= L) return 0;            else{                uil->PanX += X;                if (uil->L - uil->PanX >= L){                    uil->PanX = uil->L - L;                    return 1;                }            }        }    }    return 1;}int laScaleUiList(laUiList *uil, real factor, int L, int R, int U, int B){    int ret=1;    if(!uil->AllowScale){ return 0; }    real NewScale=uil->Scale*factor;    if(NewScale<0.2){NewScale=0.2; ret=0;}    if(NewScale>5)  {NewScale=5; ret=0;}    if(NewScale>1-1e-4 && NewScale<1+1e-4){NewScale=1;}    factor=NewScale/uil->Scale;    uil->Scale=NewScale;    real mx=(L+R)/2,my=(U+B)/2;    real dx= (mx+uil->PanX)*factor;    real dy= (my+uil->PanY)*factor;    uil->PanX=dx-mx;    uil->PanY=dy-my;    MAIN.CurrentPanel->FrameDistinguish=100;    return ret;}int laPanUiListAuto(laUiList *uil, int X, int Y, int L, int R, int U, int B){    if(uil->AllowScale) return 0;    return laPanUiList(uil,X,Y,L,R,U,B);}laPanel *laDesignPropPanel(char *Title, int X, int Y, int W, int H,                           laUiDefineFunc Define, laPropPack *This, laPropPack *OperatorProps){    laPanel *p = la_NewPanel(0, X, Y, W, H, 0, H, 0, 0, 0, 0, 0, 0);    strSafeSet(&p->Title, Title);    if (Define){        if (!This) { This = &p->PP; }        Define(laPrepareUi(p), This, OperatorProps, NULL, 0);    }    //laui_DefaultOperatorPanelTitleBar(&p->TitleBar, &p->PP, OperatorProps, 0, 0);    p->BT= &_LA_THEME_FLOATING_PANEL;    p->Mode = LA_PANEL_FLOATING_PASSIVE;    p->BoundUi = 1;    return p;}laPanel *laDesignOperatorPanel(char *Title, int X, int Y, int W, int H, int MaxW, int MaxH, int MinW, int MinH, int SnapL, int SnapR, int SnapT, int SnapB,                               laUiDefineFunc Define, laPropPack *This, laPropPack *OperatorProps){    laPanel *p = la_NewPanel(0, X, Y, W, H, MaxW, MaxH, MinW, MinH, SnapL, SnapR, SnapT, SnapB);    strSafeSet(&p->Title, Title);    if (Define){        Define(laPrepareUi(p), This, OperatorProps, NULL, 0);    }    laui_DefaultOperatorPanelTitleBar(&p->TitleBar, &p->PP, OperatorProps, 0, 0);    p->BT= &_LA_THEME_FLOATING_PANEL;    p->Mode = LA_PANEL_FLOATING_TOP;    p->BoundUi = 1;    return p;}void laDeferredDestroyPanel(laPanel *p, int immediate){    laPanel *ip;    tnsDelete2DOffscreen(p->OffScr);    p->OffScr = 0;    strSafeDestroy(&p->Title);    if (!p->AnimationMode){        if (p->Parent) lstRemoveItem(&p->Parent->SubPanels, p);        else if (p->Mode == LA_PANEL_FLOATING_TOP){            lstRemoveItem(&MAIN.CurrentWindow->Panels, p);        }else if (p->Mode == LA_PANEL_NO_PARENT_MENU){            lstRemoveItem(&MAIN.CurrentWindow->Panels, p);        }else if (p->Block){            lstRemoveItem(&p->Block->Panels, p);            if (p->Block->CurrentPanel == p) p->Block->CurrentPanel = p->Block->Panels.pFirst;        }        laNotifyUsers("la.windows.panels");    }    for (ip = p->SubPanels.pFirst; ip; ip = ip->Item.pNext){        //lstRemoveItem(&p->SubPanels, ip);        laDestroySinglePanel(ip, immediate);        laNotifyUsers("la.windows.panels");    }    la_ClearDetachedProp(p);    memFree(p->PropLinkContainer); memFree(p->PropLinkFakeProp);    la_ReturnPanelNode(p);}void laDestroySinglePanel(laPanel *p, int immediate){    la_SetPropMathcerContext(p);    if (p->PropLinkPP.LastPs&&p->PropLinkPP.LastPs->p->SubProp->Props.pFirst){        for(laProp* prop=p->PropLinkPP.LastPs->p->SubProp->Props.pFirst;prop;prop=prop->Item.pNext){            { /* la_StopUsingPropPack(&prop->DetachedPP); */ }            //laStopUsingDataBlock(prop->DetachedPP.LastPs->UseInstance, prop->DetachedPP.LastPs->p,MAIN.PropMatcherContextP);        }    }    if(MAIN.CurrentWindow&&p==MAIN.CurrentWindow->MaximizedUiPanel){ laRestoreCanvasUI(); }    la_DestroyUiList(&p->UI, 1, 1, 0);    la_DestroyUiList(&p->TitleBar, 1, 1, 0);    //la_DestroyUiList(p->MenuRefer, 0, 1, 1);    if (p->Mode){        p->AnimationMode = LA_PANEL_ANIMATION_DISSOVE; laRefreshWindow();        p->AnimationRatio = p->CloseWhenMovedOut?0.0:1.0;    }    if (p->ParentOperator && la_UiOperatorExists(p)) ((laOperator *)p->ParentOperator)->OperatorPanel = 0;    if (la_UiStillInService(p)){        la_StopUiOperatorService(p);    }    if ((!p->AnimationMode) || immediate){        laDeferredDestroyPanel(p, immediate);    }else{        p->LaterDestroy = 1;    }}int laEnclosePanelContent(laPanel *p, laUiList *uil){    int MinW,MinWt=0;    int TitleReserve=p->Mode==LA_PANEL_FLOATING_TOP?LA_RH:0;    if(!MAIN.CurrentWindow){ MAIN.CurrentWindow=MAIN.Windows.pFirst; if(!MAIN.CurrentWindow) return 0; }    int CW = MAIN.CurrentWindow->CW;    if(p->SL && p->SR){return 0;}    la_SetPropMathcerContext(p);    la_UpdateUiListRecursive(&p->TitleBar, LA_M, LA_M, p->TW - LA_M*2, p->TH, 0, p);    la_UpdateUiListRecursive(uil, LA_M+p->TitleBar.B, 0, 1000, 0, 0, p);    MinWt = la_TestUiListMinumWidth(&p->TitleBar);    MinW = la_TestUiListMinumWidth(uil);    if (MinW<MinWt){MinW=MinWt;}    int ScrollerW=(uil->ScrollerShownV?(LA_SCROLL_W+LA_M):0);    if (MinW > 20){        p->TW = MinW + LA_M*2 +ScrollerW;    }    la_PanelValidateWidth(p,uil);    laEnsurePanelInBound(p,uil);    if(p->TW>CW){ p->TW=CW; }    la_UpdateUiListRecursive(&p->TitleBar, LA_M, LA_M, p->TW-LA_M*2, p->TH, 0, p);    la_UpdateUiListRecursive(uil, LA_M+p->TitleBar.B, LA_M, p->TW-LA_M-ScrollerW, 0, 0, p);    laRedrawPanel(p);    return 1;}laPanel *laEnableIdlePanel(laPanel *Attachment, laOperator *a, laPropPack *OperatorProps, laUiDefineFunc ReplaceUiDefine, laPropPack *This,                               int L, int R, int B, int MaxGH, int MaxW, laEvent *e){    laOperator *ai = a;    laPanel *p;    int GX, GY, GW, t = 0;    int b;    laUiDefineFunc def = ReplaceUiDefine;    int MinW;    if (!def){ def=laui_DefaultPropDetails; }    GX = L; GY = B; GW = (R - L) > MaxW ? MaxW : (R - L);    p = laDesignPropPanel("TMP", GX, GY, GW, MaxGH, def, This, OperatorProps);    laEnclosePanelContent(p, &p->UI);    laSetOperatorLocalizer(p);    p->CloseWhenMovedOut=1;    laInvokeUi(a, "LA_menu_panel_operator", e, p, 0, 1);    //laShowPanelWithDropDownEffect(p);    if(!Attachment){ Attachment=MAIN.CurrentWindow->MaximizedUiPanel; }    if(Attachment){ p->Parent = Attachment; lstAppendItem(&Attachment->SubPanels, p); }    return p;}laPanel *laEnableSplashPanel(laUiDefineFunc ReplaceUiDefine, int L, int R, int B, int MaxGH, int MaxW, laEvent* e){    laPanel *p;    int GX, GY, GW, t = 0;    int b;    laUiDefineFunc def = ReplaceUiDefine;    int MinW;    if (!def) return 0;    GX = L; GY = B; GW = (R - L) > MaxW ? MaxW : (R - L);    p = laDesignPropPanel("TMP", GX, GY, GW, MaxGH, def, 0, 0);    p->Mode = LA_PANEL_FLOATING_TOP;    p->CloseWhenMovedOut=2; MAIN.PendingSplash=p;    laEnclosePanelContent(p, &p->UI);    if(MAIN.CurrentWindow->Operators.pFirst){        laSetOperatorLocalizer(MAIN.PendingSplash);        laInvokeUi(0, "LA_panel_operator", e, MAIN.PendingSplash, 0, 1);        MAIN.PendingSplash=0;    }    //laShowPanelWithExpandEffect(p);    lstPushItem(&MAIN.CurrentWindow->Panels, p);    return p;}laPanel *laEnablePropertyPanel(laPanel *Attachment, laOperator *a, laPropPack *OperatorProps, laUiDefineFunc ReplaceUiDefine, laUiDefineFunc FallBackUiDefine, laPropPack *This,                               int L, int R, int B, int MaxGH, int MaxW, laEvent *e){    laOperator *ai = a;    laPanel *p; laPropContainer* sub;    int GX, GY, GW, t = 0;    int b;    laUiDefineFunc def = ReplaceUiDefine;    int MinW;    if (!def){        if (This && This->LastPs->p){            if(This->LastPs->p->SubProp&&This->LastPs->p->SubProp->MenuUiDefine) def = This->LastPs->p->SubProp->MenuUiDefine;        }        if((!def) && (sub=la_EnsureSubTarget(This->LastPs->p,This->EndInstance)) && sub->MenuUiDefine) def=sub->MenuUiDefine;        if(!def) def = FallBackUiDefine?FallBackUiDefine:laui_DefaultPropUiDefine;    }    GX = L; GY = B;    GW = (R - L) > MaxW ? MaxW : (R - L);    p = laDesignPropPanel("TMP", GX, GY, GW, MaxGH, def, This, OperatorProps);    laEnclosePanelContent(p, &p->UI);    laSetOperatorLocalizer(p);    laInvokeUi(a, "LA_menu_panel_operator", e, p, 0, 1);    laShowPanelWithDropDownEffect(p);    if(!Attachment){ Attachment=MAIN.CurrentWindow->MaximizedUiPanel; }    if(Attachment){        p->Parent = Attachment;        lstAppendItem(&Attachment->SubPanels, p);    }    return p;}laPanel *laEnableEmptyPropertyPanel(laPanel *Attachment, laOperator *a, int L, int R, int U, int MaxGH, laEvent *e){    laPanel *p;    int t = 0;    int b;    //laLocalToWindow(0, Attachment, &L, &t);    //laLocalToWindow(0, Attachment, &R, &U);    p = laDesignPropPanel("TMP", L, U, R - L, MaxGH, 0, 0, 0);    laSetOperatorLocalizer(p);    laInvokeUi(a, "LA_menu_panel_operator", e, p, 0, 1);    laShowPanelWithDropDownEffect(p);    p->Parent = Attachment;    lstPushItem(&Attachment->SubPanels, p);    return p;}laPanel *laEnableMenuPanel(laPanel *Attachment, laOperator *a, laUiList *MenuRefer, laPropPack *This,                           int L, int R, int B, int MaxGH, int MaxW, laEvent *e){    laOperator *ai = a;    laPanel *p;    laBoxedTheme *bt = _LA_THEME_FLOATING_PANEL;    int GX, GY, GW, t = 0;    int b;    int MinW;    //laLocalToWindow(0,Attachment, &L, &t);    //laLocalToWindow(0,Attachment, &R, &B);    GX = L;    GY = B;    GW = (R - L) > MaxW ? MaxW : (R - L);    p = laDesignPropPanel("TMP", GX, GY, GW, MaxGH, 0, 0, 0);    p->MenuRefer = MenuRefer;    laEnclosePanelContent(p, MenuRefer);    laSetOperatorLocalizer(p);    laInvokeUi(a, "LA_menu_panel_operator", e, p, 0, 1);    laShowPanelWithDropDownEffect(p);    p->Parent = Attachment;    lstPushItem(&Attachment->SubPanels, p);    return p;}laPanel *laDefineAndEnableMenuPanel(laPanel *Attachment, laOperator *a, laPropPack *This,                                    int L, int B, int MaxGH, int MaxW, laEvent *e){    laOperator *ai = a;    laPanel *p;    int GX, GY, GW, t = 0;    int b;    GX = L;    GY = B;    GW = MaxW;    p = laDesignPropPanel("TMP", GX, GY, GW, MaxGH, 0, 0, 0);    p->MenuRefer = &p->UI;        p->Mode = LA_PANEL_NO_PARENT_MENU;    laSetOperatorLocalizer(p);    laInvokeUi(a, "LA_menu_panel_operator", e, p, 0, 1);    laShowPanelWithDropDownEffect(p);    if (Attachment){        p->Parent = Attachment;        lstPushItem(&Attachment->SubPanels, p);    }else{        lstPushItem(&MAIN.CurrentWindow->Panels, p);    }    return p;}laPanel *laEnableOperatorPanel(laOperator *For, laPropPack *This, int X, int Y, int W, int H, int MaxW, int MaxH, int MinW, int MinH, int SnapL, int SnapR, int SnapT, int SnapB, laEvent *e){    laOperator *ai = For;    laPanel *p;    int b;    laUiDefineFunc def = 0;    if(ai->OperatorPanel){ return ai->OperatorPanel; }    if (ai->Type->UiDefine) def = ai->Type->UiDefine;    else def = laui_DefaultPropUiDefine;        For->PP.EndInstance = For->CustomData;    p = laDesignOperatorPanel(ai->Type->Name, X, Y, W, H, MaxW, MaxH, MinW, MinH, SnapL, SnapR, SnapT, SnapB, def, This, &For->PP);    laEnclosePanelContent(p, &p->UI);    MAIN.ToPanel = p;    laShowPanelWithExpandEffect(p);    lstPushItem(&MAIN.CurrentWindow->Panels, p);    ai->OperatorPanel = p;    p->ParentOperator = For;    laInvokeUi(For, "LA_modal_panel_operator", 0, p, 0, 1);    return p;}laPanel *laEnableYesNoPanel(laOperator *a, laPanel *Attachment, char *Title, char *Message, int X, int Y, int W, laEvent *e){    laPanel *p; int b; laUiList *uil; laColumn* col;    p = la_NewPanel(0, X, Y, W, 0, 1000, 500, 50, 0, 0, 0, 0, 0);    strSafeSet(&p->Title, Title);    p->BoundUi = 1;    p->Mode = LA_PANEL_FLOATING_TOP;    p->BT = &_LA_THEME_FLOATING_PANEL;    MAIN.ToPanel = p;    laui_DefaultOperatorPanelTitleBar(&p->TitleBar, &p->PP, &p->PropLinkPP, 0, 0);    uil = laPrepareUi(p); col = laFirstColumn(uil);    laShowLabel(uil, col, Message, 0, 0)->Flags|=LA_TEXT_USE_NEWLINE|LA_TEXT_LINE_WRAP;    laUiItem* r=laBeginRow(uil,col,0,0);    laShowSeparator(uil,col)->Expand=1;    laShowItem(uil,col,0,"LA_confirm")->Flags|=LA_UI_FLAGS_HIGHLIGHT|LA_TEXT_ALIGN_CENTER;    laEndRow(uil,r);    laEnclosePanelContent(p,uil); laShowPanelWithExpandEffect(p);    lstPushItem(&MAIN.CurrentWindow->Panels, p);    laSetOperatorLocalizer(p);    laInvokeUi(a, "LA_modal_panel_operator", e, p, 0, 1);    return p;}laPanel *laEnableMessagePanel(laOperator *a, laPanel *Attachment, char *Title, char *Message, int X, int Y, int W, laEvent *e){    laPanel *p; int b; laUiList *uil; laColumn* col;    p = la_NewPanel(0, X, Y, W, 0, 1000, 0, 100, 0, 0, 0, 0, 0);    strSafeSet(&p->Title, Title);    p->BoundUi = 1;    p->Mode = LA_PANEL_FLOATING_TOP;    p->BT = &_LA_THEME_FLOATING_PANEL;    MAIN.ToPanel = p;    laui_DefaultOperatorPanelTitleBar(&p->TitleBar, &p->PP, &p->PropLinkPP, 0, 0);    uil = laPrepareUi(p); col = laFirstColumn(uil);    laShowLabel(uil, col, Message, 0, 0)->Flags|=LA_TEXT_USE_NEWLINE|LA_TEXT_LINE_WRAP;    laUiItem* r = laBeginRow(uil,col,0,0);    laShowSeparator(uil,col)->Expand=1;    laShowItemFull(uil,col,0,"LA_confirm",0,"text=Okay;",0,0)->Flags|=LA_UI_FLAGS_HIGHLIGHT;    laEndRow(uil, r);    laEnclosePanelContent(p,uil);    laShowPanelWithExpandEffect(p);    lstPushItem(&MAIN.CurrentWindow->Panels, p);    laSetOperatorLocalizer(p);    laInvokeUi(a, "LA_modal_panel_operator", e, p, 0, 1);    return p;}laPanel *laEnableEmptyMessagePanel(laOperator *a, laPanel *Attachment, char *Title, int X, int Y, int W, laEvent *e){    laPanel *p; int b; laUiList *uil; laColumn* col;    p = la_NewPanel(0, X, Y, W, 0, 1000, 0, 100, 0, 0, 0, 0, 0);    strSafeSet(&p->Title, Title);    p->BoundUi = 1;    p->Mode = LA_PANEL_FLOATING_TOP;    p->BT = &_LA_THEME_FLOATING_PANEL;    MAIN.ToPanel = p;    laui_DefaultOperatorPanelTitleBar(&p->TitleBar, &p->PP, &p->PropLinkPP, 0, 0);    uil = laPrepareUi(p); col = laFirstColumn(uil);    laShowPanelWithExpandEffect(p);    lstPushItem(&MAIN.CurrentWindow->Panels, p);    laSetOperatorLocalizer(p);    laInvokeUi(a, "LA_modal_panel_operator", e, p, 0, 1);    return p;}void laOperatorModalOver(laOperator* For){    For->ModalOver = 1;}void laDeferredRedraw(laPanel* p){    for(laListItemPointer* lip=MAIN.DeferredRedrawList.pFirst;lip;lip=lip->pNext){        if(lip->p==p) return;    }    lstAppendPointer(&MAIN.DeferredRedrawList, p);}void laRedrawAllWindows(){ if((!MAIN.CurrentWindow) || (!MAIN.CurrentWindow->win)) return;    laWindow* cur=MAIN.CurrentWindow;    for(laWindow* w=MAIN.Windows.pFirst;w;w=w->Item.pNext){        MAIN.CurrentWindow=w;        la_UpdateUiPlacement(w);    }    MAIN.CurrentWindow=cur;}void laRedrawCurrentWindow(){ if((!MAIN.CurrentWindow) || (!MAIN.CurrentWindow->win)) return;    if (MAIN.CurrentWindow) la_UpdateUiPlacement(MAIN.CurrentWindow);}void laRefreshWindow(){ MAIN.CurrentWindow->Redraw=1; }void laRedrawPanel(laPanel* p){ p->Refresh |= LA_TAG_REDRAW; MAIN.CurrentWindow->Redraw=1; }void laRecalcPanel(laPanel* p){ p->Refresh |= LA_TAG_RECALC; MAIN.CurrentWindow->Redraw=1; }void laRedrawCurrentPanel(){    if (MAIN.CurrentPanel) laRedrawPanel(MAIN.CurrentPanel);    elif (MAIN.CurrentWindow->MaximizedUiPanel) laRedrawPanel(MAIN.CurrentWindow->MaximizedUiPanel);}void laRecalcCurrentPanel(){    if (MAIN.CurrentPanel) laRecalcPanel(MAIN.CurrentPanel);    elif (MAIN.CurrentWindow->MaximizedUiPanel) laRecalcPanel(MAIN.CurrentWindow->MaximizedUiPanel);}void laRecalcPanelImmediate(laPanel* p){    p->FrameDistinguish++;    laBoxedTheme* bt = (*p->BT);    int em=bt->BoxStyle==-1?LA_M:0;    int scrollw=p->UI.ScrollerShownV?LA_M*2+LA_SCROLL_W:0;    la_PanelRefreshDetachedProp(p);    int enclosed=0;    if(p->BoundUi || p->MenuRefer){        if(p->MenuRefer) enclosed=laEnclosePanelContent(p, p->MenuRefer);        else enclosed=laEnclosePanelContent(p, &p->UI);    }    if(!enclosed){        la_PanelValidateWidth(p,&p->UI);        laEnsurePanelInBound(p,p->MenuRefer?p->MenuRefer:&p->UI);        la_UpdateUiListRecursive(&p->TitleBar, LA_M+em, LA_M+em, p->TW-LA_M, p->TH-LA_M, 0, p);        int UseB=p->TitleBar.TB; if((!p->Mode)||(p->Mode==LA_PANEL_FLOATING_PASSIVE)){ UseB=em; }        la_UpdateUiListRecursive(&p->UI, UseB+LA_M, LA_M+em, p->TW-LA_M-scrollw, p->TH-LA_M, 0, p);    }    laWindow* w=MAIN.CurrentWindow;    if(w->MaximizedUiPanel==p&&w->MaximizedUi){ int CW = w->CW; int CH = w->CH;        laUiItem* ui=w->MaximizedUi; ui->TU=ui->U=0; ui->TB=ui->B=CH; ui->TL=ui->L=0; ui->TR=ui->R=CW;        if(!ui->Page) return; laBoxedTheme* bt=(*ui->Type->Theme);        la_UpdateUiListRecursive(ui->Page, ui->TU+LA_M, ui->TL+LA_M, ui->TR-LA_M, ui->TB, 0, w->MaximizedUiPanel);    }}void laRecalcCurrentPanelImmediate(){    laRecalcPanelImmediate(MAIN.CurrentPanel);}int laNonFixedPanelExists(laPanel *p){    laPanel *ip;    if (!p) return 0;    //for (ip = MAIN.CurrentWindow->CurrentLayout->Panels.pLast; ip; ip = ip->Item.pPrev) {    //	if (ip == p) return 1;    //}    for (ip = MAIN.CurrentWindow->Panels.pLast; ip; ip = ip->Item.pPrev){        if (ip == p) return 1;    }    return 0;}int laIsInPanel(laPanel *p, int PanelX, int PanelY){    if (PanelX < 0 || PanelY < 0 || PanelY > p->H || PanelX > p->W) return 0;    return 1;}int laIsCloseToPanel(laPanel *p, int PanelX, int PanelY){    int tt=MAIN.TooltipCloseDistance;    if (PanelX < -tt || PanelY < -tt || PanelY > p->H+tt || PanelX > p->W+tt) return 0;    return 1;}int laPanelOverlappingEachOther(laPanel *p1, laPanel *p2){    if (p1->X > p2->X + p2->W || p1->X + p1->W < p2->X ||        p1->Y > p2->Y + p2->H || p1->Y + p1->H < p2->Y)        return 0;    return 1;}void laUnlinkSharedPanel(laPanel *p){    laWindow *w;    laPanel *ip;    for (w = MAIN.Windows.pFirst; w; w = w->Item.pNext){        for (ip = w->Panels.pFirst; ip; ip = ip->Item.pNext){            if (ip == p){                lstRemoveItem(&w->Panels, ip);                return;            }        }    }}int laIsPanelCovered(laPanel *p){    //laLayout* l = MAIN.CurrentWindow->CurrentLayout;    laPanel *ip;    laPanel *resp;    int in1 = 0, in2 = 0, in3 = 0;    laPanel *d1 = 0, *d2 = 0, *d3 = 0;    //for (ip = MAIN.CurrentWindow->CurrentLayout->Panels.pLast; ip; ip = ip->Item.pPrev) {    //	if (ip == p) { in1 = 1; d1 = 0; continue; }    //	if (ip->Show && laPanelOverlappingEachOther(ip, p)) d1 = ip;    //}    for (ip = MAIN.CurrentWindow->Panels.pLast; ip; ip = ip->Item.pPrev){        if (ip == p){            in3 = 1;            d3 = 0;            continue;        }        if (ip->Show && laPanelOverlappingEachOther(ip, p)) d3 = ip;    }    if (!in2 && !in3) in1 = 1;    if (in1){        if (d1 || d2 || d3) return 1;    }else{        if (in2){            if (d2 || d3) return 1;        }else if (in3)            if (d3) return 1;    }    return 0;}int laIsTopPanel(laPanel *p){    //if (!p->Item.pPrev) return 1;    //else {    if (!laIsPanelCovered(p)){        //laPopPanel(p);        return 1;    }    return 0;    //}    return 0;}void laPanelToLocal(laOperator *a, int *x, int *y){    int ix = *x, iy = *y;    laListItemPointer *lip;    if (a){    //printf("\n");        int SL,SR,SU,SB; int PX=0,PY=0;        for (lip = a->LocalUiLists.pLast; lip; lip = lip->pPrev){            laUiList *uil = lip->p;            if(lip->pNext){                int PadR=(uil->AllowScale && uil->ScrollerShownV)?LA_SCROLL_W+LA_M*4:0;                int PadB=(uil->AllowScale && uil->ScrollerShownH)?LA_SCROLL_W+LA_M*3:0;                int UseB=uil->LimH?uil->U+uil->LimH:uil->B;                SL=TNS_MAX2(SL,uil->L); SR=TNS_MIN2(SR-PadR,uil->R);                SU=TNS_MAX2(SU,uil->U); SB=TNS_MIN2(SB-PadB,UseB);                SL+=uil->PanX; SR+=uil->PanX; SU+=uil->PanY; SB+=uil->PanY;            }else{                SL=uil->L+uil->PanX;SR=uil->R+uil->PanX;SU=uil->U+uil->PanY;SB=uil->B+uil->PanY;            }            PX += uil->PanX; PY += uil->PanY;            //printf("u %d %d %d %d %s\n",uil->L,uil->R,uil->U,uil->B,SSTR(uil->TabName));        }        (*x)+=PX; (*y)+=PY;        lip=a->LocalUiLists.pFirst; if(lip){            laUiList *uil = lip->p;            uil->FL=SL; uil->FR=SR; uil->FU=SU; uil->FB=SB;            //printf("uil limit %d %d | %d %d %d %d %d %d\n",*x,*y,uil->FL,uil->FR,uil->FU,uil->FB,PX,PY);        }    }}void laWindowToLocal(laOperator *a, laPanel *p, int *x, int *y){    if(!p) return;    int ix = *x, iy = *y;    laListItemPointer *lip;    laOperator *ai = a;    (*x) = ix - ((MAIN.CurrentWindow->MaximizedUiPanel==p)?0: p->X);    (*y) = iy - ((MAIN.CurrentWindow->MaximizedUiPanel==p)?0: p->Y);    laPanelToLocal(a,x,y);}void laLocalToWindow(laOperator *a, laPanel *p, int *x, int *y){    if(!p) return;    int ix = *x, iy = *y;    laListItemPointer *lip;    (*x) = ix + ((MAIN.CurrentWindow->MaximizedUiPanel==p)?0: p->X);    (*y) = iy + ((MAIN.CurrentWindow->MaximizedUiPanel==p)?0: p->Y);    if (a){        for (lip = a->LocalUiLists.pFirst; lip; lip = lip->pNext){            laUiList *uil = lip->p;            (*x) -= uil->PanX;            (*y) -= uil->PanY;        }    }}void laPanelToWindow(laPanel *p, int *x, int *y){    int ix = *x, iy = *y;    laListItemPointer *lip;    (*x) = ix + ((MAIN.CurrentWindow->MaximizedUiPanel==p)?0: p->X);    (*y) = iy + ((MAIN.CurrentWindow->MaximizedUiPanel==p)?0: p->Y);}void laLocalToPanel(laOperator *a, int *x, int *y){    int ix = *x, iy = *y;    laListItemPointer *lip;    if (a){        for (lip = a->LocalUiLists.pFirst; lip; lip = lip->pNext){            laUiList *uil = lip->p;            (*x) -= uil->PanX;            (*y) -= uil->PanY;        }    }}void laSetNextMenuPos(int X, int Y, int W, int H){    MAIN.NextX = X;    MAIN.NextY = Y;    MAIN.NextW = W;    MAIN.NextH = H;}int laIsInBlock(laBlock *b, int X, int Y){    if (X >= b->X && X <= b->X + b->W && Y >= b->Y && Y <= b->Y + b->H) return 1;    return 0;}int laIsInBlockHeader(laBlock *b, int X, int Y){ if (X >= b->X && X <= b->X + b->W && Y >= b->Y && Y <= b->Y + LA_RH) return 1; return 0; }int laIsInBlockBotton1(laBlock *b, int X, int Y){ if (X >= b->X && X <= b->X + LA_RH && Y >= b->Y && Y <= b->Y + LA_RH) return 1; return 0; }int laIsInBlockBotton2(laBlock *b, int X, int Y){ if (X >= b->X+LA_RH && X <= b->X+LA_2RH && Y >= b->Y && Y <= b->Y + LA_RH) return 1; return 0; }laBlock *laDetectBlockRecursive(laBlock *b, int X, int Y){    laPanel *p;    laBlock *sb = 0;    if (!laIsInBlock(b, X, Y)) return 0;    if (!b->B1 && !b->B2) return b;    if (sb = laDetectBlockRecursive(b->B1, X, Y)) return sb;    return laDetectBlockRecursive(b->B2, X, Y);}laPanel *laDetectPanel(int X, int Y){    laPanel *p; laBlock *b;    for (p = MAIN.CurrentWindow->Panels.pFirst; p; p = p->Item.pNext){        int x = X, y = Y;        laWindowToLocal(0, p, &x, &y);        if (p->Show && laIsInPanel(p, x, y)){            return p;        }    }    if(MAIN.CurrentWindow->MaximizedUiPanel){return 0;}    laBlock* RootBlock=MAIN.CurrentWindow->MaximizedBlock?MAIN.CurrentWindow->MaximizedBlock:MAIN.CurrentWindow->CurrentLayout->FirstBlock;    if (b = laDetectBlockRecursive(RootBlock, X, Y)) return b->CurrentPanel;    return 0;}laUiList *laPrepareUi(laPanel *p){    return &p->UI;}laColumn *laFirstColumn(laUiList *uil){    if (uil->Columns.pFirst) return uil->Columns.pFirst;    else{        laColumn *c = memAcquireSimple(sizeof(laColumn));        c->SP = 1;        c->PreWidth = 1;        lstAppendItem(&uil->Columns, c);        c->Top = c;        return uil->Columns.pFirst;    }}laColumn *laSplitColumn(laUiList *uil, laColumn *c, real Percent){    laColumn *lc, *rc;    if (c->LS || c->RS) return c;    lc = memAcquireSimple(sizeof(laColumn));    rc = memAcquireSimple(sizeof(laColumn));    c->LS = lc;    c->RS = rc;    c->LS->SP = Percent;    c->RS->SP = Percent;    c->LS->Top = c->Top;    c->RS->Top = c->Top;    if (uil){        lstAppendItem(&uil->Columns, lc);        lstAppendItem(&uil->Columns, rc);    }    if (c->LS && c->RS->MaxW == 0){        c->LS->PreWidth = c->PreWidth * c->LS->SP;        c->RS->PreWidth = c->PreWidth * (1 - c->RS->SP);    }else if (c->RS && c->LS->MaxW == 0){        c->LS->PreWidth = c->PreWidth * c->LS->SP;        c->RS->PreWidth = c->PreWidth * (1 - c->RS->SP);    }    return c;}laColumn *laLeftColumn(laColumn *c, int MaxWidth){    if (c->LS && MaxWidth) c->LS->MaxW = MaxWidth;    return c->LS;}laColumn *laRightColumn(laColumn *c, int MaxWidth){    if (c->LS && c->LS->MaxW && MaxWidth) return c->RS;    if (MaxWidth) c->RS->MaxW = MaxWidth;    return c->RS;}void la_DestroyColumnRecursive(laListHandle *List, laColumn *c){    lstRemoveItem(List, c);    if (c->LS) la_DestroyColumnRecursive(List, c->LS);    if (c->RS) la_DestroyColumnRecursive(List, c->RS);    memFree(c);}int laCheckAndMergeSubColumnsUiList(laUiList *TopUil, laColumn *c, int DoMerge){    laUiList *uil = TopUil;    laUiList *sub;    laUiItem *ui;    laColumn *cc, *NextCC = 0;    int Occupied = 0;    int Removed = 0;    if (!c->LS) return 0;    else{        laCheckAndMergeSubColumnsUiList(TopUil, c->LS, DoMerge);        laCheckAndMergeSubColumnsUiList(TopUil, c->RS, DoMerge);    }    for (ui = TopUil->UiItems.pFirst; ui; ui = ui->Item.pNext){        if (ui->C == c->LS || ui->C == c->RS){            if (DoMerge){                ui->C = c;                Occupied = 1;            }else                return 1;        }        if (ui->Subs.pFirst){            for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){                laCheckAndMergeSubColumnsUiList(sub, c, DoMerge);            }        }    }    if (!Removed){        for (cc = uil->Columns.pFirst; cc; cc = cc->Item.pNext){            if (cc == c){                if (c->LS) la_DestroyColumnRecursive(&uil->Columns, c->LS);                if (c->RS) la_DestroyColumnRecursive(&uil->Columns, c->RS);                c->LS = 0;                c->RS = 0;                Removed = 1;                break;            }        }    }    return Occupied;}laPropContainer* laUiHasExtraProps(laUiType *ut, int size, int Hyper){    ut->ExtraProps = laAddPropertyContainer(ut->Identifier, 0,0,U'◳',0,size,0,0,Hyper);    ut->FakeProp = memAcquire(sizeof(laSubProp));    ut->FakeProp->Base.SubProp = ut->ExtraProps;    ut->FakeProp->Base.Identifier = ut->Identifier;    ut->FakeProp->Base.PropertyType = LA_PROP_SUB;    ut->FakeProp->Base.Offset = offsetof(laUiItem, Extra);    ut->FakeProp->Base.OffsetIsPointer = 1;    //ut->FakeProp->Base.Container = ut->ExtraProps;    return ut->ExtraProps;}laPropContainer* laCanvasHasExtraProps(laCanvasTemplate *ct, int size, int Hyper){    ct->ExtraProps = laAddPropertyContainer(ct->Identifier->Ptr, 0,0,U'◳',0,size,0,0,Hyper);    ct->FakeProp = memAcquire(sizeof(laSubProp));    ct->FakeProp->Base.SubProp = ct->ExtraProps;    ct->FakeProp->Base.Identifier = ct->Identifier->Ptr;    ct->FakeProp->Base.PropertyType = LA_PROP_SUB;    ct->FakeProp->Base.Offset = offsetof(laUiItem, Extra);    ct->FakeProp->Base.OffsetIsPointer = 1;    //ut->FakeProp->Base.Container = ut->ExtraProps;    return ct->ExtraProps;}void la_DestroyUiType(laUiType* uit){    laKeyMapItem* kmi; while(kmi=lstPopItem(&uit->KeyMapper.Items)){ la_FreeKeyMapItem(kmi); }    memFree(uit);}laUiType *la_RegisterUiType(const char *Identifer, int ForType, const char *UseOperator, laBoxedTheme **bt, laUiDrawFunc *Draw, laUiGetHeightFunc GetHeight, laUiInitFunc Init, laUiDestroyFunc Destroy){    laUiType *ut = memAcquire(sizeof(laUiType));    ut->Identifier = Identifer;    ut->OperatorID = UseOperator;    ut->Draw = Draw;    ut->Theme = bt;    ut->ForType = ForType;    ut->OperatorType = laGetOperatorType(UseOperator);    ut->GetHeight = GetHeight;    ut->Init = Init;    ut->Destroy = Destroy;    la_UDFAppendSharedTypePointer(Identifer, ut);    lstAppendItem(&MAIN.UiTypes, ut);    return ut;}laUiType *la_GetUiTypeFromProperty(laProp *P){    laUiType *ut = MAIN.UiTypes.pFirst;    if (!P) return 0;    if (P->DefaultUiType) return P->DefaultUiType;    if (P->SubProp == LA_PC_SOCKET_IN || P->SubProp == LA_PC_SOCKET_OUT) return _LA_UI_NODE_SOCKET;     if (P->PropertyType == LA_PROP_SUB) return _LA_UI_COLLECTION;    for (ut; ut; ut = ut->Item.pNext){        if ((ut->ForType&LA_PROP_GENERIC_BITS) == (P->PropertyType&LA_PROP_GENERIC_BITS)){            return ut;        }    }    return 0;}laUiType *la_GetUiButtonType(){    laUiType *ut = MAIN.UiTypes.pFirst;    for (ut; ut; ut = ut->Item.pNext){        if (ut->ForType == LA_PROP_OPERATOR) return ut;    }    return 0;}laCanvasTemplate *la_GetCanvasTemplate(char* TargetContainerID, char* TemplateID){    laCanvasTemplate *vdt;    for (vdt = MAIN.View2DTemplates.pFirst; vdt; vdt = vdt->Item.pNext){        if (strSame(TemplateID, vdt->Identifier->Ptr) || strSame(TargetContainerID, vdt->TargetContainerID)) return vdt;    }    return 0;}void la_AssignPropExtras(laUiItem* ui){    if(!ui->Type || !ui->Type->FakeProp) return;    ui->FakePs.p = ui->Type->FakeProp;    ui->FakePs.Type = U'.';    ui->FakePs.UseInstance = ui;    ui->ExtraPP.LastPs = &ui->FakePs;}void la_AssignCanvasPropExtras(laUiItem* ui){    if(!ui->CanvasTemplate || !ui->CanvasTemplate->FakeProp) return;    laCanvasTemplate*ct=ui->CanvasTemplate;    ui->FakePs.p = ct->FakeProp;    ui->FakePs.Type = U'.';    ui->FakePs.UseInstance = ui;    ui->ExtraPP.EndInstance = ui->Extra;    ui->ExtraPP.LastPs = &ui->FakePs;}laUiItem *la_UpdatePropDisplay(laUiItem *ui, laPropPack *Base, const char *Path, laUiDefineFunc Template, laWidget* Widget, char* instructions){    int result;    if (!ui) return 0;    laUiType* OverrideType=Widget&&Widget->Type?Widget->Type:0;    if (Path){        result = la_GetPropFromPath(&ui->PP, Base, Path, 0);        if (!result){            ui->AT = laGetOperatorType(Path);            if (!ui->AT /* && !OverrideType*/) return la_UpdatePropDisplay(ui, 0, "la.unknown_prop", 0, 0, instructions);            ui->Type = la_GetUiButtonType();            if (OverrideType && (OverrideType->ForType == LA_PROP_OPERATOR)) ui->Type = OverrideType;        }else{            ui->Type = (OverrideType && ((!OverrideType->ForType)||                                        (OverrideType->ForType&&OverrideType->ForType == ui->PP.LastPs->p->PropertyType)||                                        (OverrideType->TargetSub && !strcmp(OverrideType->TargetSub, ui->PP.LastPs->p->Identifier)))) ?                                            OverrideType : la_GetUiTypeFromProperty(ui->PP.LastPs->p);            ui->Flags|=ui->PP.LastPs->p->DefaultFlags;        }        if (Base){            ui->PP.RawThis = Base;        }    }else if (Base){        ui->PP.LastPs = Base->LastPs;        ui->Type = (OverrideType && ((!OverrideType->ForType)||                                    (OverrideType->ForType&&OverrideType->ForType == ui->PP.LastPs->p->PropertyType)||                                    (OverrideType->TargetSub && !strcmp(OverrideType->TargetSub, ui->PP.LastPs->p->SubProp->Identifier)))) ?                                        OverrideType : la_GetUiTypeFromProperty(ui->PP.LastPs->p);        ui->PP.RawThis = Base; //HACK! Not Unified For Prop Access!!!<<<----------??????????        ui->Flags|=ui->PP.LastPs->p->DefaultFlags;    }    la_AssignPropExtras(ui);    if(Widget){ ui->Flags|= Widget->Flags; }    if(Template) ui->Template = Template; ui->State = LA_UI_NORMAL;    if(!ui->Type) ui->Type = Widget?Widget->Type:0;    if(instructions) strSafeSet(&ui->ExtraInstructions, instructions);    return ui;}laUiItem *la_UpdateLabelDisplay(laUiItem *ui, laUiDefineFunc Template, char *Content){    ui->Type = _LA_UI_LABEL;    ui->Template = Template;    ui->State = LA_UI_NORMAL;    strSafeSet(&ui->Display, Content);    la_AssignPropExtras(ui);    return ui;}laUiItem *la_CreateGroupHandle(laWidget* Widget){    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));    ui->Type = (Widget&&Widget->Type)?Widget->Type : _LA_UI_FIXED_GROUP;    ui->State = LA_UI_NORMAL;    la_AssignPropExtras(ui);    return ui;}laUiItem *laShowLabel(laUiList *uil, laColumn *c, const char *Content, laUiDefineFunc Template, laWidget* Widget){    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));    transLate(Content);    la_UpdateLabelDisplay(ui, Template, Content);    ui->C = c;    if (ui->Type->Init) ui->Type->Init(ui);    ui->ExtraPP.EndInstance = ui->Extra;    lstAppendItem(&uil->UiItems, ui);    return ui;}laUiItem *laShowLabelDynamic(laUiList *uil, laColumn *c, const char *Content, laUiDefineFunc Template, laWidget* Widget){    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));    la_UpdateLabelDisplay(ui, Template, Content);    ui->C = c;    if (ui->Type->Init) ui->Type->Init(ui);    ui->ExtraPP.EndInstance = ui->Extra;    lstAppendItem(&uil->UiItems, ui);    return ui;}laUiItem *laShowIcon(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, laWidget* Widget){    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));    la_UpdatePropDisplay(ui, Base, Path, 0, Widget, 0);    ui->Flags |= LA_UI_FLAGS_INT_ICON;    ui->C = c;    if (ui->Type->Init) ui->Type->Init(ui);    ui->ExtraPP.EndInstance = ui->Extra;    lstAppendItem(&uil->UiItems, ui);    return ui;}laUiItem *laShowInvisibleItem(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path){    laWidget wg={&_LA_UI_INVISIBLE, 0}; return laShowItemFull(uil,c,Base,Path,&wg,0,0,0);}laUiItem *laShowItem(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path){    return laShowItemFull(uil,c,Base,Path,0,0,0,0);}laUiItem *laShowItemFull(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, laWidget* Widget, char* instructions, laUiDefineFunc Template, int TemplateContext){    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));    la_UpdatePropDisplay(ui, Base, Path, Template, Widget, instructions);    ui->C = c;    ui->TemplateContext = TemplateContext;    if (ui->Type->Init) ui->Type->Init(ui);    ui->ExtraPP.EndInstance = ui->Extra;        lstAppendItem(&uil->UiItems, ui);    return ui;}laUiItem *laShowItemWithLabel(laUiList *uil, laColumn *clabel, laColumn *cmain, laPropPack *Base, const char *Path, laWidget* Widget, char* instructions, laUiDefineFunc Template, int TemplateContext,                              char* Label, int LabelFlags, laColumn* AlignAt){    if(AlignAt){ laShowSeparator(uil,AlignAt)->Flags|=LA_UI_FLAGS_NO_DECAL; }    laUiItem* ui=laShowItemFull(uil,cmain,Base,Path,Widget,instructions,Template,TemplateContext);    if(!Label && ui && ui->PP.LastPs && ui->PP.LastPs->p){ laProp* p=ui->PP.LastPs->p; Label=p->Name; }    laUiItem* labelui=laShowLabel(uil,clabel,Label,0,0); if(!LabelFlags){ labelui->Flags|= LA_TEXT_ALIGN_RIGHT; }else{ labelui->Flags|=LabelFlags; }    lstRemoveItem(&uil->UiItems,ui); lstAppendItem(&uil->UiItems,ui);    return ui;}laUiItem *laShowImage(laUiList *uil, laColumn *c, tnsImage* Image, int Height){    laUiItem *ui = memAcquire(sizeof(laUiItem));    ui->C = c; memAssignRef(ui,&ui->Extra,Image);    ui->Type=_LA_UI_IMAGE; ui->Type->Init(ui);    ui->Extent=Height;    lstAppendItem(&uil->UiItems, ui);    return ui;}laUiItem *laShowNodeSocket(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, char* instructions){    return laShowItemFull(uil,c,Base,Path,LA_WIDGET_NODE_SOCKET,instructions,0,0);}laUiItem *laShowHeightAdjuster(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, char* instructions){    return laShowItemFull(uil,c,Base,Path,LA_WIDGET_HEIGHT_ADJUSTER,instructions,0,0);}laUiItem *laShowCanvas(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, const char *id2DTemplate, int Height){    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));    ui->Type = _LA_UI_CANVAS;    ui->State = LA_UI_NORMAL;    ui->C = c;    la_GetPropFromPath(&ui->PP, Base, Path, 0);    if (id2DTemplate) ui->CanvasTemplate = la_GetCanvasTemplate(0, id2DTemplate);    else{        if(!ui->PP.LastPs || ui->PP.LastPs->p->PropertyType!=LA_PROP_SUB){ la_FreePropStepCache(ui->PP.Go); memFree(ui); return laShowItem(uil,c,Base,Path); }        laSubProp* sp=ui->PP.LastPs->p; ui->PP.LastPs->p->SubProp=la_EnsureSubTarget(sp,0);        ui->CanvasTemplate = la_GetCanvasTemplate(sp->TargetID, 0);        if(!ui->CanvasTemplate){ la_FreePropStepCache(ui->PP.Go); memFree(ui); return laShowItem(uil,c,Base,Path); }    }    if (ui->Type->Init) ui->Type->Init(ui);    la_AssignCanvasPropExtras(ui);    if (Height) ui->Expand=Height; else ui->Expand=6;    lstAppendItem(&uil->UiItems, ui);    return ui;}laUiItem *laShow3DCanvasCombo(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, int Height, laPropPack* Detached){    laUiItem* ui=0;#define ADD_CANVAS \    laUiItem* b=laBeginRow(uil,cr,0,0);\    laUiItem* b3=laOnConditionThat(uil,cr,laPropExpression(&rb->PP,"active"));{\        laShowLabel(uil,cr,"⯈",0,0); laShowItem(uil,cr,&rb->PP,"active.name")->Flags|=LA_UI_FLAGS_NO_DECAL;\    }laEndCondition(uil,b3);\    laEndRow(uil,b);        if(Detached){        laColumn* cl,*cll,*clr,*cr;        laSplitColumn(uil,c,0.35); cl=laLeftColumn(c,7); cr=laRightColumn(c,0);        laSplitColumn(uil,cl,0.4); cll=laLeftColumn(cl,1); clr=laRightColumn(cl,0);        laShowItemFull(uil,cll,Detached,"detached",0,0,0,0)->Flags|=LA_UI_FLAGS_HIGHLIGHT|LA_UI_FLAGS_ICON;        laUiItem* b2=laOnConditionThat(uil,c,laPropExpression(Detached,"detached"));{            laUiItem* rb=laShowItemFull(uil,clr,Detached,"root_object",LA_WIDGET_COLLECTION_SELECTOR,0,laui_IdentifierOnly,0);            ADD_CANVAS            ui=laShowCanvas(uil,c,Detached,"root_object",0,Height); laDefault3DViewOverlay(ui);        }laElse(uil,b2);{            laUiItem* rb=laShowItemFull(uil,clr,0,"tns.world.active_root",LA_WIDGET_COLLECTION_SELECTOR,0,laui_IdentifierOnly,0);            ADD_CANVAS            ui=laShowCanvas(uil,c,0,"tns.world.active_root",0,Height); laDefault3DViewOverlay(ui);        }laEndCondition(uil,b2);    }else{        ui=laShowCanvas(uil,c,Base,Path,0,Height); laDefault3DViewOverlay(ui);    }#undef ADD_CANVAS    return ui;}laUiItem *laShowColumnAdjuster(laUiList *uil, laColumn *c){    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));    laCanvasExtra *e;    ui->Type = _LA_UI_COLUMN_ADJUSTER;    ui->Flags |= LA_WIDGET_COLUMN_ADJUSTER->Flags;    ui->C = c;    if (ui->Type->Init) ui->Type->Init(ui);    ui->ExtraPP.EndInstance = ui->Extra;        lstAppendItem(&uil->UiItems, ui);    return ui;}laPropPack* laShowCompoundValue(laUiItem* ui, int slot, laPropPack *Base, const char *Path){    laPropPack PP={0}; int result;    if (Path){        result = la_GetPropFromPath(&PP, Base, Path, 0);        if (!result){ return 0; }        if (Base){ PP.RawThis = Base; }    }else if (Base){        PP.LastPs = Base->LastPs; PP.RawThis = Base; //HACK! Not Unified For Prop Access!!!<<<----------??????????    }    laCompoundPP* CPP = memAcquire(sizeof(laCompoundPP));    CPP->Slot = slot; memcpy(&CPP->PP, &PP, sizeof(laPropPack));    lstAppendItem(&ui->CompoundPPs,CPP);    return &CPP->PP;}laUiItem *laShowMouseActionReporter(laUiList* uil, laColumn* c, int Height, const char* Display, const char* instructions){    laUiItem *ui = memAcquire(sizeof(laUiItem));    ui->C = c;    ui->Type=_LA_UI_MOUSE_ACTION_REPORTER;    ui->State=Height; if(!ui->State){ ui->State=1; }    if(Display) strSafeSet(&ui->Display, Display);    if(instructions) strSafeSet(&ui->ExtraInstructions, instructions);    lstAppendItem(&uil->UiItems, ui);    return ui;}laUiItem *laBeginRow(laUiList *uil, laColumn *c, int Expand, int Even){    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));    ui->Type = &_LA_UI_ROW_BEGIN;    ui->State=Expand;    ui->Flags=Even;    ui->C = c;    if (ui->Type->Init) ui->Type->Init(ui);    ui->ExtraPP.EndInstance = ui->Extra;        lstAppendItem(&uil->UiItems, ui);    return ui;}laUiItem *laEndRow(laUiList *uil, laUiItem* Begin){    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));    ui->Type = &_LA_UI_ROW_END;    ui->C = Begin->C;    ui->Page = (laUiList*)Begin;    if (ui->Type->Init) ui->Type->Init(ui);    ui->ExtraPP.EndInstance = ui->Extra;        lstAppendItem(&uil->UiItems, ui);    return ui;}void la_ConditionerInit(laUiItem *ui, laUiConditionNode *Expression){    laConditionUiExtraData *e = CreateNew(laConditionUiExtraData);    e->Expression = Expression;    ui->Extra = e;    la_AssignPropExtras(ui);}laUiItem *laMakeGroup(laUiList *uil, laColumn *c, const char *Name, laWidget* Widget){    laUiItem *ui = la_CreateGroupHandle(Widget);    laUiList *nuil;    ui->C = c;    lstAppendItem(&uil->UiItems, ui);    nuil = memAcquireSimple(sizeof(laUiList));    strSafeSet(&nuil->TabName, Name);    ui->Page = nuil;    lstAppendItem(&ui->Subs, nuil);    if (ui->Type->Init) ui->Type->Init(ui);    ui->ExtraPP.EndInstance = ui->Extra;        return ui;}laUiItem *laMakeFoldableGroup(laUiList *uil, laColumn *c, const char *Name, laWidget* Widget, int DefaultFolded, int ButtonFlags){    laUiItem *SubUi = laMakeGroup(uil, c, Name, Widget?Widget:0);    laUiList *sub = SubUi->Page;    laColumn *s = laFirstColumn(sub);    SubUi->State = LA_UI_ACTIVE;    laUiItem *b1 = laOnConditionToggle(sub, s, 0, 0, 0, 0, 0);    strSafePrint(&b1->ExtraInstructions, "text=%s", Name);    if(!DefaultFolded) b1->State=LA_UI_ACTIVE;    if(ButtonFlags)b1->Flags|=ButtonFlags; else b1->Flags|=LA_UI_FLAGS_NO_DECAL;    laShowSeparator(sub, s);    return SubUi;}laUiItem *laMakeEmptyGroup(laUiList *uil, laColumn *c, const char *Name, laWidget* Widget){    laUiItem *SubUi = laMakeGroup(uil, c, Name, Widget?Widget->Type:0);    laUiList *sub = SubUi->Page;    laColumn *s = laFirstColumn(sub);    SubUi->State = LA_UI_ACTIVE;    return SubUi;}void laEndFoldableGroup(laUiList *sub, laUiItem *group){    laEndCondition(sub, sub->UiItems.pFirst);}laUiItem *laMakeTab(laUiList *uil, laColumn *c, laWidget* Widget){    laUiItem *ui = la_CreateGroupHandle(Widget?Widget:LA_WIDGET_TAB);    laUiList *nuil;    ui->C = c;    lstAppendItem(&uil->UiItems, ui);    if (ui->Type->Init) ui->Type->Init(ui);    ui->ExtraPP.EndInstance = ui->Extra;        return ui;}laUiList *laAddTabPage(laUiItem *ui, const char *Name){    laUiList *uil = memAcquireSimple(sizeof(laUiList));    if (!ui->Page) ui->Page = uil;    lstAppendItem(&ui->Subs, uil);    strSafeSet(&uil->TabName, Name);    laFirstColumn(uil);    //laFirstColumn(uil);    return uil;}laUiList *la_AddInstancePage(laUiItem *ui, void *Instance, laWidget* Widget){    laUiList *uil = memAcquireSimple(sizeof(laUiList));    /*if (!ui->Page) */ ui->Page = uil;    lstAppendItem(&ui->Subs, uil);    uil->Instance = Instance; ui->PP.EndInstance=Instance;    return uil;}laUiConditionNode *laTrue(){    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));    ucn->Type = LA_CONDITION_TRUE;    return ucn;}laUiConditionNode *laFalse(){    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));    ucn->Type = LA_CONDITION_FALSE;    return ucn;}laUiConditionNode *laPropExpression(laPropPack *Base, char *Prop){    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));    ucn->Type = LA_CONDITION_PROP;    la_GetPropFromPath(&ucn->PP, Base, Prop, 0);    strSafeSet(&ucn->String, Prop);    return ucn;}laUiConditionNode *laIntExpression(int Value){    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));    ucn->Type = LA_CONDITION_INT;    ucn->IntValue = Value;    return ucn;}laUiConditionNode *laFloatExpression(real Value){    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));    ucn->Type = LA_CONDITION_FLOAT;    ucn->FloatValue = Value;    return ucn;}laUiConditionNode *laStringExpression(char *Content){    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));    ucn->Type = LA_CONDITION_STRING;    strSafeSet(&ucn->String, Content);    return ucn;}laUiConditionNode *laAnd(laUiConditionNode *Expression1, laUiConditionNode *Expression2){    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));    ucn->Type = LA_CONDITION_AND;    ucn->Expression1 = Expression1;    ucn->Expression2 = Expression2;    return ucn;}laUiConditionNode *laOr(laUiConditionNode *Expression1, laUiConditionNode *Expression2){    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));    ucn->Type = LA_CONDITION_OR;    ucn->Expression1 = Expression1;    ucn->Expression2 = Expression2;    return ucn;}laUiConditionNode *laNot(laUiConditionNode *Expression1){    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));    ucn->Type = LA_CONDITION_NOT;    ucn->Expression1 = Expression1;    return ucn;}laUiConditionNode *laEqual(laUiConditionNode *Expression1, laUiConditionNode *Expression2){    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));    ucn->Type = LA_CONDITION_EQ;    ucn->Expression1 = Expression1;    ucn->Expression2 = Expression2;    return ucn;}laUiConditionNode *laGreaterThan(laUiConditionNode *Expression1, laUiConditionNode *Expression2){    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));    ucn->Type = LA_CONDITION_GT;    ucn->Expression1 = Expression1;    ucn->Expression2 = Expression2;    return ucn;}laUiConditionNode *laLessThan(laUiConditionNode *Expression1, laUiConditionNode *Expression2){    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));    ucn->Type = LA_CONDITION_LT;    ucn->Expression1 = Expression1;    ucn->Expression2 = Expression2;    return ucn;}laUiConditionNode *laGreaterEqual(laUiConditionNode *Expression1, laUiConditionNode *Expression2){    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));    ucn->Type = LA_CONDITION_GE;    ucn->Expression1 = Expression1;    ucn->Expression2 = Expression2;    return ucn;}laUiConditionNode *laLessEqual(laUiConditionNode *Expression1, laUiConditionNode *Expression2){    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));    ucn->Type = LA_CONDITION_LE;    ucn->Expression1 = Expression1;    ucn->Expression2 = Expression2;    return ucn;}int la_GetIntConditionValue(laUiConditionNode *Expression){    if (Expression->Type != LA_CONDITION_INT) return 0;    return Expression->IntValue;}real la_GetFloatConditionValue(laUiConditionNode *Expression){    if (Expression->Type != LA_CONDITION_FLOAT) return 0;    return Expression->FloatValue;}char *la_GetStringConditionValue(laUiConditionNode *Expression){    return Expression->String->Ptr;}int la_DoCompare(int CompMode, int Mode1, int i1, real f1, char *s1, void *p1, int Mode2, int i2, real f2, char *s2, void *p2){    switch (Mode1){    case LA_PROP_ENUM:    case LA_PROP_INT:    case LA_CONDITION_INT:        switch (Mode2){        case LA_PROP_ENUM:        case LA_PROP_INT:        case LA_CONDITION_INT:            switch (CompMode){            case LA_CONDITION_GE:                return (i1 >= i2);            case LA_CONDITION_GT:                return (i1 > i2);            case LA_CONDITION_EQ:                return (i1 == i2);            case LA_CONDITION_LT:                return (i1 < i2);            case LA_CONDITION_LE:                return (i1 <= i2);            }        case LA_PROP_FLOAT:        case LA_CONDITION_FLOAT:            switch (CompMode){            case LA_CONDITION_GE:                return ((real)i1 >= f2);            case LA_CONDITION_GT:                return ((real)i1 > f2);            case LA_CONDITION_EQ:                return ((real)i1 >= f2 - 0.0001 && (real)i1 <= f2 + 0.0001);            case LA_CONDITION_LT:                return ((real)i1 < f2);            case LA_CONDITION_LE:                return ((real)i1 <= f2);            }        case LA_PROP_SUB:            if (CompMode == LA_CONDITION_EQ) return i1 == (int)p2;        default:            return 0;        }    case LA_PROP_FLOAT:    case LA_CONDITION_FLOAT:        switch (Mode2){        case LA_PROP_INT:        case LA_PROP_ENUM:        case LA_CONDITION_INT:            switch (CompMode){            case LA_CONDITION_GE:                return (f1 >= (real)i2);            case LA_CONDITION_GT:                return (f1 > (real)i2);            case LA_CONDITION_EQ:                return (f1 + 0.0001 >= (real)i2 && f1 - 0.0001 <= (real)i2);            case LA_CONDITION_LT:                return (f1 < (real)i2);            case LA_CONDITION_LE:                return (f1 <= (real)i2);            }        case LA_PROP_FLOAT:        case LA_CONDITION_FLOAT:            switch (CompMode){            case LA_CONDITION_GE:                return (f1 >= f2);            case LA_CONDITION_GT:                return (f1 > f2);            case LA_CONDITION_EQ:                return (f1 == f2);            case LA_CONDITION_LT:                return (f1 < f2);            case LA_CONDITION_LE:                return (f1 <= f2);            }        default:            return 0;        }    case LA_PROP_STRING:    case LA_CONDITION_STRING:        switch (Mode2){        case LA_PROP_STRING:        case LA_CONDITION_STRING:            return strSame(s1, s2);        default:            return 0;        }    case LA_PROP_SUB:        switch (Mode2){        case LA_PROP_SUB:            return p1 == p2;        case LA_CONDITION_INT:        case LA_PROP_INT:        case LA_PROP_ENUM:            return (int)p1 == i2;        default:            return 0;        }    default:        switch (CompMode){        case LA_CONDITION_GE:            return (i1 >= i2);        case LA_CONDITION_GT:            return (i1 > i2);        case LA_CONDITION_EQ:            return (i1 == i2);        case LA_CONDITION_LT:            return (i1 < i2);        case LA_CONDITION_LE:            return (i1 <= i2);        }    }    return 0;}int la_DoExpression(laUiConditionNode *Expression, int *IResult, real *FResult, char *_StrResult, void **PtrResult){    void *Instance = 0;    int IValue1 = 0, IValue2 = 0;    real FValue1 = 0, FValue2 = 0;    void *Ptr1 = 0, *Ptr2 = 0;    char Str1[128], Str2[128]={0}; char* StrResult=_StrResult;    int Result1, Result2;    laEnumItem *ei; laSubProp*sp;    if (!Expression) return 0;    Str1[0] = 0;    Str2[0] = 0;    laPropIterator pi = {0};    switch (Expression->Type){    case LA_CONDITION_PROP:        if (!Expression->PP.LastPs){            (*IResult) = 0;            return 0;        }        switch (Expression->PP.LastPs->p->PropertyType){        case LA_PROP_INT:            *IResult = laGetInt(&Expression->PP);            if (*IResult) return LA_CONDITION_INT;            else return 0;        case LA_PROP_FLOAT:            *FResult = laGetFloat(&Expression->PP);            if (*FResult) return 1;            else return 0;            break;        case LA_PROP_STRING:            laGetString(&Expression->PP, _StrResult, &StrResult);            if (StrResult[0]) return 1;            else return 0;            break;        case LA_PROP_ENUM:            ei = laGetEnum(&Expression->PP);            if (!ei) return 0;            /*if(ei) */ *IResult = ei->Index;            if (*IResult) return LA_CONDITION_INT;            else return 0;            break;        case LA_PROP_SUB:            sp=Expression->PP.LastPs->p;            //if (sp->IsDetached){ *PtrResult = sp->Detached; if (sp->Detached) return 1; else return 0; }            if (!Expression->PP.Go) Instance = Expression->PP.EndInstance;            else Instance = laGetActiveInstance(Expression->PP.LastPs->p, Expression->PP.LastPs->UseInstance, &pi);            if(!Instance){ Expression->PP.LastPs->p; if((!sp->GetActive) && (sp->Base.Offset<=0)){                     Instance=laGetInstance(sp,Expression->PP.LastPs->UseInstance, &pi);                }            }            *PtrResult = Instance;            if (Instance) return 1;            break;        default:            return 0;        }        break;    case LA_CONDITION_INT:        *IResult = Expression->IntValue;        if (*IResult) return 1;        else            return 0;    case LA_CONDITION_FLOAT:        *FResult = Expression->FloatValue;        if (*FResult) return 1;        else            return 0;    case LA_CONDITION_STRING:        if (Expression->String){            strCopyFull(StrResult, Expression->String->Ptr);            return 1;        }else            return 0;    case LA_CONDITION_TRUE:        if (*IResult) *IResult = 1;        return 1;    case LA_CONDITION_FALSE:        if (*IResult) *IResult = 0;        return 0;    default:        Result1 = la_DoExpression(Expression->Expression1, &IValue1, &FValue1, &Str1, &Ptr1);        switch (Expression->Type){        case LA_CONDITION_AND:            if (Result1){                Result2 = la_DoExpression(Expression->Expression2, &IValue2, &FValue2, &Str2, &Ptr2);                if (Result2) *IResult = 1;                return (Result2);            }else                return 0;        case LA_CONDITION_OR:            if (!Result1){                Result2 = la_DoExpression(Expression->Expression2, &IValue2, &FValue2, &Str2, &Ptr2);                if (Result2) *IResult = 1;                return (Result2);            }else                return 1;        case LA_CONDITION_NOT:            return !Result1;        default:            Result2 = la_DoExpression(Expression->Expression2, &IValue2, &FValue2, &Str2, &Ptr2);            return la_DoCompare(Expression->Type,                                 (Expression->Expression1->Type == LA_CONDITION_PROP && Expression->Expression1->PP.LastPs) ? Expression->Expression1->PP.LastPs->p->PropertyType : Expression->Expression1->Type, IValue1, FValue1, Str1, Ptr1,                                 (Expression->Expression2->Type == LA_CONDITION_PROP && Expression->Expression2->PP.LastPs) ? Expression->Expression2->PP.LastPs->p->PropertyType : Expression->Expression2->Type, IValue2, FValue2, Str2, Ptr2);        }        break;    }    return 0;}int la_DoSingleExpression(laUiConditionNode *Expression){    int a;    real b;    char c[128]={0};    void *p;    if (!Expression) return 1;    c[0] = 0;    return la_DoExpression(Expression, &a, &b, c, &p);}void la_StepExpression(laUiConditionNode *e){    if (!e) return;    switch (e->Type){    case LA_CONDITION_AND:    case LA_CONDITION_OR:    case LA_CONDITION_GE:    case LA_CONDITION_GT:    case LA_CONDITION_EQ:    case LA_CONDITION_LT:    case LA_CONDITION_LE:        la_StepExpression(e->Expression1);        la_StepExpression(e->Expression2);        break;    case LA_CONDITION_NOT:        la_StepExpression(e->Expression1);        break;    case LA_CONDITION_PROP:        la_StepPropPack(&e->PP);        //if (e->PP.LastPs && e->PP.LastPs->p->Container && e->PP.LastPs->p->Container->Hyper){ // doesn't seem needed now with getuser            la_UsePropPack(&e->PP, 1);            //laUseDataBlock(e->PP.Go ? e->PP.LastPs->UseInstance : e->PP.EndInstance, e->PP.LastPs->p, MAIN.PropMatcherContextP->FrameDistinguish, MAIN.PropMatcherContextP, la_PropPanelUserRemover,1);        //}        break;    default:        break;    }}void la_ConditionNodeFreeRecursive(laUiConditionNode *ucn){    if (!ucn) return;    la_ConditionNodeFreeRecursive(ucn->Expression1);    la_ConditionNodeFreeRecursive(ucn->Expression2);    if (ucn->PP.LastPs) la_FreePropStepCache(ucn->PP.Go);    if (ucn->String) strSafeDestroy(&ucn->String);    if (ucn) memFree(ucn);}laUiItem *laOnConditionThat(laUiList *uil, laColumn *c, laUiConditionNode *Expression){    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));    ui->C = c;    ui->Type = &_LA_UI_CONDITION;    la_ConditionerInit(ui, Expression);    lstAppendItem(&uil->UiItems, ui);    return ui;}laUiItem *laElse(laUiList *uil, laUiItem *Beginner){    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));    laConditionUiExtraData *cued;    ui->Type = &_LA_UI_CONDITION_ELSE;    la_ConditionerInit(ui, 0);    cued = ui->Extra;    cued->EndUi = Beginner;    ((laConditionUiExtraData *)Beginner->Extra)->ElseUi = ui;    ui->C = Beginner->C;    lstAppendItem(&uil->UiItems, ui);    return ui;}laUiItem *laOnConditionToggle(laUiList *uil, laColumn *col, laUiDefineFunc define, int Remove, laPropPack *ExtraBase, laPropPack *ExtraThis, laWidget* Widget){    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));    laConditionUiExtraData *cued;    ui->Template = define;    ui->C = col;    ui->PP.RawThis = ExtraBase;    ui->Page = ExtraThis;    ui->Type = Widget? Widget->Type : _LA_UI_CONDITION_TOGGLE;    la_ConditionerInit(ui, 0);    cued = ui->Extra;    //cued->Remove = Remove;    ui->State = LA_UI_NORMAL;    lstAppendItem(&uil->UiItems, ui);    return ui;}laUiItem *laEndCondition(laUiList *uil, laUiItem *Beginner){    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));    laConditionUiExtraData *cued;    ui->Type = &_LA_UI_CONDITION_END;    la_ConditionerInit(ui, 0);    cued = ui->Extra;    cued->EndUi = Beginner;    ((laConditionUiExtraData *)Beginner->Extra)->EndUi = ui;    ui->C = Beginner->C;    lstAppendItem(&uil->UiItems, ui);    return ui;}laUiList* laMakeMenuPageEx(laUiList* uil, laColumn* c, const char* Title, int flags) {    laUiItem* ui = memAcquireSimple(sizeof(laUiItem));    laUiList* muil = memAcquireSimple(sizeof(laUiList));    ui->Type = _LA_UI_MENU_ROOT;    strSafeSet(&ui->Display, Title);    ui->State = LA_UI_NORMAL; ui->Flags|=LA_TEXT_ALIGN_CENTER;    ui->C = c;    ui->Flags|=flags;    lstAppendItem(&uil->UiItems, ui);        muil->Flags|=flags;    lstAppendItem(&ui->Subs, muil);    return muil;}laUiList* laMakeMenuPage(laUiList* uil, laColumn* c, const char* Title) {    return laMakeMenuPageEx(uil,c,Title,0);}laUiItem *laShowSeparator(laUiList *uil, laColumn *widest){    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));    ui->Type = _LA_UI_ALIGN;    ui->C = widest;    lstAppendItem(&uil->UiItems, ui);    return ui;}void laFixHeight(laUiList *uil, short Rows){    if (!uil) return;    uil->HeightCoeff = Rows;}void laMakeUiListFromTemplate(laUiList *Into, laUiDefineFunc Template,                               laPropPack *PanelPP, laPropPack *PanelExtraPP, laPropPack *Base, laPropPack *Operator, laListHandle *ExtraColumns, int Context){    if (!ExtraColumns) return;    Template(Into, Base, Operator, ExtraColumns->pFirst, Context);}laUiTemplate *laFindUiTemplate(char *Identifier){    laUiTemplate *uit;    for (uit = MAIN.PanelTemplates.pFirst; uit; uit = uit->Item.pNext){        if (!strcmp(uit->Identifier->Ptr, Identifier)) return uit;    }    for (uit = MAIN.InitPanelTemplates.pFirst; uit; uit = uit->Item.pNext){        if (!strcmp(uit->Identifier->Ptr, Identifier)) return uit;    }    return 0;}void la_DestroyUiTemplate(laUiTemplate* uit){    strSafeDestroy(&uit->Identifier);    strSafeDestroy(&uit->Title);    laKeyMapItem* kmi; while(kmi=lstPopItem(&uit->KeyMap.Items)){ la_FreeKeyMapItem(kmi); }    memFree(uit);}void la_DestroyCanvasTemplate(laCanvasTemplate* uit){    strSafeDestroy(&uit->Identifier);    laKeyMapItem* kmi; while(kmi=lstPopItem(&uit->KeyMapper.Items)){ la_FreeKeyMapItem(kmi); }    memFree(uit);}laUiTemplate *laRegisterUiTemplate(char *Identifier, char* Title, laUiDefineFunc func,laPanelDetachedPropFunc PropFunc, laUiDefineFunc header, char* NewCategory, int DefaultGLFormat, int DefaultW_RH, int DefaultH_RH){    laUiTemplate *uit = memAcquire(sizeof(laUiTemplate));    strSafeSet(&uit->Identifier, Identifier);    strSafeSet(&uit->Title, Title);    strSafeSet(&uit->CategoryName, NewCategory);    uit->Define = func; uit->Header = header; uit->PropFunc = PropFunc;    uit->DefaultGLFormat=DefaultGLFormat;    uit->DefaultH_RH=DefaultH_RH?abs(DefaultH_RH):15; uit->DefaultW_RH=DefaultW_RH?abs(DefaultW_RH):15;    if(MAIN.InitDone) lstAppendItem(&MAIN.PanelTemplates, uit); else lstAppendItem(&MAIN.InitPanelTemplates, uit);    la_UDFAppendSharedTypePointer(Identifier, uit);    return uit;}void laUiTemplateSetExtras(laUiTemplate *uit, int flags, laStringGetF SaveOptions, laStringSetF RestoreOptions){    uit->Flags=flags; uit->SaveOptions=SaveOptions; uit->RestoreOptions=RestoreOptions;}laCanvasTemplate *laRegisterCanvasTemplate(char *Identifier, char *ForContainer, laModalFunc ExtraModal, laCanvasDrawFunc Func, laUiDrawFunc SecondDraw, laUiInitFunc CustomInit, laUiDestroyFunc CustomDestroy){    laCanvasTemplate *t = memAcquire(sizeof(laCanvasTemplate));    strSafeSet(&t->Identifier, Identifier);    t->Draw = Func; t->SecondDraw = SecondDraw; t->TargetContainerID = ForContainer; t->ExtraModal=ExtraModal;    t->Init = CustomInit; t->Destroy = CustomDestroy;    lstAppendItem(&MAIN.View2DTemplates, t);    la_UDFAppendSharedTypePointer(Identifier, t);    return t;}void laFinalizeUiTemplates(){    laUiTemplate *uit;    laCanvasTemplate *u2d;    for (u2d = MAIN.View2DTemplates.pFirst; u2d; u2d = u2d->Item.pNext){        if (u2d->TargetContainerID) u2d->TargetContainer = la_ContainerLookup(u2d->TargetContainerID);    }}laPanel *la_FindFreePanelByTemplate(laWindow *w, const laUiTemplate *uit){    laPanel *p;    for (p=w->Panels.pFirst; p; p = p->Item.pNext){        if (p->PanelTemplate==uit){            return p;        }    }    return 0;}void la_DestroyUiItem(laUiItem *ui, int RemoveUsers){    laUiList *uil, *NextUil;    for (uil = ui->Subs.pFirst; uil; uil = NextUil){        NextUil = uil->Item.pNext;        lstRemoveItem(&ui->Subs, uil);        la_DestroyUiList(uil, 0, RemoveUsers, 0);    }    la_StopUiOperatorService(ui);    strSafeDestroy(&ui->ExtraInstructions);strDestroyStringSplitor(&ui->Instructions);    strSafeDestroy(&ui->Display);    //if (RemoveUsers && ui->PP.LastPs && ui->PP.LastPs->p->Container->Hyper)    //    { /*la_StopUsingPropPack(&ui->PP);*/ }        //laStopUsingDataBlock(ui->PP.LastPs->UseInstance,ui->PP.LastPs->p,MAIN.PropMatcherContextP);    la_FreePropStepCache(ui->PP.Go); //-------[Up Here], instance already been freed.XXXXXXXXXXXX!!!!!!!!!!1    if (ui->CompoundPPs.pFirst){laCompoundPP* CPP;        while(CPP = lstPopItem(&ui->CompoundPPs)){ la_FreePropStepCache(CPP->PP.Go); memFree(CPP); }    }    if (ui->Type->Destroy) ui->Type->Destroy(ui);    memFree(ui);}void la_DestroyUiList(laUiList *uil, int NoFree, int RemoveUsers, int OnlyRemoveUser){    laUiItem *ui, *NextUi;    laColumn *col, *NextCol;    if (!uil) return;    for (ui = uil->UiItems.pFirst; ui; ui = NextUi){        NextUi = ui->Item.pNext;        if(OnlyRemoveUser && RemoveUsers){            if (ui->PP.LastPs && ui->PP.LastPs->p->Container->Hyper)                { /*la_StopUsingPropPack(&ui->PP);*/ }                //laStopUsingDataBlock(ui->PP.LastPs->UseInstance,ui->PP.LastPs->p,MAIN.PropMatcherContextP);            continue;        }        lstRemoveItem(&uil->UiItems, ui);        la_DestroyUiItem(ui, RemoveUsers);    }    if(OnlyRemoveUser){ return; }    for (col = uil->Columns.pFirst; col; col = NextCol){        NextCol = col->Item.pNext;        lstRemoveItem(&uil->Columns, col);        memFree(col);    }    strSafeDestroy(&uil->TabName);    if (!NoFree) memFree(uil);}void la_DestroyTabPage(laUiItem *ui, laUiList *Tab, int RemoveUsers){    if(ui) lstRemoveItem(&ui->Subs, Tab);    la_DestroyUiList(Tab, 1, RemoveUsers, 0);}void la_CreateUiAfter(laUiList *uil, laUiItem *after, laUiDefineFunc Define, laPropPack *Base, laPropPack *This, laColumn **ExtraColums){    laUiItem *Next = after->Item.pNext;    laUiItem *Last = uil->UiItems.pLast;    after->Item.pNext = 0;    uil->UiItems.pLast = after;    Define(uil, Base, This, ExtraColums, 0);    if (Next) Next->Item.pPrev = uil->UiItems.pLast;    ((laUiItem *)uil->UiItems.pLast)->Item.pNext = Next;    if (Next != Last) uil->UiItems.pLast = Last;}//void la_RefreshExtraColumns(laUiItem* ui, int B,int FromL,int ToL,int FromR,int ToR){//	int i = 0;//	int FromW=FromR-FromL, ToW=ToR-ToL;//	if (!ui->ExtraColums) return;//	for (i; ui->ExtraColums[i]; i++) {//		laColumn* c = ui->ExtraColums[i];//		c->B = B;//		c->IL = (c->IL - FromL) / FromW*ToW + ToL;//		c->IR = (c->IR - FromL) / FromW*ToW + ToL;//	}//}void la_PropPanelUserRemover(void* this_UNUSED, laItemUserLinker* iul){    laPanel* p = iul->Pointer.p; if(p->FrameDistinguish == iul->FrameDistinguish){ laRecalcPanel(p); }}void la_CalcUiItemInfluence(laListHandle *lst, laUiItem *ui){    laColumn *c = ui->C;    laColumn *ic = lst->pFirst;    c->B = ui->TB + LA_M;    for (ic; ic; ic = ic->Item.pNext){        if (((ic->IR > c->IL) && (ic->IL < c->IR)) || ((ic->IL < c->IR) && (ic->IR > c->IL))){            ic->B = ic->B < c->B ? c->B : ic->B;        }    }    ic = ui->C;    while (ic->Item.pPrev && (ic = ic->Item.pPrev))        ;    for (ic; ic; ic = ic->Item.pNext){        if (((ic->IR > c->IL) && (ic->IL < c->IR)) || ((ic->IL < c->IR) && (ic->IR > c->IL))){            ic->B = ic->B < c->B ? c->B : ic->B;        }    }}void la_CalcUiTopInfluence(laListHandle *lst, laUiItem *ui){    laColumn *c = ui->C;    laColumn *ic = lst->pFirst;    c->B = ui->TB + LA_M;    for (ic; ic; ic = ic->Item.pNext){        if (((ic->IR > c->IL) && (ic->IL < c->IR)) || ((ic->IL < c->IR) && (ic->IR > c->IL))){            ic->B = ic->B < c->B ? c->B : ic->B;        }    }    ic = ui->C;    while (ic->Item.pPrev && (ic = ic->Item.pPrev))        ;    for (ic; ic; ic = ic->Item.pNext){        if (((ic->IR > c->IL) && (ic->IL < c->IR)) || ((ic->IL < c->IR) && (ic->IR > c->IL))){            ic->B = ic->B < c->B ? c->B : ic->B;        }    }}int la_ResetUiColum(laColumn *c, laColumn *Top, int U, int L, int R, int LR, int repos){ //1=L,2=R    int rep;    int sp;    int rev;    int M=LA_M*2;    if (!c) return 0;    sp = (c->SP * (R - L)) + L;    rev = sp;    /*if (U)*/ c->B = U;    if (LR == 1){        c->IL = L;        c->IR = sp;        if (repos){            c->IR = repos;        }else if (c->MaxW*LA_RH && c->IR - c->IL > c->MaxW*LA_RH+M){            c->IR = c->IL + c->MaxW*LA_RH+M;            rev = c->IR;        }    }else if (LR == 2){        c->IL = sp;        c->IR = R;        if (repos){            c->IL = repos;        }else if (c->MaxW*LA_RH && c->IR - c->IL > c->MaxW*LA_RH+M){            c->IL = c->IR - c->MaxW*LA_RH-M;            rev = c->IL;        }    }else if (LR == 0){        c->IL = L;        c->IR = R;    }    if (c->LS && c->RS->MaxW == 0){        rep = la_ResetUiColum(c->LS, Top, U, c->IL, c->IR, 1, 0);        la_ResetUiColum(c->RS, Top, U, c->IL, c->IR, 2, rep);        c->LS->PreWidth = c->PreWidth * c->LS->SP;        c->RS->PreWidth = c->PreWidth * (1 - c->RS->SP);    }else if (c->RS && c->LS->MaxW == 0){        rep = la_ResetUiColum(c->RS, Top, U, c->IL, c->IR, 2, 0);        la_ResetUiColum(c->LS, Top, U, c->IL, c->IR, 1, rep);        c->LS->PreWidth = c->PreWidth * c->LS->SP;        c->RS->PreWidth = c->PreWidth * (1 - c->RS->SP);    }    return rev;}STRUCTURE(laRowInfo){    int MaxW;    int MinW;    int UnitMinW;    int NonExpandW;    int TotalPadding;    int Expand, Even;    int ExpandAccum;    int CountElements;    int U,MaxB,L;    laListHandle Elements;    int LastNoHeight;};STRUCTURE(laRowNode){    laListItem Item;    laUiItem* ui;    int GotW, LP, RP, H;    int Expand;    int UseLast;    int WaitAnimation;};void la_InitRowNode(laRowInfo* ri, laUiItem* ui, laBoxedTheme* bt){    ri->MaxW = ui->TR-ui->TL;//row node does not use margin    ri->UnitMinW=LA_RH;    ri->Expand=ui->State?1:0;    ri->Even=ui->Flags?1:0;    ri->U=ui->TU; ri->L=ui->TL;    ri->MaxB=ui->TU;}void la_AddRowNode(laRowInfo* ri, laUiItem* ui, laBoxedTheme* bt, int H, int WaitAnimation){    laRowNode* rn=CreateNew(laRowNode); int margin=LA_M;    if(ui->Flags&LA_UI_FLAGS_NO_GAP){ margin=0; }    rn->LP=margin;rn->RP=margin;    rn->GotW = (ui->Type->GetMinWidth?ui->Type->GetMinWidth(ui):(LA_RH));    rn->ui=ui;    rn->H=H;    rn->Expand=ui->Expand;    rn->WaitAnimation=WaitAnimation;    lstAppendItem(&ri->Elements, rn);    if(ri->LastNoHeight){ ri->LastNoHeight=0; rn->UseLast=1; return; }    if(ui->Flags&LA_UI_FLAGS_UNDERNEATH){ ri->LastNoHeight=1; };    if(!ri->UnitMinW){ri->UnitMinW=LA_RH;}    ri->TotalPadding += LA_M*2;    ri->MinW+=ri->UnitMinW;    ri->NonExpandW+=rn->GotW;    ri->ExpandAccum+=ui->Expand;    ri->CountElements++;    if(ui->Expand){ri->Expand=1;}    if(ri->U+H+margin>ri->MaxB){ri->MaxB=ri->U+H+margin;}}int la_ShrinkableRowElements(laRowInfo* ri){    int count=0;    for(laRowNode* rn=ri->Elements.pFirst;rn;rn=rn->Item.pNext){        if(rn->GotW<=ri->UnitMinW || rn->UseLast) continue;        count++;    }    return count;}void la_RecordSocketRuntimePosition(laUiItem* ui);void la_CalculateRowExpand(laRowInfo* ri, laUiItem* ui_end){    int Available=ri->MaxW-ri->NonExpandW-ri->TotalPadding;    int ShareCount=0, Additional=0, AdditionalRemaining=0, Shrinkable=0; real NodeAddFraction=0;    if(Available<0){        ShareCount=1;// Shrinkable=la_ShrinkableRowElements(ri);        Additional=(ri->MaxW-ri->MinW-ri->TotalPadding)/ri->CountElements;        AdditionalRemaining = (ri->MaxW-ri->MinW-ri->TotalPadding)-Additional*ri->CountElements;    }else{        if(!ri->Expand && Available>0){Available=0;}        ShareCount=ri->ExpandAccum?ri->ExpandAccum:ri->CountElements;    }    if(!ShareCount) return;    int PerNode = Available/ShareCount;    int Remaining = Available-PerNode*ShareCount;    int L = ri->L; int i=0; laRowNode* rn;    for(rn=ri->Elements.pFirst;rn;rn=rn->Item.pNext){        laUiItem* ui=rn->ui;        int NodeAdd, Node=rn->GotW;        if(rn->UseLast){            laRowNode* prevrn=rn->Item.pPrev; laUiItem* prevui=prevrn->ui;            rn->ui->TL=prevui->TL;rn->ui->TR=prevui->TR;rn->ui->TU=prevui->TU;rn->ui->TB=prevui->TB;            continue;        }        if(Available>=0){            NodeAdd=ri->ExpandAccum?(PerNode*rn->Expand):PerNode;            NodeAdd+=(i<Remaining?1:0);i++;        }else{            if(ri->MaxW>=ri->MinW+ri->TotalPadding) {                NodeAddFraction+=((rn->GotW>ri->UnitMinW)?(real)Available*(real)(rn->GotW-ri->UnitMinW)/(real)(ri->NonExpandW-ri->MinW):0);                NodeAdd=(int)NodeAddFraction; NodeAddFraction-=NodeAdd;            }else{ Node=ri->UnitMinW;                NodeAdd=Additional+(i<-AdditionalRemaining?-1:0);i++;            }        }        ui->TL = L + rn->LP;        ui->TR = ui->TL + Node+NodeAdd;        ui->TB = ui->TU + rn->H;        L=ui->TR+rn->RP;        if (!rn->WaitAnimation){            ui->L = ui->TL; ui->R = ui->TR;            ui->U = ui->TU; ui->B = ui->TB;        }        if(ui->Type==_LA_UI_NODE_SOCKET){ la_RecordSocketRuntimePosition(ui); }    }    ui_end->TB = ui_end->Flags&LA_UI_FLAGS_UNDERNEATH?ri->U:ri->MaxB;    while(rn=lstPopItem(&ri->Elements)){ FreeMem(rn); }    memset(ri, 0, sizeof(laRowInfo));}void la_RecordSocketRuntimePosition(laUiItem* ui){    laProp* p=ui->PP.LastPs->p; laPropContainer* pc=la_EnsureSubTarget(p,0);    real sl,sr,su,sb;    if(ui->Flags&LA_UI_SOCKET_LABEL_N){ sl=ui->TL; sr=ui->TR; su=ui->TU+LA_RH; }    elif(ui->Flags&LA_UI_SOCKET_LABEL_S){ sl=ui->TL; sr=ui->TR; su=ui->TU; }    elif(ui->Flags&LA_UI_SOCKET_LABEL_W){ sl=ui->TL+LA_2RH; sr=ui->TR; su=ui->TU; }    elif(ui->Flags&LA_UI_SOCKET_LABEL_E){ sl=ui->TL; sr=ui->TR-LA_2RH; su=ui->TU; }    else{ sl=ui->TL; su=ui->TU; sr=ui->TR; } sb=su+LA_RH;     if(pc==LA_PC_SOCKET_OUT){        laNodeOutSocket* s=ui->PP.EndInstance; s->RuntimeX=(sl+sr)/2.0f; s->RuntimeY=(su+sb)/2.0f;    }else{        laNodeInSocket* s=ui->PP.EndInstance;  s->RuntimeX=(sl+sr)/2.0f; s->RuntimeY=(su+sb)/2.0f;        laUseDataBlock(s, LA_PROP_SOCKET_SOURCE, MAIN.PropMatcherContextP->FrameDistinguish, MAIN.PropMatcherContextP, la_PropPanelUserRemover, 0);    }}laUiList* la_GiveExistingPage(laListHandle* from, void* instance){    for(laUiList* uil=from->pFirst;uil;uil=uil->Item.pNext){ if(uil->Instance == instance){ lstRemoveItem(from,uil); return uil; } } return 0;}void la_SwitchThemeQuick(laTheme* t, laTheme* DefaultTheme);int laget_Hyper2InstanceModified(void* instance){    int level; laMemNodeHyper* m=memGetHead(instance,&level);    if(level==2){        laManagedUDF* mu=m->FromFile;        int not_assigned = (!mu) || mu==MAIN.DummyManageUDF|| mu==MAIN.DummyManageUDFSingle || mu==MAIN.DummyManageUDFSingleForce;        return (m->Modified||not_assigned)?1:0;    }    return 1;}int la_UpdateUiListRecursive(laUiList *uil, int U, int L, int R, int B, int Fast, laPanel *ParentPanel){    laUiItem *ui; laListHandle TempPages={0}; laUiList* FoundUil;    laBoxedTheme *bt;    int Lowest = 0;    int HyperValue = 0;    int WaitAnimation;    int RowMode=0; laRowInfo ri={0};    laBoxedTheme* pt=*(ParentPanel->BT);    //int _PL=-pt->LM,_PR=-pt->RM,_PT=-pt->TM,_PB=-pt->BM;    int MaxR=0;    if(!uil->Scale){uil->Scale=1;}    uil->SaveScale=MAIN.UiScale;    MAIN.UiScale*=uil->Scale;    MAIN.ScaledUiRowHeight=MAIN.UiRowHeight*MAIN.UiScale;    uil->TU = U;uil->TL = L;uil->TR = R;uil->TB = uil->TU;    WaitAnimation = 0;    if (!uil->Columns.pFirst && !uil->UiItems.pFirst) return U;    la_ResetUiColum(uil->Columns.pFirst, uil->Columns.pFirst, U, L, R, 0, 0);    for (ui = uil->UiItems.pFirst; ui;){        int SubB = 0;        int H;        WaitAnimation = 0;        int NoGap=ui->Flags&LA_UI_FLAGS_NO_GAP;        int NoHeight=ui->Flags&LA_UI_FLAGS_UNDERNEATH;        //if (Fast && ui->C->B > B) {        //	//la_CalcUiItemInfluence(&uil->Colums, ui);        //	ui = ui->Item.pNext;        //	continue;        //}        if (!ui->Instructions){            if (ui->ExtraInstructions) strMakeInstructions(&ui->Instructions, ui->ExtraInstructions->Ptr);            if (ui->AT && ui->AT->ExtraInstructions) strMakeInstructions(&ui->Instructions, ui->AT->ExtraInstructions);            if (ui->PP.LastPs && ui->PP.LastPs->p->PropertyType == LA_PROP_OPERATOR){                laOperatorProp *ap = ui->PP.LastPs->p;                if (!ap->OperatorType) ap->OperatorType = laGetOperatorType(ap->OperatorID);                if (ap->OperatorType&&ap->OperatorType->ExtraInstructions) strMakeInstructions(&ui->Instructions, ap->OperatorType->ExtraInstructions);            }        }        if (ui->PP.LastPs){ la_StepPropPack(&ui->PP); }        la_UsePropPack(&ui->PP, 0);        if (ui->CompoundPPs.pFirst){            for(laCompoundPP* CPP=ui->CompoundPPs.pFirst;CPP;CPP=CPP->Item.pNext){                la_StepPropPack(&CPP->PP); la_UsePropPack(&CPP->PP, 0);            }        }        if(ui->Type==&_LA_UI_INVISIBLE){ ui=ui->Item.pNext; continue; }        //if (ui->PP.LastPs && (HyperValue = ui->PP.LastPs->p->Container ? ui->PP.LastPs->p->Container->Hyper : 0)){        //    laUseDataBlock(ui->PP.Go ? ui->PP.LastPs->UseInstance : ui->PP.RawThis->LastPs->UseInstance, ui->PP.LastPs->p, MAIN.PropMatcherContextP->FrameDistinguish, MAIN.PropMatcherContextP, la_PropPanelUserRemover, 0);        //}        if ((ui->AnimationDistinguish + 1) == ParentPanel->FrameDistinguish){            ParentPanel->Refresh |= LA_TAG_ANIMATION; laRefreshWindow();            WaitAnimation = 1;        }        ui->AnimationDistinguish = ParentPanel->FrameDistinguish;        bt = (*ui->Type->Theme);        if (ui->Type == &_LA_UI_CONDITION){            laConditionUiExtraData *cued = ui->Extra;            la_StepExpression(cued->Expression);            cued->IsTrue = la_DoSingleExpression(cued->Expression);            if (!cued->IsTrue){                ui = cued->ElseUi ? cued->ElseUi : cued->EndUi;            }else{                ui = ui->Item.pNext;            }            continue;        }else if (ui->Type == &_LA_UI_CONDITION_END){            ui = ui->Item.pNext;            continue;        }else if (ui->Type == &_LA_UI_CONDITION_ELSE){            laConditionUiExtraData *cued = ((laConditionUiExtraData *)ui->Extra)->EndUi->Extra;            if (cued->IsTrue) ui = cued->EndUi;            else                ui = ui->Item.pNext;            continue;        }else if (ui->Type == _LA_UI_CONDITION_TOGGLE){            laConditionUiExtraData *cued = ui->Extra;            ui->TL = ui->C->IL + LA_M; ui->TR = ui->C->IR - LA_M;            ui->TU = ui->C->B + LA_M;  ui->TB = ui->TU + LA_RH;            if (!WaitAnimation){                ui->L = ui->TL; ui->R = ui->TR;                ui->U = ui->TU; ui->B = ui->TB;            }            if(!RowMode){                la_CalcUiItemInfluence(&uil->Columns, ui);            }else{                H = ui->Type->GetHeight ? ui->Type->GetHeight(ui) : (ui->Extent==0?1:ui->Extent);                la_AddRowNode(&ri, ui, bt, H*LA_RH,WaitAnimation);            }            if (ui->State == LA_UI_NORMAL){                cued->IsTrue = 0;                ui = cued->ElseUi ? cued->ElseUi : cued->EndUi;            }else{                cued->IsTrue = 1;                //if (cued->Remove && (ui->Item.pNext == cued->EndUi || ui->Item.pNext==cued->ElseUi)) {                //	la_CreateUiAfter(uil, ui, ui->Template, ui->PP.RawThis, ui->Page, uil->Columns.pFirst);                //}                ui = ui->Item.pNext;            }            continue;        }        if (ui->Type == _LA_UI_ALIGN){            if(ui->Flags&LA_UI_FLAGS_NO_DECAL){                ui->TU = ui->C->B - LA_M; ui->TB = ui->TU;            }else{                ui->TU = ui->C->B + LA_M; ui->TB = ui->TU+LA_RH/5;            }            ui->TL = ui->C->IL; ui->TR = ui->C->IR;            if (ui->TB > Lowest) Lowest = ui->TB;            if (!WaitAnimation){                ui->L = ui->TL; ui->R = ui->TR;                ui->U = ui->TU; ui->B = ui->TB;            }            if(!RowMode){                la_CalcUiItemInfluence(&uil->Columns, ui);            }else{                ui->Flags|=LA_UI_FLAGS_TRANSPOSE;                H = ui->Type->GetHeight ? ui->Type->GetHeight(ui) : 1;                la_AddRowNode(&ri, ui, bt, H*LA_RH,WaitAnimation);            }            ui = ui->Item.pNext; continue;        }        if (ui->Type == &_LA_UI_ROW_BEGIN){            ui->TU = ui->C->B; ui->TL = ui->C->IL; ui->TR = ui->C->IR;            la_InitRowNode(&ri, ui, bt);            RowMode=1; ui=ui->Item.pNext; continue;        }        if (ui->Type == &_LA_UI_ROW_END){            la_CalculateRowExpand(&ri, ui);            la_CalcUiItemInfluence(&uil->Columns, ui);            RowMode=0; ui=ui->Item.pNext; continue;        }        if(!RowMode){ ui->TL = ui->C->IL + (NoGap?0:LA_M); ui->TR = ui->C->IR - (NoGap?0:LA_M); }        int GB=0;        if (ui->Type == _LA_UI_FIXED_GROUP && ui->Page->HeightCoeff < 0 && ui->Flags&LA_UI_FLAGS_PREFER_BOTTOM){ GB=ui->Page->TB-ui->Page->PanY-LA_M; }        H = ui->Type->GetHeight ? ui->Type->GetHeight(ui) : (ui->Extent==0?1:ui->Extent);        ui->TU = ui->C->B + (NoGap?0:LA_M);        if (H < 0){            if(B){ H = B + (H+1) * LA_RH - ui->TU-LA_M+((H<-1)?-LA_M:0); }            else{ H=LA_RH; }        }         else H *= LA_RH;        ui->TB = ui->TU;                int NoDecal=ui->Flags&LA_UI_FLAGS_NO_DECAL;        if (ui->Type->ForType == LA_PROP_SUB && ui->PP.LastPs && ui->PP.LastPs->p && ui->PP.LastPs->p->PropertyType == LA_PROP_SUB && ui->Type != _LA_UI_CANVAS){ //DynamicCreation            laPropIterator pi = {0}; laSubProp* uisp=ui->PP.LastPs->p;            if (ui->Type == _LA_UI_COLLECTION){                //void* TInstance = ui->PP.Go?laGetInstance(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, &pi):ui->PP.EndInstance;                void *TInstance = laGetInstance(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, &pi);                ui->PP.EndInstance = TInstance;                laUiList *iuil = ui->Subs.pFirst;                 laUiList *puil = iuil;                int Row = 0, Col = 0, RowPriority = ui->Extent > 0 ? 1 : 0, ElementLimit = ui->Extent ? abs(ui->Extent) : 0;                int Spread=ui->Expand>2?ui->Expand:0; if(Spread){ RowPriority=0; ElementLimit=0; }                laUiDefineFunc Template = ui->Template ? ui->Template : laGetPropertyUiDefine(&ui->PP, TInstance);                int Begin = ui->TB;                int SpreadWidth = Spread*LA_RH; if((!uil->AllowScale) && (SpreadWidth > ui->TR-ui->TL)){ SpreadWidth=ui->TR-ui->TL; }                int EL = ui->TL, ER = Spread?(SpreadWidth+ui->TL):ui->TR; int MaxER=ER;                int ElementB = ui->TU;                real ElementWidth = ElementLimit ? 1.0f / ElementLimit : 1.0;                int MaxB = ElementB;                int CanGetTheme = laCanGetTheme(ui->PP.LastPs->p);laTheme* OriginalTheme=MAIN.CurrentTheme;                int CanGetGap= laCanGetGap(ui->PP.LastPs->p); int Gap=0;                int CanGetCategory= laCanGetCategory(ui->PP.LastPs->p); char _cat[256]; char* cat=_cat; int GotCategory=0,FirstIn=1;                int BoxStyle=(*ui->Type->Theme)->BoxStyle; if(NoDecal) BoxStyle=0;                int MainDropOffset=BoxStyle>0?-LA_M:(BoxStyle<0?LA_M:0); Begin+=MainDropOffset;                int DropOffset=MainDropOffset;                if (!ElementLimit) RowPriority = 0;                if (!TInstance){                    while (iuil){                        puil = iuil->Item.pNext;                        la_DestroyTabPage(ui, iuil, 0);                        iuil = puil;                    }                }                while (TInstance){                    int UiFilterSkip = uisp->UiFilter && (!uisp->UiFilter(ui->PP.LastPs->UseInstance, TInstance));                    int ManagerFilterSkip = MAIN.ManagerFilterInstances && (ui->Flags&LA_UI_COLLECTION_MANAGER_FILTER) && (!laget_Hyper2InstanceModified(TInstance));                    if(UiFilterSkip || ManagerFilterSkip){                        TInstance = laGetNextInstance(ui->PP.LastPs->p, TInstance, &pi);                        Template = ui->Template?ui->Template:laGetPropertyUiDefine(&ui->PP, TInstance);                        ui->PP.EndInstance = TInstance; continue;                    }                    if(CanGetTheme){                        laTheme* t=laGetUiTheme(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, ui->PP.EndInstance);                        la_SwitchThemeQuick(t, OriginalTheme);                    }                    if(CanGetGap){                        int g=laGetUiGap(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, ui->PP.EndInstance); g=g<0?0:g;                        Gap=g*LA_RH;                    }else Gap=0;                    if(CanGetCategory){ _cat[0]=0; cat=_cat; GotCategory=0;                        laGetCategory(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, ui->PP.EndInstance, _cat, &cat); if(cat[0]) GotCategory=1;                    }else GotCategory=0;                    if(GotCategory){ Begin+=LA_RH*(FirstIn?1:1.5);                         if (RowPriority){                            Row += 1; Col=0; Begin = ElementB+LA_RH*(FirstIn?1:1.5);                        }                    }                    FirstIn=0;                    if (ElementLimit){                        EL = tnsInterpolate(ui->TL, ui->TR, (Col)*ElementWidth);                        ER = tnsInterpolate(ui->TL, ui->TR, (Col + 1) * ElementWidth); MaxER=TNS_MAX2(ER,MaxER);                    }                    while (iuil && iuil->Instance != TInstance){                        if(FoundUil=la_GiveExistingPage(&TempPages, TInstance)){                            lstInsertItemBefore(&ui->Subs, FoundUil, iuil); puil = FoundUil;                        }else{                            puil = iuil->Item.pNext; lstRemoveItem(&ui->Subs, iuil); lstAppendItem(&TempPages, iuil);                        }                        iuil = puil;                    }                    if(!iuil){                        if(FoundUil=la_GiveExistingPage(&TempPages, TInstance)){ lstAppendItem(&ui->Subs, FoundUil); iuil = FoundUil; }                    }                    if (!iuil){                            la_AddInstancePage(ui, TInstance, 0); if(GotCategory){ strSafeSet(&ui->Page->TabName,cat); }                            la_CalcUiTopInfluence(&uil->Columns, ui);                            if (Template) laMakeUiListFromTemplate(ui->Page, Template, &ParentPanel->PP, &ParentPanel->PropLinkPP, &ui->PP, 0, &uil->Columns, ui->TemplateContext);                            SubB = la_UpdateUiListRecursive(ui->Page, Gap+Begin, EL+(NoDecal?0:LA_M)+DropOffset, ER-(NoDecal?0:LA_M), B, Fast, ParentPanel);                            ElementB = RowPriority ? (SubB > ElementB ? SubB : ElementB) : SubB;                            iuil = ui->Page->Item.pNext;                    }else{                        la_CalcUiTopInfluence(&uil->Columns, ui); if(GotCategory){ strSafeSet(&iuil->TabName,cat); }                        SubB = la_UpdateUiListRecursive(iuil, Gap+Begin, EL+(NoDecal?0:LA_M)+DropOffset, ER-(NoDecal?0:LA_M), B, Fast, ParentPanel);                        ElementB = RowPriority ? (SubB > ElementB ? SubB : ElementB) : SubB;                        la_CalcUiItemInfluence(&uil->Columns, ui);                        iuil = iuil->Item.pNext;                    }                    TInstance = laGetNextInstance(ui->PP.LastPs->p, TInstance, &pi);                    Template = ui->Template?ui->Template:laGetPropertyUiDefine(&ui->PP, TInstance);                    ui->PP.EndInstance = TInstance;                                        if(CanGetTheme){ la_SwitchThemeQuick(0, OriginalTheme); }                    if (RowPriority){                        Col += 1; DropOffset=0;                        if (Col >= ElementLimit){                            Col = 0;                            Row += 1;                            Begin = ElementB;                        }                    }elif(Spread){                        EL+=SpreadWidth;                        ER+=SpreadWidth;                        MaxER=TNS_MAX2(ER,MaxER);                        if((!uil->AllowScale) && (ER > ui->TR)){                            EL=ui->TL; ER=SpreadWidth+EL;                            Begin = ElementB;                        }                    }else{                        Row += 1;                        Begin = ElementB;                        if (ElementLimit && Row >= ElementLimit){                            Row = 0;                            Col += 1;                            Begin = ui->TU+MainDropOffset;                        }                    }                    ui->TB = ElementB;                    MaxB = MaxB < ElementB ? ElementB : MaxB;                }                while (iuil){ puil = iuil->Item.pNext; la_DestroyTabPage(ui, iuil, 0); iuil = puil; }                while (iuil=lstPopItem(&TempPages)){ la_DestroyTabPage(0, iuil, 0); }                ui->PP.EndInstance = laGetActiveInstance(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, &pi);                ui->TB = MaxB;                if(Spread){ ui->TR=MaxER-SpreadWidth; if(ui->TR>MaxR) MaxR=ui->TR; }                if (!WaitAnimation){ ui->L = ui->TL; ui->R = ui->TR; ui->U = ui->TU; ui->B = ui->TB = MaxB; }            }else if (ui->Type == _LA_UI_COLLECTION_SELECTOR || ui->Type == _LA_UI_COLLECTION_SINGLE){                if(ui->Flags&LA_UI_COLLECTION_SIMPLE_SELECTOR){                    ui->TB=ui->TU+LA_RH;                }else{                    void *TInstance = laGetActiveInstanceStrict(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance);                    ui->PP.EndInstance = TInstance;                    laUiTemplate *Template = ui->Template ? ui->Template : laGetPropertyUiDefine(&ui->PP, TInstance);                    if(!Template) Template=laui_SubPropInfoDefault;                    //ui->Template = Template;                    int EraseWidth=(ui->Type == _LA_UI_COLLECTION_SELECTOR)?LA_RH:0;                    int BoxStyle=(*ui->Type->Theme)->BoxStyle;                    int DropOffset=BoxStyle>0?-LA_M:(BoxStyle<0?LA_M:0);                    int TopPad = (ui->Type == _LA_UI_COLLECTION_SINGLE)?(NoDecal?0:(LA_M+DropOffset)):(-LA_M+DropOffset);                    int SidePad = NoDecal?0:(LA_M+DropOffset);                    if (!ui->Subs.pFirst && TInstance){                        la_AddInstancePage(ui, TInstance, 0);                        la_CalcUiTopInfluence(&uil->Columns, ui);                        laMakeUiListFromTemplate(ui->Page, Template, &ParentPanel->PP, &ParentPanel->PropLinkPP, &ui->PP, 0, &uil->Columns, ui->TemplateContext);                        SubB = la_UpdateUiListRecursive(ui->Page, ui->TB+TopPad, ui->TL+SidePad, ui->TR-SidePad-EraseWidth, B, Fast, ParentPanel);                        ui->TB = SubB - (NoDecal?0:LA_M);                    }else if (ui->Subs.pFirst){                        if (!TInstance || TInstance != ui->Page->Instance){                            la_DestroyTabPage(ui, ui->Subs.pFirst, 0);                            ui->Page = 0;                            if (TInstance){                                la_AddInstancePage(ui, TInstance, 0);                                la_CalcUiTopInfluence(&uil->Columns, ui);                                laMakeUiListFromTemplate(ui->Page, Template, &ParentPanel->PP, &ParentPanel->PropLinkPP, &ui->PP, 0, &uil->Columns, ui->TemplateContext);                                SubB = la_UpdateUiListRecursive(ui->Page, ui->TB+TopPad, ui->TL+SidePad, ui->TR-SidePad-EraseWidth, B, Fast, ParentPanel);                                ui->TB = SubB - (NoDecal?0:LA_M);                            }else                                ui->TB = ui->TU + LA_RH;// + bt->BM;                        }else{                            SubB = la_UpdateUiListRecursive(ui->Page, ui->TB+TopPad, ui->TL+SidePad, ui->TR-SidePad-EraseWidth, B, Fast, ParentPanel);                            ui->TB = SubB - (NoDecal?0:LA_M);                        }                    }                    if(ui->Type == _LA_UI_COLLECTION_SELECTOR && (ui->TB>(ui->TU+LA_RH*0.9))&&(ui->TB<ui->TU+(LA_RH*1.1))){                        ui->TB=ui->TU+LA_RH;                    }                    if(ui->Type == _LA_UI_COLLECTION_SINGLE){                        ui->TB+= NoDecal?0:LA_M*2;                    }                }                if (ui->TB-ui->TU<LA_RH) ui->TB = ui->TU + LA_RH;                if (!WaitAnimation){                    ui->L = ui->TL;                    ui->R = ui->TR;                    ui->U = ui->TU;                    ui->B = ui->TB;                }            }        }else{            if (ui->Type != _LA_UI_COLLECTION && (ui->Subs.pFirst || ui->Page) && ui->Type != _LA_UI_MENU_ROOT){                if (ui->Type != _LA_UI_CANVAS){                    int BoxStyle=(*ui->Type->Theme)->BoxStyle;                    int DropOffset=BoxStyle>0?-LA_M:(BoxStyle<0?LA_M:0);                    int scrollw=ui->Page->ScrollerShownV?LA_M*2+LA_SCROLL_W:0;                    la_CalcUiTopInfluence(&uil->Columns, ui); int first_in=((ui->Flags&LA_UI_FLAGS_PREFER_BOTTOM) && ui->Page->B==0);                    SubB = la_UpdateUiListRecursive(ui->Page,                        ui->TB + (ui->State == LA_UI_ACTIVE ? 0 : LA_RH)+(NoDecal?0:(LA_M+DropOffset)),                        ui->TL+(NoDecal?0:(LA_M+DropOffset)), ui->TR-(NoDecal?0:LA_M)-scrollw, B, Fast, ParentPanel);                    ui->TB = (ui->Page->HeightCoeff > 0 ? ui->TU + ui->Page->HeightCoeff * LA_RH :                            (ui->Page->HeightCoeff < 0 ? B + (ui->Page->HeightCoeff+1) * LA_RH - (LA_M*2)+(ui->Page->HeightCoeff==-2?-LA_M:0) : SubB)) + (NoDecal?0:LA_M);                    ui->Page->LimH = ui->TB-ui->Page->TU - (NoDecal?0:LA_M);                    int subh = ui->TB-ui->TU-LA_RH-LA_M*2;                    if((ui->Page->TR>ui->TR-(NoDecal?0:LA_M) && (!ui->Page->ScrollerShownH)) ||                        (ui->Page->TR<=ui->TR-(NoDecal?0:LA_M) && ui->Page->ScrollerShownH)){                        ui->Page->ScrollerShownH=!ui->Page->ScrollerShownH;                    }                    if(ui->Page->AllowScale){ui->Page->ScrollerShownH=1;}                    if(ui->Page->ScrollerShownH){subh-=LA_SCROLL_W-LA_M;}                    if((GB && ui->TB >= GB)||first_in){ ui->Page->PanY=(SubB-ui->TB-LA_M); if(ui->Page->PanY<0)ui->Page->PanY=0; }                    if(ui->Page->HeightCoeff){                        if((subh<ui->Page->TB-ui->Page->TU && (!ui->Page->ScrollerShownV)) ||                            (subh>=ui->Page->TB-ui->Page->TU && ui->Page->ScrollerShownV)){                            ui->Page->ScrollerShownV=!ui->Page->ScrollerShownV;                            ParentPanel->Refresh|=LA_TAG_RECALC_SCROLLER;  laRefreshWindow();                        }                        if(SubB-ui->Page->PanY<ui->TB-LA_M-(ui->Page->ScrollerShownH?LA_SCROLL_W+LA_M:0)){                            ui->Page->PanY = (SubB-ui->TB-LA_M+(ui->Page->ScrollerShownH?LA_SCROLL_W+LA_M:0));                            if(ui->Page->PanY<0){ui->Page->PanY=0;}                            //ParentPanel->Refresh|=LA_TAG_RECALC_SCROLLER;                        }                    }                    if(ui->Page->ScrollerShownH && !ui->Page->HeightCoeff){                        ui->TB+=(LA_M*2+LA_SCROLL_W); }                }else{                    laUiList *suil;                    if(!MAIN.CurrentWindow->MaximizedUi || ui!=MAIN.CurrentWindow->MaximizedUi){                        la_CalcUiTopInfluence(&uil->Columns, ui);                        for (suil = ui->Subs.pFirst; suil; suil = suil->Item.pNext){                            SubB = la_UpdateUiListRecursive(suil, ui->TB+(NoDecal?0:LA_M), ui->TL+(NoDecal?0:LA_M), ui->TR-(NoDecal?0:LA_M), ui->TU+H, Fast, ParentPanel);                        }                    }                    ui->TB = ui->TU + H;                }            }else ui->TB = ui->TU + H;        }        if (ui->TB > Lowest && (!NoHeight)) Lowest = ui->TB + (bt ? (NoGap?0:LA_M) : 0);        if(!RowMode){            if(!NoHeight) la_CalcUiItemInfluence(&uil->Columns, ui);        }else{            la_AddRowNode(&ri, ui, bt, H, WaitAnimation);        }        if (!WaitAnimation){ ui->L = ui->TL; ui->R = ui->TR; ui->U = ui->TU; ui->B = ui->TB; }        if(ui->Type==_LA_UI_NODE_SOCKET){  la_RecordSocketRuntimePosition(ui); }        ui = ui->Item.pNext;    }    uil->TR=MaxR>uil->TR?MaxR:uil->TR;    if (uil->Columns.pFirst) uil->TB = ((laColumn *)uil->Columns.pFirst)->B;    else uil->TB = Lowest;    if (!WaitAnimation){        uil->L = uil->TL;        uil->R = uil->TR;        uil->U = uil->TU;        uil->B = uil->TB;    }    MAIN.UiScale=uil->SaveScale;    MAIN.ScaledUiRowHeight=MAIN.UiRowHeight*MAIN.UiScale;    return uil->TB;}int la_AnimateSingleUiSize(int To, int *Now){    int Delta;    if (To != *Now){        Delta = (To - (*Now)) * (MAIN.AnimationSpeed) * MAIN.LastFrameTime * 60;        if (!Delta) Delta = To > (*Now) ? 1 : -1;        *Now += Delta;        return 1;    }else        return 0;}int la_AnimateUiListRecursive(laUiList *uil){    laUiItem *ui;    int Again = 0;    for (ui = uil->UiItems.pFirst; ui; ui = ui->Item.pNext){        int TB = ui->B, TU = ui->U, TL = ui->L, TR = ui->R, SB, SU, SL, SR;                if(ui->AnimationDistinguish != MAIN.CurrentPanel->FrameDistinguish){            ui->B=ui->TB; ui->L=ui->TL; ui->R=ui->TR; ui->U=ui->TU;        }else{            Again += (la_AnimateSingleUiSize(ui->TB, &ui->B) +                    la_AnimateSingleUiSize(ui->TU, &ui->U) +                    la_AnimateSingleUiSize(ui->TL, &ui->L) +                    la_AnimateSingleUiSize(ui->TR, &ui->R));        }        if (ui->Type == _LA_UI_COLLECTION_SELECTOR || ui->Type == _LA_UI_COLLECTION_SINGLE ||            (ui->PP.LastPs && ui->PP.LastPs->p && ui->PP.LastPs->p->PropertyType == LA_PROP_SUB && ui->Type != _LA_UI_CANVAS)){            laUiList *suil;            for (suil = ui->Subs.pFirst; suil; suil = suil->Item.pNext){                Again += la_AnimateUiListRecursive(suil);            }        }else if (ui->Type != _LA_UI_COLLECTION && ui->Type != &_LA_UI_ROW_END &&                 (ui->Subs.pFirst || ui->Page) && ui->Type != _LA_UI_MENU_ROOT){            Again += la_AnimateUiListRecursive(ui->Page);        }    }    Again += (la_AnimateSingleUiSize(uil->TB, &uil->B) +              la_AnimateSingleUiSize(uil->TU, &uil->U) +              la_AnimateSingleUiSize(uil->TL, &uil->L) +              la_AnimateSingleUiSize(uil->TR, &uil->R));    return Again;}void la_DrawEmptyUiItem(laUiItem *ui){    tnsUseNoTexture();    tnsColor4d(1, 1, 1, 1);    tnsVertex2d(ui->L, ui->U);    tnsVertex2d(ui->R, ui->U);    tnsVertex2d(ui->R, ui->B);    tnsVertex2d(ui->L, ui->B);    tnsPackAs(GL_LINE_LOOP);}void la_DrawActiveUiItemOverlay(laUiItem *ui){    tnsUseNoTexture();    tnsColor4d(1, 1, 1, 1);    tnsVertex2d(ui->L - 1, ui->U - 1);    tnsVertex2d(ui->R + 1, ui->U - 1);    tnsVertex2d(ui->R + 1, ui->B + 1);    tnsVertex2d(ui->L - 1, ui->B + 1);    tnsPackAs(GL_LINE_LOOP);}int la_UiInBound(laUiItem *ui, int L, int R, int U, int B){    if (ui->R <= L || ui->L >= R || ui->U >= B || ui->B <= U) return 0;    return 1;}int la_UiInBoundEx(laUiItem *ui, laUiListDraw *uild){    laUiListDrawItem *uildi = uild->Items.pFirst;    laUiList *Target = uildi->Target;    int L, R, U, B;    if (!Target) return la_UiInBound(ui, uildi->L, uildi->R, uildi->U, uildi->B);    L = Target->L + Target->PanX + uildi->DifX;    R = Target->L + Target->PanX + uildi->DifX + (uildi->R - uildi->L);    B = Target->U + Target->PanY + uildi->DifY + (uildi->B - uildi->U);    U = Target->U + Target->PanY + uildi->DifY;    return la_UiInBound(ui, L, R, U, B);}int la_UiListInBoundEx(laUiList *uil, laUiListDraw *uild){    laUiListDrawItem *uildi = uild->Items.pFirst;    laUiList *Target = uildi->Target;    int L, R, U, B;    if (Target){        L = Target->L + Target->PanX + uildi->DifX;        R = Target->L + Target->PanX + uildi->DifX + (uildi->R - uildi->L);        B = Target->U + Target->PanY + uildi->DifY + (uildi->B - uildi->U);        U = Target->U + Target->PanY + uildi->DifY;        if (uil->R <= L || uil->L >= R || uil->U >= B || uil->B <= U) return 0;        return 1;    }else{        if (uil->R <= uildi->L || uil->L >= uildi->R || uil->U >= uildi->B || uil->B <= uildi->U) return 0;        return 1;    }}laUiItem *la_FindUiWithMark(laUiList *uil, char *mark){    laUiItem *ui = uil->UiItems.pFirst;    while (!strGetArgument(ui->Instructions, mark))        ui = ui->Item.pNext;    return ui;}laUiList *la_FindSubListWithInstance(laUiItem *ui, void *Instance){    laUiList *uil;    for (uil = ui->Subs.pFirst; uil; uil = uil->Item.pNext){        if (uil->Instance == Instance) return uil;    }    return uil;}void la_DrawUiListArrows(laUiList *uil, int L, int R, int U, int B, real* color){    int mx=(L+R)/2; int my=(U+B)/2;    int PadR=uil->ScrollerShownV?LA_SCROLL_W+LA_M*2:0;    if(uil->R-uil->PanX>R){ tnsDrawStringAuto("⯈", color, R-PadR-LA_RH, R-PadR, my-LA_RH2, LA_TEXT_ALIGN_RIGHT|LA_TEXT_SHADOW); }    if(uil->L-uil->PanX<L){ tnsDrawStringAuto("⯇", color, L, L+LA_RH, my-LA_RH2, LA_TEXT_ALIGN_LEFT|LA_TEXT_SHADOW); }    if(uil->U-uil->PanY<U){ tnsDrawStringAuto("⯅", color, mx-LA_RH2, mx+LA_RH2, U, LA_TEXT_ALIGN_CENTER|LA_TEXT_SHADOW); }    if(uil->B-uil->PanY>B){ tnsDrawStringAuto("⯆", color, mx-LA_RH2, mx+LA_RH2, B-LA_RH, LA_TEXT_ALIGN_CENTER|LA_TEXT_SHADOW); }    tnsFlush();}void la_DrawUiListScrollerV(laUiList *uil, int DisplayOffset, int TotalH, int DisplayedH, int UiR, int BarTop, int BarBottom){    if(!uil->ScrollerShownV) return;        int W = LA_SCROLL_W, RM=LA_M;    int DrawH = (BarBottom-BarTop);    int Len = (int)((real)DisplayedH / (real)TotalH * (real)DrawH);    int Offset = (int)((real)DisplayOffset / (real)TotalH * (real)DrawH);    int U = BarTop + Offset;    int B = U + Len;    int L = UiR - RM*2 - W;    int R = L + W;    if (B > BarBottom) B = BarBottom;    if (U < BarTop) U = BarTop;    Len=B-U;    if(Len < LA_RH0){ int Sub=(LA_RH0-Len)/2; U-=Sub; B+=(LA_RH0-Len-Sub); }    if(U < BarTop){ int Sub=BarTop-U; U+=Sub; B+=Sub; }    if(B > BarBottom){ int Sub=B-BarBottom; B-=Sub; U-=Sub; }    if (U < BarTop) U = BarTop;    tnsUseNoTexture();    laBoxedTheme* bt=_LA_THEME_PANEL;    real* color=laThemeColor(bt, LA_BT_TEXT);    real colorb[4]; tnsVectorSet3v(colorb,color); colorb[3]=0.3;    la_DrawBoxAutoArrayStyle(L+RM,R-RM,BarTop,BarBottom,bt,LA_BT_NORMAL,colorb,0,1,-1);    colorb[3]=1;    la_DrawBoxAutoArrayStyle(L,R,U,B,bt,LA_BT_NORMAL,colorb,0,0,0);    int HU=(U+B)/2+LA_RH2;    tnsDrawStringAuto("⋮",laThemeColor(bt, LA_BT_BORDER),L-100,R+100,HU,LA_TEXT_REVERT_Y|LA_TEXT_ALIGN_CENTER);    tnsFlush();}void la_DrawUiListScrollerH(laUiList *uil, int DisplayOffset, int TotalW, int DisplayW, int UiB, int BarLeft, int BarRight){    if(!uil->ScrollerShownH) return;        int W = LA_SCROLL_W,RM=LA_M;    int DrawW = (BarRight-BarLeft);    int Len = (int)((real)DisplayW / (real)TotalW * (real)DrawW);    int Offset = (int)((real)DisplayOffset / (real)TotalW * (real)DrawW);    int L = BarLeft + Offset;    int R = L + Len;    int U = UiB - RM - W;    int B = U + W;    if (R > BarRight) R = BarRight;    if (L < BarLeft) L = BarLeft;    Len=R-L;    if(Len < LA_RH0){ int Sub=(LA_RH0-Len)/2; L-=Sub; R+=(LA_RH0-Len-Sub); }    if(L < BarLeft){ int Sub=BarLeft-L; L+=Sub; R+=Sub; }    if(R > BarRight){ int Sub=R-BarRight; R-=Sub; L-=Sub; }    if (L < BarLeft) L = BarLeft;    tnsUseNoTexture();    laBoxedTheme* bt=_LA_THEME_PANEL;    real* color=laThemeColor(bt, LA_BT_TEXT);        real colorb[4]; tnsVectorSet3v(colorb,color); colorb[3]=0.3;    la_DrawBoxAutoArrayStyle(BarLeft,BarRight,U+RM,B-RM,bt,LA_BT_NORMAL,colorb,0,1,-1);    tnsPackAs(GL_LINE_LOOP);    colorb[3]=1;    la_DrawBoxAutoArrayStyle(L,R,U,B,bt,LA_BT_NORMAL,colorb,0,0,0);    int HU=(U+B)/2+LA_RH2;    tnsDrawStringAuto("⋯",laThemeColor(bt, LA_BT_BORDER),L-100,R+100,HU,LA_TEXT_REVERT_Y|LA_TEXT_ALIGN_CENTER);    tnsFlush();}void la_DrawInstanceBkg(laUiList *uil, real* color, int LP, int RP){    tnsUseNoTexture(); tnsColor4dv(color);    la_DrawBox(uil->L-LP,uil->R+RP-1,uil->U,uil->B-1);}void la_InitSocketRecord(laUiListDraw* uild, laUiList* container){    laSocketRecord* sr;    while(sr=lstPopItem(&uild->SocketRecord)){ memFree(sr); }    uild->WiresContainer=container;}void la_GetUiListOffsetUntil(laUiListDraw* uild, real* X, real* Y){    *X=*Y=0; for(laUiListDrawItem* lip=uild->Items.pLast;lip&&lip->Target;lip=lip->Item.pPrev){        if(lip->Target==uild->WiresContainer) break;        laUiList* uil=lip->Target; *X+=uil->PanX; *Y+=uil->PanY;    }}void la_RecordSocket(laUiListDraw* uild, laUiList* uil, laUiItem* ui){    laProp* p=ui->PP.LastPs->p; laPropContainer* pc=la_EnsureSubTarget(p,0);    if(pc==LA_PC_SOCKET_OUT){        laNodeOutSocket* s=ui->PP.EndInstance;        la_GetUiListOffsetUntil(uild, &s->RuntimePX, &s->RuntimePY);     }else{        laNodeInSocket* s=ui->PP.EndInstance; if(!s->Source) return;        laSocketRecord* sr=memAcquireSimple(sizeof(laSocketRecord));        sr->In=s; sr->Out=s->Source; lstAppendItem(&uild->SocketRecord, sr);    }}void la_RegenerateWireColors(){    if(MAIN.WireColorCache) free(MAIN.WireColorCache);    laTheme* t=MAIN.CurrentTheme; if(!t) return;    MAIN.WireColorCache = calloc(1, sizeof(real)*4*MAIN.WireColorSlices);    real hsl[]={0.0,0.8,0.6}; hsl[1]=t->WireSaturation; hsl[2]=t->WireBrightness;    for(int i=0;i<MAIN.WireColorSlices;i++){        hsl[0]=(real)i/(real)MAIN.WireColorSlices;        tnsHSL2RGB(hsl, &MAIN.WireColorCache[i*4]); MAIN.WireColorCache[i*4+3]=t->WireTransparency;    }}void la_SendWireVerts(real x1, real y1, real x2, real y2, real circle_r, real line_width){    tnsVector2d v1,vi,v2,v1s,v2s; real dist=0;    v1[0]=x1; v1[1]=y1; v2[0]=x2; v2[1]=y2;    tnsInterpolate2dv(v1,v2,0.5,vi);    if(MAIN.WireSaggyness>0.01){ dist=tnsDist2dv(v1,v2); vi[1]+=dist*MAIN.WireSaggyness; }    tnsVectorMinus2d(v1s,vi,v1); if(tnsLength2d(v1s)<1e-3){ v1s[0]=-1; v1s[1]=0; }else{ tnsNormalizeSelf2d(v1s); } tnsVectorMultiSelf2d(v1s,circle_r);    tnsVectorMinus2d(v2s,vi,v2); if(tnsLength2d(v2s)<1e-3){ v2s[0]=1; v2s[1]=0; }else{ tnsNormalizeSelf2d(v2s); } tnsVectorMultiSelf2d(v2s,circle_r);    tnsVectorAccum2d(v1, v1s); tnsVectorAccum2d(v2, v2s);    //if(MAIN.WireSaggyness<0.01){ tnsVertex2d(v1[0],v1[1]); tnsVertex2d(v2[0],v2[1]); return; }    int seglen=3, steps=dist/seglen+1; real step=1.0f/steps;    real* middle=malloc(sizeof(real)*2*(steps+1));    real* normal=malloc(sizeof(real)*2*(steps+1));    real* final=malloc(sizeof(real)*4*(steps+1));    real tangent[2];    tnsVectorSet2v(&middle[0],v1);    for(int i=1;i<=steps;i++){        real ratio=i==steps?1.0f:step*i;        tnsInterpolateTripple2d(v1,vi,v2,ratio, v1s);        tnsVectorSet2v(&middle[i*2],v1s);    }    for(int i=1;i<steps;i++){        tnsVectorMinus2d(tangent,&middle[(i+1)*2],&middle[(i-1)*2]);        LA_SWAP(real,tangent[0],tangent[1]); tangent[1]*=-1; tnsNormalizeSelf2d(tangent);        tnsVectorSet2v(&normal[i*2],tangent);    }    tnsVectorMinus2d(tangent,&middle[2],&middle[0]);    LA_SWAP(real,tangent[0],tangent[1]); tangent[1]*=-1; tnsNormalizeSelf2d(tangent);    tnsVectorSet2v(&normal[0],tangent);    tnsVectorMinus2d(tangent,&middle[steps*2],&middle[(steps-1)*2]);    LA_SWAP(real,tangent[0],tangent[1]); tangent[1]*=-1; tnsNormalizeSelf2d(tangent);    tnsVectorSet2v(&normal[steps*2],tangent);    real th=line_width;    for(int i=0;i<=steps;i++){        final[i*4]=  middle[i*2]  +normal[i*2]  *th;        final[i*4+1]=middle[i*2+1]+normal[i*2+1]*th;        final[i*4+2]=middle[i*2]  -normal[i*2]  *th;        final[i*4+3]=middle[i*2+1]-normal[i*2+1]*th;    }    tnsVertexArray2d(final,(steps+1)*2); tnsPackAs(GL_TRIANGLE_STRIP);}void la_DrawNodeWires(laUiListDraw* uild){    if(!uild->SocketRecord.pFirst && !MAIN.tNodeIn->Source){ return; }    laBoxedTheme* bt=_LA_THEME_SOCKET;    tnsUseNoTexture();#define _RSLICES 16    real v[_RSLICES*4]; int idx[_RSLICES*2+2]; real r=LA_RH/2.0f/TNS_MAX2(uild->WiresContainer->Scale,1);    for(laSocketRecord*sr=uild->SocketRecord.pFirst;sr;sr=sr->Item.pNext){        int cid=sr->In->ColorId%MAIN.WireColorSlices*4;        real inx=sr->In->RuntimeX+sr->In->RuntimePX, iny=sr->In->RuntimeY+sr->In->RuntimePY;        real outx=sr->Out->RuntimeX+sr->Out->RuntimePX, outy=sr->Out->RuntimeY+sr->Out->RuntimePY;        if(sr->Out==MAIN.tNodeOut){ outx=inx+MAIN.tNodeOut->RuntimeX+MAIN.tNodeOut->RuntimePX; outy=iny+MAIN.tNodeOut->RuntimeY+MAIN.tNodeOut->RuntimePY; }        tnsMakeRing2d(v,idx,_RSLICES, inx, iny, r, r*0.6);        tnsVertexArray2d(v,_RSLICES*2); tnsIndexArray(idx, _RSLICES*2+2);        tnsColor4d(LA_COLOR3(&MAIN.WireColorCache[cid]),1); tnsPackAs(GL_TRIANGLE_STRIP);        tnsMakeRing2d(v,idx,_RSLICES, outx, outy, r, r*0.6);        tnsVertexArray2d(v,_RSLICES*2); tnsIndexArray(idx, _RSLICES*2+2);        tnsColor4d(LA_COLOR3(&MAIN.WireColorCache[cid]),1); tnsPackAs(GL_TRIANGLE_STRIP);    }    if(MAIN.tNodeIn->Source){        laNodeInSocket* ins=MAIN.tNodeIn; laNodeOutSocket* outs=ins->Source;        int cid=ins->ColorId%MAIN.WireColorSlices*4;        real outx=outs->RuntimeX+outs->RuntimePX, outy=outs->RuntimeY+outs->RuntimePY;        real inx=ins->RuntimeX+ins->RuntimePX+outx, iny=ins->RuntimeY+ins->RuntimePY+outy;        tnsMakeRing2d(v,idx,_RSLICES, inx, iny, r, r*0.6);        tnsVertexArray2d(v,_RSLICES*2); tnsIndexArray(idx, _RSLICES*2+2);        tnsColor4d(LA_COLOR3(&MAIN.WireColorCache[cid]),1); tnsPackAs(GL_TRIANGLE_STRIP);        tnsMakeRing2d(v,idx,_RSLICES, outx, outy, r, r*0.6);        tnsVertexArray2d(v,_RSLICES*2); tnsIndexArray(idx, _RSLICES*2+2);        tnsColor4d(LA_COLOR3(&MAIN.WireColorCache[cid]),1); tnsPackAs(GL_TRIANGLE_STRIP);    }#undef _RSLICES    tnsFlush();    real ww=MAIN.WireThickness*TNS_MIN2(uild->WiresContainer->Scale,1);    for(laSocketRecord*sr=uild->SocketRecord.pFirst;sr;sr=sr->Item.pNext){        int cid=sr->In->ColorId%MAIN.WireColorSlices*4;        real inx=sr->In->RuntimeX+sr->In->RuntimePX, iny=sr->In->RuntimeY+sr->In->RuntimePY;        real outx=sr->Out->RuntimeX+sr->Out->RuntimePX, outy=sr->Out->RuntimeY+sr->Out->RuntimePY;        if(sr->Out==MAIN.tNodeOut){ outx=inx+MAIN.tNodeOut->RuntimeX+MAIN.tNodeOut->RuntimePX; outy=iny+MAIN.tNodeOut->RuntimeY+MAIN.tNodeOut->RuntimePY; }        tnsColor4dv(&MAIN.WireColorCache[cid]);         la_SendWireVerts(inx, iny, outx, outy, r*0.9, ww);    }    if(MAIN.tNodeIn->Source){        laNodeInSocket* ins=MAIN.tNodeIn; laNodeOutSocket* outs=ins->Source;        int cid=ins->ColorId%MAIN.WireColorSlices*4;        real outx=outs->RuntimeX+outs->RuntimePX, outy=outs->RuntimeY+outs->RuntimePY;        real inx=ins->RuntimeX+ins->RuntimePX+outx, iny=ins->RuntimeY+ins->RuntimePY+outy;                tnsColor4dv(&MAIN.WireColorCache[cid]);        la_SendWireVerts(inx, iny, outx, outy, r*0.9, ww);    }    tnsFlush();    la_InitSocketRecord(uild,0);}void la_SwitchThemeQuick(laTheme* t, laTheme* DefaultTheme){    if(!DefaultTheme){return;} MAIN.CurrentTheme = t?t:DefaultTheme; t=MAIN.CurrentTheme;    for(laBoxedTheme* bt = t->BoxedThemes.pFirst;bt;bt=bt->Item.pNext){ (*bt->BackRef) = bt; }}int la_DrawUiListRecursive(laUiListDraw *uild, laUiList *uil, int L, int R, int U, int B, int LimH, int ConditionStackLevel, int RegisterNodes){    laUiItem *ui;    laBoxedTheme *bt;    laUiList *sub;    laUiListDrawItem *uildi;    int Ret = 0, failed_matrix=0;    if (!uil) return 0;    //printf("d %d\n",MAIN.CurrentPanel->FrameDistinguish);    ui = uil->UiItems.pFirst;    if(uil->PanY<0){uil->PanY=0;}    if (!la_SetUpUiListMatrix(uild, uil, L, R-1, LimH, B - U)){        if(RegisterNodes){ failed_matrix=1; }else{ return 0; }    }    uil->SaveScale=MAIN.UiScale;    MAIN.UiScale*=uil->Scale;    MAIN.ScaledUiRowHeight=MAIN.UiRowHeight*MAIN.UiScale;    for (; ui;){ if(ui->Type==&_LA_UI_INVISIBLE){ ui=ui->Item.pNext; continue; }        bt = ui->Type->Theme ? (*ui->Type->Theme) : 0;        if (ui->Type == &_LA_UI_CONDITION){            laConditionUiExtraData *cued = ui->Extra;            la_StepExpression(cued->Expression);            cued->IsTrue = la_DoSingleExpression(cued->Expression);            if (!cued->IsTrue){                ui = cued->ElseUi ? cued->ElseUi : cued->EndUi;            }else{                ui = ui->Item.pNext;            }            continue;        }else if (ui->Type == &_LA_UI_CONDITION_END){            ui = ui->Item.pNext;            continue;        }else if (ui->Type == &_LA_UI_CONDITION_ELSE){            laConditionUiExtraData *cued = ((laConditionUiExtraData *)ui->Extra)->EndUi->Extra;            if (cued->IsTrue) ui = cued->EndUi;            else                ui = ui->Item.pNext;            continue;        }else if (ui->Type == _LA_UI_CONDITION_TOGGLE){            laConditionUiExtraData *cued = ui->Extra;            ui->Type->Draw(ui, LA_RH);            if (ui->State == LA_UI_NORMAL){                cued->IsTrue = 0;                ui = cued->ElseUi ? cued->ElseUi : cued->EndUi;            }else{                cued->IsTrue = 1;                ui = ui->Item.pNext;            }            continue;        }        if (ui->AnimationDistinguish != MAIN.CurrentPanel->FrameDistinguish) Ret = 1;        int NeedDraw=0;        if (la_UiInBoundEx(ui, uild) && !failed_matrix){ NeedDraw=1; }        if(NeedDraw){            if (!ui->Type->Draw){ la_DrawEmptyUiItem(ui); tnsFlush();            }else{ ui->Type->Draw(ui, LA_RH); }            if (ui->Type->Tag & LA_UI_TAG_IS_OFFSCREEN){                tnsFlush();                tnsDrawToOffscreen(MAIN.CurrentPanel->OffScr, 1, 0);                tnsResetViewMatrix();            }            if (ui->Type->Tag & (LA_UI_TAG_NEED_REBUILD)){                la_RebuildCurrentUiListMatrix(uild, uil, LimH, B - U);                if (ui->CanvasTemplate->SecondDraw) ui->CanvasTemplate->SecondDraw(ui, LA_RH);                tnsFlush();            }        }        if(NeedDraw || RegisterNodes){            if (RegisterNodes && ui->Type==_LA_UI_NODE_SOCKET){ la_RecordSocket(uild,uil,ui); }            if (ui->Type == _LA_UI_FIXED_GROUP ||                ui->Type == _LA_UI_TAB ||                ui->Type == _LA_UI_COLLECTION_SINGLE ||                ui->Type == _LA_UI_COLLECTION_SELECTOR && (ui->Subs.pFirst || ui->Page)){                if (!ui->Page){ ui = ui->Item.pNext; continue; }                tnsFlush(); int DoNodes=RegisterNodes; int NoDecal=ui->Flags&LA_UI_FLAGS_NO_DECAL;                int SidePad=NoDecal?-LA_M:LA_M;                int RightPad=(ui->Page->ScrollerShownV?LA_SCROLL_W+LA_M*2:0);                int BottomPad=(ui->Page->ScrollerShownH?LA_SCROLL_W+LA_M:0);                if(ui->Flags&LA_UI_FLAGS_NODE_CONTAINER){ la_InitSocketRecord(uild, ui->Page); DoNodes=1; }                int LimH=(ui->Page->HeightCoeff ? ui->B - ui->Page->U : 10000);                Ret += la_DrawUiListRecursive(uild, ui->Page, ui->L+SidePad, ui->R-SidePad-RightPad,                    U, B, LimH-(NoDecal?0:LA_M)-BottomPad, ConditionStackLevel, DoNodes);                                if (ui->Page->ScrollerShownH){                    int PadBottom=(ui->Page->ScrollerShownH?LA_SCROLL_W+LA_M:0);                    int PadRight=(ui->Page->ScrollerShownV?LA_SCROLL_W+LA_M:0);                    la_DrawUiListScrollerH(ui->Page, ui->Page->PanX,                        ui->Page->R-ui->Page->L, ui->R-ui->L-PadRight,ui->B,                        ui->L+LA_M, ui->R-LA_M-PadRight);                }                if (ui->Page->HeightCoeff){                    int PadBottom=(ui->Page->ScrollerShownH?LA_SCROLL_W:0);                    la_DrawUiListScrollerV(ui->Page, ui->Page->PanY,                        ui->Page->B-ui->Page->U, ui->B-ui->Page->U-PadBottom,ui->R,                        ui->Page->U+LA_M,ui->B-LA_M-PadBottom);                }                if (ui->Page->AllowScale){ la_DrawUiListArrows(ui->Page,ui->L, ui->R, ui->Page->U, ui->B-LA_SCROLL_W-LA_M*2, laThemeColor(bt, LA_BT_TEXT)); }                        }elif (ui->Type == _LA_UI_COLLECTION){                int CanGetState = laCanGetState(ui->PP.LastPs->p);                int CanGetTheme = laCanGetTheme(ui->PP.LastPs->p);laTheme* OriginalTheme=MAIN.CurrentTheme;                void *Active = laGetActiveInstanceStrict(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance);                void* SaveInstance = ui->PP.EndInstance;                for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){                    int State;                    ui->PP.EndInstance = sub->Instance;                    if ((!la_UiListInBoundEx(sub, uild)) && (!RegisterNodes)) continue;                    laTheme* SwitchedTheme=0;                    if(CanGetTheme){                        SwitchedTheme=laGetUiTheme(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, ui->PP.EndInstance);                        la_SwitchThemeQuick(SwitchedTheme, OriginalTheme);                    }                    if(NeedDraw){ int drawn=0;                        if (!(ui->Flags&LA_UI_COLLECTION_NO_HIGHLIGHT) && sub->Instance == Active){                            la_DrawInstanceBkg(sub, laAccentColor(LA_BT_NORMAL),LA_M,LA_M); drawn=1;                        }                        if (CanGetState && !drawn){                            State = laGetUiState(ui->PP.LastPs->p, sub->Instance);                            if(State >= 0){                                la_DrawInstanceBkg(sub, laAccentColor(State),LA_M,LA_M); drawn=1;                            }                        }                        if((!drawn) && SwitchedTheme){                            la_DrawInstanceBkg(sub, laThemeColor(_LA_THEME_FLOATING_PANEL ,LA_BT_NORMAL),LA_M,LA_M);                        }                    }                    if(sub->TabName && sub->TabName->Ptr){                        int NoDecal=ui->Flags&LA_UI_FLAGS_NO_DECAL;                        int NoGap=ui->Flags&LA_UI_FLAGS_NO_GAP;                        tnsDrawStringAuto(transLate(sub->TabName->Ptr),laThemeColor(bt,LA_BT_DISABLED|LA_BT_TEXT),                            ui->L+(NoDecal?0:LA_M)+(NoGap?0:LA_M),ui->R,sub->U-LA_RH,LA_TEXT_MONO);                        tnsFlush();                    }                    tnsFlush();                    Ret += la_DrawUiListRecursive(uild, sub, L, R, U, B, 10000, ConditionStackLevel, RegisterNodes);                                        if(CanGetTheme){ la_SwitchThemeQuick(0, OriginalTheme); }                }                //ui->PP.EndInstance = Active;                ui->PP.EndInstance = SaveInstance;                        }elif (ui->Type == _LA_UI_CANVAS){                if(!(ui->Flags&LA_UI_FLAGS_NO_OVERLAY)){                    for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){                        tnsFlush();                        Ret += la_DrawUiListRecursive(uild, sub, L-1, R+1, U-1, B+1, ui->B-LA_M*2-LA_M*2, ConditionStackLevel, RegisterNodes);                    }                }            }            ui = ui->Item.pNext;        }else{            ui = ui->Item.pNext;        }    }    tnsFlush();    if(uild->WiresContainer == uil){ la_DrawNodeWires(uild); }    if(!failed_matrix){        la_RestoreLastUiListMatrix(uild, B - U);    }    MAIN.UiScale=uil->SaveScale;    MAIN.ScaledUiRowHeight=MAIN.UiRowHeight*MAIN.UiScale;    return Ret;}int la_RejectByUiList(laOperator* a, int x, int y){    laListItemPointer* lip=a->LocalUiLists.pFirst;    if(lip){ laUiList* uil=lip->p;        if(uil->FL!=uil->FR && (x < uil->FL || y < uil->FU || x > uil->FR || y > uil->FB)){            //printf("rejected %d %d | %d %d %d %d\n",x,y,uil->FL,uil->FR,uil->FU,uil->FB);            return 1;        }    }    return 0;}int laIsInUiItem(laUiItem *ui, laOperator* a, int x, int y){    if (x < ui->L || x > ui->R || y < ui->U || y > ui->B) return 0;    if (a && la_RejectByUiList(a,x,y)) return 0;    return 1;}int laIsInBound(int x, int y, int l, int r, int u, int b){    if (x < l || x > r || y < u || y > b) return 0;    return 1;}laColumn *la_DetectSplit(laColumn *Root, int LocalX);laUiItem *la_DetectUiItemRecursive(laUiList *uil, int x, int y, int LimB, laListHandle *LocalBuf, int Deep){    laUiItem *ui, *tui;    laBoxedTheme *bt;    laUiList *sub;    int CPB = 0;    if (!uil || (LimB && y > LimB)) return 0;    x += uil->PanX;    y += uil->PanY;    for (ui = uil->UiItems.pFirst; ui;){        bt = ui->Type->Theme ? (*ui->Type->Theme) : 0;        if (ui->Type == &_LA_UI_CONDITION){            laConditionUiExtraData *cued = ui->Extra;            //la_StepExpression(cued->Expression); for some reason we can't step here, only step in update :thinking:            cued->IsTrue = la_DoSingleExpression(cued->Expression);            if (!cued->IsTrue){                ui = cued->ElseUi ? cued->ElseUi : cued->EndUi;            }else{                ui = ui->Item.pNext;            }            continue;        }else if (ui->Type == &_LA_UI_CONDITION_END){            ui = ui->Item.pNext;            continue;        }else if (ui->Type == &_LA_UI_CONDITION_ELSE){            laConditionUiExtraData *cued = ((laConditionUiExtraData *)ui->Extra)->EndUi->Extra;            if (cued->IsTrue) ui = cued->EndUi;            else                ui = ui->Item.pNext;            continue;        }else if (ui->Type == _LA_UI_CONDITION_TOGGLE){            laConditionUiExtraData *cued = ui->Extra;            if (laIsInUiItem(ui, 0, x, y)){                lstAppendPointer(LocalBuf, uil);                return ui;            }            if (ui->State == LA_UI_NORMAL){                cued->IsTrue = 0;                ui = cued->ElseUi ? cued->ElseUi : cued->EndUi;            }else{                cued->IsTrue = 1;                ui = ui->Item.pNext;            }            continue;        }        //printf("%s > ",ui->Type->Identifier?ui->Type->Identifier:"-");        if (ui->Type != _LA_UI_COLLECTION && ui->Type != _LA_UI_COLLECTION_SINGLE &&            ui->Type != _LA_UI_FIXED_GROUP && ui->Type != _LA_UI_TAB && ui->Type != _LA_UI_CANVAS && laIsInUiItem(ui, 0, x, y)){            int Add=1; if(ui->Type==_LA_UI_COLUMN_ADJUSTER){                if(!la_DetectSplit(ui->C, x)) Add=0;            }            if(Add){ lstAppendPointer(LocalBuf, uil); return ui; }        }        if ((ui->Type == _LA_UI_FIXED_GROUP || ui->Type == _LA_UI_TAB) && (ui->Subs.pFirst || ui->Page)){            if (ui->Page->HeightCoeff) CPB = ui->B;            else CPB = ui->Page->B;            if (laIsInBound(x, y, ui->Page->L, ui->Page->R, ui->Page->U, CPB)){                if (tui = la_DetectUiItemRecursive(ui->Page, x /* + ui->Page->PanX*/, y /*+ ui->Page->PanY*/, CPB, LocalBuf, Deep)){                    lstAppendPointer(LocalBuf, uil);                    return tui;                }            }else if (laIsInUiItem(ui, 0, x, y)){                lstAppendPointer(LocalBuf, uil);return ui;            }        }        if (ui->Type == _LA_UI_COLLECTION || ui->Type==_LA_UI_COLLECTION_SINGLE){            if (laIsInUiItem(ui, 0, x, y)){                if (ui->Subs.pFirst) ((laUiList *)ui->Subs.pFirst)->HeightCoeff = LimB;                if(Deep){                    for(laUiList* iuil=ui->Subs.pFirst;iuil;iuil=iuil->Item.pNext){                        if (laIsInBound(x, y, iuil->L, iuil->R, iuil->U, iuil->B)){                            if (tui = la_DetectUiItemRecursive(iuil, x , y , iuil->B, LocalBuf, Deep)){                                lstAppendPointer(LocalBuf, iuil);                                lstAppendPointer(LocalBuf, uil);                                return tui;                            }                        }                    }                }                lstAppendPointer(LocalBuf, uil);                return ui;            }        }        if (ui->Type == _LA_UI_CANVAS){            if(!(ui->Flags&LA_UI_FLAGS_NO_OVERLAY)){                for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){                    if (tui = la_DetectUiItemRecursive(sub, x, y, ui->B, LocalBuf, Deep)){                        lstAppendPointer(LocalBuf, uil);                        return tui;                    }                }            }            if (laIsInUiItem(ui, 0, x, y)){                lstAppendPointer(LocalBuf, uil);                return ui;            }        }        ui = ui->Item.pNext;    }    return 0;}laUiItem *la_DetectSocketRecursive(laUiList* uil, int x, int y, int LimB, laPropContainer* PCInOrOut){    laListHandle Locals={0};    laUiItem* ui=la_DetectUiItemRecursive(uil, x,y,LimB,&Locals, 1);    while(lstPopPointer(&Locals));    //printf("%s\n", ui?ui->Type->Identifier:"?");    if(ui && ui->Type==_LA_UI_NODE_SOCKET){        laProp* p=ui->PP.LastPs->p; laPropContainer* pc=la_EnsureSubTarget(p,0);        if(pc==PCInOrOut) return ui;    }    return 0;}laUiList *la_DetectUiListRecursive(laUiList *uil, int x, int y, int LimH,                                   laUiItem **ParentUi, laUiList **ScrollUil, laUiList **ContainerParent, int InToContainerUI, laUiItem *Exception){    laUiItem *ui = uil->UiItems.pFirst;    laBoxedTheme *bt;    laUiList *tuil;    laUiList *sub;    int CPB = 0;    x += uil->PanX;    y += uil->PanY;    if (y > LimH) return uil;    if ((uil->ScrollerShownV && laIsInBound(x, y, uil->R, uil->R+LA_SCROLL_W+4, uil->U, uil->B)) ||        (uil->ScrollerShownH && laIsInBound(x, y, uil->L, uil->R, uil->B, uil->B+LA_SCROLL_W+4))){        if (ScrollUil) *ScrollUil = uil; /* if (ParentUi)*ParentUi = uil;*/        return uil;    }    for (ui = uil->UiItems.pFirst; ui;){        bt = ui->Type->Theme ? (*ui->Type->Theme) : 0;        if (ui->Type == &_LA_UI_CONDITION){            laConditionUiExtraData *cued = ui->Extra;            //la_StepExpression(cued->Expression);            cued->IsTrue = la_DoSingleExpression(cued->Expression);            if (!cued->IsTrue){                ui = cued->ElseUi ? cued->ElseUi : cued->EndUi;            }else{                ui = ui->Item.pNext;            }            continue;        }        if (ui->Type == &_LA_UI_CONDITION_END){            ui = ui->Item.pNext;            continue;        }else if (ui->Type == &_LA_UI_CONDITION_ELSE){            laConditionUiExtraData *cued = ((laConditionUiExtraData *)ui->Extra)->EndUi->Extra;            if (cued->IsTrue) ui = cued->EndUi;            else                ui = ui->Item.pNext;            continue;        }else if (ui->Type == _LA_UI_CONDITION_TOGGLE){            laConditionUiExtraData *cued = ui->Extra;            if (ui->State == LA_UI_NORMAL){                cued->IsTrue = 0;                ui = cued->ElseUi ? cued->ElseUi : cued->EndUi;            }else{                cued->IsTrue = 1;                ui = ui->Item.pNext;            }            continue;        }        if (InToContainerUI && ui != Exception){            if (ui->Type == _LA_UI_CANVAS && !(ui->Flags&LA_UI_FLAGS_NO_OVERLAY)){                if (ContainerParent) (*ContainerParent) = uil;                if (ParentUi) *ParentUi = ui;                for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){                    //if (y > LimH) return uil;                    if (laIsInBound(x, y, sub->L, sub->R, sub->U, sub->B) && (tuil = la_DetectUiListRecursive(sub, x, y, ui->B, ParentUi, ScrollUil, ContainerParent, InToContainerUI, Exception))){                        return tuil;                    }                }            }        }        if ((ui->Type == _LA_UI_FIXED_GROUP || ui->Type == _LA_UI_TAB) && (ui->Subs.pFirst || ui->Page)){            if (ui->Page->HeightCoeff) CPB = ui->B+ui->Page->PanY;            else CPB = ui->Page->B;            if (ui->Page->ScrollerShownV && laIsInBound(x, y, ui->R - LA_SCROLL_W - LA_M*2, ui->R, ui->Page->U, CPB)){                if (ScrollUil) *ScrollUil = ui->Page; if (ParentUi) *ParentUi = ui;            }elif (ui->Page->ScrollerShownH && laIsInBound(x, y, ui->Page->L, ui->Page->R, ui->B - LA_SCROLL_W - LA_M*2, ui->B)){                if (ScrollUil) *ScrollUil = ui->Page; if (ParentUi) *ParentUi = ui;            }elif (laIsInBound(x, y, ui->Page->L, ui->Page->R, ui->Page->U, CPB)){                if (ParentUi) *ParentUi = ui;                 if (tuil = la_DetectUiListRecursive(ui->Page, x, y, CPB+ui->Page->PanY, ParentUi, ScrollUil, ContainerParent, InToContainerUI, Exception)) return tuil;            }        }        ui = ui->Item.pNext;    }    return uil;}laUiList *la_DetectUiListRecursiveDeep(laUiList *uil, int x, int y, int LimH, laUiItem **ParentUi, laUiList **ScrollUil,                                       laUiList **ContainerParent, int InToContainerUI, laUiItem *Exception, laListHandle* levels){    laUiItem *ui = uil->UiItems.pFirst;    laBoxedTheme *bt;    laUiList *tuil;    laUiList *sub;    int CPB = 0;    laUiListRecord* uilr=lstAppendPointerSized(levels, uil, sizeof(laUiListRecord));    x += uil->PanX;    y += uil->PanY;    if (y > LimH) return uil;        if (/*uil->ScrollerShownV && */ laIsInBound(x, y, uil->R, uil->R+LA_SCROLL_W+4, uil->U, uil->B) ||        /*uil->ScrollerShownH && */ laIsInBound(x, y, uil->L, uil->R, uil->B, uil->B+LA_SCROLL_W+4)){        if (ScrollUil) *ScrollUil = uil; /* if (ParentUi)*ParentUi = uil;*/        return uil;    }    for (ui = uil->UiItems.pFirst; ui;){        bt = ui->Type->Theme ? (*ui->Type->Theme) : 0;        if (ui->Type == &_LA_UI_CONDITION){            laConditionUiExtraData *cued = ui->Extra;            //la_StepExpression(cued->Expression);            cued->IsTrue = la_DoSingleExpression(cued->Expression);            if (!cued->IsTrue){                ui = cued->ElseUi ? cued->ElseUi : cued->EndUi;            }else{                ui = ui->Item.pNext;            }            continue;        }        if (ui->Type == &_LA_UI_CONDITION_END){            ui = ui->Item.pNext;            continue;        }else if (ui->Type == &_LA_UI_CONDITION_ELSE){            laConditionUiExtraData *cued = ((laConditionUiExtraData *)ui->Extra)->EndUi->Extra;            if (cued->IsTrue) ui = cued->EndUi;            else                ui = ui->Item.pNext;            continue;        }else if (ui->Type == _LA_UI_CONDITION_TOGGLE){            laConditionUiExtraData *cued = ui->Extra;            if (ui->State == LA_UI_NORMAL){                cued->IsTrue = 0;                ui = cued->ElseUi ? cued->ElseUi : cued->EndUi;            }else{                cued->IsTrue = 1;                ui = ui->Item.pNext;            }            continue;        }        if (InToContainerUI && ui != Exception){            if (ui->Type == _LA_UI_CANVAS && !(ui->Flags&LA_UI_FLAGS_NO_OVERLAY)){                if (ContainerParent) (*ContainerParent) = uil;                if (ParentUi) *ParentUi = ui; uilr->pui=ui;                for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){                    //if (y > LimH) return uil;                    if (laIsInBound(x, y, sub->L, sub->R, sub->U, sub->B) && (tuil = la_DetectUiListRecursiveDeep(sub, x, y, ui->B, ParentUi, ScrollUil, ContainerParent, InToContainerUI, Exception, levels))){                        return tuil;                    }                }            }        }        if ((ui->Type == _LA_UI_FIXED_GROUP || ui->Type == _LA_UI_TAB) && (ui->Subs.pFirst || ui->Page)){            if (ui->Page->HeightCoeff) CPB = ui->B;            else CPB = ui->Page->B;            if (ui->Page->ScrollerShownV && laIsInBound(x, y, ui->R - LA_SCROLL_W - LA_M*2, ui->R, ui->Page->U, CPB)){                if (ScrollUil) *ScrollUil = ui->Page; if (ParentUi) *ParentUi = ui; uilr->pui=ui;            }elif (ui->Page->ScrollerShownH && laIsInBound(x, y, ui->Page->L, ui->Page->R, ui->B - LA_SCROLL_W - LA_M*2, ui->B)){                if (ScrollUil) *ScrollUil = ui->Page; if (ParentUi) *ParentUi = ui; uilr->pui=ui;            }elif (laIsInBound(x, y, ui->Page->L, ui->Page->R, ui->Page->U, CPB)){                if (ParentUi) *ParentUi = ui; uilr->pui=ui;                if (tuil = la_DetectUiListRecursiveDeep(ui->Page, x, y, CPB, ParentUi, ScrollUil, ContainerParent, InToContainerUI, Exception, levels)) return tuil;            }        }        if ((ui->PP.LastPs && ui->PP.LastPs->p->PropertyType == LA_PROP_SUB) && (ui->Subs.pFirst || ui->Page)){            if (ui->Page->HeightCoeff) CPB = ui->B;            else                CPB = ui->Page->B;            if (laIsInBound(x, y, ui->Page->R, ui->Page->R + LA_SCROLL_W + LA_M, ui->Page->U, CPB)){                if (ScrollUil) *ScrollUil = ui->Page;                if (ParentUi) *ParentUi = ui; uilr->pui=ui;            }            if (laIsInBound(x, y, ui->Page->L, ui->Page->R, ui->Page->U, CPB)){                if (ParentUi) *ParentUi = ui; uilr->pui=ui;                if (tuil = la_DetectUiListRecursiveDeep(ui->Page, x, y, CPB, ParentUi, ScrollUil, ContainerParent, InToContainerUI, Exception, levels)) return tuil;            }        }        ui = ui->Item.pNext;    }    return uil;}int la_TestUiListMinumWidth(laUiList *uil){    laUiItem *ui, *tui;    laBoxedTheme *bt;    laUiList *sub;    int CPB = 0;    int W = 0;    int tW, sW, RowMode=0, rW;    void *Restore;    for (ui = uil->UiItems.pFirst; ui;){        bt = ui->Type->Theme ? (*ui->Type->Theme) : 0;        if ((ui->Type == _LA_UI_FIXED_GROUP || ui->Type == _LA_UI_TAB) && (ui->Subs.pFirst || ui->Page)){            tW = la_TestUiListMinumWidth(ui->Page) + LA_M*2;            tW = (int)((float)tW / ui->C->PreWidth + 2);            if (W < tW) W = tW;        }elif (ui->Type == _LA_UI_COLLECTION){            Restore = ui->PP.EndInstance;            tW = 0; sW = 0;            for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){                ui->PP.EndInstance = sub->Instance;                sW = la_TestUiListMinumWidth(sub) + LA_M*2;                if (sW > tW) tW = sW;            }            ui->PP.EndInstance = Restore;            tW = (int)((float)tW / ui->C->PreWidth + 2);            tW *= (ui->Extent > 0 ? ui->Extent : 1);            if (W < tW) W = tW;        }elif (ui->Type==&_LA_UI_ROW_BEGIN){            RowMode=1; rW=0;        }elif (ui->Type==&_LA_UI_ROW_END){            RowMode=0; rW=(int)((float)rW / ui->C->PreWidth + 2); if (W < rW) W = rW;        }elif (ui->Type->GetMinWidth){            tW = ui->Type->GetMinWidth(ui) + LA_M*2;            if(RowMode){ rW+=tW; }else{ tW = (int)((float)tW / ui->C->PreWidth + 2); if (W < tW) W = tW; }        }        ui = ui->Item.pNext;    }    return W;}void la_InitLLVM(){    //LLVMLinkInMCJIT();    //LLVMInitializeNativeTarget();    //LLVMInitializeNativeAsmPrinter();    //LLVMInitializeNativeAsmParser();    //   MAIN.llvmContext = LLVMGetGlobalContext();    //MAIN.llvmModule = LLVMModuleCreateWithNameInContext(LA_NODE_MAIN_MODULE_NAME, MAIN.llvmContext);}//==================================================================================================void la_FreeKeyMapItem(laKeyMapItem* kmi){    if(kmi->Instructions) strSafeDestroy(&kmi->Instructions);    if(kmi->Operation) strSafeDestroy(&kmi->Operation);    if(kmi->Action.Go) la_FreePropStepCache(kmi->Action.Go);    if(kmi->Base.Go) la_FreePropStepCache(kmi->Action.Go);    memFree(kmi);}laKeyMapItem *laAssignNewKey(laKeyMapper *km, char *Path, char *Operation, char SelectBase, int SpecialKeyBits, int EventType, int Key, char *ExtraInstructions){    laKeyMapItem *kmi;    if (!km) return 0;    kmi = memAcquire(sizeof(laKeyMapItem));    if (la_GetPropFromPath(&kmi->Base, 0, Path, 0)){        la_GetPropFromPath(&kmi->Action, &kmi->Base, Operation, 0);    }else{        strSafeSet(&kmi->Operation, Operation);    }    strSafeSet(&kmi->Instructions, ExtraInstructions);    kmi->SpecialKeyBits = SpecialKeyBits;    kmi->EventType = EventType;    kmi->Key = tolowerGuarded(Key);    kmi->SelectBase = SelectBase;    lstAppendItem(&km->Items, kmi);    return kmi;}int laKeyMapExecuteEvent(laOperator *from, laKeyMapper *km, laEvent *e){    laKeyMapItem *kmi; int inv=0;    char *instructions;    if(e->type==LA_MOUSEMOVE) return 0;    for (kmi = km->Items.pFirst; kmi; kmi = kmi->Item.pNext){        if ((kmi->SpecialKeyBits == e->SpecialKeyBit||kmi->EventType==LA_SIGNAL_EVENT) &&            kmi->EventType == e->type && ((kmi->Key == e->Input) || (kmi->Key == e->key))){            instructions = kmi->Instructions ? kmi->Instructions->Ptr : 0;            if (kmi->Operation)                laInvoke(from, kmi->Operation->Ptr, e, 0, instructions, 0);            else                laInvoke(from, ((laOperatorProp *)&kmi->Action.LastPs)->OperatorID, e, &kmi->Base, instructions, 0);            inv = 1;        }    }    return inv;}int laKeyMapExecuteEventEx(laOperator *from, laPropPack *UiExtra, laKeyMapper *km, laEvent *e){    laKeyMapItem *kmi;    char *instructions;    int inv = 0; int lx = -1, ly = -1;    if(e->type==LA_MOUSEMOVE) return 0;    if(e->type == LA_OPERATOR_EVENT && e->OperatorBase){        if (e->OperatorBase == LA_KM_SEL_UI_EXTRA){            laInvokeP(from, e->Operator, e, UiExtra, e->OperatorInstructions, 0);        }elif (e->OperatorBase == LA_KM_SEL_PANEL){            laInvokeP(from, e->Operator, e, &((laPanel *)MAIN.ToPanel)->PP, e->OperatorInstructions, 0);        }        return 1;    }    for (kmi = km->Items.pFirst; kmi; kmi = kmi->Item.pNext){        if ((kmi->SpecialKeyBits == e->SpecialKeyBit||kmi->EventType==LA_SIGNAL_EVENT) &&            kmi->EventType == e->type && ((kmi->Key == e->Input) || (kmi->Key == e->key))){            if (e->Localized){                lx = e->x;                ly = e->y;                laLocalToWindow(from, MAIN.ToPanel, &e->x, &e->y);                e->Localized = 0;            }            instructions = kmi->Instructions ? kmi->Instructions->Ptr : 0;            if (kmi->SelectBase == LA_KM_SEL_UI_EXTRA){                laInvoke(from, kmi->Operation->Ptr, e, UiExtra, instructions, 0);            }elif (kmi->SelectBase == LA_KM_SEL_PANEL){                laInvoke(from, kmi->Operation->Ptr, e, &((laPanel *)MAIN.ToPanel)->PP, instructions, 0);            }elif (kmi->Operation){                laInvoke(from, kmi->Operation->Ptr, e, 0, instructions, 0);            }else{                laInvoke(from, ((laOperatorProp *)&kmi->Action.LastPs)->OperatorID, e, &kmi->Base, instructions, 0);            }            inv = 1;            if (lx >= 0){                e->x = lx;                e->y = ly;                e->Localized = 1;            }        }    }    return inv;}void la_DefaultOperatorParser(laStringSplitor *ss, char *IconID, char *DisplayString);void la_DestroyOperatorType(laOperatorType* at){    //if(at->PC) la_FreePropertyContainer(at->PC);    memFree(at);}laOperatorType *laCreateOperatorType(const char *ID, const char *Name, const char *Description,                                     laCheckFunc Check, laInitFunc Init, laExitFunc Exit, laInvokeFunc Invoke, laModalFunc Modal,                                     uint32_t IconID, int ExtraMark){    laOperatorType *at = memAcquire(sizeof(laOperatorType));    at->Identifier = ID;    at->Name = Name;    at->Description = Description;    at->Check = Check;    at->Invoke = Invoke;    at->Init = Init;    at->Exit = Exit;    at->Modal = Modal;    at->IconID = IconID;    at->ExtraMark = ExtraMark;    at->ParseArgs = la_DefaultOperatorParser;    hsh256InsertItemCSTR(&MAIN.OperatorTypeHash, at, at->Identifier);    lstAppendItem2(&MAIN.OperatorList, at);    return at;}laPropContainer* laDefineOperatorProps(laOperatorType* ot, int HyperLevel){    ot->PC = memAcquire(sizeof(laPropContainer));    ot->PC->Identifier = ot->Identifier;    ot->PC->Hyper = HyperLevel;     return ot->PC;}laOperator *la_CreateOperator(laOperatorType *at){    laOperator *a = CreateNew(laOperator);    a->Type = at;    if (at->PC && at->PC->Props.pFirst){        a->PP.LastPs = memAcquireSimple(sizeof(laPropStep));        a->PP.LastPs->p = memAcquire(sizeof(laSubProp));        a->PP.LastPs->p->SubProp = at->PC;        a->PP.LastPs->p->PropertyType = LA_PROP_SUB;        a->PP.LastPs->p->Identifier = at->PC->Identifier;        a->PP.LastPs->Type = U'.';    }    return a;}int la_OperatorTypeByID(laOperatorType *a, char *id){    return (!strcmp(a->Identifier, id));}laOperatorType *laGetOperatorType(const char *ID){    return hsh256FindItemSTR(&MAIN.OperatorTypeHash, la_OperatorTypeByID, ID);}int laOperatorExistsT(laOperatorType* at){    if (!at) return 0;    for (laOperator *a = MAIN.CurrentWindow->Operators.pFirst; a; a = a->Item.pNext){ if (at == a->Type){ return 1; } }    return 0;}int laOperatorExists(const char* ID){    laOperatorType* at=laGetOperatorType(ID); if (!at) return 0;    return laOperatorExistsT(at);}int la_OperatorExists(laOperator *ac){    if (!ac) return 0;    laOperator *a;    for (a = MAIN.CurrentWindow->Operators.pFirst; a; a = a->Item.pNext){ if (ac == a){return 1;}}    return 0;}int la_UiOperatorExists(void *inst){    laOperator *a;    if (!inst) return 0;    for (a = MAIN.CurrentWindow->Operators.pFirst; a; a = a->Item.pNext){        if (((laUiItem *)a->Instance) == inst){            return 1;        }    }    for (a = MAIN.CurrentWindow->PendingOperators.pFirst; a; a = a->Item.pNext){        if (a->Instance == inst){            return 1;        }    }    return 0;}int la_OperatorPending(laOperator *target){    laOperator *a;    if (!target) return 0;    for (a = MAIN.CurrentWindow->PendingOperators.pFirst; a; a = a->Item.pNext){        if (a == target){            return 1;        }    }    return 0;}void laSetOperatorLocalizer(void *ToPanel){    MAIN.ToPanel = ToPanel;}void la_DestroyConfirmData(laConfirmData **cd);void *la_DestroyOperator(laOperator **a, laListHandle *Operators, int OnlyThisOne){    laOperator *ai = (*a);    laOperator *ac = ((*a)->Child);    void *Ret = 0;    if (!OnlyThisOne && ac && la_OperatorExists(ac) && !ac->Using && !ac->ModalOver){        la_DestroyOperator(&ac, Operators, OnlyThisOne);    }    if ((*a)->ConfirmData) la_DestroyConfirmData(&((*a)->ConfirmData));    if ((*a)->PP.LastPs){        memFree((*a)->PP.LastPs->p);        memFree((*a)->PP.LastPs);    }    if (laNonFixedPanelExists((*a)->OperatorPanel)){        la_SetPropMathcerContext((*a)->OperatorPanel);        MAIN.CurrentPanel = (*a)->OperatorPanel;        laDestroySinglePanel((*a)->OperatorPanel,0);    }    if ((*a)->CreatedThis){ la_FreePropStepCache((*a)->CreatedThis->Go); memFree((*a)->CreatedThis); }    if ((*a)->ExtraInstructionsP) strDestroyStringSplitor(&(*a)->ExtraInstructionsP);    lstClearPointer(&(*a)->LocalUiLists);    if (Operators){        Ret = ai->Item.pNext;        if (la_OperatorPending((*a) /*->Instance*/)) lstRemoveItem(&MAIN.CurrentWindow->PendingOperators, *a);        else            lstRemoveItem(Operators, *a);        for (ai = Operators->pFirst; ai; ai = ai->Item.pNext){            if (ai->Child == (*a)) ai->Child = 0;        }    }    strSafeDestroy(&(*a)->RuntimeHint);    free(*a);    return Ret;}int laOperatorAvailable(char *ID, laPropPack *This, laStringSplitor *Instructions){    laOperatorType *at = hsh256FindItemSTR(&MAIN.OperatorTypeHash, la_OperatorTypeByID, ID);    if (!at) return 0;    if (!at->Check) return 1;    return (at->Check(This, Instructions));}int laOperatorAvailableP(laOperatorType *at, laPropPack *This, laStringSplitor *Instructions){    if (!at) return 0;    if (!at->Check) return 1;    return (at->Check(This, Instructions));}int laOperatorAvailablePSafe(laOperatorType *at, laPropPack *This, void *Real_FromInstance, laStringSplitor *Instructions){    laPropPack FakePP = {0};    laPropStep FakePs = {0};    if (!at) return 0;    if (!at->Check) return 1;    FakePP.LastPs = &FakePs;    FakePP.Go = FakePP.LastPs;    FakePP.LastPs->p = This->LastPs->p;    FakePP.LastPs->UseInstance = This->EndInstance;    FakePP.EndInstance = Real_FromInstance;    FakePP.LastIndex = This->LastIndex;    return (at->Check(&FakePP, Instructions));}int laOperatorAvailableSafe(char *ID, laPropPack *This, void *Real_FromInstance, laStringSplitor *Instructions){    laOperatorType *at = hsh256FindItemSTR(&MAIN.OperatorTypeHash, la_OperatorTypeByID, ID);    return laOperatorAvailablePSafe(at, This, Real_FromInstance, Instructions);}void la_EnsureLocalizedEvent(laOperator *From, laOperator *a, laEvent *e){    if(!a){ return; }    laOperatorType *at=a->Type;    if (e&&!e->Localized && at->ExtraMark & LA_EXTRA_TO_PANEL){        laWindowToLocal(0, a->ToPanel, &e->x, &e->y);        e->Localized = 1;    }    if (e&&e->Localized && From){        if (!at->ExtraMark & LA_EXTRA_TO_PANEL){            laLocalToWindow(From, From->ToPanel, &e->x, &e->y);            e->Localized = 0;        }else{            laLocalToWindow(From, From->ToPanel, &e->x, &e->y);            laWindowToLocal(a, a->ToPanel, &e->x, &e->y);        }    }}int laInvokeP(laOperator *From, laOperatorType *at, laEvent *e, laPropPack *This, char *args, char *args2){    laOperator *a, *f = From;    int rev;    if (!f && e&&e->Localized) return -1;    a = la_CreateOperator(at);    a->ToPanel = MAIN.ToPanel;    a->This = This;    a->ExtraInstructions = args;    strMakeInstructions(&a->ExtraInstructionsP, args);    strMakeInstructions(&a->ExtraInstructionsP, args2);    strMakeInstructions(&a->ExtraInstructionsP, at->ExtraInstructions);    if (!laOperatorAvailableP(at, This, a->ExtraInstructionsP)){        la_DestroyOperator(&a, 0, 0);        return LA_CANCELED;    }    lstGeneratePointerList(f ? &f->LocalUiLists : 0, 0, &a->LocalUiLists);    la_EnsureLocalizedEvent(From,a,e);    if (From) f->Child = a;    a->Using = 1;    if (at->Init) at->Init(a);    rev = at->Invoke(a, e);    a->Using = 0;    if (rev & LA_FINISH){        a->StopNow = 1;  if(From)From->Child=0;        laConfirmSameDataIfAny(a); la_DestroyConfirmData(&MAIN.InvokeConfirmData); MAIN.InvokeConfirmData=a->NextConfirmData;    }    la_EnsureLocalizedEvent(a, From, e);    if (!a->StopNow && (rev&LA_BLOCK || rev&LA_PASS_ON)){        if(a->ModalOver){ lstPushItem(&MAIN.CurrentWindow->PendingOperators, a); }        else{ lstAppendItem(&MAIN.CurrentWindow->PendingOperators, a); }        a->State = rev;        a->PP.EndInstance = a->CustomData;        if (a->PP.LastPs) a->PP.LastPs->Type = U'.';    } else {        la_DestroyOperator(&a, 0, 0);    }    return rev;}int laInvoke(laOperator *From, char *ID, laEvent *e, laPropPack *This, char *args, char *args2){    laOperatorType *at; laOperator *a, *f = From;    at = hsh256FindItemSTR(&MAIN.OperatorTypeHash, la_OperatorTypeByID, ID);    if (!at) return -1;    return laInvokeP(From,at,e,This,args,args2);}int laInvokePCreateThis(laOperator *From, laOperatorType *at, laEvent *e, laPropPack *OrigionalThis, void *FromInstance, char *args, char *args2){    laOperator *a, *f = From;    int rev;    laPropPack *created;    if (!f && e&&e->Localized || !OrigionalThis || !OrigionalThis->LastPs) return -1;    created = memAcquireSimple(sizeof(laPropPack));    la_CopyPropPack(OrigionalThis, created);    created->EndInstance = FromInstance;    a = la_CreateOperator(at);    a->ToPanel = MAIN.ToPanel;    a->This = created;    a->CreatedThis = created;    a->ExtraInstructions = args;    strMakeInstructions(&a->ExtraInstructionsP, args);    strMakeInstructions(&a->ExtraInstructionsP, args2);    strMakeInstructions(&a->ExtraInstructionsP, at->ExtraInstructions);    if (!laOperatorAvailableP(at, created, a->ExtraInstructionsP)){        la_DestroyOperator(&a, 0, 0);        return LA_CANCELED;    }    lstGeneratePointerList(f ? &f->LocalUiLists : 0, 0, &a->LocalUiLists);    la_EnsureLocalizedEvent(From,a,e);    if (From) f->Child = a;    a->Using = 1;    if (at->Init) at->Init(a);    rev = at->Invoke(a, e);    a->Using = 0;    la_EnsureLocalizedEvent(a,From,e);    if (rev & LA_FINISH){        a->StopNow = 1; if(From)From->Child=0;        laConfirmSameDataIfAny(a); la_DestroyConfirmData(&MAIN.InvokeConfirmData); MAIN.InvokeConfirmData=a->NextConfirmData;    }    if (!a->StopNow && (rev&LA_BLOCK || rev&LA_PASS_ON)){        if(a->ModalOver){ lstPushItem(&MAIN.CurrentWindow->PendingOperators, a); }        else{ lstAppendItem(&MAIN.CurrentWindow->PendingOperators, a); }        a->State = rev;        a->PP.EndInstance = a->CustomData;    }else        la_DestroyOperator(&a, 0, 0);    return rev;}int laInvokeUiP(laOperator *From, laOperatorType *at, laEvent *e, void *inst, laListHandle *Locals, int IgnoreLocals){    laOperator *a, *f = From;    int rev=0;    if (!at || (la_UiOperatorExists(inst))){ return -1; }    a = la_CreateOperator(at);    a->Instance = inst;    a->ToPanel = MAIN.ToPanel;    if (!IgnoreLocals) lstGeneratePointerList(f ? &f->LocalUiLists : 0, Locals, &a->LocalUiLists);    la_EnsureLocalizedEvent(From,a,e);    if (From) f->Child = a;    a->Using = 1;    if (at->Init) at->Init(a);    rev = at->Invoke(a, e);    a->Using = 0;    la_EnsureLocalizedEvent(a,From,e);    if (rev & LA_FINISH){        a->StopNow = 1; if(From)From->Child=0;    }elif (rev & LA_BLOCK){        lstAppendItem(&MAIN.CurrentWindow->PendingOperators, a);        a->State = rev;    }else la_DestroyOperator(&a, 0, 0);    DEB = a;    return rev;}int laInvokeUi(laOperator *From, char *ID, laEvent *e, void *inst, laListHandle *Locals, int IgnoreLocals){    laOperatorType *at;    laOperator *a, *f = From;    if (la_UiOperatorExists(inst)) return -1;    at = hsh256FindItemSTR(&MAIN.OperatorTypeHash, la_OperatorTypeByID, ID); if (!at) return -1;    return laInvokeUiP(From,at,e,inst,Locals,IgnoreLocals);}void laRequestDelayEvent(real Seconds){    MAIN.DelayTriggered=0; MAIN.DelayStart=MAIN.TimeAccum; MAIN.DelayTime = Seconds; }int la_UiStillInService(void *UiInstance){    laOperator *ai, *dai; if(!MAIN.CurrentWindow) return 0;    for (ai = MAIN.CurrentWindow->Operators.pFirst; ai; ai = ai->Item.pNext){        if (ai->Instance == UiInstance) return 1;    }    return 0;}void la_StopUiOperatorService(void *UiInstance){    laOperator *ai, *dai, *NextAi;    if (!MAIN.CurrentWindow) return;    for (ai = MAIN.CurrentWindow->PendingOperators.pFirst; ai; ai = NextAi){        NextAi = ai->Item.pNext;        if (ai->Instance == UiInstance){            if (ai->Child){                la_StopUiOperatorService(ai->Child->Instance);                ai->Child = 0;            }            laOperator *dai = ai;            la_DestroyOperator(&dai, &MAIN.CurrentWindow->PendingOperators, 1);            continue;        }    }    for (ai = MAIN.CurrentWindow->Operators.pFirst; ai; ai = NextAi){        NextAi = ai->Item.pNext;        if (ai->Instance == UiInstance){            if (ai->Instance == ai->ToPanel){                //laHidePanelWithDissoveEffect(ai->ToPanel);                //ai->ToPanel->LaterDestroy = 1;            }            if (ai->Child && la_OperatorExists(ai->Child)){                la_StopUiOperatorService(ai->Child->Instance);                //ai->Child = 0;            }            if (!ai->Using){                laOperator *dai = ai;                la_DestroyOperator(&dai, &MAIN.CurrentWindow->Operators, 1);            }else                ai->StopNow = 1;        }    }}void la_StopAllOperators(){    laOperator *ai, *dai, *NextAi;    if (!MAIN.CurrentWindow) return;    for (ai = MAIN.CurrentWindow->PendingOperators.pFirst; ai; ai = NextAi){        NextAi = ai->Item.pNext;        NextAi = la_DestroyOperator(&ai, &MAIN.CurrentWindow->PendingOperators, 1);        continue;    }    for (ai = MAIN.CurrentWindow->Operators.pFirst; ai; ai = NextAi){        NextAi = ai->Item.pNext;        if (ai->ToPanel && ai->Instance == ai->ToPanel && !ai->ToPanel->IsMenuPanel){            laHidePanelWithDissoveEffect(ai->ToPanel);            ai->ToPanel->LaterDestroy = 1;        }        if (!ai->Using){            laOperator *dai = ai;            la_DestroyOperator(&dai, &MAIN.CurrentWindow->Operators, 1);        }else ai->StopNow = 1;    }}void la_DestroyConfirmData(laConfirmData **cd){    if((!cd)||!(*cd)) return;    if ((*cd)->CustomData && (*cd)->Destroy) (*cd)->Destroy((*cd)->CustomData);    if ((*cd)->StrData) free((*cd)->StrData);    FreeMem((*cd));    (*cd) = 0;}void laConfirmPointer(laOperator *a, void* Data,laPropContainer* PointerType, int mode){    laOperator *ai = a; laConfirmData *cd = CreateNew(laConfirmData);    cd->PointerData = Data; cd->Mode = mode; cd->PointerType=PointerType;    ai->NextConfirmData = cd; laRetriggerOperators();}void laConfirmInt(laOperator *a, int Data, int mode){    laOperator *ai = a;laConfirmData *cd = CreateNew(laConfirmData);    cd->IData = Data; cd->Mode = mode;    ai->NextConfirmData = cd; laRetriggerOperators();}void laConfirmFloat(laOperator *a, real Data, int mode){    laOperator *ai = a;laConfirmData *cd = CreateNew(laConfirmData);    cd->FData = Data; cd->Mode = mode;    ai->NextConfirmData = cd; laRetriggerOperators();}void laConfirmString(laOperator *a, char *Str, int mode){    laOperator *ai = a;    laConfirmData *cd = CreateNew(laConfirmData);    int len = strlen(Str);    char *buf = calloc(len + 1, sizeof(char));    strcpy(buf, Str);    cd->StrData = buf;    cd->Mode = mode;    cd->Destroy = free;    ai->NextConfirmData = cd;    laRetriggerOperators();}int laConfirmSameDataIfAny(laOperator *a){    laOperator *ai = a;    laConfirmData *cd;    char *buf = 0;    if (!ai->ConfirmData || ai->NextConfirmData) return 0;    cd = CreateNew(laConfirmData);    if (ai->ConfirmData->StrData){        int len = strlen(ai->ConfirmData->StrData);        buf = calloc(len + 1, sizeof(char));        strcpy(buf, ai->ConfirmData->StrData);    }    //cd->CustomData = cd->CustomData;    cd->IData = ai->ConfirmData->IData;    cd->FData = ai->ConfirmData->FData;    cd->PointerData = ai->ConfirmData->PointerData;    cd->PointerType = a->ConfirmData->PointerType;    cd->StrData = buf;    cd->Mode = ai->ConfirmData->Mode;    cd->Destroy = ai->ConfirmData->Destroy;    ai->NextConfirmData = cd;    laRetriggerOperators();    return 1;}void laConfirmUserData(laOperator *a, void *UserData, laConfirmDataDestroyFunc Destroy, int mode){    laOperator *ai = a;    laConfirmData *cd = CreateNew(laConfirmData);    cd->CustomData = UserData;    cd->Mode = mode;    cd->Destroy = Destroy;    ai->NextConfirmData = cd;    laRetriggerOperators();}int laGetConfirmMode(laOperator *a){    return ((laOperator *)a)->ConfirmData->Mode;}int laGetConfirmInt(laOperator *a){    laOperator *ai = a;    int rev = ai->ConfirmData->IData;    la_DestroyConfirmData(&ai->ConfirmData);    ai->ConfirmData = 0;    return rev;}real laGetConfirmFloat(laOperator *a){    laOperator *ai = a;    real rev = ai->ConfirmData->FData;    la_DestroyConfirmData(&ai->ConfirmData);    ai->ConfirmData = 0;    return rev;}void laGetConfirmString(laOperator *a, char *buf){    laOperator *ai = a;    strcpy(buf, ai->ConfirmData->StrData);    la_DestroyConfirmData(&ai->ConfirmData);    ai->ConfirmData = 0;}void *laGetConfirmUserData(laOperator *a){    laOperator *ai = a;    return ai->ConfirmData->CustomData;}void laFinalizeOperators(){    laOperatorType *at;    laListHandle *lst;    int i;    for (i = 0; i < 256; i++){        lst = &MAIN.OperatorTypeHash.Entries[i];        for (at = lst->pFirst; at; at = at->Item.pNext){            if (at->PC && at->PC->Props.pFirst){                lstAppendItem(&MAIN.PropContainers, at->PC);            }        }    }}//=================#ifdef LA_LINUXstatic void la_RecordWacomMotions(XIRawEvent *event){    double *valuator = event->valuators.values;    int IsStylus=event->deviceid==MAIN.WacomDeviceStylus;    if(!IsStylus) MAIN.PointerIsEraser = 1; else MAIN.PointerIsEraser = 0;    //SYSWINDOW root_return, child_return;    //int root_x_return, root_y_return;    //int win_x_return, win_y_return;    //unsigned int mask_return;    //int retval = XQueryPointer(MAIN.dpy, RootWindow(MAIN.dpy,0), &root_return, &child_return,    //                            &root_x_return, &root_y_return,    //                            &win_x_return, &win_y_return,    //                            &mask_return);    //    //printf("root: x %d y %d\n", win_x_return, win_y_return);    if(XIMaskIsSet(event->valuators.mask, 2)){ if(IsStylus) MAIN.StylusPressure=valuator[2]/MAIN.StylusMaxPressure; else MAIN.EraserPressure=valuator[2]/MAIN.EraserMaxPressure; }    if(XIMaskIsSet(event->valuators.mask, 3) && XIMaskIsSet(event->valuators.mask, 4)){        real x=valuator[3],y=valuator[4];        real orientation=atan2(y,x); real deviation=sqrt(x*x+y*y); deviation=rad(deviation);        if(IsStylus){ MAIN.StylusOrientation=orientation;MAIN.StylusDeviation=deviation; }        else { MAIN.EraserOrientation=orientation;MAIN.EraserDeviation=deviation; }    }else{ MAIN.StylusDeviation=MAIN.StylusOrientation=MAIN.EraserDeviation=MAIN.EraserOrientation=0; }    if(XIMaskIsSet(event->valuators.mask, 5)){        real angle=valuator[5]; angle=rad((900-angle)/10*2-180); if(angle<0) angle+=TNS_PI*2; MAIN.StylusTwist=angle;        if(TNS_DOUBLE_CLOSE_ENOUGH(angle,TNS_PI)){ MAIN.StylusHasTwist=0; }else{ MAIN.StylusHasTwist=1; }    }else{ MAIN.StylusTwist=TNS_PI; MAIN.StylusHasTwist=0; }    MAIN.IsPen=1;}#endif#ifdef _WIN32#define PARAM_2_FROM(p) LOWORD(p),HIWORD(p)LRESULT CALLBACK LA_WindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {    static uint32_t ch = 0; static int lead = 0;    static wchar_t buf[10] = { 0 }; int adv;    char mbuf[10] = { 0 }; uint32_t uchar=0;    short wheelmark = 0;    int  WheelDir = 0;    UINT32 pointerId; POINTER_INPUT_TYPE pointerType;    POINTER_PEN_INFO penInfo[128]; POINTER_TOUCH_INFO touchInfo; int peninfonum = 128;    POINT point;    PACKET pkt;    static POINT ptOld, ptNew;    static UINT prsOld, prsNew, vkey;    if (!hwnd) return DefWindowProc(hwnd, message, wparam, lparam);    switch (message) {    case WM_PAINT:        //SwapBuffers(GetDC(hwnd));        break;    case WM_MOUSEMOVE:        la_SendMouseEvent(hwnd, LA_MOUSEMOVE, PARAM_2_FROM(lparam));        MAIN.IsPen = 0;        break;    case WM_LBUTTONDOWN: la_SendMouseEvent(hwnd, LA_L_MOUSE_DOWN, PARAM_2_FROM(lparam)); break;    case WM_LBUTTONUP:   la_SendMouseEvent(hwnd, LA_L_MOUSE_UP, PARAM_2_FROM(lparam)); break;    case WM_RBUTTONDOWN: la_SendMouseEvent(hwnd, LA_R_MOUSE_DOWN, PARAM_2_FROM(lparam)); break;    case WM_RBUTTONUP:   la_SendMouseEvent(hwnd, LA_R_MOUSE_UP, PARAM_2_FROM(lparam)); break;    case WM_MBUTTONDOWN: la_SendMouseEvent(hwnd, LA_M_MOUSE_DOWN, PARAM_2_FROM(lparam)); break;    case WM_MBUTTONUP:   la_SendMouseEvent(hwnd, LA_M_MOUSE_UP, PARAM_2_FROM(lparam)); break;    case WM_MOUSEWHEEL:        POINT p; p.x=LOWORD(lparam); p.y=HIWORD(lparam); ScreenToClient(hwnd,&p);        if ((wheelmark = HIWORD(wparam)) > 0) WheelDir = LA_MOUSEUP;        else if ((wheelmark = HIWORD(wparam)) < 0) WheelDir = LA_MOUSEDOWN;        la_SendMouseEvent(hwnd, WheelDir|LA_KEY_MOUSE_SCROLL, p.x, p.y);        break;    case WT_PACKET:        if (!MAIN.InkOrWinTab) { break; /* Use Windows Ink. */ }        if (gpWTPacket((HCTX)lparam, wparam, &pkt)) {            MAIN.StylusPressure = (real)pkt.pkNormalPressure / MAIN.WinTabMaxPenPressure;            MAIN.StylusHover = (real)pkt.pkZ / MAIN.WinTabMaxHover;            real angle = (real)pkt.pkOrientation.orAzimuth / 3600 * TNS_PI * 2 + TNS_PI / 2;            MAIN.StylusOrientation = angle; MAIN.StylusDeviation = rad((90.0f - (real)pkt.pkOrientation.orAltitude / 10.0f));            real tw = (real)pkt.pkOrientation.orTwist; tw = rad(tw / 10);            MAIN.StylusTwist = tw;            if(TNS_DOUBLE_CLOSE_ENOUGH(tw,TNS_PI)){ MAIN.StylusHasTwist=0; }else{ MAIN.StylusHasTwist=1; }            MAIN.EraserDeviation = MAIN.StylusDeviation; MAIN.EraserOrientation = MAIN.StylusOrientation;            MAIN.EraserPressure = MAIN.StylusPressure;            MAIN.IsPen = 1; MAIN.PointerIsEraser = ((pkt.pkStatus & TPS_INVERT) == TPS_INVERT);            point.x = pkt.pkX; point.y = pkt.pkY; ScreenToClient(hwnd, &point);            la_SendMouseEvent(hwnd, LA_MOUSEMOVE, point.x, point.y);        }        return 0; break;    case WM_SYSCOMMAND:        switch (wparam) {        case SC_MAXIMIZE:        case SC_RESTORE:            la_CommandResizeWindow(hwnd, 0, 0, LOWORD(lparam), HIWORD(lparam));            break;        case SC_KEYMENU:            return 0;        case SC_MINIMIZE:            break;        }        break;    case WM_SIZE:        if (wparam == SIZE_MINIMIZED) break;    case WM_MOVE: /* And size */        la_CommandResizeWindow(hwnd, 0, 0, LOWORD(lparam), HIWORD(lparam));        break;    case WM_SETCURSOR:        if(MAIN.CurrentCursor) return 1;        break;    case WM_POINTERDOWN:    case WM_POINTERUP:    case WM_POINTERUPDATE:        if (MAIN.InkOrWinTab) { break;/* Use WinTab. */ }        pointerId = GET_POINTERID_WPARAM(wparam);        pointerType = PT_POINTER;        if(!GetPointerType(pointerId, &pointerType)){            pointerType = PT_POINTER;        }        if(pointerType == PT_PEN){            if(GetPointerPenInfoHistory(pointerId, &peninfonum, penInfo)){                for (int i = peninfonum-1; i>=0; i--) {                    point.x = penInfo[i].pointerInfo.ptPixelLocation.x; point.y = penInfo[i].pointerInfo.ptPixelLocation.y;                    ScreenToClient(hwnd, &point);                    MAIN.IsPen = 1; MAIN.StylusPressure = (real)penInfo[i].pressure / 1024; MAIN.PointerIsEraser = 0;                    switch (penInfo[i].pointerInfo.ButtonChangeType) {                    case POINTER_CHANGE_FIRSTBUTTON_DOWN: la_SendMouseEvent(hwnd, LA_L_MOUSE_DOWN, point.x, point.y); break;                    case POINTER_CHANGE_FIRSTBUTTON_UP: la_SendMouseEvent(hwnd, LA_L_MOUSE_UP, point.x, point.y); break;                    case POINTER_CHANGE_SECONDBUTTON_DOWN: la_SendMouseEvent(hwnd, LA_M_MOUSE_DOWN, point.x, point.y); break;                    case POINTER_CHANGE_SECONDBUTTON_UP: la_SendMouseEvent(hwnd, LA_M_MOUSE_UP, point.x, point.y); break;                    case POINTER_CHANGE_THIRDBUTTON_DOWN: la_SendMouseEvent(hwnd, LA_R_MOUSE_DOWN, point.x, point.y); break;                    case POINTER_CHANGE_THIRDBUTTON_UP: la_SendMouseEvent(hwnd, LA_R_MOUSE_UP, point.x, point.y); break;                    }                    la_SendMouseEvent(hwnd, LA_MOUSEMOVE, point.x, point.y);                }            }            SkipPointerFrameMessages(pointerId);            return 0;        }        else if (pointerType == PT_TOUCH){            if (GetPointerTouchInfo(pointerId, &touchInfo)) {                point.x = touchInfo.pointerInfo.ptPixelLocation.x; point.y = touchInfo.pointerInfo.ptPixelLocation.y;                ScreenToClient(hwnd, &point);                MAIN.IsPen = 1; MAIN.StylusPressure = (real)touchInfo.pressure / 1024; MAIN.PointerIsEraser = 1;            }        }        break;    case WM_SYSKEYDOWN:        //if (lparam & 0x40000000) break;        la_SendKeyboardEvent(hwnd, LA_KEY_DOWN, la_TranslateSpecialKey(wparam));        break;    case WM_KEYDOWN:        //if (lparam & 0x40000000) break;        vkey = wparam;        la_SendKeyboardEvent(hwnd, LA_KEY_DOWN, la_TranslateSpecialKey(vkey));        break;    case WM_KEYUP:        la_SendKeyboardEvent(hwnd, LA_KEY_UP, la_TranslateSpecialKey(wparam));        break;    case WM_SYSKEYUP:        la_SendKeyboardEvent(hwnd, LA_KEY_UP, la_TranslateSpecialKey(wparam));        break;    case WM_UNICHAR:        la_SendInputEvent(hwnd, wparam);        break;    case WM_IME_CHAR:        char character[3]; character[0]=(BYTE)(wparam>>8); character[1] = wparam; character[2]=0;        wchar_t buf[10]; MultiByteToWideChar(CP_ACP, 0, character, -1, buf, 9);        la_SendInputEvent(hwnd, buf[0]);        return 0;    case WM_CHAR:        la_SendInputEvent(hwnd, wparam);        break;    case WM_SHOWWINDOW:        //SendCommandEvent(hwnd, EVT_WND_SIZE_FINISH);        break;    case WM_CLOSE:        if (!la_OnWindowDestroy(hwnd)) return 0; return 1;        break;    default:        return DefWindowProc(hwnd, message, wparam, lparam);    }    return DefWindowProc(hwnd, message, wparam, lparam);}LRESULT CALLBACK LA_ProgressWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam){    switch (message) {    case WM_CLOSE:        return 0;    case WM_DESTROY:        return 0;    case LA_PROGRESS_REPAINT_MESSAGE:        InvalidateRect(MAIN.Progress.w, 0, 1);        int w = GetSystemMetrics(SM_CXFULLSCREEN), h = GetSystemMetrics(SM_CYFULLSCREEN);        int ww = PROGRESSW + LA_RH * 2;        SetWindowPos(MAIN.Progress.w, HWND_TOPMOST,w/2-ww/2,h/2-LA_RH*2/2,ww,LA_RH*2, 0);        return 0;    case WM_PAINT:        LA_ACQUIRE_DC        laBoxedTheme* bt = _LA_THEME_TAB; real* fg = laThemeColor(bt, LA_BT_TEXT); real* bg = laThemeColor(bt, LA_BT_NORMAL);        if (!MAIN.Progress.brush_bg) { MAIN.Progress.brush_bg = CreateSolidBrush(LA_COLOR3_TO_RGB(bg)); }        if (!MAIN.Progress.brush_fg) { MAIN.Progress.brush_fg = CreateSolidBrush(LA_COLOR3_TO_RGB(fg)); }        if (!MAIN.Progress.pen_fg) { MAIN.Progress.pen_fg = CreatePen(PS_SOLID, 2, LA_COLOR3_TO_RGB(fg)); }        RECT rect; GetClientRect(MAIN.Progress.w, &rect);        PAINTSTRUCT ps; BeginPaint(MAIN.Progress.w, &ps);        SelectObject(MAIN.Progress.hdc, MAIN.Progress.brush_bg);        Rectangle(MAIN.Progress.hdc, 0, 0, rect.right, rect.bottom);        SelectObject(MAIN.Progress.hdc, MAIN.Progress.brush_fg);        Rectangle(MAIN.Progress.hdc, LA_RH * 2, 0, LA_RH * 2 + PROGRESSW * MAIN.Progress.p1, LA_RH);        Rectangle(MAIN.Progress.hdc, LA_RH * 2, LA_RH, LA_RH * 2 + PROGRESSW * MAIN.Progress.p2, LA_RH + LA_RH);        SelectObject(MAIN.Progress.hdc, MAIN.Progress.pen_fg);        tnsDrawLCD7_ProgressSystem(LA_RH * 1.5, 0, MAIN.Progress.p1);        tnsDrawLCD7_ProgressSystem(LA_RH * 1.5, LA_RH, MAIN.Progress.p2);        EndPaint(MAIN.Progress.w, &ps);        LA_LEAVE_DC    }    return DefWindowProc(hwnd, message, wparam, lparam);}#endifvoid la_UpdateOperatorHints(laWindow* w){    laSafeString* ss=0;    for(laOperator* o=w->Operators.pFirst;o;o=o->Item.pNext){        if(o->RuntimeHint&&o->RuntimeHint->Ptr){ strSafePrint(&ss, "%s | %s  ", o->Type->Name, o->RuntimeHint->Ptr);}    }    if((w->OperatorHints&&ss&&strSame(ss->Ptr,w->OperatorHints->Ptr))||(!w->OperatorHints&&!ss)){ //pass    }else{        if(ss){ strSafeSet(&w->OperatorHints,ss->Ptr); } else { strSafeDestroy(&w->OperatorHints); }        laNotifyUsers("la.windows.operator_hints");//printf("op hint\n");    }    strSafeDestroy(&ss);}int la_HandleSingleEvent(laEvent *e, laListHandle *Operators){    laOperator *a, *NextA = 0;    int Result = 0;    laConfirmData *ConfirmData = 0, *NextConfirmData = 0;    la_SendSignalsFromEvent(e);    if(MAIN.InputProcess){ MAIN.CurrentInputEvent=e; MAIN.InputProcess(e); MAIN.CurrentInputEvent=0; }    a = Operators->pFirst;    la_DestroyConfirmData(&MAIN.InvokeConfirmData);    //la_PrintOperatorStack();    while (1){        if (!a) break;                if (a->StopNow){            NextA = a->Item.pNext;            if (a->Type->Exit) a->Type->Exit(a, Result);            ConfirmData = a->NextConfirmData;            if (a->ConfirmData) la_DestroyConfirmData(&a->ConfirmData);            NextConfirmData = ConfirmData;            a->ConfirmData = 0;            a->NextConfirmData = 0;            la_DestroyOperator(&a, Operators, 0);            a = NextA;            if (a){                a->ConfirmData = NextConfirmData;            }            continue;        }        a->Using = 1;        la_SetPropMathcerContext(a->ToPanel);        laSetOperatorLocalizer(a->ToPanel);        MAIN.CurrentPanel = a->ToPanel;        if (a->Type->ExtraMark & LA_EXTRA_TO_PANEL){            laWindowToLocal(a, a->ToPanel, &e->x, &e->y);            e->Localized = 1;        }        if (a->State & LA_BLOCK){ Result = a->Type->Modal(a, e); }                if (a->Type->ExtraMark & LA_EXTRA_TO_PANEL){            laLocalToWindow(a, a->ToPanel, &e->x, &e->y);            e->Localized = 0;        }        la_SetPropMathcerContext(0);        laSetOperatorLocalizer(0);        MAIN.CurrentPanel = 0;        a->Using = 0;        if (Result & LA_PASS_ON){            laConfirmSameDataIfAny(a);            NextA = a->Item.pNext;        }else{            NextA = 0;            if (a->NextConfirmData){                la_DestroyConfirmData(&a->NextConfirmData);            }        }        ConfirmData = a->NextConfirmData;        if (a->ConfirmData) la_DestroyConfirmData(&a->ConfirmData);        NextConfirmData = ConfirmData;        a->ConfirmData = 0;        a->NextConfirmData = 0;        if (Result & LA_FINISH || Result == LA_CANCEL || (a->StopNow && a->Using == 0)){            if (a->Type->Exit) a->Type->Exit(a, Result);            la_DestroyOperator(&a, Operators, 0);            int found=0;            for(laOperator*iop=Operators->pFirst;iop;iop=iop->Item.pNext){ if(iop==NextA){found=1;} }            if(!found){ NextA=0; }            if(Result == LA_OPERATOR_CALLS_SHUTOFF){ return 0; }        }        a = NextA;        if (a){            a->ConfirmData = NextConfirmData;        }    }    if (e->type==LA_PASTE && MAIN.PasteString) strSafeDestroy(&MAIN.PasteString);    return 1;}int la_HandleEvents(laWindow *w){    laEvent *e, *NextE;    laOperator *a;    laThreadNotifier *tn;    MAIN.CurrentWindow=w;    //laSpinLock(&MAIN.csNotifier);    while (tn = lstPopItem(&MAIN.ThreadNotifiers)){        //laSpinUnlock(&MAIN.csNotifier);        laNotifyUsers(tn->Path);        FreeMem(tn);        //if (MAIN.ThreadNotifiers.pFirst)            //laSpinLock(&MAIN.csNotifier);    }    //laSpinUnlock(&MAIN.csNotifier);    while (1){        if (MAIN.ReTriggerOperators) laSendOperatorTriggerEvent();        while (w->EventList.pFirst){            while (w->PendingOperators.pLast){                a = w->PendingOperators.pLast;                if (a->OperatorPanel){                    laSetOperatorLocalizer(a->OperatorPanel);                    if (a->OperatorPanel->Mode == LA_PANEL_FLOATING_TOP)                        laInvokeUi(a, "LA_modal_panel_operator", 0, a->OperatorPanel, 0, 1);                }                lstRemoveItem(&w->PendingOperators, a);                lstPushItem(&w->Operators, a);            }            e = lstPopItem(&w->EventList);            if (e && !w->Operators.pFirst){ laInvokeUi(0, "LA_window_operator", e, w, 0, 0); }            if (e) if(!la_HandleSingleEvent(e, &w->Operators)){ la_StopAllOperators(); memFree(e); return 0; } //EXIT            memFree(e);        }        MAIN.ControllerHasNewAxis = MAIN.ControllerHasNewKey = 0;        if (!MAIN.ReTriggerOperators) break;    }    la_UpdateOperatorHints(w);    return 1;}int la_AccpetedUnicodeInput(uint32_t ch){    if(ch>=32 || ch==U'\n' || ch==U'\t' || ch==U'\b') return 1;    return 0;}int laCopyToClipboard(unsigned char * text){#ifdef LA_LINUX	XEvent event; SYSWINDOW owner, window=MAIN.CurrentWindow->win;	XSetSelectionOwner(MAIN.dpy, MAIN.selection, window, 0);	if (XGetSelectionOwner (MAIN.dpy, MAIN.selection) != window) return 0;    strSafeSet(&MAIN.CopyPending, text);    return 1;#endif#ifdef _WIN32    OpenClipboard(GetDesktopWindow());    EmptyClipboard();    size_t allocsize = strlen(text) + 1;    HGLOBAL hg = GlobalAlloc(GMEM_MOVEABLE, allocsize);    if (!hg){ CloseClipboard(); return 0; }    memcpy(GlobalLock(hg), text, allocsize);    GlobalUnlock(hg);    SetClipboardData(CF_TEXT, hg);    CloseClipboard();    GlobalFree(hg);    return 1;#endif    return 0;}void laDisableIME(laWindow* w) {#ifdef _WIN32    ImmAssociateContext(w->win, 0);#endif}void laEnableIME(laWindow* w) {#ifdef _WIN32    if(w->himc) ImmAssociateContext(w->win, w->himc);#endif}int la_ProcessSysMessage(){    int SendDelay = 0, SendIdle = 0;    if (!MAIN.DelayTriggered && MAIN.TimeAccum - MAIN.DelayStart > MAIN.DelayTime) SendDelay = 1;    if (!MAIN.IdleTriggered && MAIN.TimeAccum - MAIN.IdleStart > MAIN.IdleTime) SendIdle = 1;#ifdef LA_LINUX    XEvent e;    int type;    int InputCount = 0, CharCount=0;    KeySym InputKeysym = 0;    Status InputStatus = 0;    laWindow* wnd ;    while(XPending(MAIN.dpy)){        XGenericEventCookie *cookie = &e.xcookie;        XNextEvent(MAIN.dpy, &e);        if (XFilterEvent(&e, None)) continue;        SendIdle=0; MAIN.IdleStart=MAIN.TimeAccum; MAIN.IdleTriggered=0;        if (cookie->type == GenericEvent && cookie->extension == MAIN.xi_opcode && XGetEventData(MAIN.dpy, cookie)){            if (cookie->evtype == XI_RawMotion) la_RecordWacomMotions(cookie->data);            XFreeEventData(MAIN.dpy, cookie); continue;        }                    switch(e.type){        case ConfigureNotify:            la_CommandResizeWindow(e.xconfigure.window, e.xconfigure.x, e.xconfigure.y, e.xconfigure.width, e.xconfigure.height);            break;        case Expose:            wnd = lstFindItem(e.xexpose.window, la_IsThisSysWindow, &MAIN.Windows);            if(!wnd) break;            laRefreshWindow(wnd);            break;        case MotionNotify:            la_SendMouseEvent(e.xmotion.window, LA_MOUSEMOVE, e.xmotion.x,e.xmotion.y);            MAIN.IsPen=0;            break;        case ButtonPress:            type=LA_MOUSEDOWN;            if(e.xbutton.button==1){type|=LA_KEY_MOUSE_LEFT;}            elif(e.xbutton.button==2){type|=LA_KEY_MOUSE_MIDDLE;}            elif(e.xbutton.button==3){type|=LA_KEY_MOUSE_RIGHT;}            elif(e.xbutton.button==4){type=LA_MOUSEUP|LA_KEY_MOUSE_SCROLL;}            elif(e.xbutton.button==5){type=LA_MOUSEDOWN|LA_KEY_MOUSE_SCROLL;}            la_SendMouseEvent(e.xbutton.window, type, e.xbutton.x,e.xbutton.y);            MAIN.IsPen=0;            break;        case ButtonRelease:            type=LA_MOUSEUP;            if(e.xbutton.button==1){type|=LA_KEY_MOUSE_LEFT;}            elif(e.xbutton.button==2){type|=LA_KEY_MOUSE_MIDDLE;}            elif(e.xbutton.button==3){type|=LA_KEY_MOUSE_RIGHT;}            la_SendMouseEvent(e.xbutton.window, type, e.xbutton.x,e.xbutton.y);            MAIN.IsPen=0;            break;        case KeyPress:                InputCount=Xutf8LookupString(MAIN.ic, (XKeyPressedEvent*)&e, MAIN.InputBuf, MAIN.InputBufMax, &InputKeysym, &InputStatus);                MAIN.InputBuf[InputCount]=0;                if (InputStatus==XBufferOverflow)  printf("XInputBufferOverflow\n");                if (InputStatus == XLookupKeySym || InputStatus == XLookupBoth) { /*printf("status: %d\n", InputStatus);*/ }            if (InputCount){ MAIN.InputBuf[InputCount]=0; } strToUnicode(MAIN.InputBufU,MAIN.InputBuf); int UCount=strlenU(MAIN.InputBufU);            for(int i=0;i<UCount;i++){ if(la_AccpetedUnicodeInput(MAIN.InputBufU[i])) la_SendInputEvent(e.xkey.window, MAIN.InputBufU[i]); }            XKeyboardState x; XGetKeyboardControl(MAIN.dpy, &x);            int numlock=0; if(x.led_mask & 2){ numlock=1; }            if(InputKeysym=XkbKeycodeToKeysym(e.xkey.display, e.xkey.keycode, 0, 0)){#ifdef DEBUG                printf("pressed KEY: %d\n", (int)InputKeysym);#endif                if(/*numlock && */InputKeysym>=XK_KP_Space && InputKeysym<=XK_KP_9){                    InputKeysym=XkbKeycodeToKeysym(e.xkey.display, e.xkey.keycode, 0, 1);                }                la_SendKeyboardEvent(e.xkey.window, LA_KEY_DOWN, la_TranslateSpecialKey(InputKeysym));            }            break;        case KeyRelease:            if(InputKeysym=XkbKeycodeToKeysym(e.xkey.display, e.xkey.keycode, 0, 0)){                la_SendKeyboardEvent(e.xkey.window, LA_KEY_UP, la_TranslateSpecialKey(InputKeysym));            }        case ClientMessage:            if(e.xclient.data.l[0]==MAIN.MsgDelWindow){                if(la_OnWindowDestroy(e.xclient.window)){ return 0; }            }            break;        case SelectionNotify:            if(e.xselection.selection != MAIN.bufid) continue;            if (e.xselection.property){                char *result; unsigned long ressize, restail; int resbits; Atom fmtid;                XGetWindowProperty(MAIN.dpy, MAIN.CurrentWindow->win, MAIN.propid, 0, LONG_MAX/4, False, AnyPropertyType,                &fmtid, &resbits, &ressize, &restail, (unsigned char**)&result);                if (fmtid == MAIN.incrid) logPrintNew("Pasted buffer is too large and INCR reading is not implemented yet.\n");                else if(result) { strSafeSet(&MAIN.PasteString,result); }                XFree(result);                return True;            }        case SelectionRequest:            if(!MAIN.CopyPending){ break; }            char* text=MAIN.CopyPending->Ptr; int size=strlen(text);			if (e.xselectionrequest.selection != MAIN.selection) break;			XSelectionRequestEvent * xsr = &e.xselectionrequest;			XSelectionEvent ev = {0};			int R = 0;			ev.type = SelectionNotify, ev.display = xsr->display, ev.requestor = xsr->requestor,			ev.selection = xsr->selection, ev.time = xsr->time, ev.target = xsr->target, ev.property = xsr->property;			if (ev.target == MAIN.targets_atom) R = XChangeProperty (ev.display, ev.requestor, ev.property, XA_ATOM, 32,					PropModeReplace, (unsigned char*)&MAIN.UTF8, 1);			else if (ev.target == XA_STRING || ev.target == MAIN.text_atom) 				R = XChangeProperty(ev.display, ev.requestor, ev.property, XA_STRING, 8, PropModeReplace, text, size);			else if (ev.target == MAIN.UTF8)				R = XChangeProperty(ev.display, ev.requestor, ev.property, MAIN.UTF8, 8, PropModeReplace, text, size);			else ev.property = None;			if ((R & 2) == 0) XSendEvent (MAIN.dpy, ev.requestor, 0, 0, (XEvent *)&ev);			break;        case SelectionClear:			break;        default:            break;        }    }#endif //linux#ifdef _WIN32    MSG msg; int Processed = 0;    if (PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE) != 0) Processed = 1;    while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {        //if (msg.wParam == VK_PROCESSKEY) {        //    msg.wParam = ImmGetVirtualKey(msg.hwnd);        //}        TranslateMessage(&msg); DispatchMessage(&msg);        SendIdle = 0; MAIN.IdleStart = MAIN.TimeAccum; MAIN.IdleTriggered = 0;    };    if(!MAIN.Windows.pFirst){ return 0; }#endif#ifdef LAGUI_ANDROID    int pollResult = 0;    int pollEvents = 0;    while ((pollResult = ALooper_pollAll(MAIN.AppEnabled? 0 : -1, NULL, &pollEvents, (void**)&MAIN.event_source)) >= 0){        if (MAIN.event_source != NULL) MAIN.event_source->process(MAIN.app, MAIN.event_source);        // NOTE: Never close window, native activity is controlled by the system!        if (MAIN.app->destroyRequested != 0)        {            //CORE.Window.shouldClose = true;            //ANativeActivity_finish(MAIN.app->activity);        }    }#endif    for(laWindow* w=MAIN.Windows.pFirst;w;w=w->Item.pNext){        if(SendDelay) { la_SendTimerEvent(w->win, LA_TIME_DELAY); MAIN.DelayTriggered=1; }        if(SendIdle) { la_SendTimerEvent(w->win, LA_TIME_IDLE);  MAIN.IdleTriggered=1; }    }    return 1;};void la_PrintOperatorStack(){    laWindow *w = MAIN.CurrentWindow;    laOperator *a;    printf("\n");    for (a = w->Operators.pFirst; a; a = a->Item.pNext){        printf("OP [%-25s] For [0x%08x]  Child[%-25s][0x%08x]\n",               a->Type->Identifier, a->Instance,               (a->Child ? a->Child->Type->Identifier : ""), a->Child);    }}void la_DrawWindow(laWindow *w){    if(!w->Redraw) return; w->Redraw=0; w->RedrawTouched=1;    MAIN.CurrentWindow = w;    la_WindowDefDraw(w, 0);}void laset_UiRowHeight(void* unused, int val);int laFinalize(){    if(!laValidateProperties()){ laShutoff(0); return 0; }    if(!MAIN.Themes.pFirst){        la_CreateClassicLightTheme();        la_CreateClassicDarkTheme();    }    la_RefreshThemeColor(MAIN.CurrentTheme);        laUiTemplate* uit;    while(uit=lstPopItem(&MAIN.InitPanelTemplates)) lstAppendItem(&MAIN.PanelTemplates,uit);    laset_UiRowHeight(0, LA_RH0);    return 1;}void la_PreFrame(){    if(MAIN.PreFrame){ MAIN.PreFrame(); }    la_AnimationPreFrame();    if(MAIN.InitArgs.HasAudio) la_AudioPreFrame();}void la_PostFrame(){    laPanel* p; while(p=lstPopPointer(&MAIN.DeferredRedrawList)){ laRedrawPanel(p); }    if(MAIN.PostFrame){ MAIN.PostFrame(); }}void laMainLoop(){    laWindow *w = MAIN.Windows.pFirst, *NextW;    time_t t1, t2;    real TimeInterval, Pause, TimeAccum = 0, FrameInterval;    static int a = 0;    if(!laFinalize()) return;    laSetWindowCursor(LA_ARROW);    MAIN.DelayTriggered=1;#ifdef LAGUI_ANDROID    while(!MAIN.AppReady){ usleep(1000); }    la_CommandResizeWindow(0,0,0,MAIN.AppWidth,MAIN.AppHeight);#endif        while (1){        laRecordTime(&MAIN.FrameStartTime);        la_PerfClear();        la_PreFrame();        if(!la_ProcessSysMessage()){ return; }        la_UpdateControllerStatus();        if(MAIN.GraphNeedsRebuild){ MAIN.GraphNeedsRebuild = 0; }        for (w=MAIN.Windows.pFirst;w;w = NextW){            NextW = w->Item.pNext;            if(!la_HandleEvents(w)){ laShutoff(1); return; }        }        if(MAIN.PreDraw){ MAIN.PreDraw(); }        for(w=MAIN.Windows.pFirst;w;w=w->Item.pNext){            tnsSwitchToCurrentWindowContext(w); la_SetupWindowGLStates(w);            if(MAIN.GLDebugNeedsUpdate){                la_SetCurrentGLContextDebug();            }            la_DrawWindow(w);        }        for(w=MAIN.Windows.pFirst;w;w=w->Item.pNext){            if(!w->RedrawTouched) continue; w->RedrawTouched=0;#ifdef LA_LINUX    #ifdef LA_USE_GLES            eglSwapBuffers(MAIN.egl_dpy, w->egl_surf);    #else            glXSwapBuffers(MAIN.dpy, w->win); //XSync(MAIN.dpy,0);    #endif#endif#ifdef _WIN32            SwapBuffers(w->hdc);#endif#ifdef LAGUI_ANDROID            eglSwapBuffers(MAIN.egl_dpy, MAIN.egl_surf);#endif        }        MAIN.GLDebugNeedsUpdate=0;        la_PostFrame();        //t2 = clock();        laRecordTime(&MAIN.FrameEndTime);        TimeInterval = laTimeElapsedSecondsf(&MAIN.FrameEndTime, &MAIN.FrameStartTime);        Pause = (1.0 / MAIN.TopFramerate - TimeInterval);        if (Pause > 0){            int us = Pause * 1000000.0;            usleep(us);        }        MAIN.TimeAccum += (MAIN.LastFrameTime = Pause+TimeInterval);        //FrameInterval = 1.0 / MAIN.Animation.FrameRate;        la_AnimationPostFrame();    }}#ifdef LAGUI_ANDROIDint la_AndroidInitGraphics(void){    MAIN.AppWidth=ANativeWindow_getWidth(MAIN.app->window);    MAIN.AppHeight=ANativeWindow_getHeight(MAIN.app->window);    logPrintNew("Android init graphics %d x %d", MAIN.AppWidth, MAIN.AppHeight);    la_CommandResizeWindow(0,0,0,MAIN.AppWidth,MAIN.AppHeight);    EGLint samples = 0;    EGLint sampleBuffer = 0;    const EGLint framebufferAttribs[] = {        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,      // Type of context support        EGL_RED_SIZE, 8,            // RED color bit depth (alternative: 5)        EGL_GREEN_SIZE, 8,          // GREEN color bit dept<android/log.h>h (alternative: 6)        EGL_BLUE_SIZE, 8,           // BLUE color bit depth (alternative: 5)        //EGL_TRANSPARENT_TYPE, EGL_NONE, // Request transparent framebuffer (EGL_TRANSPARENT_RGB does not work on RPI)        EGL_DEPTH_SIZE, 16,         // Depth buffer size (Required to use Depth testing!)        //EGL_STENCIL_SIZE, 8,      // Stencil buffer size        EGL_SAMPLE_BUFFERS, sampleBuffer,    // Activate MSAA        EGL_SAMPLES, samples,       // 4x Antialiasing if activated (Free on MALI GPUs)        EGL_NONE    };    const EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE };    EGLint numConfigs = 0;    MAIN.egl_dpy=eglGetDisplay(EGL_DEFAULT_DISPLAY);    if (MAIN.egl_dpy == EGL_NO_DISPLAY){ logPrint("Android no display"); return -1; }    if (eglInitialize(MAIN.egl_dpy, NULL, NULL) == EGL_FALSE){ logPrint("Android can't init display");  return -1; }    eglChooseConfig(MAIN.egl_dpy, framebufferAttribs, &MAIN.BestFBC, 1, &numConfigs);    eglBindAPI(EGL_OPENGL_API);    MAIN.glc = eglCreateContext(MAIN.egl_dpy, MAIN.BestFBC, EGL_NO_CONTEXT, contextAttribs);    if (MAIN.glc == EGL_NO_CONTEXT){ logPrint("Android can't create context");  return -1; }    EGLint displayFormat = 0;    eglGetConfigAttrib(MAIN.egl_dpy, MAIN.BestFBC, EGL_NATIVE_VISUAL_ID, &displayFormat);    ANativeWindow_setBuffersGeometry(MAIN.app->window, MAIN.AppWidth, MAIN.AppHeight, displayFormat);    MAIN.egl_surf = eglCreateWindowSurface(MAIN.egl_dpy, MAIN.BestFBC, MAIN.app->window, NULL);    // There must be at least one frame displayed before the buffers are swapped    eglSwapInterval(MAIN.egl_dpy, 1);    if (eglMakeCurrent(MAIN.egl_dpy, MAIN.egl_surf, MAIN.egl_surf, MAIN.glc) == EGL_FALSE) { logPrint("Android can't make current"); return -1; }    eglSwapBuffers(MAIN.egl_dpy, MAIN.egl_surf);    MAIN.AppReady = 1;    return 0;}static void la_AndroidCommandCallback(struct android_app *app, int32_t cmd){    switch (cmd){    case APP_CMD_START: break;    case APP_CMD_GAINED_FOCUS: MAIN.AppEnabled = 1; break;    case APP_CMD_LOST_FOCUS: MAIN.AppEnabled = 0; break;    case APP_CMD_RESUME:break;//InitPlatform();break;    case APP_CMD_INIT_WINDOW:        if (app->window != NULL){            if (MAIN.ContextRebindRequired){                // Reset screen scaling to full display size                EGLint displayFormat = 0;                eglGetConfigAttrib(MAIN.egl_dpy, MAIN.BestFBC, EGL_NATIVE_VISUAL_ID, &displayFormat);                // Adding renderOffset here feels rather hackish, but the viewport scaling is wrong after the                // context rebinding if the screen is scaled unless offsets are added. There's probably a more                // appropriate way to fix this                MAIN.AppWidth=ANativeWindow_getWidth(MAIN.app->window);                MAIN.AppHeight=ANativeWindow_getHeight(MAIN.app->window);                ANativeWindow_setBuffersGeometry(app->window,MAIN.AppWidth,MAIN.AppHeight,                    displayFormat);                // Recreate display surface and re-attach OpenGL context                MAIN.egl_surf = eglCreateWindowSurface(MAIN.egl_dpy, MAIN.BestFBC, app->window, NULL);                eglMakeCurrent(MAIN.egl_dpy, MAIN.egl_surf, MAIN.egl_surf, MAIN.glc);                //glViewport(0,0,MAIN.AppWidth,MAIN.AppHeight);                //glClearColor(1,0.2,1,1);                //glClear(GL_COLOR_BUFFER_BIT);                //eglSwapBuffers(MAIN.egl_dpy, MAIN.egl_surf);                la_CommandResizeWindow(0,0,0,MAIN.AppWidth,MAIN.AppHeight);                MAIN.ContextRebindRequired = false;            }else{                la_AndroidInitGraphics();            }        }        break;    case APP_CMD_DESTROY:    case APP_CMD_TERM_WINDOW:        // Detach OpenGL context and destroy discom.yiming.helloplay surface        // NOTE 1: This case is used when the user exits the app without closing it. We detach the context to ensure everything is recoverable upon resuming.        // NOTE 2: Detaching context before destroying display surface avoids losing our resources (textures, shaders, VBOs...)        // NOTE 3: In some cases (too many context loaded), OS could unload context automatically... :(        if (MAIN.egl_dpy != EGL_NO_DISPLAY) {            eglMakeCurrent(MAIN.egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);            if (MAIN.egl_surf != EGL_NO_SURFACE) {                eglDestroySurface(MAIN.egl_dpy, MAIN.egl_surf);                MAIN.egl_surf = EGL_NO_SURFACE;            }            MAIN.ContextRebindRequired = true;        }        // If 'MAIN.egl_dpy' is already set to 'EGL_NO_DISPLAY'        // this means that the user has already called 'CloseWindow()'        break;    case APP_CMD_SAVE_STATE: break;    case APP_CMD_STOP: break;    case APP_CMD_CONFIG_CHANGED:    case APP_CMD_WINDOW_RESIZED:        MAIN.AppWidth=ANativeWindow_getWidth(MAIN.app->window);        MAIN.AppHeight=ANativeWindow_getHeight(MAIN.app->window);                la_CommandResizeWindow(0,0,0,MAIN.AppWidth,MAIN.AppHeight);        //AConfiguration_fromAssetManager(MAIN.app->config, MAIN.app->activity->assetManager);        //print_cur_config(MAIN.app);        // Check screen orientation here!        if (MAIN.egl_dpy != EGL_NO_DISPLAY) {            eglMakeCurrent(MAIN.egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);            if (MAIN.egl_surf != EGL_NO_SURFACE) {                eglDestroySurface(MAIN.egl_dpy, MAIN.egl_surf);                MAIN.egl_surf = EGL_NO_SURFACE;            }            EGLint displayFormat = 0;            eglGetConfigAttrib(MAIN.egl_dpy, MAIN.BestFBC, EGL_NATIVE_VISUAL_ID, &displayFormat);            ANativeWindow_setBuffersGeometry(app->window,MAIN.AppWidth,MAIN.AppHeight,                displayFormat);            MAIN.egl_surf = eglCreateWindowSurface(MAIN.egl_dpy, MAIN.BestFBC, app->window, NULL);            eglMakeCurrent(MAIN.egl_dpy, MAIN.egl_surf, MAIN.egl_surf, MAIN.glc);        }        break;    default: break;    }}#define KEYCODE_MAP_SIZE 162static const int KeycodeMap[KEYCODE_MAP_SIZE] = {    0,           // AKEYCODE_UNKNOWN    0,                  // AKEYCODE_SOFT_LEFT    0,                  // AKEYCODE_SOFT_RIGHT    0,                  // AKEYCODE_HOME    0,           // AKEYCODE_BACK    0,                  // AKEYCODE_CALL    0,                  // AKEYCODE_ENDCALL    '0',           // AKEYCODE_0    '1',            // AKEYCODE_1    '2',            // AKEYCODE_2    '3',          // AKEYCODE_3    '4',           // AKEYCODE_4    '5',           // AKEYCODE_5    '6',            // AKEYCODE_6    '7',          // AKEYCODE_7    '8',          // AKEYCODE_8    '9',           // AKEYCODE_9    0,                  // AKEYCODE_STAR    0,                  // AKEYCODE_POUND    LA_KEY_ARRUP,             // AKEYCODE_DPAD_UP    LA_KEY_ARRDOWN,           // AKEYCODE_DPAD_DOWN    LA_KEY_ARRLEFT,           // AKEYCODE_DPAD_LEFT    LA_KEY_ARRRIGHT,          // AKEYCODE_DPAD_RIGHT    0,                  // AKEYCODE_DPAD_CENTER    0,      // AKEYCODE_VOLUME_UP    0,    // AKEYCODE_VOLUME_DOWN    0,                  // AKEYCODE_POWER    0,                  // AKEYCODE_CAMERA    0,                  // AKEYCODE_CLEAR    'a',              // AKEYCODE_A    'b',              // AKEYCODE_B    'c',              // AKEYCODE_C    'd',              // AKEYCODE_D    'e',              // AKEYCODE_E    'f',              // AKEYCODE_F    'g',              // AKEYCODE_G    'h',              // AKEYCODE_H    'i',              // AKEYCODE_I    'j',              // AKEYCODE_J    'k',              // AKEYCODE_K    'l',              // AKEYCODE_L    'm',              // AKEYCODE_M    'n',              // AKEYCODE_N    'o',              // AKEYCODE_O    'p',              // AKEYCODE_P    'q',              // AKEYCODE_Q    'r',              // AKEYCODE_R    's',              // AKEYCODE_S    't',              // AKEYCODE_T    'u',              // AKEYCODE_U    'v',              // AKEYCODE_V    'w',              // AKEYCODE_W    'x',              // AKEYCODE_X    'y',              // AKEYCODE_Y    'z',              // AKEYCODE_Z    ',',          // AKEYCODE_COMMA    '.',         // AKEYCODE_PERIOD    LA_KEY_ALT,       // AKEYCODE_ALT_LEFT    LA_KEY_ALT,      // AKEYCODE_ALT_RIGHT    LA_KEY_SHIFT,     // AKEYCODE_SHIFT_LEFT    LA_KEY_SHIFT,    // AKEYCODE_SHIFT_RIGHT    LA_KEY_TAB,            // AKEYCODE_TAB    ' ',          // AKEYCODE_SPACE    0,                  // AKEYCODE_SYM    0,                  // AKEYCODE_EXPLORER    0,                  // AKEYCODE_ENVELOPE    LA_KEY_ENTER,          // AKEYCODE_ENTER    LA_KEY_BACKSPACE,      // AKEYCODE_DEL    '`',          // AKEYCODE_GRAVE    '-',          // AKEYCODE_MINUS    '=',          // AKEYCODE_EQUALS    '(',   // AKEYCODE_LEFT_BRACKET    ')',  // AKEYCODE_RIGHT_BRACKET    '\\',      // AKEYCODE_BACKSLASH    ';',      // AKEYCODE_SEMICOLON    '\'',     // AKEYCODE_APOSTROPHE    '/',          // AKEYCODE_SLASH    0,                  // AKEYCODE_AT    0,                  // AKEYCODE_NUM    0,                  // AKEYCODE_HEADSETHOOK    0,                  // AKEYCODE_FOCUS    0,                  // AKEYCODE_PLUS    0,           // AKEYCODE_MENU    0,                  // AKEYCODE_NOTIFICATION    0,                  // AKEYCODE_SEARCH    0,                  // AKEYCODE_MEDIA_PLAY_PAUSE    0,                  // AKEYCODE_MEDIA_STOP    0,                  // AKEYCODE_MEDIA_NEXT    0,                  // AKEYCODE_MEDIA_PREVIOUS    0,                  // AKEYCODE_MEDIA_REWIND    0,                  // AKEYCODE_MEDIA_FAST_FORWARD    0,                  // AKEYCODE_MUTE    0,        // AKEYCODE_PAGE_UP    0,      // AKEYCODE_PAGE_DOWN    0,                  // AKEYCODE_PICTSYMBOLS    0,                  // AKEYCODE_SWITCH_CHARSET    0,                  // AKEYCODE_BUTTON_A    0,                  // AKEYCODE_BUTTON_B    0,                  // AKEYCODE_BUTTON_C    0,                  // AKEYCODE_BUTTON_X    0,                  // AKEYCODE_BUTTON_Y    0,                  // AKEYCODE_BUTTON_Z    0,                  // AKEYCODE_BUTTON_L1    0,                  // AKEYCODE_BUTTON_R1    0,                  // AKEYCODE_BUTTON_L2    0,                  // AKEYCODE_BUTTON_R2    0,                  // AKEYCODE_BUTTON_THUMBL    0,                  // AKEYCODE_BUTTON_THUMBR    0,                  // AKEYCODE_BUTTON_START    0,                  // AKEYCODE_BUTTON_SELECT    0,                  // AKEYCODE_BUTTON_MODE    LA_KEY_ESCAPE,         // AKEYCODE_ESCAPE    LA_KEY_DELETE,         // AKEYCODE_FORWARD_DELL    LA_KEY_CTRL,   // AKEYCODE_CTRL_LEFT    LA_KEY_CTRL,  // AKEYCODE_CTRL_RIGHT    0,      // AKEYCODE_CAPS_LOCK    0,    // AKEYCODE_SCROLL_LOCK    LA_KEY_ARRLEFT,     // AKEYCODE_META_LEFT    LA_KEY_ARRRIGHT,    // AKEYCODE_META_RIGHT    0,                  // AKEYCODE_FUNCTION    0,   // AKEYCODE_SYSRQ    0,          // AKEYCODE_BREAK    0,           // AKEYCODE_MOVE_HOME    0,            // AKEYCODE_MOVE_END    0,         // AKEYCODE_INSERT    0,                  // AKEYCODE_FORWARD    0,                  // AKEYCODE_MEDIA_PLAY    0,                  // AKEYCODE_MEDIA_PAUSE    0,                  // AKEYCODE_MEDIA_CLOSE    0,                  // AKEYCODE_MEDIA_EJECT    0,                  // AKEYCODE_MEDIA_RECORD    LA_KEY_F1,             // AKEYCODE_F1    LA_KEY_F2,             // AKEYCODE_F2    LA_KEY_F3,             // AKEYCODE_F3    LA_KEY_F4,             // AKEYCODE_F4    LA_KEY_F5,             // AKEYCODE_F5    LA_KEY_F6,             // AKEYCODE_F6    LA_KEY_F7,             // AKEYCODE_F7    LA_KEY_F8,             // AKEYCODE_F8    LA_KEY_F9,             // AKEYCODE_F9    LA_KEY_F10,            // AKEYCODE_F10    LA_KEY_F11,            // AKEYCODE_F11    LA_KEY_F12,            // AKEYCODE_F12    0,       // AKEYCODE_NUM_LOCK    LA_KEY_NUM0,           // AKEYCODE_NUMPAD_0    LA_KEY_NUM1,           // AKEYCODE_NUMPAD_1    LA_KEY_NUM2,           // AKEYCODE_NUMPAD_2    LA_KEY_NUM3,           // AKEYCODE_NUMPAD_3    LA_KEY_NUM4,           // AKEYCODE_NUMPAD_4    LA_KEY_NUM5,           // AKEYCODE_NUMPAD_5    LA_KEY_NUM6,           // AKEYCODE_NUMPAD_6    LA_KEY_NUM7,           // AKEYCODE_NUMPAD_7    LA_KEY_NUM8,           // AKEYCODE_NUMPAD_8    LA_KEY_NUM9,           // AKEYCODE_NUMPAD_9    LA_KEY_NUMDIVIDE,      // AKEYCODE_NUMPAD_DIVIDE    LA_KEY_NUMMULT,    // AKEYCODE_NUMPAD_MULTIPLY    LA_KEY_NUMMINUS,    // AKEYCODE_NUMPAD_SUBTRACT    LA_KEY_NUMPLUS,         // AKEYCODE_NUMPAD_ADD    LA_KEY_NUMDOT,     // AKEYCODE_NUMPAD_DOT    0,                  // AKEYCODE_NUMPAD_COMMA    LA_KEY_NUMENTER,       // AKEYCODE_NUMPAD_ENTER    '='        // AKEYCODE_NUMPAD_EQUALS};static int32_t la_AndroidInputCallback(struct android_app *app, AInputEvent *event){    if(!MAIN.AppEnabled){return 0;}    //laRedrawAllWindows();    static int prev_button_state=0;    int type = AInputEvent_getType(event);    if(type == AINPUT_EVENT_TYPE_KEY){        int32_t keycode = AKeyEvent_getKeyCode(event);        //int32_t AKeyEvent_getMetaState(event);        int key = (keycode > 0 && keycode < KEYCODE_MAP_SIZE) ? KeycodeMap[keycode] : 0;        if (key != 0){            // Save current key and its state            // NOTE: Android key action is 0 for down and 1 for up            if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN){                la_SendKeyboardEvent(0,LA_KEY_DOWN,key);                if(key!=LA_KEY_BACKSPACE)                    la_SendInputEvent(0,key);            }            else if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_MULTIPLE){                la_SendKeyboardEvent(0,LA_KEY_DOWN,key);                la_SendInputEvent(0,key);            }            else la_SendKeyboardEvent(0,LA_KEY_UP,key);  // Key up        }        if (keycode == AKEYCODE_POWER)        {            // Let the OS handle input to avoid app stuck. Behaviour: CMD_PAUSE -> CMD_SAVE_STATE -> CMD_STOP -> CMD_CONFIG_CHANGED -> CMD_LOST_FOCUS            // Resuming Behaviour: CMD_START -> CMD_RESUME -> CMD_CONFIG_CHANGED -> CMD_CONFIG_CHANGED -> CMD_GAINED_FOCUS            // It seems like locking mobile, screen size (CMD_CONFIG_CHANGED) is affected.            // NOTE: AndroidManifest.xml must have <activity android:configChanges="orientation|keyboardHidden|screenSize" >            // Before that change, activity was calling CMD_TERM_WINDOW and CMD_DESTROY when locking mobile, so that was not a normal behaviour            return 0;        }        else if ((keycode == AKEYCODE_BACK) || (keycode == AKEYCODE_MENU))        {            // Eat BACK_BUTTON and AKEYCODE_MENU, just do nothing... and don't let to be handled by OS!            return 1;        }        else if ((keycode == AKEYCODE_VOLUME_UP) || (keycode == AKEYCODE_VOLUME_DOWN))        {            // Set default OS behaviour            return 0;        }        return 0;    }    elif(type == AINPUT_EVENT_TYPE_MOTION){        static real zoom_offset=1; static real temp_distance=0;        real zoom; int gesture_handled=0;        int pcount = AMotionEvent_getPointerCount(event); int x,y; static real cx=0,cy=0;        int32_t action = AMotionEvent_getAction(event);        unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;        int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;        real rx=AMotionEvent_getX(event, 0), ry=AMotionEvent_getY(event, 0);        if(pcount){            x=rx; y=ry;            int tool_type=AMotionEvent_getToolType(event,0);            real pressure = AMotionEvent_getAxisValue(event,AMOTION_EVENT_AXIS_PRESSURE,0);            if(tool_type == AMOTION_EVENT_TOOL_TYPE_STYLUS || tool_type==AMOTION_EVENT_TOOL_TYPE_ERASER){                MAIN.StylusPressure = MAIN.EraserPressure = pressure; MAIN.IsPen = 1;                 MAIN.PointerIsEraser = (tool_type==AMOTION_EVENT_TOOL_TYPE_ERASER);            }else{                MAIN.IsPen = 0;            }            if(pcount>=2 && (flags!=AMOTION_EVENT_ACTION_UP) && (flags!=AMOTION_EVENT_ACTION_CANCEL)                && (flags!=AMOTION_EVENT_ACTION_POINTER_UP)){                real x2=AMotionEvent_getX(event, 1), y2=AMotionEvent_getY(event, 1);                real ctx=(x+x2)/2, cty=(y+y2)/2;                real distance = tnsDistIdv2(x2,y2,rx,ry);                if(temp_distance){ zoom_offset*=(distance/temp_distance); }                temp_distance = distance;                while(zoom_offset > 1.1){ zoom_offset-=0.1;                     la_SendMouseEvent(0, LA_L_MOUSE_UP, x,y);                    la_SendMouseEvent(0, LA_MOUSEUP|LA_KEY_MOUSE_SCROLL, x,y); gesture_handled=1;                }                while(zoom_offset < (1.0/1.1)){ zoom_offset+=(0.1/1.1);                     la_SendMouseEvent(0, LA_L_MOUSE_UP, x,y);                    la_SendMouseEvent(0, LA_MOUSEDOWN|LA_KEY_MOUSE_SCROLL, x,y); gesture_handled=1;                }                if(cx || cy){                    if(!gesture_handled){                        real dist = tnsDistIdv2(ctx,cty,cx,cy);                        while(dist > LA_RH){                            int udlr = fabs(cty-cy) > fabs(ctx-cx);                            int direction = udlr?(cty>cy?LA_KEY_ARRUP:LA_KEY_ARRDOWN):                                                 (ctx>cx?LA_KEY_ARRLEFT:LA_KEY_ARRRIGHT);                            real fac = (real)(LA_RH)/dist;                            cx=tnsLinearItp(cx,ctx,fac); cy=tnsLinearItp(cy,cty,fac);                            la_SendMouseEvent(0, LA_L_MOUSE_UP, x,y);                            la_SendKeyboardEvent(0, LA_KEY_DOWN, direction|LA_KEYBOARD_EVENT|LA_KEY_PANNING);                            gesture_handled=1;                            dist = tnsDistIdv2(ctx,cty,cx,cy);                        }                    }                }else{                    cx=ctx; cy=cty;                }            }else{                temp_distance = 0; cx=0; cy=0;            }            if(flags==AMOTION_EVENT_ACTION_HOVER_MOVE){                la_SendMouseEvent(0, LA_MOUSEMOVE, rx,ry);            }        }        if(!gesture_handled){            if (flags == AMOTION_EVENT_ACTION_DOWN || flags == AMOTION_EVENT_ACTION_BUTTON_PRESS){                la_SendMouseEvent(0,LA_MOUSEMOVE,x,y);                la_SendMouseEvent(0,LA_MOUSEMOVE,x,y);                int btn=AMotionEvent_getButtonState(event);                int evtype=LA_L_MOUSE_DOWN;                if(btn & AMOTION_EVENT_BUTTON_STYLUS_PRIMARY){ evtype=LA_M_MOUSE_DOWN; }                elif(btn & AMOTION_EVENT_BUTTON_STYLUS_SECONDARY){ evtype=LA_R_MOUSE_DOWN; }                la_SendMouseEvent(0,evtype,x,y);                prev_button_state = btn;            }            else if (flags == AMOTION_EVENT_ACTION_UP || flags == AMOTION_EVENT_ACTION_BUTTON_RELEASE){                int btn=AMotionEvent_getButtonState(event); int changed = (~btn)&prev_button_state;                 int evtype=LA_L_MOUSE_UP;                if(changed & AMOTION_EVENT_BUTTON_STYLUS_PRIMARY){ evtype=LA_M_MOUSE_UP; }                elif(changed & AMOTION_EVENT_BUTTON_STYLUS_SECONDARY){ evtype=LA_R_MOUSE_UP; }                la_SendMouseEvent(0,evtype,x,y);            }            else if (flags == AMOTION_EVENT_ACTION_MOVE){                la_SendMouseEvent(0,LA_MOUSEMOVE,x,y);            }            else if (flags == AMOTION_EVENT_ACTION_CANCEL){                la_SendMouseEvent(0,LA_L_MOUSE_UP,x,y);            }        }            }    //static float r=0;    //eglMakeCurrent(MAIN.egl_dpy, MAIN.egl_surf, MAIN.egl_surf, MAIN.glc);    //glViewport(0,0,MAIN.AppWidth,MAIN.AppHeight);    //glClearColor(r,0.2,1,1); r+=0.01; if(r>1){ r=0; }    //glClear(GL_COLOR_BUFFER_BIT);    //eglSwapBuffers(MAIN.egl_dpy, MAIN.egl_surf);    return 0;}void la_InitAssetManager(AAssetManager *manager, const char *dataPath, const char *externalDataPath){    MAIN.AssetManager = manager;    MAIN.InternalDataPath = dataPath;    MAIN.ExternalDataPath = externalDataPath;}static int android_read(void *cookie, char *data, int dataSize){    return AAsset_read((AAsset *)cookie, data, dataSize);}static int android_write(void *cookie, const char *data, int dataSize){    return 0;}static fpos_t android_seek(void *cookie, fpos_t offset, int whence){    return AAsset_seek((AAsset *)cookie, offset, whence);}static int android_close(void *cookie){    AAsset_close((AAsset *)cookie);    return 0;}// Replacement for fopen()// Ref: https://developer.android.com/ndk/reference/group/assetFILE *android_fopen(const char *fileName, const char *mode){    MAIN.AndroidLastPath=0;    if (mode[0] == 'w'){        // fopen() is mapped to android_fopen() that only grants read access to        // assets directory through AAssetManager but we want to also be able to        // write data when required using the standard stdio FILE access functions        // Ref: https://stackoverflow.com/questions/11294487/android-writing-saving-files-from-native-code-only        #undef fopen        char* valid_path=laAndroidEnsureValidFilePath(fileName,W_OK); if(!valid_path){ return 0; }        FILE* result=fopen(valid_path, mode); if(result){ MAIN.AndroidLastPath=valid_path; return result; }        return 0;        #define fopen(name, mode) android_fopen(name, mode)    }else{        // NOTE: AAsset provides access to read-only asset        AAsset *asset = AAssetManager_open(MAIN.AssetManager, fileName, AASSET_MODE_UNKNOWN);        if (asset != NULL){            // Get pointer to file in the assets            return funopen(asset, android_read, android_write, android_seek, android_close);        }else{            #undef fopen            // Just do a regular open if file is not found in the assets            char* valid_path=laAndroidEnsureValidFilePath(fileName,R_OK); if(!valid_path){ return 0; }            FILE* result=fopen(valid_path, mode); if(result){ MAIN.AndroidLastPath=valid_path; return result; }            return 0;            #define fopen(name, mode) android_fopen(name, mode)        }    }}void la_HideNavBar(){    JavaVM* lJavaVM = MAIN.app->activity->vm;    JNIEnv* lJNIEnv = MAIN.app->activity->env;    (*lJavaVM)->AttachCurrentThread(lJavaVM, &lJNIEnv,0);	jclass activityClass = (*lJNIEnv)->FindClass(lJNIEnv,"android/app/NativeActivity");	jmethodID getWindow = (*lJNIEnv)->GetMethodID(lJNIEnv,activityClass, "getWindow", "()Landroid/view/Window;");	jclass windowClass = (*lJNIEnv)->FindClass(lJNIEnv,"android/view/Window");	jmethodID getDecorView = (*lJNIEnv)->GetMethodID(lJNIEnv,windowClass, "getDecorView", "()Landroid/view/View;");	jclass viewClass = (*lJNIEnv)->FindClass(lJNIEnv,"android/view/View");	jmethodID setSystemUiVisibility = (*lJNIEnv)->GetMethodID(lJNIEnv,viewClass, "setSystemUiVisibility", "(I)V");	jobject window = (*lJNIEnv)->CallObjectMethod(lJNIEnv,MAIN.app->activity->clazz, getWindow);	jobject decorView = (*lJNIEnv)->CallObjectMethod(lJNIEnv,window, getDecorView);	jfieldID flagFullscreenID = (*lJNIEnv)->GetStaticFieldID(lJNIEnv,viewClass, "SYSTEM_UI_FLAG_FULLSCREEN", "I");	jfieldID flagHideNavigationID = (*lJNIEnv)->GetStaticFieldID(lJNIEnv,viewClass, "SYSTEM_UI_FLAG_HIDE_NAVIGATION", "I");	int flagFullscreen = (*lJNIEnv)->GetStaticIntField(lJNIEnv,viewClass, flagFullscreenID);	int flagHideNavigation = (*lJNIEnv)->GetStaticIntField(lJNIEnv,viewClass, flagHideNavigationID);	int flag = flagFullscreen | flagHideNavigation;	(*lJNIEnv)->CallVoidMethod(lJNIEnv,decorView, setSystemUiVisibility, flag);    (*lJavaVM)->DetachCurrentThread(lJavaVM);}void la_InitAndroidPlatform(struct android_app *app){    MAIN.app=app;    ANativeActivity_setWindowFlags(MAIN.app->activity, AWINDOW_FLAG_FULLSCREEN, 0);  //AWINDOW_FLAG_SCALED, AWINDOW_FLAG_DITHER    //la_HideNavBar();    MAIN.app->onAppCmd = la_AndroidCommandCallback;    MAIN.app->onInputEvent = la_AndroidInputCallback;    la_InitAssetManager(MAIN.app->activity->assetManager, MAIN.app->activity->internalDataPath, MAIN.app->activity->externalDataPath);    int pollResult = 0;    int pollEvents = 0;    while (!MAIN.AppReady){        while ((pollResult = ALooper_pollAll(MAIN.AppEnabled? 0 : -1, NULL, &pollEvents, (void**)&MAIN.event_source)) >= 0){            // Process this event            if (MAIN.event_source != NULL) MAIN.event_source->process(MAIN.app, MAIN.event_source);            // NOTE: Never close window, native activity is controlled by the system!            //if (MAIN.app->destroyRequested != 0) CORE.Window.shouldClose = true;        }    }}int main(int, char *[]);void android_main(struct android_app *app){    char arg0[] = "lagui";     // NOTE: argv[] are mutable    la_InitAndroidPlatform(app);    // NOTE: Return from main is ignored    (void)main(1, (char *[]) { arg0, NULL });    // Request to end the native activity    ANativeActivity_finish(app->activity);    // Android ALooper_pollAll() variables    int pollResult = 0;    int pollEvents = 0;    // Waiting for application events before complete finishing    while (!app->destroyRequested)    {        while ((pollResult = ALooper_pollAll(0, NULL, &pollEvents, (void **)&MAIN.event_source)) >= 0)        {            if ( MAIN.event_source != NULL) MAIN.event_source->process(app, MAIN.event_source);        }    }    __android_log_print(ANDROID_LOG_DEBUG, "LAGUI", "Application successfully ended.\n");    /* Unloads the native dynamic library so we can get clean restarts. */    exit(0);}void la_DisplayKeyboard(bool pShow) {    // Attaches the current thread to the JVM.    jint lResult;    jint lFlags = 0;    JavaVM* lJavaVM = MAIN.app->activity->vm;    JNIEnv* lJNIEnv;// = MAIN.app->activity->env;    JavaVMAttachArgs lJavaVMAttachArgs;    lJavaVMAttachArgs.version = JNI_VERSION_1_6;    lJavaVMAttachArgs.name = "NativeThread";    lJavaVMAttachArgs.group = NULL;    lResult=(*lJavaVM)->AttachCurrentThread(lJavaVM, &lJNIEnv,0);    if (lResult == JNI_ERR) {        return;    }    // Retrieves NativeActivity.    jobject lNativeActivity = MAIN.app->activity->clazz;    jclass ClassNativeActivity = (*lJNIEnv)->GetObjectClass(lJNIEnv,lNativeActivity);    // Retrieves Context.INPUT_METHOD_SERVICE.    jclass ClassContext = (*lJNIEnv)->FindClass(lJNIEnv,"android/content/Context");    jfieldID FieldINPUT_METHOD_SERVICE =        (*lJNIEnv)->GetStaticFieldID(lJNIEnv,ClassContext,            "INPUT_METHOD_SERVICE", "Ljava/lang/String;");    jobject INPUT_METHOD_SERVICE =        (*lJNIEnv)->GetStaticObjectField(lJNIEnv,ClassContext,            FieldINPUT_METHOD_SERVICE);    //jniCheck(INPUT_METHOD_SERVICE);    // Runs getSystemService(Context.INPUT_METHOD_SERVICE).    jclass ClassInputMethodManager = (*lJNIEnv)->FindClass(lJNIEnv,        "android/view/inputmethod/InputMethodManager");    jmethodID MethodGetSystemService = (*lJNIEnv)->GetMethodID(lJNIEnv,        ClassNativeActivity, "getSystemService",        "(Ljava/lang/String;)Ljava/lang/Object;");    jobject lInputMethodManager = (*lJNIEnv)->CallObjectMethod(lJNIEnv,        lNativeActivity, MethodGetSystemService,        INPUT_METHOD_SERVICE);    // Runs getWindow().getDecorView().    jmethodID MethodGetWindow = (*lJNIEnv)->GetMethodID(lJNIEnv,        ClassNativeActivity, "getWindow",        "()Landroid/view/Window;");    jobject lWindow = (*lJNIEnv)->CallObjectMethod(lJNIEnv,lNativeActivity,        MethodGetWindow);    jclass ClassWindow = (*lJNIEnv)->FindClass(lJNIEnv,        "android/view/Window");    jmethodID MethodGetDecorView = (*lJNIEnv)->GetMethodID(lJNIEnv,        ClassWindow, "getDecorView", "()Landroid/view/View;");    jobject lDecorView = (*lJNIEnv)->CallObjectMethod(lJNIEnv,lWindow,        MethodGetDecorView);    if (pShow) {        // Runs lInputMethodManager.showSoftInput(...).        jmethodID MethodShowSoftInput = (*lJNIEnv)->GetMethodID(lJNIEnv,            ClassInputMethodManager, "showSoftInput",            "(Landroid/view/View;I)Z");        jboolean lResult = (*lJNIEnv)->CallBooleanMethod(lJNIEnv,            lInputMethodManager, MethodShowSoftInput,            lDecorView, lFlags);    } else {        // Runs lWindow.getViewToken()        jclass ClassView = (*lJNIEnv)->FindClass(lJNIEnv,            "android/view/View");        jmethodID MethodGetWindowToken = (*lJNIEnv)->GetMethodID(lJNIEnv,            ClassView, "getWindowToken", "()Landroid/os/IBinder;");        jobject lBinder = (*lJNIEnv)->CallObjectMethod(lJNIEnv,lDecorView,            MethodGetWindowToken);        // lInputMethodManager.hideSoftInput(...).        jmethodID MethodHideSoftInput = (*lJNIEnv)->GetMethodID(lJNIEnv,            ClassInputMethodManager, "hideSoftInputFromWindow",            "(Landroid/os/IBinder;I)Z");        jboolean lRes = (*lJNIEnv)->CallBooleanMethod(lJNIEnv,            lInputMethodManager, MethodHideSoftInput,            lBinder, lFlags);    }    if((*lJNIEnv)->ExceptionOccurred(lJNIEnv)){        logPrintNew("Java exception occured in la_DisplayKeyboard().\n");        (*lJNIEnv)->ExceptionClear(lJNIEnv);    }    // Finished with the JVM.    (*lJavaVM)->DetachCurrentThread(lJavaVM);}bool la_check_permission(const char* permission) {    int granted=0;    JavaVM* lJavaVM = MAIN.app->activity->vm;    JNIEnv* lJNIEnv=0;// = MAIN.app->activity->env;    (*lJavaVM)->AttachCurrentThread(lJavaVM, &lJNIEnv,0);logPrintNew("Attach\n");     (*lJavaVM)->AttachCurrentThread(lJavaVM, &lJNIEnv,0);    jobject lNativeActivity = MAIN.app->activity->clazz;    jclass ClassNativeActivity = (*lJNIEnv)->GetObjectClass(lJNIEnv,lNativeActivity);    jmethodID activity_checkSelfPermission = (*lJNIEnv)->GetMethodID(lJNIEnv, ClassNativeActivity, "checkSelfPermission", "(Ljava/lang/String;)I");    jstring jobj_permission = (*lJNIEnv)->NewStringUTF(lJNIEnv,permission);	jint    result          = (*lJNIEnv)->CallIntMethod(lJNIEnv,ClassNativeActivity, activity_checkSelfPermission, jobj_permission);	(*lJNIEnv)->DeleteLocalRef(lJNIEnv,jobj_permission);    granted = (result == 0);    if((*lJNIEnv)->ExceptionOccurred(lJNIEnv)){        logPrintNew("Java exception occured in la_check_permission().\n");        (*lJNIEnv)->ExceptionClear(lJNIEnv);        granted=0;    }    (*lJavaVM)->DetachCurrentThread(lJavaVM);	return granted;}void la_request_permission(const char* permission) {    JavaVM* lJavaVM = MAIN.app->activity->vm;    JNIEnv* lJNIEnv=0;// = MAIN.app->activity->env;    (*lJavaVM)->AttachCurrentThread(lJavaVM, &lJNIEnv,0);    jobject lNativeActivity = MAIN.app->activity->clazz;    jclass ClassNativeActivity = (*lJNIEnv)->GetObjectClass(lJNIEnv,lNativeActivity);	jmethodID contextCompat_checkSelfPermission = (*lJNIEnv)->GetMethodID   (lJNIEnv, ClassNativeActivity, "checkSelfPermission", "(Ljava/lang/String;)I");	jmethodID activity_requestPermissions       = (*lJNIEnv)->GetMethodID   (lJNIEnv, ClassNativeActivity, "requestPermissions",  "([Ljava/lang/String;I)V");	jstring      jobj_permission      = (*lJNIEnv)->NewStringUTF  (lJNIEnv,permission);	jobjectArray jobj_permission_list = (*lJNIEnv)->NewObjectArray(lJNIEnv,1, (*lJNIEnv)->FindClass(lJNIEnv,"java/lang/String"), NULL);	(*lJNIEnv)->SetObjectArrayElement(lJNIEnv,jobj_permission_list, 0, jobj_permission);	(*lJNIEnv)->CallVoidMethod       (lJNIEnv,lNativeActivity, activity_requestPermissions, jobj_permission_list, 0);	(*lJNIEnv)->DeleteLocalRef(lJNIEnv,jobj_permission);	(*lJNIEnv)->DeleteLocalRef(lJNIEnv,jobj_permission_list);    if((*lJNIEnv)->ExceptionOccurred(lJNIEnv)){        logPrintNew("Java exception occured in la_request_permission().\n");        (*lJNIEnv)->ExceptionClear(lJNIEnv);    }    (*lJavaVM)->DetachCurrentThread(lJavaVM);}#endif //android#ifndef LAGUI_ANDROIDvoid la_DisplayKeyboard(bool pShow) {    if(pShow){ laEnableIME(MAIN.CurrentWindow); } else { laDisableIME(MAIN.CurrentWindow); }    return;}void la_HideNavBar(){    return;}#endif
 |