ui_shared.c 146 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4. This file is part of Quake III Arena source code.
  5. Quake III Arena source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake III Arena source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Foobar; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. //
  19. // string allocation/managment
  20. #include "ui_shared.h"
  21. #define SCROLL_TIME_START 500
  22. #define SCROLL_TIME_ADJUST 150
  23. #define SCROLL_TIME_ADJUSTOFFSET 40
  24. #define SCROLL_TIME_FLOOR 20
  25. typedef struct scrollInfo_s {
  26. int nextScrollTime;
  27. int nextAdjustTime;
  28. int adjustValue;
  29. int scrollKey;
  30. float xStart;
  31. float yStart;
  32. itemDef_t *item;
  33. qboolean scrollDir;
  34. } scrollInfo_t;
  35. static scrollInfo_t scrollInfo;
  36. static void (*captureFunc) (void *p) = NULL;
  37. static void *captureData = NULL;
  38. static itemDef_t *itemCapture = NULL; // item that has the mouse captured ( if any )
  39. displayContextDef_t *DC = NULL;
  40. static qboolean g_waitingForKey = qfalse;
  41. static qboolean g_editingField = qfalse;
  42. static itemDef_t *g_bindItem = NULL;
  43. static itemDef_t *g_editItem = NULL;
  44. menuDef_t Menus[MAX_MENUS]; // defined menus
  45. int menuCount = 0; // how many
  46. menuDef_t *menuStack[MAX_OPEN_MENUS];
  47. int openMenuCount = 0;
  48. static qboolean debugMode = qfalse;
  49. #define DOUBLE_CLICK_DELAY 300
  50. static int lastListBoxClickTime = 0;
  51. void Item_RunScript(itemDef_t *item, const char *s);
  52. void Item_SetupKeywordHash(void);
  53. void Menu_SetupKeywordHash(void);
  54. int BindingIDFromName(const char *name);
  55. qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down);
  56. itemDef_t *Menu_SetPrevCursorItem(menuDef_t *menu);
  57. itemDef_t *Menu_SetNextCursorItem(menuDef_t *menu);
  58. static qboolean Menu_OverActiveItem(menuDef_t *menu, float x, float y);
  59. #ifdef CGAME
  60. #define MEM_POOL_SIZE 128 * 1024
  61. #else
  62. #define MEM_POOL_SIZE 1024 * 1024
  63. #endif
  64. static char memoryPool[MEM_POOL_SIZE];
  65. static int allocPoint, outOfMemory;
  66. /*
  67. ===============
  68. UI_Alloc
  69. ===============
  70. */
  71. void *UI_Alloc( int size ) {
  72. char *p;
  73. if ( allocPoint + size > MEM_POOL_SIZE ) {
  74. outOfMemory = qtrue;
  75. if (DC->Print) {
  76. DC->Print("UI_Alloc: Failure. Out of memory!\n");
  77. }
  78. //DC->trap_Print(S_COLOR_YELLOW"WARNING: UI Out of Memory!\n");
  79. return NULL;
  80. }
  81. p = &memoryPool[allocPoint];
  82. allocPoint += ( size + 15 ) & ~15;
  83. return p;
  84. }
  85. /*
  86. ===============
  87. UI_InitMemory
  88. ===============
  89. */
  90. void UI_InitMemory( void ) {
  91. allocPoint = 0;
  92. outOfMemory = qfalse;
  93. }
  94. qboolean UI_OutOfMemory() {
  95. return outOfMemory;
  96. }
  97. #define HASH_TABLE_SIZE 2048
  98. /*
  99. ================
  100. return a hash value for the string
  101. ================
  102. */
  103. static long hashForString(const char *str) {
  104. int i;
  105. long hash;
  106. char letter;
  107. hash = 0;
  108. i = 0;
  109. while (str[i] != '\0') {
  110. letter = tolower(str[i]);
  111. hash+=(long)(letter)*(i+119);
  112. i++;
  113. }
  114. hash &= (HASH_TABLE_SIZE-1);
  115. return hash;
  116. }
  117. typedef struct stringDef_s {
  118. struct stringDef_s *next;
  119. const char *str;
  120. } stringDef_t;
  121. static int strPoolIndex = 0;
  122. static char strPool[STRING_POOL_SIZE];
  123. static int strHandleCount = 0;
  124. static stringDef_t *strHandle[HASH_TABLE_SIZE];
  125. const char *String_Alloc(const char *p) {
  126. int len;
  127. long hash;
  128. stringDef_t *str, *last;
  129. static const char *staticNULL = "";
  130. if (p == NULL) {
  131. return NULL;
  132. }
  133. if (*p == 0) {
  134. return staticNULL;
  135. }
  136. hash = hashForString(p);
  137. str = strHandle[hash];
  138. while (str) {
  139. if (strcmp(p, str->str) == 0) {
  140. return str->str;
  141. }
  142. str = str->next;
  143. }
  144. len = strlen(p);
  145. if (len + strPoolIndex + 1 < STRING_POOL_SIZE) {
  146. int ph = strPoolIndex;
  147. strcpy(&strPool[strPoolIndex], p);
  148. strPoolIndex += len + 1;
  149. str = strHandle[hash];
  150. last = str;
  151. while (str && str->next) {
  152. last = str;
  153. str = str->next;
  154. }
  155. str = UI_Alloc(sizeof(stringDef_t));
  156. str->next = NULL;
  157. str->str = &strPool[ph];
  158. if (last) {
  159. last->next = str;
  160. } else {
  161. strHandle[hash] = str;
  162. }
  163. return &strPool[ph];
  164. }
  165. return NULL;
  166. }
  167. void String_Report() {
  168. float f;
  169. Com_Printf("Memory/String Pool Info\n");
  170. Com_Printf("----------------\n");
  171. f = strPoolIndex;
  172. f /= STRING_POOL_SIZE;
  173. f *= 100;
  174. Com_Printf("String Pool is %.1f%% full, %i bytes out of %i used.\n", f, strPoolIndex, STRING_POOL_SIZE);
  175. f = allocPoint;
  176. f /= MEM_POOL_SIZE;
  177. f *= 100;
  178. Com_Printf("Memory Pool is %.1f%% full, %i bytes out of %i used.\n", f, allocPoint, MEM_POOL_SIZE);
  179. }
  180. /*
  181. =================
  182. String_Init
  183. =================
  184. */
  185. void String_Init() {
  186. int i;
  187. for (i = 0; i < HASH_TABLE_SIZE; i++) {
  188. strHandle[i] = 0;
  189. }
  190. strHandleCount = 0;
  191. strPoolIndex = 0;
  192. menuCount = 0;
  193. openMenuCount = 0;
  194. UI_InitMemory();
  195. Item_SetupKeywordHash();
  196. Menu_SetupKeywordHash();
  197. if (DC && DC->getBindingBuf) {
  198. Controls_GetConfig();
  199. }
  200. }
  201. /*
  202. =================
  203. PC_SourceWarning
  204. =================
  205. */
  206. void PC_SourceWarning(int handle, char *format, ...) {
  207. int line;
  208. char filename[128];
  209. va_list argptr;
  210. static char string[4096];
  211. va_start (argptr, format);
  212. vsprintf (string, format, argptr);
  213. va_end (argptr);
  214. filename[0] = '\0';
  215. line = 0;
  216. trap_PC_SourceFileAndLine(handle, filename, &line);
  217. Com_Printf(S_COLOR_YELLOW "WARNING: %s, line %d: %s\n", filename, line, string);
  218. }
  219. /*
  220. =================
  221. PC_SourceError
  222. =================
  223. */
  224. void PC_SourceError(int handle, char *format, ...) {
  225. int line;
  226. char filename[128];
  227. va_list argptr;
  228. static char string[4096];
  229. va_start (argptr, format);
  230. vsprintf (string, format, argptr);
  231. va_end (argptr);
  232. filename[0] = '\0';
  233. line = 0;
  234. trap_PC_SourceFileAndLine(handle, filename, &line);
  235. Com_Printf(S_COLOR_RED "ERROR: %s, line %d: %s\n", filename, line, string);
  236. }
  237. /*
  238. =================
  239. LerpColor
  240. =================
  241. */
  242. void LerpColor(vec4_t a, vec4_t b, vec4_t c, float t)
  243. {
  244. int i;
  245. // lerp and clamp each component
  246. for (i=0; i<4; i++)
  247. {
  248. c[i] = a[i] + t*(b[i]-a[i]);
  249. if (c[i] < 0)
  250. c[i] = 0;
  251. else if (c[i] > 1.0)
  252. c[i] = 1.0;
  253. }
  254. }
  255. /*
  256. =================
  257. Float_Parse
  258. =================
  259. */
  260. qboolean Float_Parse(char **p, float *f) {
  261. char *token;
  262. token = COM_ParseExt(p, qfalse);
  263. if (token && token[0] != 0) {
  264. *f = atof(token);
  265. return qtrue;
  266. } else {
  267. return qfalse;
  268. }
  269. }
  270. /*
  271. =================
  272. PC_Float_Parse
  273. =================
  274. */
  275. qboolean PC_Float_Parse(int handle, float *f) {
  276. pc_token_t token;
  277. int negative = qfalse;
  278. if (!trap_PC_ReadToken(handle, &token))
  279. return qfalse;
  280. if (token.string[0] == '-') {
  281. if (!trap_PC_ReadToken(handle, &token))
  282. return qfalse;
  283. negative = qtrue;
  284. }
  285. if (token.type != TT_NUMBER) {
  286. PC_SourceError(handle, "expected float but found %s\n", token.string);
  287. return qfalse;
  288. }
  289. if (negative)
  290. *f = -token.floatvalue;
  291. else
  292. *f = token.floatvalue;
  293. return qtrue;
  294. }
  295. /*
  296. =================
  297. Color_Parse
  298. =================
  299. */
  300. qboolean Color_Parse(char **p, vec4_t *c) {
  301. int i;
  302. float f;
  303. for (i = 0; i < 4; i++) {
  304. if (!Float_Parse(p, &f)) {
  305. return qfalse;
  306. }
  307. (*c)[i] = f;
  308. }
  309. return qtrue;
  310. }
  311. /*
  312. =================
  313. PC_Color_Parse
  314. =================
  315. */
  316. qboolean PC_Color_Parse(int handle, vec4_t *c) {
  317. int i;
  318. float f;
  319. for (i = 0; i < 4; i++) {
  320. if (!PC_Float_Parse(handle, &f)) {
  321. return qfalse;
  322. }
  323. (*c)[i] = f;
  324. }
  325. return qtrue;
  326. }
  327. /*
  328. =================
  329. Int_Parse
  330. =================
  331. */
  332. qboolean Int_Parse(char **p, int *i) {
  333. char *token;
  334. token = COM_ParseExt(p, qfalse);
  335. if (token && token[0] != 0) {
  336. *i = atoi(token);
  337. return qtrue;
  338. } else {
  339. return qfalse;
  340. }
  341. }
  342. /*
  343. =================
  344. PC_Int_Parse
  345. =================
  346. */
  347. qboolean PC_Int_Parse(int handle, int *i) {
  348. pc_token_t token;
  349. int negative = qfalse;
  350. if (!trap_PC_ReadToken(handle, &token))
  351. return qfalse;
  352. if (token.string[0] == '-') {
  353. if (!trap_PC_ReadToken(handle, &token))
  354. return qfalse;
  355. negative = qtrue;
  356. }
  357. if (token.type != TT_NUMBER) {
  358. PC_SourceError(handle, "expected integer but found %s\n", token.string);
  359. return qfalse;
  360. }
  361. *i = token.intvalue;
  362. if (negative)
  363. *i = - *i;
  364. return qtrue;
  365. }
  366. /*
  367. =================
  368. Rect_Parse
  369. =================
  370. */
  371. qboolean Rect_Parse(char **p, rectDef_t *r) {
  372. if (Float_Parse(p, &r->x)) {
  373. if (Float_Parse(p, &r->y)) {
  374. if (Float_Parse(p, &r->w)) {
  375. if (Float_Parse(p, &r->h)) {
  376. return qtrue;
  377. }
  378. }
  379. }
  380. }
  381. return qfalse;
  382. }
  383. /*
  384. =================
  385. PC_Rect_Parse
  386. =================
  387. */
  388. qboolean PC_Rect_Parse(int handle, rectDef_t *r) {
  389. if (PC_Float_Parse(handle, &r->x)) {
  390. if (PC_Float_Parse(handle, &r->y)) {
  391. if (PC_Float_Parse(handle, &r->w)) {
  392. if (PC_Float_Parse(handle, &r->h)) {
  393. return qtrue;
  394. }
  395. }
  396. }
  397. }
  398. return qfalse;
  399. }
  400. /*
  401. =================
  402. String_Parse
  403. =================
  404. */
  405. qboolean String_Parse(char **p, const char **out) {
  406. char *token;
  407. token = COM_ParseExt(p, qfalse);
  408. if (token && token[0] != 0) {
  409. *(out) = String_Alloc(token);
  410. return qtrue;
  411. }
  412. return qfalse;
  413. }
  414. /*
  415. =================
  416. PC_String_Parse
  417. =================
  418. */
  419. qboolean PC_String_Parse(int handle, const char **out) {
  420. pc_token_t token;
  421. if (!trap_PC_ReadToken(handle, &token))
  422. return qfalse;
  423. *(out) = String_Alloc(token.string);
  424. return qtrue;
  425. }
  426. /*
  427. =================
  428. PC_Script_Parse
  429. =================
  430. */
  431. qboolean PC_Script_Parse(int handle, const char **out) {
  432. char script[1024];
  433. pc_token_t token;
  434. memset(script, 0, sizeof(script));
  435. // scripts start with { and have ; separated command lists.. commands are command, arg..
  436. // basically we want everything between the { } as it will be interpreted at run time
  437. if (!trap_PC_ReadToken(handle, &token))
  438. return qfalse;
  439. if (Q_stricmp(token.string, "{") != 0) {
  440. return qfalse;
  441. }
  442. while ( 1 ) {
  443. if (!trap_PC_ReadToken(handle, &token))
  444. return qfalse;
  445. if (Q_stricmp(token.string, "}") == 0) {
  446. *out = String_Alloc(script);
  447. return qtrue;
  448. }
  449. if (token.string[1] != '\0') {
  450. Q_strcat(script, 1024, va("\"%s\"", token.string));
  451. } else {
  452. Q_strcat(script, 1024, token.string);
  453. }
  454. Q_strcat(script, 1024, " ");
  455. }
  456. return qfalse; // bk001105 - LCC missing return value
  457. }
  458. // display, window, menu, item code
  459. //
  460. /*
  461. ==================
  462. Init_Display
  463. Initializes the display with a structure to all the drawing routines
  464. ==================
  465. */
  466. void Init_Display(displayContextDef_t *dc) {
  467. DC = dc;
  468. }
  469. // type and style painting
  470. void GradientBar_Paint(rectDef_t *rect, vec4_t color) {
  471. // gradient bar takes two paints
  472. DC->setColor( color );
  473. DC->drawHandlePic(rect->x, rect->y, rect->w, rect->h, DC->Assets.gradientBar);
  474. DC->setColor( NULL );
  475. }
  476. /*
  477. ==================
  478. Window_Init
  479. Initializes a window structure ( windowDef_t ) with defaults
  480. ==================
  481. */
  482. void Window_Init(Window *w) {
  483. memset(w, 0, sizeof(windowDef_t));
  484. w->borderSize = 1;
  485. w->foreColor[0] = w->foreColor[1] = w->foreColor[2] = w->foreColor[3] = 1.0;
  486. w->cinematic = -1;
  487. }
  488. void Fade(int *flags, float *f, float clamp, int *nextTime, int offsetTime, qboolean bFlags, float fadeAmount) {
  489. if (*flags & (WINDOW_FADINGOUT | WINDOW_FADINGIN)) {
  490. if (DC->realTime > *nextTime) {
  491. *nextTime = DC->realTime + offsetTime;
  492. if (*flags & WINDOW_FADINGOUT) {
  493. *f -= fadeAmount;
  494. if (bFlags && *f <= 0.0) {
  495. *flags &= ~(WINDOW_FADINGOUT | WINDOW_VISIBLE);
  496. }
  497. } else {
  498. *f += fadeAmount;
  499. if (*f >= clamp) {
  500. *f = clamp;
  501. if (bFlags) {
  502. *flags &= ~WINDOW_FADINGIN;
  503. }
  504. }
  505. }
  506. }
  507. }
  508. }
  509. void Window_Paint(Window *w, float fadeAmount, float fadeClamp, float fadeCycle) {
  510. //float bordersize = 0;
  511. vec4_t color;
  512. rectDef_t fillRect = w->rect;
  513. if (debugMode) {
  514. color[0] = color[1] = color[2] = color[3] = 1;
  515. DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, 1, color);
  516. }
  517. if (w == NULL || (w->style == 0 && w->border == 0)) {
  518. return;
  519. }
  520. if (w->border != 0) {
  521. fillRect.x += w->borderSize;
  522. fillRect.y += w->borderSize;
  523. fillRect.w -= w->borderSize + 1;
  524. fillRect.h -= w->borderSize + 1;
  525. }
  526. if (w->style == WINDOW_STYLE_FILLED) {
  527. // box, but possible a shader that needs filled
  528. if (w->background) {
  529. Fade(&w->flags, &w->backColor[3], fadeClamp, &w->nextTime, fadeCycle, qtrue, fadeAmount);
  530. DC->setColor(w->backColor);
  531. DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background);
  532. DC->setColor(NULL);
  533. } else {
  534. DC->fillRect(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->backColor);
  535. }
  536. } else if (w->style == WINDOW_STYLE_GRADIENT) {
  537. GradientBar_Paint(&fillRect, w->backColor);
  538. // gradient bar
  539. } else if (w->style == WINDOW_STYLE_SHADER) {
  540. if (w->flags & WINDOW_FORECOLORSET) {
  541. DC->setColor(w->foreColor);
  542. }
  543. DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background);
  544. DC->setColor(NULL);
  545. } else if (w->style == WINDOW_STYLE_TEAMCOLOR) {
  546. if (DC->getTeamColor) {
  547. DC->getTeamColor(&color);
  548. DC->fillRect(fillRect.x, fillRect.y, fillRect.w, fillRect.h, color);
  549. }
  550. } else if (w->style == WINDOW_STYLE_CINEMATIC) {
  551. if (w->cinematic == -1) {
  552. w->cinematic = DC->playCinematic(w->cinematicName, fillRect.x, fillRect.y, fillRect.w, fillRect.h);
  553. if (w->cinematic == -1) {
  554. w->cinematic = -2;
  555. }
  556. }
  557. if (w->cinematic >= 0) {
  558. DC->runCinematicFrame(w->cinematic);
  559. DC->drawCinematic(w->cinematic, fillRect.x, fillRect.y, fillRect.w, fillRect.h);
  560. }
  561. }
  562. if (w->border == WINDOW_BORDER_FULL) {
  563. // full
  564. // HACK HACK HACK
  565. if (w->style == WINDOW_STYLE_TEAMCOLOR) {
  566. if (color[0] > 0) {
  567. // red
  568. color[0] = 1;
  569. color[1] = color[2] = .5;
  570. } else {
  571. color[2] = 1;
  572. color[0] = color[1] = .5;
  573. }
  574. color[3] = 1;
  575. DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize, color);
  576. } else {
  577. DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize, w->borderColor);
  578. }
  579. } else if (w->border == WINDOW_BORDER_HORZ) {
  580. // top/bottom
  581. DC->setColor(w->borderColor);
  582. DC->drawTopBottom(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize);
  583. DC->setColor( NULL );
  584. } else if (w->border == WINDOW_BORDER_VERT) {
  585. // left right
  586. DC->setColor(w->borderColor);
  587. DC->drawSides(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize);
  588. DC->setColor( NULL );
  589. } else if (w->border == WINDOW_BORDER_KCGRADIENT) {
  590. // this is just two gradient bars along each horz edge
  591. rectDef_t r = w->rect;
  592. r.h = w->borderSize;
  593. GradientBar_Paint(&r, w->borderColor);
  594. r.y = w->rect.y + w->rect.h - 1;
  595. GradientBar_Paint(&r, w->borderColor);
  596. }
  597. }
  598. void Item_SetScreenCoords(itemDef_t *item, float x, float y) {
  599. if (item == NULL) {
  600. return;
  601. }
  602. if (item->window.border != 0) {
  603. x += item->window.borderSize;
  604. y += item->window.borderSize;
  605. }
  606. item->window.rect.x = x + item->window.rectClient.x;
  607. item->window.rect.y = y + item->window.rectClient.y;
  608. item->window.rect.w = item->window.rectClient.w;
  609. item->window.rect.h = item->window.rectClient.h;
  610. // force the text rects to recompute
  611. item->textRect.w = 0;
  612. item->textRect.h = 0;
  613. }
  614. // FIXME: consolidate this with nearby stuff
  615. void Item_UpdatePosition(itemDef_t *item) {
  616. float x, y;
  617. menuDef_t *menu;
  618. if (item == NULL || item->parent == NULL) {
  619. return;
  620. }
  621. menu = item->parent;
  622. x = menu->window.rect.x;
  623. y = menu->window.rect.y;
  624. if (menu->window.border != 0) {
  625. x += menu->window.borderSize;
  626. y += menu->window.borderSize;
  627. }
  628. Item_SetScreenCoords(item, x, y);
  629. }
  630. // menus
  631. void Menu_UpdatePosition(menuDef_t *menu) {
  632. int i;
  633. float x, y;
  634. if (menu == NULL) {
  635. return;
  636. }
  637. x = menu->window.rect.x;
  638. y = menu->window.rect.y;
  639. if (menu->window.border != 0) {
  640. x += menu->window.borderSize;
  641. y += menu->window.borderSize;
  642. }
  643. for (i = 0; i < menu->itemCount; i++) {
  644. Item_SetScreenCoords(menu->items[i], x, y);
  645. }
  646. }
  647. void Menu_PostParse(menuDef_t *menu) {
  648. if (menu == NULL) {
  649. return;
  650. }
  651. if (menu->fullScreen) {
  652. menu->window.rect.x = 0;
  653. menu->window.rect.y = 0;
  654. menu->window.rect.w = 640;
  655. menu->window.rect.h = 480;
  656. }
  657. Menu_UpdatePosition(menu);
  658. }
  659. itemDef_t *Menu_ClearFocus(menuDef_t *menu) {
  660. int i;
  661. itemDef_t *ret = NULL;
  662. if (menu == NULL) {
  663. return NULL;
  664. }
  665. for (i = 0; i < menu->itemCount; i++) {
  666. if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
  667. ret = menu->items[i];
  668. }
  669. menu->items[i]->window.flags &= ~WINDOW_HASFOCUS;
  670. if (menu->items[i]->leaveFocus) {
  671. Item_RunScript(menu->items[i], menu->items[i]->leaveFocus);
  672. }
  673. }
  674. return ret;
  675. }
  676. qboolean IsVisible(int flags) {
  677. return (flags & WINDOW_VISIBLE && !(flags & WINDOW_FADINGOUT));
  678. }
  679. qboolean Rect_ContainsPoint(rectDef_t *rect, float x, float y) {
  680. if (rect) {
  681. if (x > rect->x && x < rect->x + rect->w && y > rect->y && y < rect->y + rect->h) {
  682. return qtrue;
  683. }
  684. }
  685. return qfalse;
  686. }
  687. int Menu_ItemsMatchingGroup(menuDef_t *menu, const char *name) {
  688. int i;
  689. int count = 0;
  690. for (i = 0; i < menu->itemCount; i++) {
  691. if (Q_stricmp(menu->items[i]->window.name, name) == 0 || (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0)) {
  692. count++;
  693. }
  694. }
  695. return count;
  696. }
  697. itemDef_t *Menu_GetMatchingItemByNumber(menuDef_t *menu, int index, const char *name) {
  698. int i;
  699. int count = 0;
  700. for (i = 0; i < menu->itemCount; i++) {
  701. if (Q_stricmp(menu->items[i]->window.name, name) == 0 || (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0)) {
  702. if (count == index) {
  703. return menu->items[i];
  704. }
  705. count++;
  706. }
  707. }
  708. return NULL;
  709. }
  710. void Script_SetColor(itemDef_t *item, char **args) {
  711. const char *name;
  712. int i;
  713. float f;
  714. vec4_t *out;
  715. // expecting type of color to set and 4 args for the color
  716. if (String_Parse(args, &name)) {
  717. out = NULL;
  718. if (Q_stricmp(name, "backcolor") == 0) {
  719. out = &item->window.backColor;
  720. item->window.flags |= WINDOW_BACKCOLORSET;
  721. } else if (Q_stricmp(name, "forecolor") == 0) {
  722. out = &item->window.foreColor;
  723. item->window.flags |= WINDOW_FORECOLORSET;
  724. } else if (Q_stricmp(name, "bordercolor") == 0) {
  725. out = &item->window.borderColor;
  726. }
  727. if (out) {
  728. for (i = 0; i < 4; i++) {
  729. if (!Float_Parse(args, &f)) {
  730. return;
  731. }
  732. (*out)[i] = f;
  733. }
  734. }
  735. }
  736. }
  737. void Script_SetAsset(itemDef_t *item, char **args) {
  738. const char *name;
  739. // expecting name to set asset to
  740. if (String_Parse(args, &name)) {
  741. // check for a model
  742. if (item->type == ITEM_TYPE_MODEL) {
  743. }
  744. }
  745. }
  746. void Script_SetBackground(itemDef_t *item, char **args) {
  747. const char *name;
  748. // expecting name to set asset to
  749. if (String_Parse(args, &name)) {
  750. item->window.background = DC->registerShaderNoMip(name);
  751. }
  752. }
  753. itemDef_t *Menu_FindItemByName(menuDef_t *menu, const char *p) {
  754. int i;
  755. if (menu == NULL || p == NULL) {
  756. return NULL;
  757. }
  758. for (i = 0; i < menu->itemCount; i++) {
  759. if (Q_stricmp(p, menu->items[i]->window.name) == 0) {
  760. return menu->items[i];
  761. }
  762. }
  763. return NULL;
  764. }
  765. void Script_SetTeamColor(itemDef_t *item, char **args) {
  766. if (DC->getTeamColor) {
  767. int i;
  768. vec4_t color;
  769. DC->getTeamColor(&color);
  770. for (i = 0; i < 4; i++) {
  771. item->window.backColor[i] = color[i];
  772. }
  773. }
  774. }
  775. void Script_SetItemColor(itemDef_t *item, char **args) {
  776. const char *itemname;
  777. const char *name;
  778. vec4_t color;
  779. int i;
  780. vec4_t *out;
  781. // expecting type of color to set and 4 args for the color
  782. if (String_Parse(args, &itemname) && String_Parse(args, &name)) {
  783. itemDef_t *item2;
  784. int j;
  785. int count = Menu_ItemsMatchingGroup(item->parent, itemname);
  786. if (!Color_Parse(args, &color)) {
  787. return;
  788. }
  789. for (j = 0; j < count; j++) {
  790. item2 = Menu_GetMatchingItemByNumber(item->parent, j, itemname);
  791. if (item2 != NULL) {
  792. out = NULL;
  793. if (Q_stricmp(name, "backcolor") == 0) {
  794. out = &item2->window.backColor;
  795. } else if (Q_stricmp(name, "forecolor") == 0) {
  796. out = &item2->window.foreColor;
  797. item2->window.flags |= WINDOW_FORECOLORSET;
  798. } else if (Q_stricmp(name, "bordercolor") == 0) {
  799. out = &item2->window.borderColor;
  800. }
  801. if (out) {
  802. for (i = 0; i < 4; i++) {
  803. (*out)[i] = color[i];
  804. }
  805. }
  806. }
  807. }
  808. }
  809. }
  810. void Menu_ShowItemByName(menuDef_t *menu, const char *p, qboolean bShow) {
  811. itemDef_t *item;
  812. int i;
  813. int count = Menu_ItemsMatchingGroup(menu, p);
  814. for (i = 0; i < count; i++) {
  815. item = Menu_GetMatchingItemByNumber(menu, i, p);
  816. if (item != NULL) {
  817. if (bShow) {
  818. item->window.flags |= WINDOW_VISIBLE;
  819. } else {
  820. item->window.flags &= ~WINDOW_VISIBLE;
  821. // stop cinematics playing in the window
  822. if (item->window.cinematic >= 0) {
  823. DC->stopCinematic(item->window.cinematic);
  824. item->window.cinematic = -1;
  825. }
  826. }
  827. }
  828. }
  829. }
  830. void Menu_FadeItemByName(menuDef_t *menu, const char *p, qboolean fadeOut) {
  831. itemDef_t *item;
  832. int i;
  833. int count = Menu_ItemsMatchingGroup(menu, p);
  834. for (i = 0; i < count; i++) {
  835. item = Menu_GetMatchingItemByNumber(menu, i, p);
  836. if (item != NULL) {
  837. if (fadeOut) {
  838. item->window.flags |= (WINDOW_FADINGOUT | WINDOW_VISIBLE);
  839. item->window.flags &= ~WINDOW_FADINGIN;
  840. } else {
  841. item->window.flags |= (WINDOW_VISIBLE | WINDOW_FADINGIN);
  842. item->window.flags &= ~WINDOW_FADINGOUT;
  843. }
  844. }
  845. }
  846. }
  847. menuDef_t *Menus_FindByName(const char *p) {
  848. int i;
  849. for (i = 0; i < menuCount; i++) {
  850. if (Q_stricmp(Menus[i].window.name, p) == 0) {
  851. return &Menus[i];
  852. }
  853. }
  854. return NULL;
  855. }
  856. void Menus_ShowByName(const char *p) {
  857. menuDef_t *menu = Menus_FindByName(p);
  858. if (menu) {
  859. Menus_Activate(menu);
  860. }
  861. }
  862. void Menus_OpenByName(const char *p) {
  863. Menus_ActivateByName(p);
  864. }
  865. static void Menu_RunCloseScript(menuDef_t *menu) {
  866. if (menu && menu->window.flags & WINDOW_VISIBLE && menu->onClose) {
  867. itemDef_t item;
  868. item.parent = menu;
  869. Item_RunScript(&item, menu->onClose);
  870. }
  871. }
  872. void Menus_CloseByName(const char *p) {
  873. menuDef_t *menu = Menus_FindByName(p);
  874. if (menu != NULL) {
  875. Menu_RunCloseScript(menu);
  876. menu->window.flags &= ~(WINDOW_VISIBLE | WINDOW_HASFOCUS);
  877. }
  878. }
  879. void Menus_CloseAll() {
  880. int i;
  881. for (i = 0; i < menuCount; i++) {
  882. Menu_RunCloseScript(&Menus[i]);
  883. Menus[i].window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
  884. }
  885. }
  886. void Script_Show(itemDef_t *item, char **args) {
  887. const char *name;
  888. if (String_Parse(args, &name)) {
  889. Menu_ShowItemByName(item->parent, name, qtrue);
  890. }
  891. }
  892. void Script_Hide(itemDef_t *item, char **args) {
  893. const char *name;
  894. if (String_Parse(args, &name)) {
  895. Menu_ShowItemByName(item->parent, name, qfalse);
  896. }
  897. }
  898. void Script_FadeIn(itemDef_t *item, char **args) {
  899. const char *name;
  900. if (String_Parse(args, &name)) {
  901. Menu_FadeItemByName(item->parent, name, qfalse);
  902. }
  903. }
  904. void Script_FadeOut(itemDef_t *item, char **args) {
  905. const char *name;
  906. if (String_Parse(args, &name)) {
  907. Menu_FadeItemByName(item->parent, name, qtrue);
  908. }
  909. }
  910. void Script_Open(itemDef_t *item, char **args) {
  911. const char *name;
  912. if (String_Parse(args, &name)) {
  913. Menus_OpenByName(name);
  914. }
  915. }
  916. void Script_ConditionalOpen(itemDef_t *item, char **args) {
  917. const char *cvar;
  918. const char *name1;
  919. const char *name2;
  920. float val;
  921. if ( String_Parse(args, &cvar) && String_Parse(args, &name1) && String_Parse(args, &name2) ) {
  922. val = DC->getCVarValue( cvar );
  923. if ( val == 0.f ) {
  924. Menus_OpenByName(name2);
  925. } else {
  926. Menus_OpenByName(name1);
  927. }
  928. }
  929. }
  930. void Script_Close(itemDef_t *item, char **args) {
  931. const char *name;
  932. if (String_Parse(args, &name)) {
  933. Menus_CloseByName(name);
  934. }
  935. }
  936. void Menu_TransitionItemByName(menuDef_t *menu, const char *p, rectDef_t rectFrom, rectDef_t rectTo, int time, float amt) {
  937. itemDef_t *item;
  938. int i;
  939. int count = Menu_ItemsMatchingGroup(menu, p);
  940. for (i = 0; i < count; i++) {
  941. item = Menu_GetMatchingItemByNumber(menu, i, p);
  942. if (item != NULL) {
  943. item->window.flags |= (WINDOW_INTRANSITION | WINDOW_VISIBLE);
  944. item->window.offsetTime = time;
  945. memcpy(&item->window.rectClient, &rectFrom, sizeof(rectDef_t));
  946. memcpy(&item->window.rectEffects, &rectTo, sizeof(rectDef_t));
  947. item->window.rectEffects2.x = abs(rectTo.x - rectFrom.x) / amt;
  948. item->window.rectEffects2.y = abs(rectTo.y - rectFrom.y) / amt;
  949. item->window.rectEffects2.w = abs(rectTo.w - rectFrom.w) / amt;
  950. item->window.rectEffects2.h = abs(rectTo.h - rectFrom.h) / amt;
  951. Item_UpdatePosition(item);
  952. }
  953. }
  954. }
  955. void Script_Transition(itemDef_t *item, char **args) {
  956. const char *name;
  957. rectDef_t rectFrom, rectTo;
  958. int time;
  959. float amt;
  960. if (String_Parse(args, &name)) {
  961. if ( Rect_Parse(args, &rectFrom) && Rect_Parse(args, &rectTo) && Int_Parse(args, &time) && Float_Parse(args, &amt)) {
  962. Menu_TransitionItemByName(item->parent, name, rectFrom, rectTo, time, amt);
  963. }
  964. }
  965. }
  966. void Menu_OrbitItemByName(menuDef_t *menu, const char *p, float x, float y, float cx, float cy, int time) {
  967. itemDef_t *item;
  968. int i;
  969. int count = Menu_ItemsMatchingGroup(menu, p);
  970. for (i = 0; i < count; i++) {
  971. item = Menu_GetMatchingItemByNumber(menu, i, p);
  972. if (item != NULL) {
  973. item->window.flags |= (WINDOW_ORBITING | WINDOW_VISIBLE);
  974. item->window.offsetTime = time;
  975. item->window.rectEffects.x = cx;
  976. item->window.rectEffects.y = cy;
  977. item->window.rectClient.x = x;
  978. item->window.rectClient.y = y;
  979. Item_UpdatePosition(item);
  980. }
  981. }
  982. }
  983. void Script_Orbit(itemDef_t *item, char **args) {
  984. const char *name;
  985. float cx, cy, x, y;
  986. int time;
  987. if (String_Parse(args, &name)) {
  988. if ( Float_Parse(args, &x) && Float_Parse(args, &y) && Float_Parse(args, &cx) && Float_Parse(args, &cy) && Int_Parse(args, &time) ) {
  989. Menu_OrbitItemByName(item->parent, name, x, y, cx, cy, time);
  990. }
  991. }
  992. }
  993. void Script_SetFocus(itemDef_t *item, char **args) {
  994. const char *name;
  995. itemDef_t *focusItem;
  996. if (String_Parse(args, &name)) {
  997. focusItem = Menu_FindItemByName(item->parent, name);
  998. if (focusItem && !(focusItem->window.flags & WINDOW_DECORATION) && !(focusItem->window.flags & WINDOW_HASFOCUS)) {
  999. Menu_ClearFocus(item->parent);
  1000. focusItem->window.flags |= WINDOW_HASFOCUS;
  1001. if (focusItem->onFocus) {
  1002. Item_RunScript(focusItem, focusItem->onFocus);
  1003. }
  1004. if (DC->Assets.itemFocusSound) {
  1005. DC->startLocalSound( DC->Assets.itemFocusSound, CHAN_LOCAL_SOUND );
  1006. }
  1007. }
  1008. }
  1009. }
  1010. void Script_SetPlayerModel(itemDef_t *item, char **args) {
  1011. const char *name;
  1012. if (String_Parse(args, &name)) {
  1013. DC->setCVar("team_model", name);
  1014. }
  1015. }
  1016. void Script_SetPlayerHead(itemDef_t *item, char **args) {
  1017. const char *name;
  1018. if (String_Parse(args, &name)) {
  1019. DC->setCVar("team_headmodel", name);
  1020. }
  1021. }
  1022. void Script_SetCvar(itemDef_t *item, char **args) {
  1023. const char *cvar, *val;
  1024. if (String_Parse(args, &cvar) && String_Parse(args, &val)) {
  1025. DC->setCVar(cvar, val);
  1026. }
  1027. }
  1028. void Script_Exec(itemDef_t *item, char **args) {
  1029. const char *val;
  1030. if (String_Parse(args, &val)) {
  1031. DC->executeText(EXEC_APPEND, va("%s ; ", val));
  1032. }
  1033. }
  1034. void Script_Play(itemDef_t *item, char **args) {
  1035. const char *val;
  1036. if (String_Parse(args, &val)) {
  1037. DC->startLocalSound(DC->registerSound(val, qfalse), CHAN_LOCAL_SOUND);
  1038. }
  1039. }
  1040. void Script_playLooped(itemDef_t *item, char **args) {
  1041. const char *val;
  1042. if (String_Parse(args, &val)) {
  1043. DC->stopBackgroundTrack();
  1044. DC->startBackgroundTrack(val, val);
  1045. }
  1046. }
  1047. commandDef_t commandList[] =
  1048. {
  1049. {"fadein", &Script_FadeIn}, // group/name
  1050. {"fadeout", &Script_FadeOut}, // group/name
  1051. {"show", &Script_Show}, // group/name
  1052. {"hide", &Script_Hide}, // group/name
  1053. {"setcolor", &Script_SetColor}, // works on this
  1054. {"open", &Script_Open}, // menu
  1055. {"conditionalopen", &Script_ConditionalOpen}, // menu
  1056. {"close", &Script_Close}, // menu
  1057. {"setasset", &Script_SetAsset}, // works on this
  1058. {"setbackground", &Script_SetBackground}, // works on this
  1059. {"setitemcolor", &Script_SetItemColor}, // group/name
  1060. {"setteamcolor", &Script_SetTeamColor}, // sets this background color to team color
  1061. {"setfocus", &Script_SetFocus}, // sets this background color to team color
  1062. {"setplayermodel", &Script_SetPlayerModel}, // sets this background color to team color
  1063. {"setplayerhead", &Script_SetPlayerHead}, // sets this background color to team color
  1064. {"transition", &Script_Transition}, // group/name
  1065. {"setcvar", &Script_SetCvar}, // group/name
  1066. {"exec", &Script_Exec}, // group/name
  1067. {"play", &Script_Play}, // group/name
  1068. {"playlooped", &Script_playLooped}, // group/name
  1069. {"orbit", &Script_Orbit} // group/name
  1070. };
  1071. int scriptCommandCount = sizeof(commandList) / sizeof(commandDef_t);
  1072. void Item_RunScript(itemDef_t *item, const char *s) {
  1073. char script[1024], *p;
  1074. int i;
  1075. qboolean bRan;
  1076. memset(script, 0, sizeof(script));
  1077. if (item && s && s[0]) {
  1078. Q_strcat(script, 1024, s);
  1079. p = script;
  1080. while (1) {
  1081. const char *command;
  1082. // expect command then arguments, ; ends command, NULL ends script
  1083. if (!String_Parse(&p, &command)) {
  1084. return;
  1085. }
  1086. if (command[0] == ';' && command[1] == '\0') {
  1087. continue;
  1088. }
  1089. bRan = qfalse;
  1090. for (i = 0; i < scriptCommandCount; i++) {
  1091. if (Q_stricmp(command, commandList[i].name) == 0) {
  1092. (commandList[i].handler(item, &p));
  1093. bRan = qtrue;
  1094. break;
  1095. }
  1096. }
  1097. // not in our auto list, pass to handler
  1098. if (!bRan) {
  1099. DC->runScript(&p);
  1100. }
  1101. }
  1102. }
  1103. }
  1104. qboolean Item_EnableShowViaCvar(itemDef_t *item, int flag) {
  1105. char script[1024], *p;
  1106. memset(script, 0, sizeof(script));
  1107. if (item && item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest) {
  1108. char buff[1024];
  1109. DC->getCVarString(item->cvarTest, buff, sizeof(buff));
  1110. Q_strcat(script, 1024, item->enableCvar);
  1111. p = script;
  1112. while (1) {
  1113. const char *val;
  1114. // expect value then ; or NULL, NULL ends list
  1115. if (!String_Parse(&p, &val)) {
  1116. return (item->cvarFlags & flag) ? qfalse : qtrue;
  1117. }
  1118. if (val[0] == ';' && val[1] == '\0') {
  1119. continue;
  1120. }
  1121. // enable it if any of the values are true
  1122. if (item->cvarFlags & flag) {
  1123. if (Q_stricmp(buff, val) == 0) {
  1124. return qtrue;
  1125. }
  1126. } else {
  1127. // disable it if any of the values are true
  1128. if (Q_stricmp(buff, val) == 0) {
  1129. return qfalse;
  1130. }
  1131. }
  1132. }
  1133. return (item->cvarFlags & flag) ? qfalse : qtrue;
  1134. }
  1135. return qtrue;
  1136. }
  1137. // will optionaly set focus to this item
  1138. qboolean Item_SetFocus(itemDef_t *item, float x, float y) {
  1139. int i;
  1140. itemDef_t *oldFocus;
  1141. sfxHandle_t *sfx = &DC->Assets.itemFocusSound;
  1142. qboolean playSound = qfalse;
  1143. menuDef_t *parent; // bk001206: = (menuDef_t*)item->parent;
  1144. // sanity check, non-null, not a decoration and does not already have the focus
  1145. if (item == NULL || item->window.flags & WINDOW_DECORATION || item->window.flags & WINDOW_HASFOCUS || !(item->window.flags & WINDOW_VISIBLE)) {
  1146. return qfalse;
  1147. }
  1148. // bk001206 - this can be NULL.
  1149. parent = (menuDef_t*)item->parent;
  1150. // items can be enabled and disabled based on cvars
  1151. if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
  1152. return qfalse;
  1153. }
  1154. if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW)) {
  1155. return qfalse;
  1156. }
  1157. oldFocus = Menu_ClearFocus(item->parent);
  1158. if (item->type == ITEM_TYPE_TEXT) {
  1159. rectDef_t r;
  1160. r = item->textRect;
  1161. r.y -= r.h;
  1162. if (Rect_ContainsPoint(&r, x, y)) {
  1163. item->window.flags |= WINDOW_HASFOCUS;
  1164. if (item->focusSound) {
  1165. sfx = &item->focusSound;
  1166. }
  1167. playSound = qtrue;
  1168. } else {
  1169. if (oldFocus) {
  1170. oldFocus->window.flags |= WINDOW_HASFOCUS;
  1171. if (oldFocus->onFocus) {
  1172. Item_RunScript(oldFocus, oldFocus->onFocus);
  1173. }
  1174. }
  1175. }
  1176. } else {
  1177. item->window.flags |= WINDOW_HASFOCUS;
  1178. if (item->onFocus) {
  1179. Item_RunScript(item, item->onFocus);
  1180. }
  1181. if (item->focusSound) {
  1182. sfx = &item->focusSound;
  1183. }
  1184. playSound = qtrue;
  1185. }
  1186. if (playSound && sfx) {
  1187. DC->startLocalSound( *sfx, CHAN_LOCAL_SOUND );
  1188. }
  1189. for (i = 0; i < parent->itemCount; i++) {
  1190. if (parent->items[i] == item) {
  1191. parent->cursorItem = i;
  1192. break;
  1193. }
  1194. }
  1195. return qtrue;
  1196. }
  1197. int Item_ListBox_MaxScroll(itemDef_t *item) {
  1198. listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
  1199. int count = DC->feederCount(item->special);
  1200. int max;
  1201. if (item->window.flags & WINDOW_HORIZONTAL) {
  1202. max = count - (item->window.rect.w / listPtr->elementWidth) + 1;
  1203. }
  1204. else {
  1205. max = count - (item->window.rect.h / listPtr->elementHeight) + 1;
  1206. }
  1207. if (max < 0) {
  1208. return 0;
  1209. }
  1210. return max;
  1211. }
  1212. int Item_ListBox_ThumbPosition(itemDef_t *item) {
  1213. float max, pos, size;
  1214. listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
  1215. max = Item_ListBox_MaxScroll(item);
  1216. if (item->window.flags & WINDOW_HORIZONTAL) {
  1217. size = item->window.rect.w - (SCROLLBAR_SIZE * 2) - 2;
  1218. if (max > 0) {
  1219. pos = (size-SCROLLBAR_SIZE) / (float) max;
  1220. } else {
  1221. pos = 0;
  1222. }
  1223. pos *= listPtr->startPos;
  1224. return item->window.rect.x + 1 + SCROLLBAR_SIZE + pos;
  1225. }
  1226. else {
  1227. size = item->window.rect.h - (SCROLLBAR_SIZE * 2) - 2;
  1228. if (max > 0) {
  1229. pos = (size-SCROLLBAR_SIZE) / (float) max;
  1230. } else {
  1231. pos = 0;
  1232. }
  1233. pos *= listPtr->startPos;
  1234. return item->window.rect.y + 1 + SCROLLBAR_SIZE + pos;
  1235. }
  1236. }
  1237. int Item_ListBox_ThumbDrawPosition(itemDef_t *item) {
  1238. int min, max;
  1239. if (itemCapture == item) {
  1240. if (item->window.flags & WINDOW_HORIZONTAL) {
  1241. min = item->window.rect.x + SCROLLBAR_SIZE + 1;
  1242. max = item->window.rect.x + item->window.rect.w - 2*SCROLLBAR_SIZE - 1;
  1243. if (DC->cursorx >= min + SCROLLBAR_SIZE/2 && DC->cursorx <= max + SCROLLBAR_SIZE/2) {
  1244. return DC->cursorx - SCROLLBAR_SIZE/2;
  1245. }
  1246. else {
  1247. return Item_ListBox_ThumbPosition(item);
  1248. }
  1249. }
  1250. else {
  1251. min = item->window.rect.y + SCROLLBAR_SIZE + 1;
  1252. max = item->window.rect.y + item->window.rect.h - 2*SCROLLBAR_SIZE - 1;
  1253. if (DC->cursory >= min + SCROLLBAR_SIZE/2 && DC->cursory <= max + SCROLLBAR_SIZE/2) {
  1254. return DC->cursory - SCROLLBAR_SIZE/2;
  1255. }
  1256. else {
  1257. return Item_ListBox_ThumbPosition(item);
  1258. }
  1259. }
  1260. }
  1261. else {
  1262. return Item_ListBox_ThumbPosition(item);
  1263. }
  1264. }
  1265. float Item_Slider_ThumbPosition(itemDef_t *item) {
  1266. float value, range, x;
  1267. editFieldDef_t *editDef = item->typeData;
  1268. if (item->text) {
  1269. x = item->textRect.x + item->textRect.w + 8;
  1270. } else {
  1271. x = item->window.rect.x;
  1272. }
  1273. if (editDef == NULL && item->cvar) {
  1274. return x;
  1275. }
  1276. value = DC->getCVarValue(item->cvar);
  1277. if (value < editDef->minVal) {
  1278. value = editDef->minVal;
  1279. } else if (value > editDef->maxVal) {
  1280. value = editDef->maxVal;
  1281. }
  1282. range = editDef->maxVal - editDef->minVal;
  1283. value -= editDef->minVal;
  1284. value /= range;
  1285. //value /= (editDef->maxVal - editDef->minVal);
  1286. value *= SLIDER_WIDTH;
  1287. x += value;
  1288. // vm fuckage
  1289. //x = x + (((float)value / editDef->maxVal) * SLIDER_WIDTH);
  1290. return x;
  1291. }
  1292. int Item_Slider_OverSlider(itemDef_t *item, float x, float y) {
  1293. rectDef_t r;
  1294. r.x = Item_Slider_ThumbPosition(item) - (SLIDER_THUMB_WIDTH / 2);
  1295. r.y = item->window.rect.y - 2;
  1296. r.w = SLIDER_THUMB_WIDTH;
  1297. r.h = SLIDER_THUMB_HEIGHT;
  1298. if (Rect_ContainsPoint(&r, x, y)) {
  1299. return WINDOW_LB_THUMB;
  1300. }
  1301. return 0;
  1302. }
  1303. int Item_ListBox_OverLB(itemDef_t *item, float x, float y) {
  1304. rectDef_t r;
  1305. listBoxDef_t *listPtr;
  1306. int thumbstart;
  1307. int count;
  1308. count = DC->feederCount(item->special);
  1309. listPtr = (listBoxDef_t*)item->typeData;
  1310. if (item->window.flags & WINDOW_HORIZONTAL) {
  1311. // check if on left arrow
  1312. r.x = item->window.rect.x;
  1313. r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
  1314. r.h = r.w = SCROLLBAR_SIZE;
  1315. if (Rect_ContainsPoint(&r, x, y)) {
  1316. return WINDOW_LB_LEFTARROW;
  1317. }
  1318. // check if on right arrow
  1319. r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
  1320. if (Rect_ContainsPoint(&r, x, y)) {
  1321. return WINDOW_LB_RIGHTARROW;
  1322. }
  1323. // check if on thumb
  1324. thumbstart = Item_ListBox_ThumbPosition(item);
  1325. r.x = thumbstart;
  1326. if (Rect_ContainsPoint(&r, x, y)) {
  1327. return WINDOW_LB_THUMB;
  1328. }
  1329. r.x = item->window.rect.x + SCROLLBAR_SIZE;
  1330. r.w = thumbstart - r.x;
  1331. if (Rect_ContainsPoint(&r, x, y)) {
  1332. return WINDOW_LB_PGUP;
  1333. }
  1334. r.x = thumbstart + SCROLLBAR_SIZE;
  1335. r.w = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
  1336. if (Rect_ContainsPoint(&r, x, y)) {
  1337. return WINDOW_LB_PGDN;
  1338. }
  1339. } else {
  1340. r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
  1341. r.y = item->window.rect.y;
  1342. r.h = r.w = SCROLLBAR_SIZE;
  1343. if (Rect_ContainsPoint(&r, x, y)) {
  1344. return WINDOW_LB_LEFTARROW;
  1345. }
  1346. r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
  1347. if (Rect_ContainsPoint(&r, x, y)) {
  1348. return WINDOW_LB_RIGHTARROW;
  1349. }
  1350. thumbstart = Item_ListBox_ThumbPosition(item);
  1351. r.y = thumbstart;
  1352. if (Rect_ContainsPoint(&r, x, y)) {
  1353. return WINDOW_LB_THUMB;
  1354. }
  1355. r.y = item->window.rect.y + SCROLLBAR_SIZE;
  1356. r.h = thumbstart - r.y;
  1357. if (Rect_ContainsPoint(&r, x, y)) {
  1358. return WINDOW_LB_PGUP;
  1359. }
  1360. r.y = thumbstart + SCROLLBAR_SIZE;
  1361. r.h = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
  1362. if (Rect_ContainsPoint(&r, x, y)) {
  1363. return WINDOW_LB_PGDN;
  1364. }
  1365. }
  1366. return 0;
  1367. }
  1368. void Item_ListBox_MouseEnter(itemDef_t *item, float x, float y)
  1369. {
  1370. rectDef_t r;
  1371. listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
  1372. item->window.flags &= ~(WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN);
  1373. item->window.flags |= Item_ListBox_OverLB(item, x, y);
  1374. if (item->window.flags & WINDOW_HORIZONTAL) {
  1375. if (!(item->window.flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN))) {
  1376. // check for selection hit as we have exausted buttons and thumb
  1377. if (listPtr->elementStyle == LISTBOX_IMAGE) {
  1378. r.x = item->window.rect.x;
  1379. r.y = item->window.rect.y;
  1380. r.h = item->window.rect.h - SCROLLBAR_SIZE;
  1381. r.w = item->window.rect.w - listPtr->drawPadding;
  1382. if (Rect_ContainsPoint(&r, x, y)) {
  1383. listPtr->cursorPos = (int)((x - r.x) / listPtr->elementWidth) + listPtr->startPos;
  1384. if (listPtr->cursorPos >= listPtr->endPos) {
  1385. listPtr->cursorPos = listPtr->endPos;
  1386. }
  1387. }
  1388. } else {
  1389. // text hit..
  1390. }
  1391. }
  1392. } else if (!(item->window.flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN))) {
  1393. r.x = item->window.rect.x;
  1394. r.y = item->window.rect.y;
  1395. r.w = item->window.rect.w - SCROLLBAR_SIZE;
  1396. r.h = item->window.rect.h - listPtr->drawPadding;
  1397. if (Rect_ContainsPoint(&r, x, y)) {
  1398. listPtr->cursorPos = (int)((y - 2 - r.y) / listPtr->elementHeight) + listPtr->startPos;
  1399. if (listPtr->cursorPos > listPtr->endPos) {
  1400. listPtr->cursorPos = listPtr->endPos;
  1401. }
  1402. }
  1403. }
  1404. }
  1405. void Item_MouseEnter(itemDef_t *item, float x, float y) {
  1406. rectDef_t r;
  1407. if (item) {
  1408. r = item->textRect;
  1409. r.y -= r.h;
  1410. // in the text rect?
  1411. // items can be enabled and disabled based on cvars
  1412. if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
  1413. return;
  1414. }
  1415. if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW)) {
  1416. return;
  1417. }
  1418. if (Rect_ContainsPoint(&r, x, y)) {
  1419. if (!(item->window.flags & WINDOW_MOUSEOVERTEXT)) {
  1420. Item_RunScript(item, item->mouseEnterText);
  1421. item->window.flags |= WINDOW_MOUSEOVERTEXT;
  1422. }
  1423. if (!(item->window.flags & WINDOW_MOUSEOVER)) {
  1424. Item_RunScript(item, item->mouseEnter);
  1425. item->window.flags |= WINDOW_MOUSEOVER;
  1426. }
  1427. } else {
  1428. // not in the text rect
  1429. if (item->window.flags & WINDOW_MOUSEOVERTEXT) {
  1430. // if we were
  1431. Item_RunScript(item, item->mouseExitText);
  1432. item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
  1433. }
  1434. if (!(item->window.flags & WINDOW_MOUSEOVER)) {
  1435. Item_RunScript(item, item->mouseEnter);
  1436. item->window.flags |= WINDOW_MOUSEOVER;
  1437. }
  1438. if (item->type == ITEM_TYPE_LISTBOX) {
  1439. Item_ListBox_MouseEnter(item, x, y);
  1440. }
  1441. }
  1442. }
  1443. }
  1444. void Item_MouseLeave(itemDef_t *item) {
  1445. if (item) {
  1446. if (item->window.flags & WINDOW_MOUSEOVERTEXT) {
  1447. Item_RunScript(item, item->mouseExitText);
  1448. item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
  1449. }
  1450. Item_RunScript(item, item->mouseExit);
  1451. item->window.flags &= ~(WINDOW_LB_RIGHTARROW | WINDOW_LB_LEFTARROW);
  1452. }
  1453. }
  1454. itemDef_t *Menu_HitTest(menuDef_t *menu, float x, float y) {
  1455. int i;
  1456. for (i = 0; i < menu->itemCount; i++) {
  1457. if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
  1458. return menu->items[i];
  1459. }
  1460. }
  1461. return NULL;
  1462. }
  1463. void Item_SetMouseOver(itemDef_t *item, qboolean focus) {
  1464. if (item) {
  1465. if (focus) {
  1466. item->window.flags |= WINDOW_MOUSEOVER;
  1467. } else {
  1468. item->window.flags &= ~WINDOW_MOUSEOVER;
  1469. }
  1470. }
  1471. }
  1472. qboolean Item_OwnerDraw_HandleKey(itemDef_t *item, int key) {
  1473. if (item && DC->ownerDrawHandleKey) {
  1474. return DC->ownerDrawHandleKey(item->window.ownerDraw, item->window.ownerDrawFlags, &item->special, key);
  1475. }
  1476. return qfalse;
  1477. }
  1478. qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolean force) {
  1479. listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
  1480. int count = DC->feederCount(item->special);
  1481. int max, viewmax;
  1482. if (force || (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS)) {
  1483. max = Item_ListBox_MaxScroll(item);
  1484. if (item->window.flags & WINDOW_HORIZONTAL) {
  1485. viewmax = (item->window.rect.w / listPtr->elementWidth);
  1486. if ( key == K_LEFTARROW || key == K_KP_LEFTARROW )
  1487. {
  1488. if (!listPtr->notselectable) {
  1489. listPtr->cursorPos--;
  1490. if (listPtr->cursorPos < 0) {
  1491. listPtr->cursorPos = 0;
  1492. }
  1493. if (listPtr->cursorPos < listPtr->startPos) {
  1494. listPtr->startPos = listPtr->cursorPos;
  1495. }
  1496. if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
  1497. listPtr->startPos = listPtr->cursorPos - viewmax + 1;
  1498. }
  1499. item->cursorPos = listPtr->cursorPos;
  1500. DC->feederSelection(item->special, item->cursorPos);
  1501. }
  1502. else {
  1503. listPtr->startPos--;
  1504. if (listPtr->startPos < 0)
  1505. listPtr->startPos = 0;
  1506. }
  1507. return qtrue;
  1508. }
  1509. if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW )
  1510. {
  1511. if (!listPtr->notselectable) {
  1512. listPtr->cursorPos++;
  1513. if (listPtr->cursorPos < listPtr->startPos) {
  1514. listPtr->startPos = listPtr->cursorPos;
  1515. }
  1516. if (listPtr->cursorPos >= count) {
  1517. listPtr->cursorPos = count-1;
  1518. }
  1519. if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
  1520. listPtr->startPos = listPtr->cursorPos - viewmax + 1;
  1521. }
  1522. item->cursorPos = listPtr->cursorPos;
  1523. DC->feederSelection(item->special, item->cursorPos);
  1524. }
  1525. else {
  1526. listPtr->startPos++;
  1527. if (listPtr->startPos >= count)
  1528. listPtr->startPos = count-1;
  1529. }
  1530. return qtrue;
  1531. }
  1532. }
  1533. else {
  1534. viewmax = (item->window.rect.h / listPtr->elementHeight);
  1535. if ( key == K_UPARROW || key == K_KP_UPARROW )
  1536. {
  1537. if (!listPtr->notselectable) {
  1538. listPtr->cursorPos--;
  1539. if (listPtr->cursorPos < 0) {
  1540. listPtr->cursorPos = 0;
  1541. }
  1542. if (listPtr->cursorPos < listPtr->startPos) {
  1543. listPtr->startPos = listPtr->cursorPos;
  1544. }
  1545. if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
  1546. listPtr->startPos = listPtr->cursorPos - viewmax + 1;
  1547. }
  1548. item->cursorPos = listPtr->cursorPos;
  1549. DC->feederSelection(item->special, item->cursorPos);
  1550. }
  1551. else {
  1552. listPtr->startPos--;
  1553. if (listPtr->startPos < 0)
  1554. listPtr->startPos = 0;
  1555. }
  1556. return qtrue;
  1557. }
  1558. if ( key == K_DOWNARROW || key == K_KP_DOWNARROW )
  1559. {
  1560. if (!listPtr->notselectable) {
  1561. listPtr->cursorPos++;
  1562. if (listPtr->cursorPos < listPtr->startPos) {
  1563. listPtr->startPos = listPtr->cursorPos;
  1564. }
  1565. if (listPtr->cursorPos >= count) {
  1566. listPtr->cursorPos = count-1;
  1567. }
  1568. if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
  1569. listPtr->startPos = listPtr->cursorPos - viewmax + 1;
  1570. }
  1571. item->cursorPos = listPtr->cursorPos;
  1572. DC->feederSelection(item->special, item->cursorPos);
  1573. }
  1574. else {
  1575. listPtr->startPos++;
  1576. if (listPtr->startPos > max)
  1577. listPtr->startPos = max;
  1578. }
  1579. return qtrue;
  1580. }
  1581. }
  1582. // mouse hit
  1583. if (key == K_MOUSE1 || key == K_MOUSE2) {
  1584. if (item->window.flags & WINDOW_LB_LEFTARROW) {
  1585. listPtr->startPos--;
  1586. if (listPtr->startPos < 0) {
  1587. listPtr->startPos = 0;
  1588. }
  1589. } else if (item->window.flags & WINDOW_LB_RIGHTARROW) {
  1590. // one down
  1591. listPtr->startPos++;
  1592. if (listPtr->startPos > max) {
  1593. listPtr->startPos = max;
  1594. }
  1595. } else if (item->window.flags & WINDOW_LB_PGUP) {
  1596. // page up
  1597. listPtr->startPos -= viewmax;
  1598. if (listPtr->startPos < 0) {
  1599. listPtr->startPos = 0;
  1600. }
  1601. } else if (item->window.flags & WINDOW_LB_PGDN) {
  1602. // page down
  1603. listPtr->startPos += viewmax;
  1604. if (listPtr->startPos > max) {
  1605. listPtr->startPos = max;
  1606. }
  1607. } else if (item->window.flags & WINDOW_LB_THUMB) {
  1608. // Display_SetCaptureItem(item);
  1609. } else {
  1610. // select an item
  1611. if (DC->realTime < lastListBoxClickTime && listPtr->doubleClick) {
  1612. Item_RunScript(item, listPtr->doubleClick);
  1613. }
  1614. lastListBoxClickTime = DC->realTime + DOUBLE_CLICK_DELAY;
  1615. if (item->cursorPos != listPtr->cursorPos) {
  1616. item->cursorPos = listPtr->cursorPos;
  1617. DC->feederSelection(item->special, item->cursorPos);
  1618. }
  1619. }
  1620. return qtrue;
  1621. }
  1622. if ( key == K_HOME || key == K_KP_HOME) {
  1623. // home
  1624. listPtr->startPos = 0;
  1625. return qtrue;
  1626. }
  1627. if ( key == K_END || key == K_KP_END) {
  1628. // end
  1629. listPtr->startPos = max;
  1630. return qtrue;
  1631. }
  1632. if (key == K_PGUP || key == K_KP_PGUP ) {
  1633. // page up
  1634. if (!listPtr->notselectable) {
  1635. listPtr->cursorPos -= viewmax;
  1636. if (listPtr->cursorPos < 0) {
  1637. listPtr->cursorPos = 0;
  1638. }
  1639. if (listPtr->cursorPos < listPtr->startPos) {
  1640. listPtr->startPos = listPtr->cursorPos;
  1641. }
  1642. if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
  1643. listPtr->startPos = listPtr->cursorPos - viewmax + 1;
  1644. }
  1645. item->cursorPos = listPtr->cursorPos;
  1646. DC->feederSelection(item->special, item->cursorPos);
  1647. }
  1648. else {
  1649. listPtr->startPos -= viewmax;
  1650. if (listPtr->startPos < 0) {
  1651. listPtr->startPos = 0;
  1652. }
  1653. }
  1654. return qtrue;
  1655. }
  1656. if ( key == K_PGDN || key == K_KP_PGDN ) {
  1657. // page down
  1658. if (!listPtr->notselectable) {
  1659. listPtr->cursorPos += viewmax;
  1660. if (listPtr->cursorPos < listPtr->startPos) {
  1661. listPtr->startPos = listPtr->cursorPos;
  1662. }
  1663. if (listPtr->cursorPos >= count) {
  1664. listPtr->cursorPos = count-1;
  1665. }
  1666. if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
  1667. listPtr->startPos = listPtr->cursorPos - viewmax + 1;
  1668. }
  1669. item->cursorPos = listPtr->cursorPos;
  1670. DC->feederSelection(item->special, item->cursorPos);
  1671. }
  1672. else {
  1673. listPtr->startPos += viewmax;
  1674. if (listPtr->startPos > max) {
  1675. listPtr->startPos = max;
  1676. }
  1677. }
  1678. return qtrue;
  1679. }
  1680. }
  1681. return qfalse;
  1682. }
  1683. qboolean Item_YesNo_HandleKey(itemDef_t *item, int key) {
  1684. if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS && item->cvar) {
  1685. if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
  1686. DC->setCVar(item->cvar, va("%i", !DC->getCVarValue(item->cvar)));
  1687. return qtrue;
  1688. }
  1689. }
  1690. return qfalse;
  1691. }
  1692. int Item_Multi_CountSettings(itemDef_t *item) {
  1693. multiDef_t *multiPtr = (multiDef_t*)item->typeData;
  1694. if (multiPtr == NULL) {
  1695. return 0;
  1696. }
  1697. return multiPtr->count;
  1698. }
  1699. int Item_Multi_FindCvarByValue(itemDef_t *item) {
  1700. char buff[1024];
  1701. float value = 0;
  1702. int i;
  1703. multiDef_t *multiPtr = (multiDef_t*)item->typeData;
  1704. if (multiPtr) {
  1705. if (multiPtr->strDef) {
  1706. DC->getCVarString(item->cvar, buff, sizeof(buff));
  1707. } else {
  1708. value = DC->getCVarValue(item->cvar);
  1709. }
  1710. for (i = 0; i < multiPtr->count; i++) {
  1711. if (multiPtr->strDef) {
  1712. if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0) {
  1713. return i;
  1714. }
  1715. } else {
  1716. if (multiPtr->cvarValue[i] == value) {
  1717. return i;
  1718. }
  1719. }
  1720. }
  1721. }
  1722. return 0;
  1723. }
  1724. const char *Item_Multi_Setting(itemDef_t *item) {
  1725. char buff[1024];
  1726. float value = 0;
  1727. int i;
  1728. multiDef_t *multiPtr = (multiDef_t*)item->typeData;
  1729. if (multiPtr) {
  1730. if (multiPtr->strDef) {
  1731. DC->getCVarString(item->cvar, buff, sizeof(buff));
  1732. } else {
  1733. value = DC->getCVarValue(item->cvar);
  1734. }
  1735. for (i = 0; i < multiPtr->count; i++) {
  1736. if (multiPtr->strDef) {
  1737. if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0) {
  1738. return multiPtr->cvarList[i];
  1739. }
  1740. } else {
  1741. if (multiPtr->cvarValue[i] == value) {
  1742. return multiPtr->cvarList[i];
  1743. }
  1744. }
  1745. }
  1746. }
  1747. return "";
  1748. }
  1749. qboolean Item_Multi_HandleKey(itemDef_t *item, int key) {
  1750. multiDef_t *multiPtr = (multiDef_t*)item->typeData;
  1751. if (multiPtr) {
  1752. if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS && item->cvar) {
  1753. if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
  1754. int current = Item_Multi_FindCvarByValue(item) + 1;
  1755. int max = Item_Multi_CountSettings(item);
  1756. if ( current < 0 || current >= max ) {
  1757. current = 0;
  1758. }
  1759. if (multiPtr->strDef) {
  1760. DC->setCVar(item->cvar, multiPtr->cvarStr[current]);
  1761. } else {
  1762. float value = multiPtr->cvarValue[current];
  1763. if (((float)((int) value)) == value) {
  1764. DC->setCVar(item->cvar, va("%i", (int) value ));
  1765. }
  1766. else {
  1767. DC->setCVar(item->cvar, va("%f", value ));
  1768. }
  1769. }
  1770. return qtrue;
  1771. }
  1772. }
  1773. }
  1774. return qfalse;
  1775. }
  1776. qboolean Item_TextField_HandleKey(itemDef_t *item, int key) {
  1777. char buff[1024];
  1778. int len;
  1779. itemDef_t *newItem = NULL;
  1780. editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
  1781. if (item->cvar) {
  1782. memset(buff, 0, sizeof(buff));
  1783. DC->getCVarString(item->cvar, buff, sizeof(buff));
  1784. len = strlen(buff);
  1785. if (editPtr->maxChars && len > editPtr->maxChars) {
  1786. len = editPtr->maxChars;
  1787. }
  1788. if ( key & K_CHAR_FLAG ) {
  1789. key &= ~K_CHAR_FLAG;
  1790. if (key == 'h' - 'a' + 1 ) { // ctrl-h is backspace
  1791. if ( item->cursorPos > 0 ) {
  1792. memmove( &buff[item->cursorPos - 1], &buff[item->cursorPos], len + 1 - item->cursorPos);
  1793. item->cursorPos--;
  1794. if (item->cursorPos < editPtr->paintOffset) {
  1795. editPtr->paintOffset--;
  1796. }
  1797. }
  1798. DC->setCVar(item->cvar, buff);
  1799. return qtrue;
  1800. }
  1801. //
  1802. // ignore any non printable chars
  1803. //
  1804. if ( key < 32 || !item->cvar) {
  1805. return qtrue;
  1806. }
  1807. if (item->type == ITEM_TYPE_NUMERICFIELD) {
  1808. if (key < '0' || key > '9') {
  1809. return qfalse;
  1810. }
  1811. }
  1812. if (!DC->getOverstrikeMode()) {
  1813. if (( len == MAX_EDITFIELD - 1 ) || (editPtr->maxChars && len >= editPtr->maxChars)) {
  1814. return qtrue;
  1815. }
  1816. memmove( &buff[item->cursorPos + 1], &buff[item->cursorPos], len + 1 - item->cursorPos );
  1817. } else {
  1818. if (editPtr->maxChars && item->cursorPos >= editPtr->maxChars) {
  1819. return qtrue;
  1820. }
  1821. }
  1822. buff[item->cursorPos] = key;
  1823. DC->setCVar(item->cvar, buff);
  1824. if (item->cursorPos < len + 1) {
  1825. item->cursorPos++;
  1826. if (editPtr->maxPaintChars && item->cursorPos > editPtr->maxPaintChars) {
  1827. editPtr->paintOffset++;
  1828. }
  1829. }
  1830. } else {
  1831. if ( key == K_DEL || key == K_KP_DEL ) {
  1832. if ( item->cursorPos < len ) {
  1833. memmove( buff + item->cursorPos, buff + item->cursorPos + 1, len - item->cursorPos);
  1834. DC->setCVar(item->cvar, buff);
  1835. }
  1836. return qtrue;
  1837. }
  1838. if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW )
  1839. {
  1840. if (editPtr->maxPaintChars && item->cursorPos >= editPtr->maxPaintChars && item->cursorPos < len) {
  1841. item->cursorPos++;
  1842. editPtr->paintOffset++;
  1843. return qtrue;
  1844. }
  1845. if (item->cursorPos < len) {
  1846. item->cursorPos++;
  1847. }
  1848. return qtrue;
  1849. }
  1850. if ( key == K_LEFTARROW || key == K_KP_LEFTARROW )
  1851. {
  1852. if ( item->cursorPos > 0 ) {
  1853. item->cursorPos--;
  1854. }
  1855. if (item->cursorPos < editPtr->paintOffset) {
  1856. editPtr->paintOffset--;
  1857. }
  1858. return qtrue;
  1859. }
  1860. if ( key == K_HOME || key == K_KP_HOME) {// || ( tolower(key) == 'a' && trap_Key_IsDown( K_CTRL ) ) ) {
  1861. item->cursorPos = 0;
  1862. editPtr->paintOffset = 0;
  1863. return qtrue;
  1864. }
  1865. if ( key == K_END || key == K_KP_END) {// ( tolower(key) == 'e' && trap_Key_IsDown( K_CTRL ) ) ) {
  1866. item->cursorPos = len;
  1867. if(item->cursorPos > editPtr->maxPaintChars) {
  1868. editPtr->paintOffset = len - editPtr->maxPaintChars;
  1869. }
  1870. return qtrue;
  1871. }
  1872. if ( key == K_INS || key == K_KP_INS ) {
  1873. DC->setOverstrikeMode(!DC->getOverstrikeMode());
  1874. return qtrue;
  1875. }
  1876. }
  1877. if (key == K_TAB || key == K_DOWNARROW || key == K_KP_DOWNARROW) {
  1878. newItem = Menu_SetNextCursorItem(item->parent);
  1879. if (newItem && (newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD)) {
  1880. g_editItem = newItem;
  1881. }
  1882. }
  1883. if (key == K_UPARROW || key == K_KP_UPARROW) {
  1884. newItem = Menu_SetPrevCursorItem(item->parent);
  1885. if (newItem && (newItem->type == ITEM_TYPE_EDITFIELD || newItem->type == ITEM_TYPE_NUMERICFIELD)) {
  1886. g_editItem = newItem;
  1887. }
  1888. }
  1889. if ( key == K_ENTER || key == K_KP_ENTER || key == K_ESCAPE) {
  1890. return qfalse;
  1891. }
  1892. return qtrue;
  1893. }
  1894. return qfalse;
  1895. }
  1896. static void Scroll_ListBox_AutoFunc(void *p) {
  1897. scrollInfo_t *si = (scrollInfo_t*)p;
  1898. if (DC->realTime > si->nextScrollTime) {
  1899. // need to scroll which is done by simulating a click to the item
  1900. // this is done a bit sideways as the autoscroll "knows" that the item is a listbox
  1901. // so it calls it directly
  1902. Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
  1903. si->nextScrollTime = DC->realTime + si->adjustValue;
  1904. }
  1905. if (DC->realTime > si->nextAdjustTime) {
  1906. si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
  1907. if (si->adjustValue > SCROLL_TIME_FLOOR) {
  1908. si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
  1909. }
  1910. }
  1911. }
  1912. static void Scroll_ListBox_ThumbFunc(void *p) {
  1913. scrollInfo_t *si = (scrollInfo_t*)p;
  1914. rectDef_t r;
  1915. int pos, max;
  1916. listBoxDef_t *listPtr = (listBoxDef_t*)si->item->typeData;
  1917. if (si->item->window.flags & WINDOW_HORIZONTAL) {
  1918. if (DC->cursorx == si->xStart) {
  1919. return;
  1920. }
  1921. r.x = si->item->window.rect.x + SCROLLBAR_SIZE + 1;
  1922. r.y = si->item->window.rect.y + si->item->window.rect.h - SCROLLBAR_SIZE - 1;
  1923. r.h = SCROLLBAR_SIZE;
  1924. r.w = si->item->window.rect.w - (SCROLLBAR_SIZE*2) - 2;
  1925. max = Item_ListBox_MaxScroll(si->item);
  1926. //
  1927. pos = (DC->cursorx - r.x - SCROLLBAR_SIZE/2) * max / (r.w - SCROLLBAR_SIZE);
  1928. if (pos < 0) {
  1929. pos = 0;
  1930. }
  1931. else if (pos > max) {
  1932. pos = max;
  1933. }
  1934. listPtr->startPos = pos;
  1935. si->xStart = DC->cursorx;
  1936. }
  1937. else if (DC->cursory != si->yStart) {
  1938. r.x = si->item->window.rect.x + si->item->window.rect.w - SCROLLBAR_SIZE - 1;
  1939. r.y = si->item->window.rect.y + SCROLLBAR_SIZE + 1;
  1940. r.h = si->item->window.rect.h - (SCROLLBAR_SIZE*2) - 2;
  1941. r.w = SCROLLBAR_SIZE;
  1942. max = Item_ListBox_MaxScroll(si->item);
  1943. //
  1944. pos = (DC->cursory - r.y - SCROLLBAR_SIZE/2) * max / (r.h - SCROLLBAR_SIZE);
  1945. if (pos < 0) {
  1946. pos = 0;
  1947. }
  1948. else if (pos > max) {
  1949. pos = max;
  1950. }
  1951. listPtr->startPos = pos;
  1952. si->yStart = DC->cursory;
  1953. }
  1954. if (DC->realTime > si->nextScrollTime) {
  1955. // need to scroll which is done by simulating a click to the item
  1956. // this is done a bit sideways as the autoscroll "knows" that the item is a listbox
  1957. // so it calls it directly
  1958. Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
  1959. si->nextScrollTime = DC->realTime + si->adjustValue;
  1960. }
  1961. if (DC->realTime > si->nextAdjustTime) {
  1962. si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
  1963. if (si->adjustValue > SCROLL_TIME_FLOOR) {
  1964. si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
  1965. }
  1966. }
  1967. }
  1968. static void Scroll_Slider_ThumbFunc(void *p) {
  1969. float x, value, cursorx;
  1970. scrollInfo_t *si = (scrollInfo_t*)p;
  1971. editFieldDef_t *editDef = si->item->typeData;
  1972. if (si->item->text) {
  1973. x = si->item->textRect.x + si->item->textRect.w + 8;
  1974. } else {
  1975. x = si->item->window.rect.x;
  1976. }
  1977. cursorx = DC->cursorx;
  1978. if (cursorx < x) {
  1979. cursorx = x;
  1980. } else if (cursorx > x + SLIDER_WIDTH) {
  1981. cursorx = x + SLIDER_WIDTH;
  1982. }
  1983. value = cursorx - x;
  1984. value /= SLIDER_WIDTH;
  1985. value *= (editDef->maxVal - editDef->minVal);
  1986. value += editDef->minVal;
  1987. DC->setCVar(si->item->cvar, va("%f", value));
  1988. }
  1989. void Item_StartCapture(itemDef_t *item, int key) {
  1990. int flags;
  1991. switch (item->type) {
  1992. case ITEM_TYPE_EDITFIELD:
  1993. case ITEM_TYPE_NUMERICFIELD:
  1994. case ITEM_TYPE_LISTBOX:
  1995. {
  1996. flags = Item_ListBox_OverLB(item, DC->cursorx, DC->cursory);
  1997. if (flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW)) {
  1998. scrollInfo.nextScrollTime = DC->realTime + SCROLL_TIME_START;
  1999. scrollInfo.nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
  2000. scrollInfo.adjustValue = SCROLL_TIME_START;
  2001. scrollInfo.scrollKey = key;
  2002. scrollInfo.scrollDir = (flags & WINDOW_LB_LEFTARROW) ? qtrue : qfalse;
  2003. scrollInfo.item = item;
  2004. captureData = &scrollInfo;
  2005. captureFunc = &Scroll_ListBox_AutoFunc;
  2006. itemCapture = item;
  2007. } else if (flags & WINDOW_LB_THUMB) {
  2008. scrollInfo.scrollKey = key;
  2009. scrollInfo.item = item;
  2010. scrollInfo.xStart = DC->cursorx;
  2011. scrollInfo.yStart = DC->cursory;
  2012. captureData = &scrollInfo;
  2013. captureFunc = &Scroll_ListBox_ThumbFunc;
  2014. itemCapture = item;
  2015. }
  2016. break;
  2017. }
  2018. case ITEM_TYPE_SLIDER:
  2019. {
  2020. flags = Item_Slider_OverSlider(item, DC->cursorx, DC->cursory);
  2021. if (flags & WINDOW_LB_THUMB) {
  2022. scrollInfo.scrollKey = key;
  2023. scrollInfo.item = item;
  2024. scrollInfo.xStart = DC->cursorx;
  2025. scrollInfo.yStart = DC->cursory;
  2026. captureData = &scrollInfo;
  2027. captureFunc = &Scroll_Slider_ThumbFunc;
  2028. itemCapture = item;
  2029. }
  2030. break;
  2031. }
  2032. }
  2033. }
  2034. void Item_StopCapture(itemDef_t *item) {
  2035. }
  2036. qboolean Item_Slider_HandleKey(itemDef_t *item, int key, qboolean down) {
  2037. float x, value, width, work;
  2038. //DC->Print("slider handle key\n");
  2039. if (item->window.flags & WINDOW_HASFOCUS && item->cvar && Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
  2040. if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
  2041. editFieldDef_t *editDef = item->typeData;
  2042. if (editDef) {
  2043. rectDef_t testRect;
  2044. width = SLIDER_WIDTH;
  2045. if (item->text) {
  2046. x = item->textRect.x + item->textRect.w + 8;
  2047. } else {
  2048. x = item->window.rect.x;
  2049. }
  2050. testRect = item->window.rect;
  2051. testRect.x = x;
  2052. value = (float)SLIDER_THUMB_WIDTH / 2;
  2053. testRect.x -= value;
  2054. //DC->Print("slider x: %f\n", testRect.x);
  2055. testRect.w = (SLIDER_WIDTH + (float)SLIDER_THUMB_WIDTH / 2);
  2056. //DC->Print("slider w: %f\n", testRect.w);
  2057. if (Rect_ContainsPoint(&testRect, DC->cursorx, DC->cursory)) {
  2058. work = DC->cursorx - x;
  2059. value = work / width;
  2060. value *= (editDef->maxVal - editDef->minVal);
  2061. // vm fuckage
  2062. // value = (((float)(DC->cursorx - x)/ SLIDER_WIDTH) * (editDef->maxVal - editDef->minVal));
  2063. value += editDef->minVal;
  2064. DC->setCVar(item->cvar, va("%f", value));
  2065. return qtrue;
  2066. }
  2067. }
  2068. }
  2069. }
  2070. DC->Print("slider handle key exit\n");
  2071. return qfalse;
  2072. }
  2073. qboolean Item_HandleKey(itemDef_t *item, int key, qboolean down) {
  2074. if (itemCapture) {
  2075. Item_StopCapture(itemCapture);
  2076. itemCapture = NULL;
  2077. captureFunc = NULL;
  2078. captureData = NULL;
  2079. } else {
  2080. // bk001206 - parentheses
  2081. if ( down && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 ) ) {
  2082. Item_StartCapture(item, key);
  2083. }
  2084. }
  2085. if (!down) {
  2086. return qfalse;
  2087. }
  2088. switch (item->type) {
  2089. case ITEM_TYPE_BUTTON:
  2090. return qfalse;
  2091. break;
  2092. case ITEM_TYPE_RADIOBUTTON:
  2093. return qfalse;
  2094. break;
  2095. case ITEM_TYPE_CHECKBOX:
  2096. return qfalse;
  2097. break;
  2098. case ITEM_TYPE_EDITFIELD:
  2099. case ITEM_TYPE_NUMERICFIELD:
  2100. //return Item_TextField_HandleKey(item, key);
  2101. return qfalse;
  2102. break;
  2103. case ITEM_TYPE_COMBO:
  2104. return qfalse;
  2105. break;
  2106. case ITEM_TYPE_LISTBOX:
  2107. return Item_ListBox_HandleKey(item, key, down, qfalse);
  2108. break;
  2109. case ITEM_TYPE_YESNO:
  2110. return Item_YesNo_HandleKey(item, key);
  2111. break;
  2112. case ITEM_TYPE_MULTI:
  2113. return Item_Multi_HandleKey(item, key);
  2114. break;
  2115. case ITEM_TYPE_OWNERDRAW:
  2116. return Item_OwnerDraw_HandleKey(item, key);
  2117. break;
  2118. case ITEM_TYPE_BIND:
  2119. return Item_Bind_HandleKey(item, key, down);
  2120. break;
  2121. case ITEM_TYPE_SLIDER:
  2122. return Item_Slider_HandleKey(item, key, down);
  2123. break;
  2124. //case ITEM_TYPE_IMAGE:
  2125. // Item_Image_Paint(item);
  2126. // break;
  2127. default:
  2128. return qfalse;
  2129. break;
  2130. }
  2131. //return qfalse;
  2132. }
  2133. void Item_Action(itemDef_t *item) {
  2134. if (item) {
  2135. Item_RunScript(item, item->action);
  2136. }
  2137. }
  2138. itemDef_t *Menu_SetPrevCursorItem(menuDef_t *menu) {
  2139. qboolean wrapped = qfalse;
  2140. int oldCursor = menu->cursorItem;
  2141. if (menu->cursorItem < 0) {
  2142. menu->cursorItem = menu->itemCount-1;
  2143. wrapped = qtrue;
  2144. }
  2145. while (menu->cursorItem > -1) {
  2146. menu->cursorItem--;
  2147. if (menu->cursorItem < 0 && !wrapped) {
  2148. wrapped = qtrue;
  2149. menu->cursorItem = menu->itemCount -1;
  2150. }
  2151. if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory)) {
  2152. Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1, menu->items[menu->cursorItem]->window.rect.y + 1);
  2153. return menu->items[menu->cursorItem];
  2154. }
  2155. }
  2156. menu->cursorItem = oldCursor;
  2157. return NULL;
  2158. }
  2159. itemDef_t *Menu_SetNextCursorItem(menuDef_t *menu) {
  2160. qboolean wrapped = qfalse;
  2161. int oldCursor = menu->cursorItem;
  2162. if (menu->cursorItem == -1) {
  2163. menu->cursorItem = 0;
  2164. wrapped = qtrue;
  2165. }
  2166. while (menu->cursorItem < menu->itemCount) {
  2167. menu->cursorItem++;
  2168. if (menu->cursorItem >= menu->itemCount && !wrapped) {
  2169. wrapped = qtrue;
  2170. menu->cursorItem = 0;
  2171. }
  2172. if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory)) {
  2173. Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1, menu->items[menu->cursorItem]->window.rect.y + 1);
  2174. return menu->items[menu->cursorItem];
  2175. }
  2176. }
  2177. menu->cursorItem = oldCursor;
  2178. return NULL;
  2179. }
  2180. static void Window_CloseCinematic(windowDef_t *window) {
  2181. if (window->style == WINDOW_STYLE_CINEMATIC && window->cinematic >= 0) {
  2182. DC->stopCinematic(window->cinematic);
  2183. window->cinematic = -1;
  2184. }
  2185. }
  2186. static void Menu_CloseCinematics(menuDef_t *menu) {
  2187. if (menu) {
  2188. int i;
  2189. Window_CloseCinematic(&menu->window);
  2190. for (i = 0; i < menu->itemCount; i++) {
  2191. Window_CloseCinematic(&menu->items[i]->window);
  2192. if (menu->items[i]->type == ITEM_TYPE_OWNERDRAW) {
  2193. DC->stopCinematic(0-menu->items[i]->window.ownerDraw);
  2194. }
  2195. }
  2196. }
  2197. }
  2198. static void Display_CloseCinematics() {
  2199. int i;
  2200. for (i = 0; i < menuCount; i++) {
  2201. Menu_CloseCinematics(&Menus[i]);
  2202. }
  2203. }
  2204. void Menus_Activate(menuDef_t *menu) {
  2205. menu->window.flags |= (WINDOW_HASFOCUS | WINDOW_VISIBLE);
  2206. if (menu->onOpen) {
  2207. itemDef_t item;
  2208. item.parent = menu;
  2209. Item_RunScript(&item, menu->onOpen);
  2210. }
  2211. if (menu->soundName && *menu->soundName) {
  2212. // DC->stopBackgroundTrack(); // you don't want to do this since it will reset s_rawend
  2213. DC->startBackgroundTrack(menu->soundName, menu->soundName);
  2214. }
  2215. Display_CloseCinematics();
  2216. }
  2217. int Display_VisibleMenuCount() {
  2218. int i, count;
  2219. count = 0;
  2220. for (i = 0; i < menuCount; i++) {
  2221. if (Menus[i].window.flags & (WINDOW_FORCED | WINDOW_VISIBLE)) {
  2222. count++;
  2223. }
  2224. }
  2225. return count;
  2226. }
  2227. void Menus_HandleOOBClick(menuDef_t *menu, int key, qboolean down) {
  2228. if (menu) {
  2229. int i;
  2230. // basically the behaviour we are looking for is if there are windows in the stack.. see if
  2231. // the cursor is within any of them.. if not close them otherwise activate them and pass the
  2232. // key on.. force a mouse move to activate focus and script stuff
  2233. if (down && menu->window.flags & WINDOW_OOB_CLICK) {
  2234. Menu_RunCloseScript(menu);
  2235. menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
  2236. }
  2237. for (i = 0; i < menuCount; i++) {
  2238. if (Menu_OverActiveItem(&Menus[i], DC->cursorx, DC->cursory)) {
  2239. Menu_RunCloseScript(menu);
  2240. menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
  2241. Menus_Activate(&Menus[i]);
  2242. Menu_HandleMouseMove(&Menus[i], DC->cursorx, DC->cursory);
  2243. Menu_HandleKey(&Menus[i], key, down);
  2244. }
  2245. }
  2246. if (Display_VisibleMenuCount() == 0) {
  2247. if (DC->Pause) {
  2248. DC->Pause(qfalse);
  2249. }
  2250. }
  2251. Display_CloseCinematics();
  2252. }
  2253. }
  2254. static rectDef_t *Item_CorrectedTextRect(itemDef_t *item) {
  2255. static rectDef_t rect;
  2256. memset(&rect, 0, sizeof(rectDef_t));
  2257. if (item) {
  2258. rect = item->textRect;
  2259. if (rect.w) {
  2260. rect.y -= rect.h;
  2261. }
  2262. }
  2263. return &rect;
  2264. }
  2265. void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) {
  2266. int i;
  2267. itemDef_t *item = NULL;
  2268. qboolean inHandler = qfalse;
  2269. if (inHandler) {
  2270. return;
  2271. }
  2272. inHandler = qtrue;
  2273. if (g_waitingForKey && down) {
  2274. Item_Bind_HandleKey(g_bindItem, key, down);
  2275. inHandler = qfalse;
  2276. return;
  2277. }
  2278. if (g_editingField && down) {
  2279. if (!Item_TextField_HandleKey(g_editItem, key)) {
  2280. g_editingField = qfalse;
  2281. g_editItem = NULL;
  2282. inHandler = qfalse;
  2283. return;
  2284. } else if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3) {
  2285. g_editingField = qfalse;
  2286. g_editItem = NULL;
  2287. Display_MouseMove(NULL, DC->cursorx, DC->cursory);
  2288. } else if (key == K_TAB || key == K_UPARROW || key == K_DOWNARROW) {
  2289. return;
  2290. }
  2291. }
  2292. if (menu == NULL) {
  2293. inHandler = qfalse;
  2294. return;
  2295. }
  2296. // see if the mouse is within the window bounds and if so is this a mouse click
  2297. if (down && !(menu->window.flags & WINDOW_POPUP) && !Rect_ContainsPoint(&menu->window.rect, DC->cursorx, DC->cursory)) {
  2298. static qboolean inHandleKey = qfalse;
  2299. // bk001206 - parentheses
  2300. if (!inHandleKey && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 ) ) {
  2301. inHandleKey = qtrue;
  2302. Menus_HandleOOBClick(menu, key, down);
  2303. inHandleKey = qfalse;
  2304. inHandler = qfalse;
  2305. return;
  2306. }
  2307. }
  2308. // get the item with focus
  2309. for (i = 0; i < menu->itemCount; i++) {
  2310. if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
  2311. item = menu->items[i];
  2312. }
  2313. }
  2314. if (item != NULL) {
  2315. if (Item_HandleKey(item, key, down)) {
  2316. Item_Action(item);
  2317. inHandler = qfalse;
  2318. return;
  2319. }
  2320. }
  2321. if (!down) {
  2322. inHandler = qfalse;
  2323. return;
  2324. }
  2325. // default handling
  2326. switch ( key ) {
  2327. case K_F11:
  2328. if (DC->getCVarValue("developer")) {
  2329. debugMode ^= 1;
  2330. }
  2331. break;
  2332. case K_F12:
  2333. if (DC->getCVarValue("developer")) {
  2334. DC->executeText(EXEC_APPEND, "screenshot\n");
  2335. }
  2336. break;
  2337. case K_KP_UPARROW:
  2338. case K_UPARROW:
  2339. Menu_SetPrevCursorItem(menu);
  2340. break;
  2341. case K_ESCAPE:
  2342. if (!g_waitingForKey && menu->onESC) {
  2343. itemDef_t it;
  2344. it.parent = menu;
  2345. Item_RunScript(&it, menu->onESC);
  2346. }
  2347. break;
  2348. case K_TAB:
  2349. case K_KP_DOWNARROW:
  2350. case K_DOWNARROW:
  2351. Menu_SetNextCursorItem(menu);
  2352. break;
  2353. case K_MOUSE1:
  2354. case K_MOUSE2:
  2355. if (item) {
  2356. if (item->type == ITEM_TYPE_TEXT) {
  2357. if (Rect_ContainsPoint(Item_CorrectedTextRect(item), DC->cursorx, DC->cursory)) {
  2358. Item_Action(item);
  2359. }
  2360. } else if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD) {
  2361. if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
  2362. item->cursorPos = 0;
  2363. g_editingField = qtrue;
  2364. g_editItem = item;
  2365. DC->setOverstrikeMode(qtrue);
  2366. }
  2367. } else {
  2368. if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
  2369. Item_Action(item);
  2370. }
  2371. }
  2372. }
  2373. break;
  2374. case K_JOY1:
  2375. case K_JOY2:
  2376. case K_JOY3:
  2377. case K_JOY4:
  2378. case K_AUX1:
  2379. case K_AUX2:
  2380. case K_AUX3:
  2381. case K_AUX4:
  2382. case K_AUX5:
  2383. case K_AUX6:
  2384. case K_AUX7:
  2385. case K_AUX8:
  2386. case K_AUX9:
  2387. case K_AUX10:
  2388. case K_AUX11:
  2389. case K_AUX12:
  2390. case K_AUX13:
  2391. case K_AUX14:
  2392. case K_AUX15:
  2393. case K_AUX16:
  2394. break;
  2395. case K_KP_ENTER:
  2396. case K_ENTER:
  2397. if (item) {
  2398. if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD) {
  2399. item->cursorPos = 0;
  2400. g_editingField = qtrue;
  2401. g_editItem = item;
  2402. DC->setOverstrikeMode(qtrue);
  2403. } else {
  2404. Item_Action(item);
  2405. }
  2406. }
  2407. break;
  2408. }
  2409. inHandler = qfalse;
  2410. }
  2411. void ToWindowCoords(float *x, float *y, windowDef_t *window) {
  2412. if (window->border != 0) {
  2413. *x += window->borderSize;
  2414. *y += window->borderSize;
  2415. }
  2416. *x += window->rect.x;
  2417. *y += window->rect.y;
  2418. }
  2419. void Rect_ToWindowCoords(rectDef_t *rect, windowDef_t *window) {
  2420. ToWindowCoords(&rect->x, &rect->y, window);
  2421. }
  2422. void Item_SetTextExtents(itemDef_t *item, int *width, int *height, const char *text) {
  2423. const char *textPtr = (text) ? text : item->text;
  2424. if (textPtr == NULL ) {
  2425. return;
  2426. }
  2427. *width = item->textRect.w;
  2428. *height = item->textRect.h;
  2429. // keeps us from computing the widths and heights more than once
  2430. if (*width == 0 || (item->type == ITEM_TYPE_OWNERDRAW && item->textalignment == ITEM_ALIGN_CENTER)) {
  2431. int originalWidth = DC->textWidth(item->text, item->textscale, 0);
  2432. if (item->type == ITEM_TYPE_OWNERDRAW && (item->textalignment == ITEM_ALIGN_CENTER || item->textalignment == ITEM_ALIGN_RIGHT)) {
  2433. originalWidth += DC->ownerDrawWidth(item->window.ownerDraw, item->textscale);
  2434. } else if (item->type == ITEM_TYPE_EDITFIELD && item->textalignment == ITEM_ALIGN_CENTER && item->cvar) {
  2435. char buff[256];
  2436. DC->getCVarString(item->cvar, buff, 256);
  2437. originalWidth += DC->textWidth(buff, item->textscale, 0);
  2438. }
  2439. *width = DC->textWidth(textPtr, item->textscale, 0);
  2440. *height = DC->textHeight(textPtr, item->textscale, 0);
  2441. item->textRect.w = *width;
  2442. item->textRect.h = *height;
  2443. item->textRect.x = item->textalignx;
  2444. item->textRect.y = item->textaligny;
  2445. if (item->textalignment == ITEM_ALIGN_RIGHT) {
  2446. item->textRect.x = item->textalignx - originalWidth;
  2447. } else if (item->textalignment == ITEM_ALIGN_CENTER) {
  2448. item->textRect.x = item->textalignx - originalWidth / 2;
  2449. }
  2450. ToWindowCoords(&item->textRect.x, &item->textRect.y, &item->window);
  2451. }
  2452. }
  2453. void Item_TextColor(itemDef_t *item, vec4_t *newColor) {
  2454. vec4_t lowLight;
  2455. menuDef_t *parent = (menuDef_t*)item->parent;
  2456. Fade(&item->window.flags, &item->window.foreColor[3], parent->fadeClamp, &item->window.nextTime, parent->fadeCycle, qtrue, parent->fadeAmount);
  2457. if (item->window.flags & WINDOW_HASFOCUS) {
  2458. lowLight[0] = 0.8 * parent->focusColor[0];
  2459. lowLight[1] = 0.8 * parent->focusColor[1];
  2460. lowLight[2] = 0.8 * parent->focusColor[2];
  2461. lowLight[3] = 0.8 * parent->focusColor[3];
  2462. LerpColor(parent->focusColor,lowLight,*newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
  2463. } else if (item->textStyle == ITEM_TEXTSTYLE_BLINK && !((DC->realTime/BLINK_DIVISOR) & 1)) {
  2464. lowLight[0] = 0.8 * item->window.foreColor[0];
  2465. lowLight[1] = 0.8 * item->window.foreColor[1];
  2466. lowLight[2] = 0.8 * item->window.foreColor[2];
  2467. lowLight[3] = 0.8 * item->window.foreColor[3];
  2468. LerpColor(item->window.foreColor,lowLight,*newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
  2469. } else {
  2470. memcpy(newColor, &item->window.foreColor, sizeof(vec4_t));
  2471. // items can be enabled and disabled based on cvars
  2472. }
  2473. if (item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest) {
  2474. if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
  2475. memcpy(newColor, &parent->disableColor, sizeof(vec4_t));
  2476. }
  2477. }
  2478. }
  2479. void Item_Text_AutoWrapped_Paint(itemDef_t *item) {
  2480. char text[1024];
  2481. const char *p, *textPtr, *newLinePtr;
  2482. char buff[1024];
  2483. int width, height, len, textWidth, newLine, newLineWidth;
  2484. float y;
  2485. vec4_t color;
  2486. textWidth = 0;
  2487. newLinePtr = NULL;
  2488. if (item->text == NULL) {
  2489. if (item->cvar == NULL) {
  2490. return;
  2491. }
  2492. else {
  2493. DC->getCVarString(item->cvar, text, sizeof(text));
  2494. textPtr = text;
  2495. }
  2496. }
  2497. else {
  2498. textPtr = item->text;
  2499. }
  2500. if (*textPtr == '\0') {
  2501. return;
  2502. }
  2503. Item_TextColor(item, &color);
  2504. Item_SetTextExtents(item, &width, &height, textPtr);
  2505. y = item->textaligny;
  2506. len = 0;
  2507. buff[0] = '\0';
  2508. newLine = 0;
  2509. newLineWidth = 0;
  2510. p = textPtr;
  2511. while (p) {
  2512. if (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\0') {
  2513. newLine = len;
  2514. newLinePtr = p+1;
  2515. newLineWidth = textWidth;
  2516. }
  2517. textWidth = DC->textWidth(buff, item->textscale, 0);
  2518. if ( (newLine && textWidth > item->window.rect.w) || *p == '\n' || *p == '\0') {
  2519. if (len) {
  2520. if (item->textalignment == ITEM_ALIGN_LEFT) {
  2521. item->textRect.x = item->textalignx;
  2522. } else if (item->textalignment == ITEM_ALIGN_RIGHT) {
  2523. item->textRect.x = item->textalignx - newLineWidth;
  2524. } else if (item->textalignment == ITEM_ALIGN_CENTER) {
  2525. item->textRect.x = item->textalignx - newLineWidth / 2;
  2526. }
  2527. item->textRect.y = y;
  2528. ToWindowCoords(&item->textRect.x, &item->textRect.y, &item->window);
  2529. //
  2530. buff[newLine] = '\0';
  2531. DC->drawText(item->textRect.x, item->textRect.y, item->textscale, color, buff, 0, 0, item->textStyle);
  2532. }
  2533. if (*p == '\0') {
  2534. break;
  2535. }
  2536. //
  2537. y += height + 5;
  2538. p = newLinePtr;
  2539. len = 0;
  2540. newLine = 0;
  2541. newLineWidth = 0;
  2542. continue;
  2543. }
  2544. buff[len++] = *p++;
  2545. buff[len] = '\0';
  2546. }
  2547. }
  2548. void Item_Text_Wrapped_Paint(itemDef_t *item) {
  2549. char text[1024];
  2550. const char *p, *start, *textPtr;
  2551. char buff[1024];
  2552. int width, height;
  2553. float x, y;
  2554. vec4_t color;
  2555. // now paint the text and/or any optional images
  2556. // default to left
  2557. if (item->text == NULL) {
  2558. if (item->cvar == NULL) {
  2559. return;
  2560. }
  2561. else {
  2562. DC->getCVarString(item->cvar, text, sizeof(text));
  2563. textPtr = text;
  2564. }
  2565. }
  2566. else {
  2567. textPtr = item->text;
  2568. }
  2569. if (*textPtr == '\0') {
  2570. return;
  2571. }
  2572. Item_TextColor(item, &color);
  2573. Item_SetTextExtents(item, &width, &height, textPtr);
  2574. x = item->textRect.x;
  2575. y = item->textRect.y;
  2576. start = textPtr;
  2577. p = strchr(textPtr, '\r');
  2578. while (p && *p) {
  2579. strncpy(buff, start, p-start+1);
  2580. buff[p-start] = '\0';
  2581. DC->drawText(x, y, item->textscale, color, buff, 0, 0, item->textStyle);
  2582. y += height + 5;
  2583. start += p - start + 1;
  2584. p = strchr(p+1, '\r');
  2585. }
  2586. DC->drawText(x, y, item->textscale, color, start, 0, 0, item->textStyle);
  2587. }
  2588. void Item_Text_Paint(itemDef_t *item) {
  2589. char text[1024];
  2590. const char *textPtr;
  2591. int height, width;
  2592. vec4_t color;
  2593. if (item->window.flags & WINDOW_WRAPPED) {
  2594. Item_Text_Wrapped_Paint(item);
  2595. return;
  2596. }
  2597. if (item->window.flags & WINDOW_AUTOWRAPPED) {
  2598. Item_Text_AutoWrapped_Paint(item);
  2599. return;
  2600. }
  2601. if (item->text == NULL) {
  2602. if (item->cvar == NULL) {
  2603. return;
  2604. }
  2605. else {
  2606. DC->getCVarString(item->cvar, text, sizeof(text));
  2607. textPtr = text;
  2608. }
  2609. }
  2610. else {
  2611. textPtr = item->text;
  2612. }
  2613. // this needs to go here as it sets extents for cvar types as well
  2614. Item_SetTextExtents(item, &width, &height, textPtr);
  2615. if (*textPtr == '\0') {
  2616. return;
  2617. }
  2618. Item_TextColor(item, &color);
  2619. //FIXME: this is a fucking mess
  2620. /*
  2621. adjust = 0;
  2622. if (item->textStyle == ITEM_TEXTSTYLE_OUTLINED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
  2623. adjust = 0.5;
  2624. }
  2625. if (item->textStyle == ITEM_TEXTSTYLE_SHADOWED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
  2626. Fade(&item->window.flags, &DC->Assets.shadowColor[3], DC->Assets.fadeClamp, &item->window.nextTime, DC->Assets.fadeCycle, qfalse);
  2627. DC->drawText(item->textRect.x + DC->Assets.shadowX, item->textRect.y + DC->Assets.shadowY, item->textscale, DC->Assets.shadowColor, textPtr, adjust);
  2628. }
  2629. */
  2630. // if (item->textStyle == ITEM_TEXTSTYLE_OUTLINED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
  2631. // Fade(&item->window.flags, &item->window.outlineColor[3], DC->Assets.fadeClamp, &item->window.nextTime, DC->Assets.fadeCycle, qfalse);
  2632. // /*
  2633. // Text_Paint(item->textRect.x-1, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
  2634. // Text_Paint(item->textRect.x, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
  2635. // Text_Paint(item->textRect.x+1, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
  2636. // Text_Paint(item->textRect.x-1, item->textRect.y, item->textscale, item->window.foreColor, textPtr, adjust);
  2637. // Text_Paint(item->textRect.x+1, item->textRect.y, item->textscale, item->window.foreColor, textPtr, adjust);
  2638. // Text_Paint(item->textRect.x-1, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
  2639. // Text_Paint(item->textRect.x, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
  2640. // Text_Paint(item->textRect.x+1, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
  2641. // */
  2642. // DC->drawText(item->textRect.x - 1, item->textRect.y + 1, item->textscale * 1.02, item->window.outlineColor, textPtr, adjust);
  2643. // }
  2644. DC->drawText(item->textRect.x, item->textRect.y, item->textscale, color, textPtr, 0, 0, item->textStyle);
  2645. }
  2646. //float trap_Cvar_VariableValue( const char *var_name );
  2647. //void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
  2648. void Item_TextField_Paint(itemDef_t *item) {
  2649. char buff[1024];
  2650. vec4_t newColor, lowLight;
  2651. int offset;
  2652. menuDef_t *parent = (menuDef_t*)item->parent;
  2653. editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
  2654. Item_Text_Paint(item);
  2655. buff[0] = '\0';
  2656. if (item->cvar) {
  2657. DC->getCVarString(item->cvar, buff, sizeof(buff));
  2658. }
  2659. parent = (menuDef_t*)item->parent;
  2660. if (item->window.flags & WINDOW_HASFOCUS) {
  2661. lowLight[0] = 0.8 * parent->focusColor[0];
  2662. lowLight[1] = 0.8 * parent->focusColor[1];
  2663. lowLight[2] = 0.8 * parent->focusColor[2];
  2664. lowLight[3] = 0.8 * parent->focusColor[3];
  2665. LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
  2666. } else {
  2667. memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
  2668. }
  2669. offset = (item->text && *item->text) ? 8 : 0;
  2670. if (item->window.flags & WINDOW_HASFOCUS && g_editingField) {
  2671. char cursor = DC->getOverstrikeMode() ? '_' : '|';
  2672. DC->drawTextWithCursor(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textscale, newColor, buff + editPtr->paintOffset, item->cursorPos - editPtr->paintOffset , cursor, editPtr->maxPaintChars, item->textStyle);
  2673. } else {
  2674. DC->drawText(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textscale, newColor, buff + editPtr->paintOffset, 0, editPtr->maxPaintChars, item->textStyle);
  2675. }
  2676. }
  2677. void Item_YesNo_Paint(itemDef_t *item) {
  2678. vec4_t newColor, lowLight;
  2679. float value;
  2680. menuDef_t *parent = (menuDef_t*)item->parent;
  2681. value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
  2682. if (item->window.flags & WINDOW_HASFOCUS) {
  2683. lowLight[0] = 0.8 * parent->focusColor[0];
  2684. lowLight[1] = 0.8 * parent->focusColor[1];
  2685. lowLight[2] = 0.8 * parent->focusColor[2];
  2686. lowLight[3] = 0.8 * parent->focusColor[3];
  2687. LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
  2688. } else {
  2689. memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
  2690. }
  2691. if (item->text) {
  2692. Item_Text_Paint(item);
  2693. DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0, item->textStyle);
  2694. } else {
  2695. DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0, item->textStyle);
  2696. }
  2697. }
  2698. void Item_Multi_Paint(itemDef_t *item) {
  2699. vec4_t newColor, lowLight;
  2700. const char *text = "";
  2701. menuDef_t *parent = (menuDef_t*)item->parent;
  2702. if (item->window.flags & WINDOW_HASFOCUS) {
  2703. lowLight[0] = 0.8 * parent->focusColor[0];
  2704. lowLight[1] = 0.8 * parent->focusColor[1];
  2705. lowLight[2] = 0.8 * parent->focusColor[2];
  2706. lowLight[3] = 0.8 * parent->focusColor[3];
  2707. LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
  2708. } else {
  2709. memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
  2710. }
  2711. text = Item_Multi_Setting(item);
  2712. if (item->text) {
  2713. Item_Text_Paint(item);
  2714. DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, text, 0, 0, item->textStyle);
  2715. } else {
  2716. DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, text, 0, 0, item->textStyle);
  2717. }
  2718. }
  2719. typedef struct {
  2720. char *command;
  2721. int id;
  2722. int defaultbind1;
  2723. int defaultbind2;
  2724. int bind1;
  2725. int bind2;
  2726. } bind_t;
  2727. typedef struct
  2728. {
  2729. char* name;
  2730. float defaultvalue;
  2731. float value;
  2732. } configcvar_t;
  2733. static bind_t g_bindings[] =
  2734. {
  2735. {"+scores", K_TAB, -1, -1, -1},
  2736. {"+button2", K_ENTER, -1, -1, -1},
  2737. {"+speed", K_SHIFT, -1, -1, -1},
  2738. {"+forward", K_UPARROW, -1, -1, -1},
  2739. {"+back", K_DOWNARROW, -1, -1, -1},
  2740. {"+moveleft", ',', -1, -1, -1},
  2741. {"+moveright", '.', -1, -1, -1},
  2742. {"+moveup", K_SPACE, -1, -1, -1},
  2743. {"+movedown", 'c', -1, -1, -1},
  2744. {"+left", K_LEFTARROW, -1, -1, -1},
  2745. {"+right", K_RIGHTARROW, -1, -1, -1},
  2746. {"+strafe", K_ALT, -1, -1, -1},
  2747. {"+lookup", K_PGDN, -1, -1, -1},
  2748. {"+lookdown", K_DEL, -1, -1, -1},
  2749. {"+mlook", '/', -1, -1, -1},
  2750. {"centerview", K_END, -1, -1, -1},
  2751. {"+zoom", -1, -1, -1, -1},
  2752. {"weapon 1", '1', -1, -1, -1},
  2753. {"weapon 2", '2', -1, -1, -1},
  2754. {"weapon 3", '3', -1, -1, -1},
  2755. {"weapon 4", '4', -1, -1, -1},
  2756. {"weapon 5", '5', -1, -1, -1},
  2757. {"weapon 6", '6', -1, -1, -1},
  2758. {"weapon 7", '7', -1, -1, -1},
  2759. {"weapon 8", '8', -1, -1, -1},
  2760. {"weapon 9", '9', -1, -1, -1},
  2761. {"weapon 10", '0', -1, -1, -1},
  2762. {"weapon 11", -1, -1, -1, -1},
  2763. {"weapon 12", -1, -1, -1, -1},
  2764. {"weapon 13", -1, -1, -1, -1},
  2765. {"+attack", K_CTRL, -1, -1, -1},
  2766. {"weapprev", '[', -1, -1, -1},
  2767. {"weapnext", ']', -1, -1, -1},
  2768. {"+button3", K_MOUSE3, -1, -1, -1},
  2769. {"+button4", K_MOUSE4, -1, -1, -1},
  2770. {"prevTeamMember", 'w', -1, -1, -1},
  2771. {"nextTeamMember", 'r', -1, -1, -1},
  2772. {"nextOrder", 't', -1, -1, -1},
  2773. {"confirmOrder", 'y', -1, -1, -1},
  2774. {"denyOrder", 'n', -1, -1, -1},
  2775. {"taskOffense", 'o', -1, -1, -1},
  2776. {"taskDefense", 'd', -1, -1, -1},
  2777. {"taskPatrol", 'p', -1, -1, -1},
  2778. {"taskCamp", 'c', -1, -1, -1},
  2779. {"taskFollow", 'f', -1, -1, -1},
  2780. {"taskRetrieve", 'v', -1, -1, -1},
  2781. {"taskEscort", 'e', -1, -1, -1},
  2782. {"taskOwnFlag", 'i', -1, -1, -1},
  2783. {"taskSuicide", 'k', -1, -1, -1},
  2784. {"tauntKillInsult", K_F1, -1, -1, -1},
  2785. {"tauntPraise", K_F2, -1, -1, -1},
  2786. {"tauntTaunt", K_F3, -1, -1, -1},
  2787. {"tauntDeathInsult", K_F4, -1, -1, -1},
  2788. {"tauntGauntlet", K_F5, -1, -1, -1},
  2789. {"scoresUp", K_KP_PGUP, -1, -1, -1},
  2790. {"scoresDown", K_KP_PGDN, -1, -1, -1},
  2791. // bk001205 - this one below was: '-1'
  2792. {"messagemode", -1, -1, -1, -1},
  2793. {"messagemode2", -1, -1, -1, -1},
  2794. {"messagemode3", -1, -1, -1, -1},
  2795. {"messagemode4", -1, -1, -1, -1}
  2796. };
  2797. static const int g_bindCount = sizeof(g_bindings) / sizeof(bind_t);
  2798. #ifndef MISSIONPACK // bk001206
  2799. static configcvar_t g_configcvars[] =
  2800. {
  2801. {"cl_run", 0, 0},
  2802. {"m_pitch", 0, 0},
  2803. {"cg_autoswitch", 0, 0},
  2804. {"sensitivity", 0, 0},
  2805. {"in_joystick", 0, 0},
  2806. {"joy_threshold", 0, 0},
  2807. {"m_filter", 0, 0},
  2808. {"cl_freelook", 0, 0},
  2809. {NULL, 0, 0}
  2810. };
  2811. #endif
  2812. /*
  2813. =================
  2814. Controls_GetKeyAssignment
  2815. =================
  2816. */
  2817. static void Controls_GetKeyAssignment (char *command, int *twokeys)
  2818. {
  2819. int count;
  2820. int j;
  2821. char b[256];
  2822. twokeys[0] = twokeys[1] = -1;
  2823. count = 0;
  2824. for ( j = 0; j < 256; j++ )
  2825. {
  2826. DC->getBindingBuf( j, b, 256 );
  2827. if ( *b == 0 ) {
  2828. continue;
  2829. }
  2830. if ( !Q_stricmp( b, command ) ) {
  2831. twokeys[count] = j;
  2832. count++;
  2833. if (count == 2) {
  2834. break;
  2835. }
  2836. }
  2837. }
  2838. }
  2839. /*
  2840. =================
  2841. Controls_GetConfig
  2842. =================
  2843. */
  2844. void Controls_GetConfig( void )
  2845. {
  2846. int i;
  2847. int twokeys[2];
  2848. // iterate each command, get its numeric binding
  2849. for (i=0; i < g_bindCount; i++)
  2850. {
  2851. Controls_GetKeyAssignment(g_bindings[i].command, twokeys);
  2852. g_bindings[i].bind1 = twokeys[0];
  2853. g_bindings[i].bind2 = twokeys[1];
  2854. }
  2855. //s_controls.invertmouse.curvalue = DC->getCVarValue( "m_pitch" ) < 0;
  2856. //s_controls.smoothmouse.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "m_filter" ) );
  2857. //s_controls.alwaysrun.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_run" ) );
  2858. //s_controls.autoswitch.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cg_autoswitch" ) );
  2859. //s_controls.sensitivity.curvalue = UI_ClampCvar( 2, 30, Controls_GetCvarValue( "sensitivity" ) );
  2860. //s_controls.joyenable.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "in_joystick" ) );
  2861. //s_controls.joythreshold.curvalue = UI_ClampCvar( 0.05, 0.75, Controls_GetCvarValue( "joy_threshold" ) );
  2862. //s_controls.freelook.curvalue = UI_ClampCvar( 0, 1, Controls_GetCvarValue( "cl_freelook" ) );
  2863. }
  2864. /*
  2865. =================
  2866. Controls_SetConfig
  2867. =================
  2868. */
  2869. void Controls_SetConfig(qboolean restart)
  2870. {
  2871. int i;
  2872. // iterate each command, get its numeric binding
  2873. for (i=0; i < g_bindCount; i++)
  2874. {
  2875. if (g_bindings[i].bind1 != -1)
  2876. {
  2877. DC->setBinding( g_bindings[i].bind1, g_bindings[i].command );
  2878. if (g_bindings[i].bind2 != -1)
  2879. DC->setBinding( g_bindings[i].bind2, g_bindings[i].command );
  2880. }
  2881. }
  2882. //if ( s_controls.invertmouse.curvalue )
  2883. // DC->setCVar("m_pitch", va("%f),-fabs( DC->getCVarValue( "m_pitch" ) ) );
  2884. //else
  2885. // trap_Cvar_SetValue( "m_pitch", fabs( trap_Cvar_VariableValue( "m_pitch" ) ) );
  2886. //trap_Cvar_SetValue( "m_filter", s_controls.smoothmouse.curvalue );
  2887. //trap_Cvar_SetValue( "cl_run", s_controls.alwaysrun.curvalue );
  2888. //trap_Cvar_SetValue( "cg_autoswitch", s_controls.autoswitch.curvalue );
  2889. //trap_Cvar_SetValue( "sensitivity", s_controls.sensitivity.curvalue );
  2890. //trap_Cvar_SetValue( "in_joystick", s_controls.joyenable.curvalue );
  2891. //trap_Cvar_SetValue( "joy_threshold", s_controls.joythreshold.curvalue );
  2892. //trap_Cvar_SetValue( "cl_freelook", s_controls.freelook.curvalue );
  2893. DC->executeText(EXEC_APPEND, "in_restart\n");
  2894. //trap_Cmd_ExecuteText( EXEC_APPEND, "in_restart\n" );
  2895. }
  2896. /*
  2897. =================
  2898. Controls_SetDefaults
  2899. =================
  2900. */
  2901. void Controls_SetDefaults( void )
  2902. {
  2903. int i;
  2904. // iterate each command, set its default binding
  2905. for (i=0; i < g_bindCount; i++)
  2906. {
  2907. g_bindings[i].bind1 = g_bindings[i].defaultbind1;
  2908. g_bindings[i].bind2 = g_bindings[i].defaultbind2;
  2909. }
  2910. //s_controls.invertmouse.curvalue = Controls_GetCvarDefault( "m_pitch" ) < 0;
  2911. //s_controls.smoothmouse.curvalue = Controls_GetCvarDefault( "m_filter" );
  2912. //s_controls.alwaysrun.curvalue = Controls_GetCvarDefault( "cl_run" );
  2913. //s_controls.autoswitch.curvalue = Controls_GetCvarDefault( "cg_autoswitch" );
  2914. //s_controls.sensitivity.curvalue = Controls_GetCvarDefault( "sensitivity" );
  2915. //s_controls.joyenable.curvalue = Controls_GetCvarDefault( "in_joystick" );
  2916. //s_controls.joythreshold.curvalue = Controls_GetCvarDefault( "joy_threshold" );
  2917. //s_controls.freelook.curvalue = Controls_GetCvarDefault( "cl_freelook" );
  2918. }
  2919. int BindingIDFromName(const char *name) {
  2920. int i;
  2921. for (i=0; i < g_bindCount; i++)
  2922. {
  2923. if (Q_stricmp(name, g_bindings[i].command) == 0) {
  2924. return i;
  2925. }
  2926. }
  2927. return -1;
  2928. }
  2929. char g_nameBind1[32];
  2930. char g_nameBind2[32];
  2931. void BindingFromName(const char *cvar) {
  2932. int i, b1, b2;
  2933. // iterate each command, set its default binding
  2934. for (i=0; i < g_bindCount; i++)
  2935. {
  2936. if (Q_stricmp(cvar, g_bindings[i].command) == 0) {
  2937. b1 = g_bindings[i].bind1;
  2938. if (b1 == -1) {
  2939. break;
  2940. }
  2941. DC->keynumToStringBuf( b1, g_nameBind1, 32 );
  2942. Q_strupr(g_nameBind1);
  2943. b2 = g_bindings[i].bind2;
  2944. if (b2 != -1)
  2945. {
  2946. DC->keynumToStringBuf( b2, g_nameBind2, 32 );
  2947. Q_strupr(g_nameBind2);
  2948. strcat( g_nameBind1, " or " );
  2949. strcat( g_nameBind1, g_nameBind2 );
  2950. }
  2951. return;
  2952. }
  2953. }
  2954. strcpy(g_nameBind1, "???");
  2955. }
  2956. void Item_Slider_Paint(itemDef_t *item) {
  2957. vec4_t newColor, lowLight;
  2958. float x, y, value;
  2959. menuDef_t *parent = (menuDef_t*)item->parent;
  2960. value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
  2961. if (item->window.flags & WINDOW_HASFOCUS) {
  2962. lowLight[0] = 0.8 * parent->focusColor[0];
  2963. lowLight[1] = 0.8 * parent->focusColor[1];
  2964. lowLight[2] = 0.8 * parent->focusColor[2];
  2965. lowLight[3] = 0.8 * parent->focusColor[3];
  2966. LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
  2967. } else {
  2968. memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
  2969. }
  2970. y = item->window.rect.y;
  2971. if (item->text) {
  2972. Item_Text_Paint(item);
  2973. x = item->textRect.x + item->textRect.w + 8;
  2974. } else {
  2975. x = item->window.rect.x;
  2976. }
  2977. DC->setColor(newColor);
  2978. DC->drawHandlePic( x, y, SLIDER_WIDTH, SLIDER_HEIGHT, DC->Assets.sliderBar );
  2979. x = Item_Slider_ThumbPosition(item);
  2980. DC->drawHandlePic( x - (SLIDER_THUMB_WIDTH / 2), y - 2, SLIDER_THUMB_WIDTH, SLIDER_THUMB_HEIGHT, DC->Assets.sliderThumb );
  2981. }
  2982. void Item_Bind_Paint(itemDef_t *item) {
  2983. vec4_t newColor, lowLight;
  2984. float value;
  2985. int maxChars = 0;
  2986. menuDef_t *parent = (menuDef_t*)item->parent;
  2987. editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
  2988. if (editPtr) {
  2989. maxChars = editPtr->maxPaintChars;
  2990. }
  2991. value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
  2992. if (item->window.flags & WINDOW_HASFOCUS) {
  2993. if (g_bindItem == item) {
  2994. lowLight[0] = 0.8f * 1.0f;
  2995. lowLight[1] = 0.8f * 0.0f;
  2996. lowLight[2] = 0.8f * 0.0f;
  2997. lowLight[3] = 0.8f * 1.0f;
  2998. } else {
  2999. lowLight[0] = 0.8f * parent->focusColor[0];
  3000. lowLight[1] = 0.8f * parent->focusColor[1];
  3001. lowLight[2] = 0.8f * parent->focusColor[2];
  3002. lowLight[3] = 0.8f * parent->focusColor[3];
  3003. }
  3004. LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
  3005. } else {
  3006. memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
  3007. }
  3008. if (item->text) {
  3009. Item_Text_Paint(item);
  3010. BindingFromName(item->cvar);
  3011. DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, g_nameBind1, 0, maxChars, item->textStyle);
  3012. } else {
  3013. DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? "FIXME" : "FIXME", 0, maxChars, item->textStyle);
  3014. }
  3015. }
  3016. qboolean Display_KeyBindPending() {
  3017. return g_waitingForKey;
  3018. }
  3019. qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) {
  3020. int id;
  3021. int i;
  3022. if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && !g_waitingForKey)
  3023. {
  3024. if (down && (key == K_MOUSE1 || key == K_ENTER)) {
  3025. g_waitingForKey = qtrue;
  3026. g_bindItem = item;
  3027. }
  3028. return qtrue;
  3029. }
  3030. else
  3031. {
  3032. if (!g_waitingForKey || g_bindItem == NULL) {
  3033. return qtrue;
  3034. }
  3035. if (key & K_CHAR_FLAG) {
  3036. return qtrue;
  3037. }
  3038. switch (key)
  3039. {
  3040. case K_ESCAPE:
  3041. g_waitingForKey = qfalse;
  3042. return qtrue;
  3043. case K_BACKSPACE:
  3044. id = BindingIDFromName(item->cvar);
  3045. if (id != -1) {
  3046. g_bindings[id].bind1 = -1;
  3047. g_bindings[id].bind2 = -1;
  3048. }
  3049. Controls_SetConfig(qtrue);
  3050. g_waitingForKey = qfalse;
  3051. g_bindItem = NULL;
  3052. return qtrue;
  3053. case '`':
  3054. return qtrue;
  3055. }
  3056. }
  3057. if (key != -1)
  3058. {
  3059. for (i=0; i < g_bindCount; i++)
  3060. {
  3061. if (g_bindings[i].bind2 == key) {
  3062. g_bindings[i].bind2 = -1;
  3063. }
  3064. if (g_bindings[i].bind1 == key)
  3065. {
  3066. g_bindings[i].bind1 = g_bindings[i].bind2;
  3067. g_bindings[i].bind2 = -1;
  3068. }
  3069. }
  3070. }
  3071. id = BindingIDFromName(item->cvar);
  3072. if (id != -1) {
  3073. if (key == -1) {
  3074. if( g_bindings[id].bind1 != -1 ) {
  3075. DC->setBinding( g_bindings[id].bind1, "" );
  3076. g_bindings[id].bind1 = -1;
  3077. }
  3078. if( g_bindings[id].bind2 != -1 ) {
  3079. DC->setBinding( g_bindings[id].bind2, "" );
  3080. g_bindings[id].bind2 = -1;
  3081. }
  3082. }
  3083. else if (g_bindings[id].bind1 == -1) {
  3084. g_bindings[id].bind1 = key;
  3085. }
  3086. else if (g_bindings[id].bind1 != key && g_bindings[id].bind2 == -1) {
  3087. g_bindings[id].bind2 = key;
  3088. }
  3089. else {
  3090. DC->setBinding( g_bindings[id].bind1, "" );
  3091. DC->setBinding( g_bindings[id].bind2, "" );
  3092. g_bindings[id].bind1 = key;
  3093. g_bindings[id].bind2 = -1;
  3094. }
  3095. }
  3096. Controls_SetConfig(qtrue);
  3097. g_waitingForKey = qfalse;
  3098. return qtrue;
  3099. }
  3100. void AdjustFrom640(float *x, float *y, float *w, float *h) {
  3101. //*x = *x * DC->scale + DC->bias;
  3102. *x *= DC->xscale;
  3103. *y *= DC->yscale;
  3104. *w *= DC->xscale;
  3105. *h *= DC->yscale;
  3106. }
  3107. void Item_Model_Paint(itemDef_t *item) {
  3108. float x, y, w, h;
  3109. refdef_t refdef;
  3110. refEntity_t ent;
  3111. vec3_t mins, maxs, origin;
  3112. vec3_t angles;
  3113. modelDef_t *modelPtr = (modelDef_t*)item->typeData;
  3114. if (modelPtr == NULL) {
  3115. return;
  3116. }
  3117. // setup the refdef
  3118. memset( &refdef, 0, sizeof( refdef ) );
  3119. refdef.rdflags = RDF_NOWORLDMODEL;
  3120. AxisClear( refdef.viewaxis );
  3121. x = item->window.rect.x+1;
  3122. y = item->window.rect.y+1;
  3123. w = item->window.rect.w-2;
  3124. h = item->window.rect.h-2;
  3125. AdjustFrom640( &x, &y, &w, &h );
  3126. refdef.x = x;
  3127. refdef.y = y;
  3128. refdef.width = w;
  3129. refdef.height = h;
  3130. DC->modelBounds( item->asset, mins, maxs );
  3131. origin[2] = -0.5 * ( mins[2] + maxs[2] );
  3132. origin[1] = 0.5 * ( mins[1] + maxs[1] );
  3133. // calculate distance so the model nearly fills the box
  3134. if (qtrue) {
  3135. float len = 0.5 * ( maxs[2] - mins[2] );
  3136. origin[0] = len / 0.268; // len / tan( fov/2 )
  3137. //origin[0] = len / tan(w/2);
  3138. } else {
  3139. origin[0] = item->textscale;
  3140. }
  3141. refdef.fov_x = (modelPtr->fov_x) ? modelPtr->fov_x : w;
  3142. refdef.fov_y = (modelPtr->fov_y) ? modelPtr->fov_y : h;
  3143. //refdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f);
  3144. //xx = refdef.width / tan( refdef.fov_x / 360 * M_PI );
  3145. //refdef.fov_y = atan2( refdef.height, xx );
  3146. //refdef.fov_y *= ( 360 / M_PI );
  3147. DC->clearScene();
  3148. refdef.time = DC->realTime;
  3149. // add the model
  3150. memset( &ent, 0, sizeof(ent) );
  3151. //adjust = 5.0 * sin( (float)uis.realtime / 500 );
  3152. //adjust = 360 % (int)((float)uis.realtime / 1000);
  3153. //VectorSet( angles, 0, 0, 1 );
  3154. // use item storage to track
  3155. if (modelPtr->rotationSpeed) {
  3156. if (DC->realTime > item->window.nextTime) {
  3157. item->window.nextTime = DC->realTime + modelPtr->rotationSpeed;
  3158. modelPtr->angle = (int)(modelPtr->angle + 1) % 360;
  3159. }
  3160. }
  3161. VectorSet( angles, 0, modelPtr->angle, 0 );
  3162. AnglesToAxis( angles, ent.axis );
  3163. ent.hModel = item->asset;
  3164. VectorCopy( origin, ent.origin );
  3165. VectorCopy( origin, ent.lightingOrigin );
  3166. ent.renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
  3167. VectorCopy( ent.origin, ent.oldorigin );
  3168. DC->addRefEntityToScene( &ent );
  3169. DC->renderScene( &refdef );
  3170. }
  3171. void Item_Image_Paint(itemDef_t *item) {
  3172. if (item == NULL) {
  3173. return;
  3174. }
  3175. DC->drawHandlePic(item->window.rect.x+1, item->window.rect.y+1, item->window.rect.w-2, item->window.rect.h-2, item->asset);
  3176. }
  3177. void Item_ListBox_Paint(itemDef_t *item) {
  3178. float x, y, size, count, i, thumb;
  3179. qhandle_t image;
  3180. qhandle_t optionalImage;
  3181. listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
  3182. // the listbox is horizontal or vertical and has a fixed size scroll bar going either direction
  3183. // elements are enumerated from the DC and either text or image handles are acquired from the DC as well
  3184. // textscale is used to size the text, textalignx and textaligny are used to size image elements
  3185. // there is no clipping available so only the last completely visible item is painted
  3186. count = DC->feederCount(item->special);
  3187. // default is vertical if horizontal flag is not here
  3188. if (item->window.flags & WINDOW_HORIZONTAL) {
  3189. // draw scrollbar in bottom of the window
  3190. // bar
  3191. x = item->window.rect.x + 1;
  3192. y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE - 1;
  3193. DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowLeft);
  3194. x += SCROLLBAR_SIZE - 1;
  3195. size = item->window.rect.w - (SCROLLBAR_SIZE * 2);
  3196. DC->drawHandlePic(x, y, size+1, SCROLLBAR_SIZE, DC->Assets.scrollBar);
  3197. x += size - 1;
  3198. DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowRight);
  3199. // thumb
  3200. thumb = Item_ListBox_ThumbDrawPosition(item);//Item_ListBox_ThumbPosition(item);
  3201. if (thumb > x - SCROLLBAR_SIZE - 1) {
  3202. thumb = x - SCROLLBAR_SIZE - 1;
  3203. }
  3204. DC->drawHandlePic(thumb, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb);
  3205. //
  3206. listPtr->endPos = listPtr->startPos;
  3207. size = item->window.rect.w - 2;
  3208. // items
  3209. // size contains max available space
  3210. if (listPtr->elementStyle == LISTBOX_IMAGE) {
  3211. // fit = 0;
  3212. x = item->window.rect.x + 1;
  3213. y = item->window.rect.y + 1;
  3214. for (i = listPtr->startPos; i < count; i++) {
  3215. // always draw at least one
  3216. // which may overdraw the box if it is too small for the element
  3217. image = DC->feederItemImage(item->special, i);
  3218. if (image) {
  3219. DC->drawHandlePic(x+1, y+1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image);
  3220. }
  3221. if (i == item->cursorPos) {
  3222. DC->drawRect(x, y, listPtr->elementWidth-1, listPtr->elementHeight-1, item->window.borderSize, item->window.borderColor);
  3223. }
  3224. size -= listPtr->elementWidth;
  3225. if (size < listPtr->elementWidth) {
  3226. listPtr->drawPadding = size; //listPtr->elementWidth - size;
  3227. break;
  3228. }
  3229. x += listPtr->elementWidth;
  3230. listPtr->endPos++;
  3231. // fit++;
  3232. }
  3233. } else {
  3234. //
  3235. }
  3236. } else {
  3237. // draw scrollbar to right side of the window
  3238. x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE - 1;
  3239. y = item->window.rect.y + 1;
  3240. DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowUp);
  3241. y += SCROLLBAR_SIZE - 1;
  3242. listPtr->endPos = listPtr->startPos;
  3243. size = item->window.rect.h - (SCROLLBAR_SIZE * 2);
  3244. DC->drawHandlePic(x, y, SCROLLBAR_SIZE, size+1, DC->Assets.scrollBar);
  3245. y += size - 1;
  3246. DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowDown);
  3247. // thumb
  3248. thumb = Item_ListBox_ThumbDrawPosition(item);//Item_ListBox_ThumbPosition(item);
  3249. if (thumb > y - SCROLLBAR_SIZE - 1) {
  3250. thumb = y - SCROLLBAR_SIZE - 1;
  3251. }
  3252. DC->drawHandlePic(x, thumb, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb);
  3253. // adjust size for item painting
  3254. size = item->window.rect.h - 2;
  3255. if (listPtr->elementStyle == LISTBOX_IMAGE) {
  3256. // fit = 0;
  3257. x = item->window.rect.x + 1;
  3258. y = item->window.rect.y + 1;
  3259. for (i = listPtr->startPos; i < count; i++) {
  3260. // always draw at least one
  3261. // which may overdraw the box if it is too small for the element
  3262. image = DC->feederItemImage(item->special, i);
  3263. if (image) {
  3264. DC->drawHandlePic(x+1, y+1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image);
  3265. }
  3266. if (i == item->cursorPos) {
  3267. DC->drawRect(x, y, listPtr->elementWidth - 1, listPtr->elementHeight - 1, item->window.borderSize, item->window.borderColor);
  3268. }
  3269. listPtr->endPos++;
  3270. size -= listPtr->elementWidth;
  3271. if (size < listPtr->elementHeight) {
  3272. listPtr->drawPadding = listPtr->elementHeight - size;
  3273. break;
  3274. }
  3275. y += listPtr->elementHeight;
  3276. // fit++;
  3277. }
  3278. } else {
  3279. x = item->window.rect.x + 1;
  3280. y = item->window.rect.y + 1;
  3281. for (i = listPtr->startPos; i < count; i++) {
  3282. const char *text;
  3283. // always draw at least one
  3284. // which may overdraw the box if it is too small for the element
  3285. if (listPtr->numColumns > 0) {
  3286. int j;
  3287. for (j = 0; j < listPtr->numColumns; j++) {
  3288. text = DC->feederItemText(item->special, i, j, &optionalImage);
  3289. if (optionalImage >= 0) {
  3290. DC->drawHandlePic(x + 4 + listPtr->columnInfo[j].pos, y - 1 + listPtr->elementHeight / 2, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage);
  3291. } else if (text) {
  3292. DC->drawText(x + 4 + listPtr->columnInfo[j].pos, y + listPtr->elementHeight, item->textscale, item->window.foreColor, text, 0, listPtr->columnInfo[j].maxChars, item->textStyle);
  3293. }
  3294. }
  3295. } else {
  3296. text = DC->feederItemText(item->special, i, 0, &optionalImage);
  3297. if (optionalImage >= 0) {
  3298. //DC->drawHandlePic(x + 4 + listPtr->elementHeight, y, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage);
  3299. } else if (text) {
  3300. DC->drawText(x + 4, y + listPtr->elementHeight, item->textscale, item->window.foreColor, text, 0, 0, item->textStyle);
  3301. }
  3302. }
  3303. if (i == item->cursorPos) {
  3304. DC->fillRect(x + 2, y + 2, item->window.rect.w - SCROLLBAR_SIZE - 4, listPtr->elementHeight, item->window.outlineColor);
  3305. }
  3306. size -= listPtr->elementHeight;
  3307. if (size < listPtr->elementHeight) {
  3308. listPtr->drawPadding = listPtr->elementHeight - size;
  3309. break;
  3310. }
  3311. listPtr->endPos++;
  3312. y += listPtr->elementHeight;
  3313. // fit++;
  3314. }
  3315. }
  3316. }
  3317. }
  3318. void Item_OwnerDraw_Paint(itemDef_t *item) {
  3319. menuDef_t *parent;
  3320. if (item == NULL) {
  3321. return;
  3322. }
  3323. parent = (menuDef_t*)item->parent;
  3324. if (DC->ownerDrawItem) {
  3325. vec4_t color, lowLight;
  3326. menuDef_t *parent = (menuDef_t*)item->parent;
  3327. Fade(&item->window.flags, &item->window.foreColor[3], parent->fadeClamp, &item->window.nextTime, parent->fadeCycle, qtrue, parent->fadeAmount);
  3328. memcpy(&color, &item->window.foreColor, sizeof(color));
  3329. if (item->numColors > 0 && DC->getValue) {
  3330. // if the value is within one of the ranges then set color to that, otherwise leave at default
  3331. int i;
  3332. float f = DC->getValue(item->window.ownerDraw);
  3333. for (i = 0; i < item->numColors; i++) {
  3334. if (f >= item->colorRanges[i].low && f <= item->colorRanges[i].high) {
  3335. memcpy(&color, &item->colorRanges[i].color, sizeof(color));
  3336. break;
  3337. }
  3338. }
  3339. }
  3340. if (item->window.flags & WINDOW_HASFOCUS) {
  3341. lowLight[0] = 0.8 * parent->focusColor[0];
  3342. lowLight[1] = 0.8 * parent->focusColor[1];
  3343. lowLight[2] = 0.8 * parent->focusColor[2];
  3344. lowLight[3] = 0.8 * parent->focusColor[3];
  3345. LerpColor(parent->focusColor,lowLight,color,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
  3346. } else if (item->textStyle == ITEM_TEXTSTYLE_BLINK && !((DC->realTime/BLINK_DIVISOR) & 1)) {
  3347. lowLight[0] = 0.8 * item->window.foreColor[0];
  3348. lowLight[1] = 0.8 * item->window.foreColor[1];
  3349. lowLight[2] = 0.8 * item->window.foreColor[2];
  3350. lowLight[3] = 0.8 * item->window.foreColor[3];
  3351. LerpColor(item->window.foreColor,lowLight,color,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
  3352. }
  3353. if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
  3354. memcpy(color, parent->disableColor, sizeof(vec4_t)); // bk001207 - FIXME: Com_Memcpy
  3355. }
  3356. if (item->text) {
  3357. Item_Text_Paint(item);
  3358. if (item->text[0]) {
  3359. // +8 is an offset kludge to properly align owner draw items that have text combined with them
  3360. DC->ownerDrawItem(item->textRect.x + item->textRect.w + 8, item->window.rect.y, item->window.rect.w, item->window.rect.h, 0, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle );
  3361. } else {
  3362. DC->ownerDrawItem(item->textRect.x + item->textRect.w, item->window.rect.y, item->window.rect.w, item->window.rect.h, 0, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle );
  3363. }
  3364. } else {
  3365. DC->ownerDrawItem(item->window.rect.x, item->window.rect.y, item->window.rect.w, item->window.rect.h, item->textalignx, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle );
  3366. }
  3367. }
  3368. }
  3369. void Item_Paint(itemDef_t *item) {
  3370. vec4_t red;
  3371. menuDef_t *parent = (menuDef_t*)item->parent;
  3372. red[0] = red[3] = 1;
  3373. red[1] = red[2] = 0;
  3374. if (item == NULL) {
  3375. return;
  3376. }
  3377. if (item->window.flags & WINDOW_ORBITING) {
  3378. if (DC->realTime > item->window.nextTime) {
  3379. float rx, ry, a, c, s, w, h;
  3380. item->window.nextTime = DC->realTime + item->window.offsetTime;
  3381. // translate
  3382. w = item->window.rectClient.w / 2;
  3383. h = item->window.rectClient.h / 2;
  3384. rx = item->window.rectClient.x + w - item->window.rectEffects.x;
  3385. ry = item->window.rectClient.y + h - item->window.rectEffects.y;
  3386. a = 3 * M_PI / 180;
  3387. c = cos(a);
  3388. s = sin(a);
  3389. item->window.rectClient.x = (rx * c - ry * s) + item->window.rectEffects.x - w;
  3390. item->window.rectClient.y = (rx * s + ry * c) + item->window.rectEffects.y - h;
  3391. Item_UpdatePosition(item);
  3392. }
  3393. }
  3394. if (item->window.flags & WINDOW_INTRANSITION) {
  3395. if (DC->realTime > item->window.nextTime) {
  3396. int done = 0;
  3397. item->window.nextTime = DC->realTime + item->window.offsetTime;
  3398. // transition the x,y
  3399. if (item->window.rectClient.x == item->window.rectEffects.x) {
  3400. done++;
  3401. } else {
  3402. if (item->window.rectClient.x < item->window.rectEffects.x) {
  3403. item->window.rectClient.x += item->window.rectEffects2.x;
  3404. if (item->window.rectClient.x > item->window.rectEffects.x) {
  3405. item->window.rectClient.x = item->window.rectEffects.x;
  3406. done++;
  3407. }
  3408. } else {
  3409. item->window.rectClient.x -= item->window.rectEffects2.x;
  3410. if (item->window.rectClient.x < item->window.rectEffects.x) {
  3411. item->window.rectClient.x = item->window.rectEffects.x;
  3412. done++;
  3413. }
  3414. }
  3415. }
  3416. if (item->window.rectClient.y == item->window.rectEffects.y) {
  3417. done++;
  3418. } else {
  3419. if (item->window.rectClient.y < item->window.rectEffects.y) {
  3420. item->window.rectClient.y += item->window.rectEffects2.y;
  3421. if (item->window.rectClient.y > item->window.rectEffects.y) {
  3422. item->window.rectClient.y = item->window.rectEffects.y;
  3423. done++;
  3424. }
  3425. } else {
  3426. item->window.rectClient.y -= item->window.rectEffects2.y;
  3427. if (item->window.rectClient.y < item->window.rectEffects.y) {
  3428. item->window.rectClient.y = item->window.rectEffects.y;
  3429. done++;
  3430. }
  3431. }
  3432. }
  3433. if (item->window.rectClient.w == item->window.rectEffects.w) {
  3434. done++;
  3435. } else {
  3436. if (item->window.rectClient.w < item->window.rectEffects.w) {
  3437. item->window.rectClient.w += item->window.rectEffects2.w;
  3438. if (item->window.rectClient.w > item->window.rectEffects.w) {
  3439. item->window.rectClient.w = item->window.rectEffects.w;
  3440. done++;
  3441. }
  3442. } else {
  3443. item->window.rectClient.w -= item->window.rectEffects2.w;
  3444. if (item->window.rectClient.w < item->window.rectEffects.w) {
  3445. item->window.rectClient.w = item->window.rectEffects.w;
  3446. done++;
  3447. }
  3448. }
  3449. }
  3450. if (item->window.rectClient.h == item->window.rectEffects.h) {
  3451. done++;
  3452. } else {
  3453. if (item->window.rectClient.h < item->window.rectEffects.h) {
  3454. item->window.rectClient.h += item->window.rectEffects2.h;
  3455. if (item->window.rectClient.h > item->window.rectEffects.h) {
  3456. item->window.rectClient.h = item->window.rectEffects.h;
  3457. done++;
  3458. }
  3459. } else {
  3460. item->window.rectClient.h -= item->window.rectEffects2.h;
  3461. if (item->window.rectClient.h < item->window.rectEffects.h) {
  3462. item->window.rectClient.h = item->window.rectEffects.h;
  3463. done++;
  3464. }
  3465. }
  3466. }
  3467. Item_UpdatePosition(item);
  3468. if (done == 4) {
  3469. item->window.flags &= ~WINDOW_INTRANSITION;
  3470. }
  3471. }
  3472. }
  3473. if (item->window.ownerDrawFlags && DC->ownerDrawVisible) {
  3474. if (!DC->ownerDrawVisible(item->window.ownerDrawFlags)) {
  3475. item->window.flags &= ~WINDOW_VISIBLE;
  3476. } else {
  3477. item->window.flags |= WINDOW_VISIBLE;
  3478. }
  3479. }
  3480. if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE)) {
  3481. if (!Item_EnableShowViaCvar(item, CVAR_SHOW)) {
  3482. return;
  3483. }
  3484. }
  3485. if (item->window.flags & WINDOW_TIMEDVISIBLE) {
  3486. }
  3487. if (!(item->window.flags & WINDOW_VISIBLE)) {
  3488. return;
  3489. }
  3490. // paint the rect first..
  3491. Window_Paint(&item->window, parent->fadeAmount , parent->fadeClamp, parent->fadeCycle);
  3492. if (debugMode) {
  3493. vec4_t color;
  3494. rectDef_t *r = Item_CorrectedTextRect(item);
  3495. color[1] = color[3] = 1;
  3496. color[0] = color[2] = 0;
  3497. DC->drawRect(r->x, r->y, r->w, r->h, 1, color);
  3498. }
  3499. //DC->drawRect(item->window.rect.x, item->window.rect.y, item->window.rect.w, item->window.rect.h, 1, red);
  3500. switch (item->type) {
  3501. case ITEM_TYPE_OWNERDRAW:
  3502. Item_OwnerDraw_Paint(item);
  3503. break;
  3504. case ITEM_TYPE_TEXT:
  3505. case ITEM_TYPE_BUTTON:
  3506. Item_Text_Paint(item);
  3507. break;
  3508. case ITEM_TYPE_RADIOBUTTON:
  3509. break;
  3510. case ITEM_TYPE_CHECKBOX:
  3511. break;
  3512. case ITEM_TYPE_EDITFIELD:
  3513. case ITEM_TYPE_NUMERICFIELD:
  3514. Item_TextField_Paint(item);
  3515. break;
  3516. case ITEM_TYPE_COMBO:
  3517. break;
  3518. case ITEM_TYPE_LISTBOX:
  3519. Item_ListBox_Paint(item);
  3520. break;
  3521. //case ITEM_TYPE_IMAGE:
  3522. // Item_Image_Paint(item);
  3523. // break;
  3524. case ITEM_TYPE_MODEL:
  3525. Item_Model_Paint(item);
  3526. break;
  3527. case ITEM_TYPE_YESNO:
  3528. Item_YesNo_Paint(item);
  3529. break;
  3530. case ITEM_TYPE_MULTI:
  3531. Item_Multi_Paint(item);
  3532. break;
  3533. case ITEM_TYPE_BIND:
  3534. Item_Bind_Paint(item);
  3535. break;
  3536. case ITEM_TYPE_SLIDER:
  3537. Item_Slider_Paint(item);
  3538. break;
  3539. default:
  3540. break;
  3541. }
  3542. }
  3543. void Menu_Init(menuDef_t *menu) {
  3544. memset(menu, 0, sizeof(menuDef_t));
  3545. menu->cursorItem = -1;
  3546. menu->fadeAmount = DC->Assets.fadeAmount;
  3547. menu->fadeClamp = DC->Assets.fadeClamp;
  3548. menu->fadeCycle = DC->Assets.fadeCycle;
  3549. Window_Init(&menu->window);
  3550. }
  3551. itemDef_t *Menu_GetFocusedItem(menuDef_t *menu) {
  3552. int i;
  3553. if (menu) {
  3554. for (i = 0; i < menu->itemCount; i++) {
  3555. if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
  3556. return menu->items[i];
  3557. }
  3558. }
  3559. }
  3560. return NULL;
  3561. }
  3562. menuDef_t *Menu_GetFocused() {
  3563. int i;
  3564. for (i = 0; i < menuCount; i++) {
  3565. if (Menus[i].window.flags & WINDOW_HASFOCUS && Menus[i].window.flags & WINDOW_VISIBLE) {
  3566. return &Menus[i];
  3567. }
  3568. }
  3569. return NULL;
  3570. }
  3571. void Menu_ScrollFeeder(menuDef_t *menu, int feeder, qboolean down) {
  3572. if (menu) {
  3573. int i;
  3574. for (i = 0; i < menu->itemCount; i++) {
  3575. if (menu->items[i]->special == feeder) {
  3576. Item_ListBox_HandleKey(menu->items[i], (down) ? K_DOWNARROW : K_UPARROW, qtrue, qtrue);
  3577. return;
  3578. }
  3579. }
  3580. }
  3581. }
  3582. void Menu_SetFeederSelection(menuDef_t *menu, int feeder, int index, const char *name) {
  3583. if (menu == NULL) {
  3584. if (name == NULL) {
  3585. menu = Menu_GetFocused();
  3586. } else {
  3587. menu = Menus_FindByName(name);
  3588. }
  3589. }
  3590. if (menu) {
  3591. int i;
  3592. for (i = 0; i < menu->itemCount; i++) {
  3593. if (menu->items[i]->special == feeder) {
  3594. if (index == 0) {
  3595. listBoxDef_t *listPtr = (listBoxDef_t*)menu->items[i]->typeData;
  3596. listPtr->cursorPos = 0;
  3597. listPtr->startPos = 0;
  3598. }
  3599. menu->items[i]->cursorPos = index;
  3600. DC->feederSelection(menu->items[i]->special, menu->items[i]->cursorPos);
  3601. return;
  3602. }
  3603. }
  3604. }
  3605. }
  3606. qboolean Menus_AnyFullScreenVisible() {
  3607. int i;
  3608. for (i = 0; i < menuCount; i++) {
  3609. if (Menus[i].window.flags & WINDOW_VISIBLE && Menus[i].fullScreen) {
  3610. return qtrue;
  3611. }
  3612. }
  3613. return qfalse;
  3614. }
  3615. menuDef_t *Menus_ActivateByName(const char *p) {
  3616. int i;
  3617. menuDef_t *m = NULL;
  3618. menuDef_t *focus = Menu_GetFocused();
  3619. for (i = 0; i < menuCount; i++) {
  3620. if (Q_stricmp(Menus[i].window.name, p) == 0) {
  3621. m = &Menus[i];
  3622. Menus_Activate(m);
  3623. if (openMenuCount < MAX_OPEN_MENUS && focus != NULL) {
  3624. menuStack[openMenuCount++] = focus;
  3625. }
  3626. } else {
  3627. Menus[i].window.flags &= ~WINDOW_HASFOCUS;
  3628. }
  3629. }
  3630. Display_CloseCinematics();
  3631. return m;
  3632. }
  3633. void Item_Init(itemDef_t *item) {
  3634. memset(item, 0, sizeof(itemDef_t));
  3635. item->textscale = 0.55f;
  3636. Window_Init(&item->window);
  3637. }
  3638. void Menu_HandleMouseMove(menuDef_t *menu, float x, float y) {
  3639. int i, pass;
  3640. qboolean focusSet = qfalse;
  3641. itemDef_t *overItem;
  3642. if (menu == NULL) {
  3643. return;
  3644. }
  3645. if (!(menu->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
  3646. return;
  3647. }
  3648. if (itemCapture) {
  3649. //Item_MouseMove(itemCapture, x, y);
  3650. return;
  3651. }
  3652. if (g_waitingForKey || g_editingField) {
  3653. return;
  3654. }
  3655. // FIXME: this is the whole issue of focus vs. mouse over..
  3656. // need a better overall solution as i don't like going through everything twice
  3657. for (pass = 0; pass < 2; pass++) {
  3658. for (i = 0; i < menu->itemCount; i++) {
  3659. // turn off focus each item
  3660. // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
  3661. if (!(menu->items[i]->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
  3662. continue;
  3663. }
  3664. // items can be enabled and disabled based on cvars
  3665. if (menu->items[i]->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(menu->items[i], CVAR_ENABLE)) {
  3666. continue;
  3667. }
  3668. if (menu->items[i]->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(menu->items[i], CVAR_SHOW)) {
  3669. continue;
  3670. }
  3671. if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
  3672. if (pass == 1) {
  3673. overItem = menu->items[i];
  3674. if (overItem->type == ITEM_TYPE_TEXT && overItem->text) {
  3675. if (!Rect_ContainsPoint(Item_CorrectedTextRect(overItem), x, y)) {
  3676. continue;
  3677. }
  3678. }
  3679. // if we are over an item
  3680. if (IsVisible(overItem->window.flags)) {
  3681. // different one
  3682. Item_MouseEnter(overItem, x, y);
  3683. // Item_SetMouseOver(overItem, qtrue);
  3684. // if item is not a decoration see if it can take focus
  3685. if (!focusSet) {
  3686. focusSet = Item_SetFocus(overItem, x, y);
  3687. }
  3688. }
  3689. }
  3690. } else if (menu->items[i]->window.flags & WINDOW_MOUSEOVER) {
  3691. Item_MouseLeave(menu->items[i]);
  3692. Item_SetMouseOver(menu->items[i], qfalse);
  3693. }
  3694. }
  3695. }
  3696. }
  3697. void Menu_Paint(menuDef_t *menu, qboolean forcePaint) {
  3698. int i;
  3699. if (menu == NULL) {
  3700. return;
  3701. }
  3702. if (!(menu->window.flags & WINDOW_VISIBLE) && !forcePaint) {
  3703. return;
  3704. }
  3705. if (menu->window.ownerDrawFlags && DC->ownerDrawVisible && !DC->ownerDrawVisible(menu->window.ownerDrawFlags)) {
  3706. return;
  3707. }
  3708. if (forcePaint) {
  3709. menu->window.flags |= WINDOW_FORCED;
  3710. }
  3711. // draw the background if necessary
  3712. if (menu->fullScreen) {
  3713. // implies a background shader
  3714. // FIXME: make sure we have a default shader if fullscreen is set with no background
  3715. DC->drawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, menu->window.background );
  3716. } else if (menu->window.background) {
  3717. // this allows a background shader without being full screen
  3718. //UI_DrawHandlePic(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, menu->backgroundShader);
  3719. }
  3720. // paint the background and or border
  3721. Window_Paint(&menu->window, menu->fadeAmount, menu->fadeClamp, menu->fadeCycle );
  3722. for (i = 0; i < menu->itemCount; i++) {
  3723. Item_Paint(menu->items[i]);
  3724. }
  3725. if (debugMode) {
  3726. vec4_t color;
  3727. color[0] = color[2] = color[3] = 1;
  3728. color[1] = 0;
  3729. DC->drawRect(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, 1, color);
  3730. }
  3731. }
  3732. /*
  3733. ===============
  3734. Item_ValidateTypeData
  3735. ===============
  3736. */
  3737. void Item_ValidateTypeData(itemDef_t *item) {
  3738. if (item->typeData) {
  3739. return;
  3740. }
  3741. if (item->type == ITEM_TYPE_LISTBOX) {
  3742. item->typeData = UI_Alloc(sizeof(listBoxDef_t));
  3743. memset(item->typeData, 0, sizeof(listBoxDef_t));
  3744. } else if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD || item->type == ITEM_TYPE_YESNO || item->type == ITEM_TYPE_BIND || item->type == ITEM_TYPE_SLIDER || item->type == ITEM_TYPE_TEXT) {
  3745. item->typeData = UI_Alloc(sizeof(editFieldDef_t));
  3746. memset(item->typeData, 0, sizeof(editFieldDef_t));
  3747. if (item->type == ITEM_TYPE_EDITFIELD) {
  3748. if (!((editFieldDef_t *) item->typeData)->maxPaintChars) {
  3749. ((editFieldDef_t *) item->typeData)->maxPaintChars = MAX_EDITFIELD;
  3750. }
  3751. }
  3752. } else if (item->type == ITEM_TYPE_MULTI) {
  3753. item->typeData = UI_Alloc(sizeof(multiDef_t));
  3754. } else if (item->type == ITEM_TYPE_MODEL) {
  3755. item->typeData = UI_Alloc(sizeof(modelDef_t));
  3756. }
  3757. }
  3758. /*
  3759. ===============
  3760. Keyword Hash
  3761. ===============
  3762. */
  3763. #define KEYWORDHASH_SIZE 512
  3764. typedef struct keywordHash_s
  3765. {
  3766. char *keyword;
  3767. qboolean (*func)(itemDef_t *item, int handle);
  3768. struct keywordHash_s *next;
  3769. } keywordHash_t;
  3770. int KeywordHash_Key(char *keyword) {
  3771. int register hash, i;
  3772. hash = 0;
  3773. for (i = 0; keyword[i] != '\0'; i++) {
  3774. if (keyword[i] >= 'A' && keyword[i] <= 'Z')
  3775. hash += (keyword[i] + ('a' - 'A')) * (119 + i);
  3776. else
  3777. hash += keyword[i] * (119 + i);
  3778. }
  3779. hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (KEYWORDHASH_SIZE-1);
  3780. return hash;
  3781. }
  3782. void KeywordHash_Add(keywordHash_t *table[], keywordHash_t *key) {
  3783. int hash;
  3784. hash = KeywordHash_Key(key->keyword);
  3785. /*
  3786. if (table[hash]) {
  3787. int collision = qtrue;
  3788. }
  3789. */
  3790. key->next = table[hash];
  3791. table[hash] = key;
  3792. }
  3793. keywordHash_t *KeywordHash_Find(keywordHash_t *table[], char *keyword)
  3794. {
  3795. keywordHash_t *key;
  3796. int hash;
  3797. hash = KeywordHash_Key(keyword);
  3798. for (key = table[hash]; key; key = key->next) {
  3799. if (!Q_stricmp(key->keyword, keyword))
  3800. return key;
  3801. }
  3802. return NULL;
  3803. }
  3804. /*
  3805. ===============
  3806. Item Keyword Parse functions
  3807. ===============
  3808. */
  3809. // name <string>
  3810. qboolean ItemParse_name( itemDef_t *item, int handle ) {
  3811. if (!PC_String_Parse(handle, &item->window.name)) {
  3812. return qfalse;
  3813. }
  3814. return qtrue;
  3815. }
  3816. // name <string>
  3817. qboolean ItemParse_focusSound( itemDef_t *item, int handle ) {
  3818. const char *temp;
  3819. if (!PC_String_Parse(handle, &temp)) {
  3820. return qfalse;
  3821. }
  3822. item->focusSound = DC->registerSound(temp, qfalse);
  3823. return qtrue;
  3824. }
  3825. // text <string>
  3826. qboolean ItemParse_text( itemDef_t *item, int handle ) {
  3827. if (!PC_String_Parse(handle, &item->text)) {
  3828. return qfalse;
  3829. }
  3830. return qtrue;
  3831. }
  3832. // group <string>
  3833. qboolean ItemParse_group( itemDef_t *item, int handle ) {
  3834. if (!PC_String_Parse(handle, &item->window.group)) {
  3835. return qfalse;
  3836. }
  3837. return qtrue;
  3838. }
  3839. // asset_model <string>
  3840. qboolean ItemParse_asset_model( itemDef_t *item, int handle ) {
  3841. const char *temp;
  3842. modelDef_t *modelPtr;
  3843. Item_ValidateTypeData(item);
  3844. modelPtr = (modelDef_t*)item->typeData;
  3845. if (!PC_String_Parse(handle, &temp)) {
  3846. return qfalse;
  3847. }
  3848. item->asset = DC->registerModel(temp);
  3849. modelPtr->angle = rand() % 360;
  3850. return qtrue;
  3851. }
  3852. // asset_shader <string>
  3853. qboolean ItemParse_asset_shader( itemDef_t *item, int handle ) {
  3854. const char *temp;
  3855. if (!PC_String_Parse(handle, &temp)) {
  3856. return qfalse;
  3857. }
  3858. item->asset = DC->registerShaderNoMip(temp);
  3859. return qtrue;
  3860. }
  3861. // model_origin <number> <number> <number>
  3862. qboolean ItemParse_model_origin( itemDef_t *item, int handle ) {
  3863. modelDef_t *modelPtr;
  3864. Item_ValidateTypeData(item);
  3865. modelPtr = (modelDef_t*)item->typeData;
  3866. if (PC_Float_Parse(handle, &modelPtr->origin[0])) {
  3867. if (PC_Float_Parse(handle, &modelPtr->origin[1])) {
  3868. if (PC_Float_Parse(handle, &modelPtr->origin[2])) {
  3869. return qtrue;
  3870. }
  3871. }
  3872. }
  3873. return qfalse;
  3874. }
  3875. // model_fovx <number>
  3876. qboolean ItemParse_model_fovx( itemDef_t *item, int handle ) {
  3877. modelDef_t *modelPtr;
  3878. Item_ValidateTypeData(item);
  3879. modelPtr = (modelDef_t*)item->typeData;
  3880. if (!PC_Float_Parse(handle, &modelPtr->fov_x)) {
  3881. return qfalse;
  3882. }
  3883. return qtrue;
  3884. }
  3885. // model_fovy <number>
  3886. qboolean ItemParse_model_fovy( itemDef_t *item, int handle ) {
  3887. modelDef_t *modelPtr;
  3888. Item_ValidateTypeData(item);
  3889. modelPtr = (modelDef_t*)item->typeData;
  3890. if (!PC_Float_Parse(handle, &modelPtr->fov_y)) {
  3891. return qfalse;
  3892. }
  3893. return qtrue;
  3894. }
  3895. // model_rotation <integer>
  3896. qboolean ItemParse_model_rotation( itemDef_t *item, int handle ) {
  3897. modelDef_t *modelPtr;
  3898. Item_ValidateTypeData(item);
  3899. modelPtr = (modelDef_t*)item->typeData;
  3900. if (!PC_Int_Parse(handle, &modelPtr->rotationSpeed)) {
  3901. return qfalse;
  3902. }
  3903. return qtrue;
  3904. }
  3905. // model_angle <integer>
  3906. qboolean ItemParse_model_angle( itemDef_t *item, int handle ) {
  3907. modelDef_t *modelPtr;
  3908. Item_ValidateTypeData(item);
  3909. modelPtr = (modelDef_t*)item->typeData;
  3910. if (!PC_Int_Parse(handle, &modelPtr->angle)) {
  3911. return qfalse;
  3912. }
  3913. return qtrue;
  3914. }
  3915. // rect <rectangle>
  3916. qboolean ItemParse_rect( itemDef_t *item, int handle ) {
  3917. if (!PC_Rect_Parse(handle, &item->window.rectClient)) {
  3918. return qfalse;
  3919. }
  3920. return qtrue;
  3921. }
  3922. // style <integer>
  3923. qboolean ItemParse_style( itemDef_t *item, int handle ) {
  3924. if (!PC_Int_Parse(handle, &item->window.style)) {
  3925. return qfalse;
  3926. }
  3927. return qtrue;
  3928. }
  3929. // decoration
  3930. qboolean ItemParse_decoration( itemDef_t *item, int handle ) {
  3931. item->window.flags |= WINDOW_DECORATION;
  3932. return qtrue;
  3933. }
  3934. // notselectable
  3935. qboolean ItemParse_notselectable( itemDef_t *item, int handle ) {
  3936. listBoxDef_t *listPtr;
  3937. Item_ValidateTypeData(item);
  3938. listPtr = (listBoxDef_t*)item->typeData;
  3939. if (item->type == ITEM_TYPE_LISTBOX && listPtr) {
  3940. listPtr->notselectable = qtrue;
  3941. }
  3942. return qtrue;
  3943. }
  3944. // manually wrapped
  3945. qboolean ItemParse_wrapped( itemDef_t *item, int handle ) {
  3946. item->window.flags |= WINDOW_WRAPPED;
  3947. return qtrue;
  3948. }
  3949. // auto wrapped
  3950. qboolean ItemParse_autowrapped( itemDef_t *item, int handle ) {
  3951. item->window.flags |= WINDOW_AUTOWRAPPED;
  3952. return qtrue;
  3953. }
  3954. // horizontalscroll
  3955. qboolean ItemParse_horizontalscroll( itemDef_t *item, int handle ) {
  3956. item->window.flags |= WINDOW_HORIZONTAL;
  3957. return qtrue;
  3958. }
  3959. // type <integer>
  3960. qboolean ItemParse_type( itemDef_t *item, int handle ) {
  3961. if (!PC_Int_Parse(handle, &item->type)) {
  3962. return qfalse;
  3963. }
  3964. Item_ValidateTypeData(item);
  3965. return qtrue;
  3966. }
  3967. // elementwidth, used for listbox image elements
  3968. // uses textalignx for storage
  3969. qboolean ItemParse_elementwidth( itemDef_t *item, int handle ) {
  3970. listBoxDef_t *listPtr;
  3971. Item_ValidateTypeData(item);
  3972. listPtr = (listBoxDef_t*)item->typeData;
  3973. if (!PC_Float_Parse(handle, &listPtr->elementWidth)) {
  3974. return qfalse;
  3975. }
  3976. return qtrue;
  3977. }
  3978. // elementheight, used for listbox image elements
  3979. // uses textaligny for storage
  3980. qboolean ItemParse_elementheight( itemDef_t *item, int handle ) {
  3981. listBoxDef_t *listPtr;
  3982. Item_ValidateTypeData(item);
  3983. listPtr = (listBoxDef_t*)item->typeData;
  3984. if (!PC_Float_Parse(handle, &listPtr->elementHeight)) {
  3985. return qfalse;
  3986. }
  3987. return qtrue;
  3988. }
  3989. // feeder <float>
  3990. qboolean ItemParse_feeder( itemDef_t *item, int handle ) {
  3991. if (!PC_Float_Parse(handle, &item->special)) {
  3992. return qfalse;
  3993. }
  3994. return qtrue;
  3995. }
  3996. // elementtype, used to specify what type of elements a listbox contains
  3997. // uses textstyle for storage
  3998. qboolean ItemParse_elementtype( itemDef_t *item, int handle ) {
  3999. listBoxDef_t *listPtr;
  4000. Item_ValidateTypeData(item);
  4001. if (!item->typeData)
  4002. return qfalse;
  4003. listPtr = (listBoxDef_t*)item->typeData;
  4004. if (!PC_Int_Parse(handle, &listPtr->elementStyle)) {
  4005. return qfalse;
  4006. }
  4007. return qtrue;
  4008. }
  4009. // columns sets a number of columns and an x pos and width per..
  4010. qboolean ItemParse_columns( itemDef_t *item, int handle ) {
  4011. int num, i;
  4012. listBoxDef_t *listPtr;
  4013. Item_ValidateTypeData(item);
  4014. if (!item->typeData)
  4015. return qfalse;
  4016. listPtr = (listBoxDef_t*)item->typeData;
  4017. if (PC_Int_Parse(handle, &num)) {
  4018. if (num > MAX_LB_COLUMNS) {
  4019. num = MAX_LB_COLUMNS;
  4020. }
  4021. listPtr->numColumns = num;
  4022. for (i = 0; i < num; i++) {
  4023. int pos, width, maxChars;
  4024. if (PC_Int_Parse(handle, &pos) && PC_Int_Parse(handle, &width) && PC_Int_Parse(handle, &maxChars)) {
  4025. listPtr->columnInfo[i].pos = pos;
  4026. listPtr->columnInfo[i].width = width;
  4027. listPtr->columnInfo[i].maxChars = maxChars;
  4028. } else {
  4029. return qfalse;
  4030. }
  4031. }
  4032. } else {
  4033. return qfalse;
  4034. }
  4035. return qtrue;
  4036. }
  4037. qboolean ItemParse_border( itemDef_t *item, int handle ) {
  4038. if (!PC_Int_Parse(handle, &item->window.border)) {
  4039. return qfalse;
  4040. }
  4041. return qtrue;
  4042. }
  4043. qboolean ItemParse_bordersize( itemDef_t *item, int handle ) {
  4044. if (!PC_Float_Parse(handle, &item->window.borderSize)) {
  4045. return qfalse;
  4046. }
  4047. return qtrue;
  4048. }
  4049. qboolean ItemParse_visible( itemDef_t *item, int handle ) {
  4050. int i;
  4051. if (!PC_Int_Parse(handle, &i)) {
  4052. return qfalse;
  4053. }
  4054. if (i) {
  4055. item->window.flags |= WINDOW_VISIBLE;
  4056. }
  4057. return qtrue;
  4058. }
  4059. qboolean ItemParse_ownerdraw( itemDef_t *item, int handle ) {
  4060. if (!PC_Int_Parse(handle, &item->window.ownerDraw)) {
  4061. return qfalse;
  4062. }
  4063. item->type = ITEM_TYPE_OWNERDRAW;
  4064. return qtrue;
  4065. }
  4066. qboolean ItemParse_align( itemDef_t *item, int handle ) {
  4067. if (!PC_Int_Parse(handle, &item->alignment)) {
  4068. return qfalse;
  4069. }
  4070. return qtrue;
  4071. }
  4072. qboolean ItemParse_textalign( itemDef_t *item, int handle ) {
  4073. if (!PC_Int_Parse(handle, &item->textalignment)) {
  4074. return qfalse;
  4075. }
  4076. return qtrue;
  4077. }
  4078. qboolean ItemParse_textalignx( itemDef_t *item, int handle ) {
  4079. if (!PC_Float_Parse(handle, &item->textalignx)) {
  4080. return qfalse;
  4081. }
  4082. return qtrue;
  4083. }
  4084. qboolean ItemParse_textaligny( itemDef_t *item, int handle ) {
  4085. if (!PC_Float_Parse(handle, &item->textaligny)) {
  4086. return qfalse;
  4087. }
  4088. return qtrue;
  4089. }
  4090. qboolean ItemParse_textscale( itemDef_t *item, int handle ) {
  4091. if (!PC_Float_Parse(handle, &item->textscale)) {
  4092. return qfalse;
  4093. }
  4094. return qtrue;
  4095. }
  4096. qboolean ItemParse_textstyle( itemDef_t *item, int handle ) {
  4097. if (!PC_Int_Parse(handle, &item->textStyle)) {
  4098. return qfalse;
  4099. }
  4100. return qtrue;
  4101. }
  4102. qboolean ItemParse_backcolor( itemDef_t *item, int handle ) {
  4103. int i;
  4104. float f;
  4105. for (i = 0; i < 4; i++) {
  4106. if (!PC_Float_Parse(handle, &f)) {
  4107. return qfalse;
  4108. }
  4109. item->window.backColor[i] = f;
  4110. }
  4111. return qtrue;
  4112. }
  4113. qboolean ItemParse_forecolor( itemDef_t *item, int handle ) {
  4114. int i;
  4115. float f;
  4116. for (i = 0; i < 4; i++) {
  4117. if (!PC_Float_Parse(handle, &f)) {
  4118. return qfalse;
  4119. }
  4120. item->window.foreColor[i] = f;
  4121. item->window.flags |= WINDOW_FORECOLORSET;
  4122. }
  4123. return qtrue;
  4124. }
  4125. qboolean ItemParse_bordercolor( itemDef_t *item, int handle ) {
  4126. int i;
  4127. float f;
  4128. for (i = 0; i < 4; i++) {
  4129. if (!PC_Float_Parse(handle, &f)) {
  4130. return qfalse;
  4131. }
  4132. item->window.borderColor[i] = f;
  4133. }
  4134. return qtrue;
  4135. }
  4136. qboolean ItemParse_outlinecolor( itemDef_t *item, int handle ) {
  4137. if (!PC_Color_Parse(handle, &item->window.outlineColor)){
  4138. return qfalse;
  4139. }
  4140. return qtrue;
  4141. }
  4142. qboolean ItemParse_background( itemDef_t *item, int handle ) {
  4143. const char *temp;
  4144. if (!PC_String_Parse(handle, &temp)) {
  4145. return qfalse;
  4146. }
  4147. item->window.background = DC->registerShaderNoMip(temp);
  4148. return qtrue;
  4149. }
  4150. qboolean ItemParse_cinematic( itemDef_t *item, int handle ) {
  4151. if (!PC_String_Parse(handle, &item->window.cinematicName)) {
  4152. return qfalse;
  4153. }
  4154. return qtrue;
  4155. }
  4156. qboolean ItemParse_doubleClick( itemDef_t *item, int handle ) {
  4157. listBoxDef_t *listPtr;
  4158. Item_ValidateTypeData(item);
  4159. if (!item->typeData) {
  4160. return qfalse;
  4161. }
  4162. listPtr = (listBoxDef_t*)item->typeData;
  4163. if (!PC_Script_Parse(handle, &listPtr->doubleClick)) {
  4164. return qfalse;
  4165. }
  4166. return qtrue;
  4167. }
  4168. qboolean ItemParse_onFocus( itemDef_t *item, int handle ) {
  4169. if (!PC_Script_Parse(handle, &item->onFocus)) {
  4170. return qfalse;
  4171. }
  4172. return qtrue;
  4173. }
  4174. qboolean ItemParse_leaveFocus( itemDef_t *item, int handle ) {
  4175. if (!PC_Script_Parse(handle, &item->leaveFocus)) {
  4176. return qfalse;
  4177. }
  4178. return qtrue;
  4179. }
  4180. qboolean ItemParse_mouseEnter( itemDef_t *item, int handle ) {
  4181. if (!PC_Script_Parse(handle, &item->mouseEnter)) {
  4182. return qfalse;
  4183. }
  4184. return qtrue;
  4185. }
  4186. qboolean ItemParse_mouseExit( itemDef_t *item, int handle ) {
  4187. if (!PC_Script_Parse(handle, &item->mouseExit)) {
  4188. return qfalse;
  4189. }
  4190. return qtrue;
  4191. }
  4192. qboolean ItemParse_mouseEnterText( itemDef_t *item, int handle ) {
  4193. if (!PC_Script_Parse(handle, &item->mouseEnterText)) {
  4194. return qfalse;
  4195. }
  4196. return qtrue;
  4197. }
  4198. qboolean ItemParse_mouseExitText( itemDef_t *item, int handle ) {
  4199. if (!PC_Script_Parse(handle, &item->mouseExitText)) {
  4200. return qfalse;
  4201. }
  4202. return qtrue;
  4203. }
  4204. qboolean ItemParse_action( itemDef_t *item, int handle ) {
  4205. if (!PC_Script_Parse(handle, &item->action)) {
  4206. return qfalse;
  4207. }
  4208. return qtrue;
  4209. }
  4210. qboolean ItemParse_special( itemDef_t *item, int handle ) {
  4211. if (!PC_Float_Parse(handle, &item->special)) {
  4212. return qfalse;
  4213. }
  4214. return qtrue;
  4215. }
  4216. qboolean ItemParse_cvarTest( itemDef_t *item, int handle ) {
  4217. if (!PC_String_Parse(handle, &item->cvarTest)) {
  4218. return qfalse;
  4219. }
  4220. return qtrue;
  4221. }
  4222. qboolean ItemParse_cvar( itemDef_t *item, int handle ) {
  4223. editFieldDef_t *editPtr;
  4224. Item_ValidateTypeData(item);
  4225. if (!PC_String_Parse(handle, &item->cvar)) {
  4226. return qfalse;
  4227. }
  4228. if (item->typeData) {
  4229. editPtr = (editFieldDef_t*)item->typeData;
  4230. editPtr->minVal = -1;
  4231. editPtr->maxVal = -1;
  4232. editPtr->defVal = -1;
  4233. }
  4234. return qtrue;
  4235. }
  4236. qboolean ItemParse_maxChars( itemDef_t *item, int handle ) {
  4237. editFieldDef_t *editPtr;
  4238. int maxChars;
  4239. Item_ValidateTypeData(item);
  4240. if (!item->typeData)
  4241. return qfalse;
  4242. if (!PC_Int_Parse(handle, &maxChars)) {
  4243. return qfalse;
  4244. }
  4245. editPtr = (editFieldDef_t*)item->typeData;
  4246. editPtr->maxChars = maxChars;
  4247. return qtrue;
  4248. }
  4249. qboolean ItemParse_maxPaintChars( itemDef_t *item, int handle ) {
  4250. editFieldDef_t *editPtr;
  4251. int maxChars;
  4252. Item_ValidateTypeData(item);
  4253. if (!item->typeData)
  4254. return qfalse;
  4255. if (!PC_Int_Parse(handle, &maxChars)) {
  4256. return qfalse;
  4257. }
  4258. editPtr = (editFieldDef_t*)item->typeData;
  4259. editPtr->maxPaintChars = maxChars;
  4260. return qtrue;
  4261. }
  4262. qboolean ItemParse_cvarFloat( itemDef_t *item, int handle ) {
  4263. editFieldDef_t *editPtr;
  4264. Item_ValidateTypeData(item);
  4265. if (!item->typeData)
  4266. return qfalse;
  4267. editPtr = (editFieldDef_t*)item->typeData;
  4268. if (PC_String_Parse(handle, &item->cvar) &&
  4269. PC_Float_Parse(handle, &editPtr->defVal) &&
  4270. PC_Float_Parse(handle, &editPtr->minVal) &&
  4271. PC_Float_Parse(handle, &editPtr->maxVal)) {
  4272. return qtrue;
  4273. }
  4274. return qfalse;
  4275. }
  4276. qboolean ItemParse_cvarStrList( itemDef_t *item, int handle ) {
  4277. pc_token_t token;
  4278. multiDef_t *multiPtr;
  4279. int pass;
  4280. Item_ValidateTypeData(item);
  4281. if (!item->typeData)
  4282. return qfalse;
  4283. multiPtr = (multiDef_t*)item->typeData;
  4284. multiPtr->count = 0;
  4285. multiPtr->strDef = qtrue;
  4286. if (!trap_PC_ReadToken(handle, &token))
  4287. return qfalse;
  4288. if (*token.string != '{') {
  4289. return qfalse;
  4290. }
  4291. pass = 0;
  4292. while ( 1 ) {
  4293. if (!trap_PC_ReadToken(handle, &token)) {
  4294. PC_SourceError(handle, "end of file inside menu item\n");
  4295. return qfalse;
  4296. }
  4297. if (*token.string == '}') {
  4298. return qtrue;
  4299. }
  4300. if (*token.string == ',' || *token.string == ';') {
  4301. continue;
  4302. }
  4303. if (pass == 0) {
  4304. multiPtr->cvarList[multiPtr->count] = String_Alloc(token.string);
  4305. pass = 1;
  4306. } else {
  4307. multiPtr->cvarStr[multiPtr->count] = String_Alloc(token.string);
  4308. pass = 0;
  4309. multiPtr->count++;
  4310. if (multiPtr->count >= MAX_MULTI_CVARS) {
  4311. return qfalse;
  4312. }
  4313. }
  4314. }
  4315. return qfalse; // bk001205 - LCC missing return value
  4316. }
  4317. qboolean ItemParse_cvarFloatList( itemDef_t *item, int handle ) {
  4318. pc_token_t token;
  4319. multiDef_t *multiPtr;
  4320. Item_ValidateTypeData(item);
  4321. if (!item->typeData)
  4322. return qfalse;
  4323. multiPtr = (multiDef_t*)item->typeData;
  4324. multiPtr->count = 0;
  4325. multiPtr->strDef = qfalse;
  4326. if (!trap_PC_ReadToken(handle, &token))
  4327. return qfalse;
  4328. if (*token.string != '{') {
  4329. return qfalse;
  4330. }
  4331. while ( 1 ) {
  4332. if (!trap_PC_ReadToken(handle, &token)) {
  4333. PC_SourceError(handle, "end of file inside menu item\n");
  4334. return qfalse;
  4335. }
  4336. if (*token.string == '}') {
  4337. return qtrue;
  4338. }
  4339. if (*token.string == ',' || *token.string == ';') {
  4340. continue;
  4341. }
  4342. multiPtr->cvarList[multiPtr->count] = String_Alloc(token.string);
  4343. if (!PC_Float_Parse(handle, &multiPtr->cvarValue[multiPtr->count])) {
  4344. return qfalse;
  4345. }
  4346. multiPtr->count++;
  4347. if (multiPtr->count >= MAX_MULTI_CVARS) {
  4348. return qfalse;
  4349. }
  4350. }
  4351. return qfalse; // bk001205 - LCC missing return value
  4352. }
  4353. qboolean ItemParse_addColorRange( itemDef_t *item, int handle ) {
  4354. colorRangeDef_t color;
  4355. if (PC_Float_Parse(handle, &color.low) &&
  4356. PC_Float_Parse(handle, &color.high) &&
  4357. PC_Color_Parse(handle, &color.color) ) {
  4358. if (item->numColors < MAX_COLOR_RANGES) {
  4359. memcpy(&item->colorRanges[item->numColors], &color, sizeof(color));
  4360. item->numColors++;
  4361. }
  4362. return qtrue;
  4363. }
  4364. return qfalse;
  4365. }
  4366. qboolean ItemParse_ownerdrawFlag( itemDef_t *item, int handle ) {
  4367. int i;
  4368. if (!PC_Int_Parse(handle, &i)) {
  4369. return qfalse;
  4370. }
  4371. item->window.ownerDrawFlags |= i;
  4372. return qtrue;
  4373. }
  4374. qboolean ItemParse_enableCvar( itemDef_t *item, int handle ) {
  4375. if (PC_Script_Parse(handle, &item->enableCvar)) {
  4376. item->cvarFlags = CVAR_ENABLE;
  4377. return qtrue;
  4378. }
  4379. return qfalse;
  4380. }
  4381. qboolean ItemParse_disableCvar( itemDef_t *item, int handle ) {
  4382. if (PC_Script_Parse(handle, &item->enableCvar)) {
  4383. item->cvarFlags = CVAR_DISABLE;
  4384. return qtrue;
  4385. }
  4386. return qfalse;
  4387. }
  4388. qboolean ItemParse_showCvar( itemDef_t *item, int handle ) {
  4389. if (PC_Script_Parse(handle, &item->enableCvar)) {
  4390. item->cvarFlags = CVAR_SHOW;
  4391. return qtrue;
  4392. }
  4393. return qfalse;
  4394. }
  4395. qboolean ItemParse_hideCvar( itemDef_t *item, int handle ) {
  4396. if (PC_Script_Parse(handle, &item->enableCvar)) {
  4397. item->cvarFlags = CVAR_HIDE;
  4398. return qtrue;
  4399. }
  4400. return qfalse;
  4401. }
  4402. keywordHash_t itemParseKeywords[] = {
  4403. {"name", ItemParse_name, NULL},
  4404. {"text", ItemParse_text, NULL},
  4405. {"group", ItemParse_group, NULL},
  4406. {"asset_model", ItemParse_asset_model, NULL},
  4407. {"asset_shader", ItemParse_asset_shader, NULL},
  4408. {"model_origin", ItemParse_model_origin, NULL},
  4409. {"model_fovx", ItemParse_model_fovx, NULL},
  4410. {"model_fovy", ItemParse_model_fovy, NULL},
  4411. {"model_rotation", ItemParse_model_rotation, NULL},
  4412. {"model_angle", ItemParse_model_angle, NULL},
  4413. {"rect", ItemParse_rect, NULL},
  4414. {"style", ItemParse_style, NULL},
  4415. {"decoration", ItemParse_decoration, NULL},
  4416. {"notselectable", ItemParse_notselectable, NULL},
  4417. {"wrapped", ItemParse_wrapped, NULL},
  4418. {"autowrapped", ItemParse_autowrapped, NULL},
  4419. {"horizontalscroll", ItemParse_horizontalscroll, NULL},
  4420. {"type", ItemParse_type, NULL},
  4421. {"elementwidth", ItemParse_elementwidth, NULL},
  4422. {"elementheight", ItemParse_elementheight, NULL},
  4423. {"feeder", ItemParse_feeder, NULL},
  4424. {"elementtype", ItemParse_elementtype, NULL},
  4425. {"columns", ItemParse_columns, NULL},
  4426. {"border", ItemParse_border, NULL},
  4427. {"bordersize", ItemParse_bordersize, NULL},
  4428. {"visible", ItemParse_visible, NULL},
  4429. {"ownerdraw", ItemParse_ownerdraw, NULL},
  4430. {"align", ItemParse_align, NULL},
  4431. {"textalign", ItemParse_textalign, NULL},
  4432. {"textalignx", ItemParse_textalignx, NULL},
  4433. {"textaligny", ItemParse_textaligny, NULL},
  4434. {"textscale", ItemParse_textscale, NULL},
  4435. {"textstyle", ItemParse_textstyle, NULL},
  4436. {"backcolor", ItemParse_backcolor, NULL},
  4437. {"forecolor", ItemParse_forecolor, NULL},
  4438. {"bordercolor", ItemParse_bordercolor, NULL},
  4439. {"outlinecolor", ItemParse_outlinecolor, NULL},
  4440. {"background", ItemParse_background, NULL},
  4441. {"onFocus", ItemParse_onFocus, NULL},
  4442. {"leaveFocus", ItemParse_leaveFocus, NULL},
  4443. {"mouseEnter", ItemParse_mouseEnter, NULL},
  4444. {"mouseExit", ItemParse_mouseExit, NULL},
  4445. {"mouseEnterText", ItemParse_mouseEnterText, NULL},
  4446. {"mouseExitText", ItemParse_mouseExitText, NULL},
  4447. {"action", ItemParse_action, NULL},
  4448. {"special", ItemParse_special, NULL},
  4449. {"cvar", ItemParse_cvar, NULL},
  4450. {"maxChars", ItemParse_maxChars, NULL},
  4451. {"maxPaintChars", ItemParse_maxPaintChars, NULL},
  4452. {"focusSound", ItemParse_focusSound, NULL},
  4453. {"cvarFloat", ItemParse_cvarFloat, NULL},
  4454. {"cvarStrList", ItemParse_cvarStrList, NULL},
  4455. {"cvarFloatList", ItemParse_cvarFloatList, NULL},
  4456. {"addColorRange", ItemParse_addColorRange, NULL},
  4457. {"ownerdrawFlag", ItemParse_ownerdrawFlag, NULL},
  4458. {"enableCvar", ItemParse_enableCvar, NULL},
  4459. {"cvarTest", ItemParse_cvarTest, NULL},
  4460. {"disableCvar", ItemParse_disableCvar, NULL},
  4461. {"showCvar", ItemParse_showCvar, NULL},
  4462. {"hideCvar", ItemParse_hideCvar, NULL},
  4463. {"cinematic", ItemParse_cinematic, NULL},
  4464. {"doubleclick", ItemParse_doubleClick, NULL},
  4465. {NULL, NULL, NULL}
  4466. };
  4467. keywordHash_t *itemParseKeywordHash[KEYWORDHASH_SIZE];
  4468. /*
  4469. ===============
  4470. Item_SetupKeywordHash
  4471. ===============
  4472. */
  4473. void Item_SetupKeywordHash(void) {
  4474. int i;
  4475. memset(itemParseKeywordHash, 0, sizeof(itemParseKeywordHash));
  4476. for (i = 0; itemParseKeywords[i].keyword; i++) {
  4477. KeywordHash_Add(itemParseKeywordHash, &itemParseKeywords[i]);
  4478. }
  4479. }
  4480. /*
  4481. ===============
  4482. Item_Parse
  4483. ===============
  4484. */
  4485. qboolean Item_Parse(int handle, itemDef_t *item) {
  4486. pc_token_t token;
  4487. keywordHash_t *key;
  4488. if (!trap_PC_ReadToken(handle, &token))
  4489. return qfalse;
  4490. if (*token.string != '{') {
  4491. return qfalse;
  4492. }
  4493. while ( 1 ) {
  4494. if (!trap_PC_ReadToken(handle, &token)) {
  4495. PC_SourceError(handle, "end of file inside menu item\n");
  4496. return qfalse;
  4497. }
  4498. if (*token.string == '}') {
  4499. return qtrue;
  4500. }
  4501. key = KeywordHash_Find(itemParseKeywordHash, token.string);
  4502. if (!key) {
  4503. PC_SourceError(handle, "unknown menu item keyword %s", token.string);
  4504. continue;
  4505. }
  4506. if ( !key->func(item, handle) ) {
  4507. PC_SourceError(handle, "couldn't parse menu item keyword %s", token.string);
  4508. return qfalse;
  4509. }
  4510. }
  4511. return qfalse; // bk001205 - LCC missing return value
  4512. }
  4513. // Item_InitControls
  4514. // init's special control types
  4515. void Item_InitControls(itemDef_t *item) {
  4516. if (item == NULL) {
  4517. return;
  4518. }
  4519. if (item->type == ITEM_TYPE_LISTBOX) {
  4520. listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
  4521. item->cursorPos = 0;
  4522. if (listPtr) {
  4523. listPtr->cursorPos = 0;
  4524. listPtr->startPos = 0;
  4525. listPtr->endPos = 0;
  4526. listPtr->cursorPos = 0;
  4527. }
  4528. }
  4529. }
  4530. /*
  4531. ===============
  4532. Menu Keyword Parse functions
  4533. ===============
  4534. */
  4535. qboolean MenuParse_font( itemDef_t *item, int handle ) {
  4536. menuDef_t *menu = (menuDef_t*)item;
  4537. if (!PC_String_Parse(handle, &menu->font)) {
  4538. return qfalse;
  4539. }
  4540. if (!DC->Assets.fontRegistered) {
  4541. DC->registerFont(menu->font, 48, &DC->Assets.textFont);
  4542. DC->Assets.fontRegistered = qtrue;
  4543. }
  4544. return qtrue;
  4545. }
  4546. qboolean MenuParse_name( itemDef_t *item, int handle ) {
  4547. menuDef_t *menu = (menuDef_t*)item;
  4548. if (!PC_String_Parse(handle, &menu->window.name)) {
  4549. return qfalse;
  4550. }
  4551. if (Q_stricmp(menu->window.name, "main") == 0) {
  4552. // default main as having focus
  4553. //menu->window.flags |= WINDOW_HASFOCUS;
  4554. }
  4555. return qtrue;
  4556. }
  4557. qboolean MenuParse_fullscreen( itemDef_t *item, int handle ) {
  4558. menuDef_t *menu = (menuDef_t*)item;
  4559. if (!PC_Int_Parse(handle, (int*) &menu->fullScreen)) { // bk001206 - cast qboolean
  4560. return qfalse;
  4561. }
  4562. return qtrue;
  4563. }
  4564. qboolean MenuParse_rect( itemDef_t *item, int handle ) {
  4565. menuDef_t *menu = (menuDef_t*)item;
  4566. if (!PC_Rect_Parse(handle, &menu->window.rect)) {
  4567. return qfalse;
  4568. }
  4569. return qtrue;
  4570. }
  4571. qboolean MenuParse_style( itemDef_t *item, int handle ) {
  4572. menuDef_t *menu = (menuDef_t*)item;
  4573. if (!PC_Int_Parse(handle, &menu->window.style)) {
  4574. return qfalse;
  4575. }
  4576. return qtrue;
  4577. }
  4578. qboolean MenuParse_visible( itemDef_t *item, int handle ) {
  4579. int i;
  4580. menuDef_t *menu = (menuDef_t*)item;
  4581. if (!PC_Int_Parse(handle, &i)) {
  4582. return qfalse;
  4583. }
  4584. if (i) {
  4585. menu->window.flags |= WINDOW_VISIBLE;
  4586. }
  4587. return qtrue;
  4588. }
  4589. qboolean MenuParse_onOpen( itemDef_t *item, int handle ) {
  4590. menuDef_t *menu = (menuDef_t*)item;
  4591. if (!PC_Script_Parse(handle, &menu->onOpen)) {
  4592. return qfalse;
  4593. }
  4594. return qtrue;
  4595. }
  4596. qboolean MenuParse_onClose( itemDef_t *item, int handle ) {
  4597. menuDef_t *menu = (menuDef_t*)item;
  4598. if (!PC_Script_Parse(handle, &menu->onClose)) {
  4599. return qfalse;
  4600. }
  4601. return qtrue;
  4602. }
  4603. qboolean MenuParse_onESC( itemDef_t *item, int handle ) {
  4604. menuDef_t *menu = (menuDef_t*)item;
  4605. if (!PC_Script_Parse(handle, &menu->onESC)) {
  4606. return qfalse;
  4607. }
  4608. return qtrue;
  4609. }
  4610. qboolean MenuParse_border( itemDef_t *item, int handle ) {
  4611. menuDef_t *menu = (menuDef_t*)item;
  4612. if (!PC_Int_Parse(handle, &menu->window.border)) {
  4613. return qfalse;
  4614. }
  4615. return qtrue;
  4616. }
  4617. qboolean MenuParse_borderSize( itemDef_t *item, int handle ) {
  4618. menuDef_t *menu = (menuDef_t*)item;
  4619. if (!PC_Float_Parse(handle, &menu->window.borderSize)) {
  4620. return qfalse;
  4621. }
  4622. return qtrue;
  4623. }
  4624. qboolean MenuParse_backcolor( itemDef_t *item, int handle ) {
  4625. int i;
  4626. float f;
  4627. menuDef_t *menu = (menuDef_t*)item;
  4628. for (i = 0; i < 4; i++) {
  4629. if (!PC_Float_Parse(handle, &f)) {
  4630. return qfalse;
  4631. }
  4632. menu->window.backColor[i] = f;
  4633. }
  4634. return qtrue;
  4635. }
  4636. qboolean MenuParse_forecolor( itemDef_t *item, int handle ) {
  4637. int i;
  4638. float f;
  4639. menuDef_t *menu = (menuDef_t*)item;
  4640. for (i = 0; i < 4; i++) {
  4641. if (!PC_Float_Parse(handle, &f)) {
  4642. return qfalse;
  4643. }
  4644. menu->window.foreColor[i] = f;
  4645. menu->window.flags |= WINDOW_FORECOLORSET;
  4646. }
  4647. return qtrue;
  4648. }
  4649. qboolean MenuParse_bordercolor( itemDef_t *item, int handle ) {
  4650. int i;
  4651. float f;
  4652. menuDef_t *menu = (menuDef_t*)item;
  4653. for (i = 0; i < 4; i++) {
  4654. if (!PC_Float_Parse(handle, &f)) {
  4655. return qfalse;
  4656. }
  4657. menu->window.borderColor[i] = f;
  4658. }
  4659. return qtrue;
  4660. }
  4661. qboolean MenuParse_focuscolor( itemDef_t *item, int handle ) {
  4662. int i;
  4663. float f;
  4664. menuDef_t *menu = (menuDef_t*)item;
  4665. for (i = 0; i < 4; i++) {
  4666. if (!PC_Float_Parse(handle, &f)) {
  4667. return qfalse;
  4668. }
  4669. menu->focusColor[i] = f;
  4670. }
  4671. return qtrue;
  4672. }
  4673. qboolean MenuParse_disablecolor( itemDef_t *item, int handle ) {
  4674. int i;
  4675. float f;
  4676. menuDef_t *menu = (menuDef_t*)item;
  4677. for (i = 0; i < 4; i++) {
  4678. if (!PC_Float_Parse(handle, &f)) {
  4679. return qfalse;
  4680. }
  4681. menu->disableColor[i] = f;
  4682. }
  4683. return qtrue;
  4684. }
  4685. qboolean MenuParse_outlinecolor( itemDef_t *item, int handle ) {
  4686. menuDef_t *menu = (menuDef_t*)item;
  4687. if (!PC_Color_Parse(handle, &menu->window.outlineColor)){
  4688. return qfalse;
  4689. }
  4690. return qtrue;
  4691. }
  4692. qboolean MenuParse_background( itemDef_t *item, int handle ) {
  4693. const char *buff;
  4694. menuDef_t *menu = (menuDef_t*)item;
  4695. if (!PC_String_Parse(handle, &buff)) {
  4696. return qfalse;
  4697. }
  4698. menu->window.background = DC->registerShaderNoMip(buff);
  4699. return qtrue;
  4700. }
  4701. qboolean MenuParse_cinematic( itemDef_t *item, int handle ) {
  4702. menuDef_t *menu = (menuDef_t*)item;
  4703. if (!PC_String_Parse(handle, &menu->window.cinematicName)) {
  4704. return qfalse;
  4705. }
  4706. return qtrue;
  4707. }
  4708. qboolean MenuParse_ownerdrawFlag( itemDef_t *item, int handle ) {
  4709. int i;
  4710. menuDef_t *menu = (menuDef_t*)item;
  4711. if (!PC_Int_Parse(handle, &i)) {
  4712. return qfalse;
  4713. }
  4714. menu->window.ownerDrawFlags |= i;
  4715. return qtrue;
  4716. }
  4717. qboolean MenuParse_ownerdraw( itemDef_t *item, int handle ) {
  4718. menuDef_t *menu = (menuDef_t*)item;
  4719. if (!PC_Int_Parse(handle, &menu->window.ownerDraw)) {
  4720. return qfalse;
  4721. }
  4722. return qtrue;
  4723. }
  4724. // decoration
  4725. qboolean MenuParse_popup( itemDef_t *item, int handle ) {
  4726. menuDef_t *menu = (menuDef_t*)item;
  4727. menu->window.flags |= WINDOW_POPUP;
  4728. return qtrue;
  4729. }
  4730. qboolean MenuParse_outOfBounds( itemDef_t *item, int handle ) {
  4731. menuDef_t *menu = (menuDef_t*)item;
  4732. menu->window.flags |= WINDOW_OOB_CLICK;
  4733. return qtrue;
  4734. }
  4735. qboolean MenuParse_soundLoop( itemDef_t *item, int handle ) {
  4736. menuDef_t *menu = (menuDef_t*)item;
  4737. if (!PC_String_Parse(handle, &menu->soundName)) {
  4738. return qfalse;
  4739. }
  4740. return qtrue;
  4741. }
  4742. qboolean MenuParse_fadeClamp( itemDef_t *item, int handle ) {
  4743. menuDef_t *menu = (menuDef_t*)item;
  4744. if (!PC_Float_Parse(handle, &menu->fadeClamp)) {
  4745. return qfalse;
  4746. }
  4747. return qtrue;
  4748. }
  4749. qboolean MenuParse_fadeAmount( itemDef_t *item, int handle ) {
  4750. menuDef_t *menu = (menuDef_t*)item;
  4751. if (!PC_Float_Parse(handle, &menu->fadeAmount)) {
  4752. return qfalse;
  4753. }
  4754. return qtrue;
  4755. }
  4756. qboolean MenuParse_fadeCycle( itemDef_t *item, int handle ) {
  4757. menuDef_t *menu = (menuDef_t*)item;
  4758. if (!PC_Int_Parse(handle, &menu->fadeCycle)) {
  4759. return qfalse;
  4760. }
  4761. return qtrue;
  4762. }
  4763. qboolean MenuParse_itemDef( itemDef_t *item, int handle ) {
  4764. menuDef_t *menu = (menuDef_t*)item;
  4765. if (menu->itemCount < MAX_MENUITEMS) {
  4766. menu->items[menu->itemCount] = UI_Alloc(sizeof(itemDef_t));
  4767. Item_Init(menu->items[menu->itemCount]);
  4768. if (!Item_Parse(handle, menu->items[menu->itemCount])) {
  4769. return qfalse;
  4770. }
  4771. Item_InitControls(menu->items[menu->itemCount]);
  4772. menu->items[menu->itemCount++]->parent = menu;
  4773. }
  4774. return qtrue;
  4775. }
  4776. keywordHash_t menuParseKeywords[] = {
  4777. {"font", MenuParse_font, NULL},
  4778. {"name", MenuParse_name, NULL},
  4779. {"fullscreen", MenuParse_fullscreen, NULL},
  4780. {"rect", MenuParse_rect, NULL},
  4781. {"style", MenuParse_style, NULL},
  4782. {"visible", MenuParse_visible, NULL},
  4783. {"onOpen", MenuParse_onOpen, NULL},
  4784. {"onClose", MenuParse_onClose, NULL},
  4785. {"onESC", MenuParse_onESC, NULL},
  4786. {"border", MenuParse_border, NULL},
  4787. {"borderSize", MenuParse_borderSize, NULL},
  4788. {"backcolor", MenuParse_backcolor, NULL},
  4789. {"forecolor", MenuParse_forecolor, NULL},
  4790. {"bordercolor", MenuParse_bordercolor, NULL},
  4791. {"focuscolor", MenuParse_focuscolor, NULL},
  4792. {"disablecolor", MenuParse_disablecolor, NULL},
  4793. {"outlinecolor", MenuParse_outlinecolor, NULL},
  4794. {"background", MenuParse_background, NULL},
  4795. {"ownerdraw", MenuParse_ownerdraw, NULL},
  4796. {"ownerdrawFlag", MenuParse_ownerdrawFlag, NULL},
  4797. {"outOfBoundsClick", MenuParse_outOfBounds, NULL},
  4798. {"soundLoop", MenuParse_soundLoop, NULL},
  4799. {"itemDef", MenuParse_itemDef, NULL},
  4800. {"cinematic", MenuParse_cinematic, NULL},
  4801. {"popup", MenuParse_popup, NULL},
  4802. {"fadeClamp", MenuParse_fadeClamp, NULL},
  4803. {"fadeCycle", MenuParse_fadeCycle, NULL},
  4804. {"fadeAmount", MenuParse_fadeAmount, NULL},
  4805. {NULL, NULL, NULL}
  4806. };
  4807. keywordHash_t *menuParseKeywordHash[KEYWORDHASH_SIZE];
  4808. /*
  4809. ===============
  4810. Menu_SetupKeywordHash
  4811. ===============
  4812. */
  4813. void Menu_SetupKeywordHash(void) {
  4814. int i;
  4815. memset(menuParseKeywordHash, 0, sizeof(menuParseKeywordHash));
  4816. for (i = 0; menuParseKeywords[i].keyword; i++) {
  4817. KeywordHash_Add(menuParseKeywordHash, &menuParseKeywords[i]);
  4818. }
  4819. }
  4820. /*
  4821. ===============
  4822. Menu_Parse
  4823. ===============
  4824. */
  4825. qboolean Menu_Parse(int handle, menuDef_t *menu) {
  4826. pc_token_t token;
  4827. keywordHash_t *key;
  4828. if (!trap_PC_ReadToken(handle, &token))
  4829. return qfalse;
  4830. if (*token.string != '{') {
  4831. return qfalse;
  4832. }
  4833. while ( 1 ) {
  4834. memset(&token, 0, sizeof(pc_token_t));
  4835. if (!trap_PC_ReadToken(handle, &token)) {
  4836. PC_SourceError(handle, "end of file inside menu\n");
  4837. return qfalse;
  4838. }
  4839. if (*token.string == '}') {
  4840. return qtrue;
  4841. }
  4842. key = KeywordHash_Find(menuParseKeywordHash, token.string);
  4843. if (!key) {
  4844. PC_SourceError(handle, "unknown menu keyword %s", token.string);
  4845. continue;
  4846. }
  4847. if ( !key->func((itemDef_t*)menu, handle) ) {
  4848. PC_SourceError(handle, "couldn't parse menu keyword %s", token.string);
  4849. return qfalse;
  4850. }
  4851. }
  4852. return qfalse; // bk001205 - LCC missing return value
  4853. }
  4854. /*
  4855. ===============
  4856. Menu_New
  4857. ===============
  4858. */
  4859. void Menu_New(int handle) {
  4860. menuDef_t *menu = &Menus[menuCount];
  4861. if (menuCount < MAX_MENUS) {
  4862. Menu_Init(menu);
  4863. if (Menu_Parse(handle, menu)) {
  4864. Menu_PostParse(menu);
  4865. menuCount++;
  4866. }
  4867. }
  4868. }
  4869. int Menu_Count() {
  4870. return menuCount;
  4871. }
  4872. void Menu_PaintAll() {
  4873. int i;
  4874. if (captureFunc) {
  4875. captureFunc(captureData);
  4876. }
  4877. for (i = 0; i < Menu_Count(); i++) {
  4878. Menu_Paint(&Menus[i], qfalse);
  4879. }
  4880. if (debugMode) {
  4881. vec4_t v = {1, 1, 1, 1};
  4882. DC->drawText(5, 25, .5, v, va("fps: %f", DC->FPS), 0, 0, 0);
  4883. }
  4884. }
  4885. void Menu_Reset() {
  4886. menuCount = 0;
  4887. }
  4888. displayContextDef_t *Display_GetContext() {
  4889. return DC;
  4890. }
  4891. #ifndef MISSIONPACK // bk001206
  4892. static float captureX;
  4893. static float captureY;
  4894. #endif
  4895. void *Display_CaptureItem(int x, int y) {
  4896. int i;
  4897. for (i = 0; i < menuCount; i++) {
  4898. // turn off focus each item
  4899. // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
  4900. if (Rect_ContainsPoint(&Menus[i].window.rect, x, y)) {
  4901. return &Menus[i];
  4902. }
  4903. }
  4904. return NULL;
  4905. }
  4906. // FIXME:
  4907. qboolean Display_MouseMove(void *p, int x, int y) {
  4908. int i;
  4909. menuDef_t *menu = p;
  4910. if (menu == NULL) {
  4911. menu = Menu_GetFocused();
  4912. if (menu) {
  4913. if (menu->window.flags & WINDOW_POPUP) {
  4914. Menu_HandleMouseMove(menu, x, y);
  4915. return qtrue;
  4916. }
  4917. }
  4918. for (i = 0; i < menuCount; i++) {
  4919. Menu_HandleMouseMove(&Menus[i], x, y);
  4920. }
  4921. } else {
  4922. menu->window.rect.x += x;
  4923. menu->window.rect.y += y;
  4924. Menu_UpdatePosition(menu);
  4925. }
  4926. return qtrue;
  4927. }
  4928. int Display_CursorType(int x, int y) {
  4929. int i;
  4930. for (i = 0; i < menuCount; i++) {
  4931. rectDef_t r2;
  4932. r2.x = Menus[i].window.rect.x - 3;
  4933. r2.y = Menus[i].window.rect.y - 3;
  4934. r2.w = r2.h = 7;
  4935. if (Rect_ContainsPoint(&r2, x, y)) {
  4936. return CURSOR_SIZER;
  4937. }
  4938. }
  4939. return CURSOR_ARROW;
  4940. }
  4941. void Display_HandleKey(int key, qboolean down, int x, int y) {
  4942. menuDef_t *menu = Display_CaptureItem(x, y);
  4943. if (menu == NULL) {
  4944. menu = Menu_GetFocused();
  4945. }
  4946. if (menu) {
  4947. Menu_HandleKey(menu, key, down );
  4948. }
  4949. }
  4950. static void Window_CacheContents(windowDef_t *window) {
  4951. if (window) {
  4952. if (window->cinematicName) {
  4953. int cin = DC->playCinematic(window->cinematicName, 0, 0, 0, 0);
  4954. DC->stopCinematic(cin);
  4955. }
  4956. }
  4957. }
  4958. static void Item_CacheContents(itemDef_t *item) {
  4959. if (item) {
  4960. Window_CacheContents(&item->window);
  4961. }
  4962. }
  4963. static void Menu_CacheContents(menuDef_t *menu) {
  4964. if (menu) {
  4965. int i;
  4966. Window_CacheContents(&menu->window);
  4967. for (i = 0; i < menu->itemCount; i++) {
  4968. Item_CacheContents(menu->items[i]);
  4969. }
  4970. if (menu->soundName && *menu->soundName) {
  4971. DC->registerSound(menu->soundName, qfalse);
  4972. }
  4973. }
  4974. }
  4975. void Display_CacheAll() {
  4976. int i;
  4977. for (i = 0; i < menuCount; i++) {
  4978. Menu_CacheContents(&Menus[i]);
  4979. }
  4980. }
  4981. static qboolean Menu_OverActiveItem(menuDef_t *menu, float x, float y) {
  4982. if (menu && menu->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED)) {
  4983. if (Rect_ContainsPoint(&menu->window.rect, x, y)) {
  4984. int i;
  4985. for (i = 0; i < menu->itemCount; i++) {
  4986. // turn off focus each item
  4987. // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
  4988. if (!(menu->items[i]->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
  4989. continue;
  4990. }
  4991. if (menu->items[i]->window.flags & WINDOW_DECORATION) {
  4992. continue;
  4993. }
  4994. if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
  4995. itemDef_t *overItem = menu->items[i];
  4996. if (overItem->type == ITEM_TYPE_TEXT && overItem->text) {
  4997. if (Rect_ContainsPoint(Item_CorrectedTextRect(overItem), x, y)) {
  4998. return qtrue;
  4999. } else {
  5000. continue;
  5001. }
  5002. } else {
  5003. return qtrue;
  5004. }
  5005. }
  5006. }
  5007. }
  5008. }
  5009. return qfalse;
  5010. }