123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "platform/platform.h"
- #include "gui/controls/guiTreeViewCtrl.h"
- #include "core/frameAllocator.h"
- #include "core/strings/findMatch.h"
- #include "gui/containers/guiScrollCtrl.h"
- #include "gui/worldEditor/editorIconRegistry.h"
- #include "console/consoleTypes.h"
- #include "console/console.h"
- #include "gui/core/guiTypes.h"
- #include "gfx/gfxDrawUtil.h"
- #include "gui/controls/guiTextEditCtrl.h"
- #ifdef TORQUE_TOOLS
- #include "gui/editor/editorFunctions.h"
- #endif
- #include "console/engineAPI.h"
- IMPLEMENT_CONOBJECT(GuiTreeViewCtrl);
- ConsoleDocClass( GuiTreeViewCtrl,
- "@brief Hierarchical list of text items with optional icons.\n\n"
- "Can also be used to inspect SimObject hierarchies, primarily within editors.\n\n"
- "GuiTreeViewCtrls can either display arbitrary user-defined trees or can be used to display SimObject hierarchies where "
- "each parent node in the tree is a SimSet or SimGroup and each leaf node is a SimObject.\n\n"
- "Each item in the tree has a text and a value. For trees that display SimObject hierarchies, the text for each item "
- "is automatically derived from objects while the value for each item is the ID of the respective SimObject. For trees "
- "that are not tied to SimObjects, both text and value of each item are set by the user.\n\n"
- "Additionally, items in the tree can have icons.\n\n"
- "Each item in the tree has a distinct numeric ID that is unique within its tree. The ID of the root item, which is always "
- "present on a tree, is 0.\n\n"
- "@tsexample\n"
- "new GuiTreeViewCtrl(DatablockEditorTree)\n"
- "{\n"
- " tabSize = \"16\";\n"
- " textOffset = \"2\";\n"
- " fullRowSelect = \"0\";\n"
- " itemHeight = \"21\";\n"
- " destroyTreeOnSleep = \"0\";\n"
- " MouseDragging = \"0\";\n"
- " MultipleSelections = \"1\";\n"
- " DeleteObjectAllowed = \"1\";\n"
- " DragToItemAllowed = \"0\";\n"
- " ClearAllOnSingleSelection = \"1\";\n"
- " showRoot = \"1\";\n"
- " internalNamesOnly = \"0\";\n"
- " objectNamesOnly = \"0\";\n"
- " compareToObjectID = \"0\";\n"
- " Profile = \"GuiTreeViewProfile\";\n"
- " tooltipprofile = \"GuiToolTipProfile\";\n"
- " hovertime = \"1000\";\n"
- "};\n"
- "@endtsexample\n\n"
- "@ingroup GuiContainers\n");
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onDeleteObject, bool, ( SimObject* object ), ( object ), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, isValidDragTarget, bool, ( S32 id, const char* value ), ( id, value ), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onDefineIcons, void, (), (), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onAddGroupSelected, void, ( SimGroup* group ), ( group ), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onAddSelection, void, ( S32 itemOrObjectId, bool isLastSelection ), ( itemOrObjectId, isLastSelection ), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onSelect, void, ( S32 itemOrObjectId ), ( itemOrObjectId ), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onInspect, void, ( S32 itemOrObjectId ), ( itemOrObjectId ), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onRemoveSelection, void, ( S32 itemOrObjectId ), ( itemOrObjectId ), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onUnselect, void, ( S32 itemOrObjectId ), ( itemOrObjectId ), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onDeleteSelection, void, (), (), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onObjectDeleteCompleted, void, (), (), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onKeyDown, void, ( S32 modifier, S32 keyCode ), ( modifier, keyCode ), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onMouseUp, void, ( S32 hitItemId, S32 mouseClickCount ), ( hitItemId, mouseClickCount ), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onMouseDragged, void, (), (), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onRightMouseDown, void, ( S32 itemId, const Point2I& mousePos, SimObject* object ), ( itemId, mousePos, object ), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onRightMouseUp, void, ( S32 itemId, const Point2I& mousePos, SimObject* object ), ( itemId, mousePos, object ), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onBeginReparenting, void, (), (), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onEndReparenting, void, (), (), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onReparent, void, ( S32 itemOrObjectId, S32 oldParentItemOrObjectId, S32 newParentItemOrObjectId ), ( itemOrObjectId, oldParentItemOrObjectId, newParentItemOrObjectId ), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onDragDropped, void, (), (), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onAddMultipleSelectionBegin, void, (), (), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onAddMultipleSelectionEnd, void, (), (), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, canRenameObject, bool, ( SimObject* object ), ( object ), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, handleRenameObject, bool, ( const char* newName, SimObject* object ), ( newName, object ), "" );
- IMPLEMENT_CALLBACK( GuiTreeViewCtrl, onClearSelection, void, (), (), "" );
- static S32 QSORT_CALLBACK itemCompareCaseSensitive( const void *a, const void *b )
- {
- GuiTreeViewCtrl::Item* itemA = *( ( GuiTreeViewCtrl::Item** ) a );
- GuiTreeViewCtrl::Item* itemB = *( ( GuiTreeViewCtrl::Item** ) b );
- char bufferA[ 1024 ];
- char bufferB[ 1024 ];
- itemA->getDisplayText( sizeof( bufferA ), bufferA );
- itemB->getDisplayText( sizeof( bufferB ), bufferB );
- return dStrnatcmp( bufferA, bufferB );
- }
- static S32 QSORT_CALLBACK itemCompareCaseInsensitive( const void *a, const void *b )
- {
- GuiTreeViewCtrl::Item* itemA = *( ( GuiTreeViewCtrl::Item** ) a );
- GuiTreeViewCtrl::Item* itemB = *( ( GuiTreeViewCtrl::Item** ) b );
- char bufferA[ 1024 ];
- char bufferB[ 1024 ];
- itemA->getDisplayText( sizeof( bufferA ), bufferA );
- itemB->getDisplayText( sizeof( bufferB ), bufferB );
- return dStrnatcasecmp( bufferA, bufferB );
- }
- static void itemSortList( GuiTreeViewCtrl::Item*& firstChild, bool caseSensitive, bool traverseHierarchy, bool parentsFirst )
- {
- // Sort the children.
- // Do this in a separate scope, so we release the buffers before
- // recursing.
- {
- Vector< GuiTreeViewCtrl::Item* > parents;
- Vector< GuiTreeViewCtrl::Item* > items;
- // Put all items into the two vectors.
- for( GuiTreeViewCtrl::Item* item = firstChild; item != NULL; item = item->mNext )
- if( parentsFirst && item->isParent() )
- parents.push_back( item );
- else
- items.push_back( item );
- // Sort both vectors.
- dQsort( parents.address(), parents.size(), sizeof( GuiTreeViewCtrl::Item* ), caseSensitive ? itemCompareCaseSensitive : itemCompareCaseInsensitive );
- dQsort( items.address(), items.size(), sizeof( GuiTreeViewCtrl::Item* ), caseSensitive ? itemCompareCaseSensitive : itemCompareCaseInsensitive );
- // Wipe current child chain then reconstruct it in reverse
- // as we prepend items.
- firstChild = NULL;
- // Add child items.
- for( U32 i = items.size(); i > 0; -- i )
- {
- GuiTreeViewCtrl::Item* child = items[ i - 1 ];
- child->mNext = firstChild;
- if( firstChild )
- firstChild->mPrevious = child;
- firstChild = child;
- }
- // Add parent child items, if requested.
- for( U32 i = parents.size(); i > 0; -- i )
- {
- GuiTreeViewCtrl::Item* child = parents[ i - 1 ];
- child->mNext = firstChild;
- if( firstChild )
- firstChild->mPrevious = child;
- firstChild = child;
- }
- firstChild->mPrevious = NULL;
- }
- // Traverse hierarchy, if requested.
- if( traverseHierarchy )
- {
- GuiTreeViewCtrl::Item* child = firstChild;
- while( child )
- {
- if( child->isParent() )
- child->sort( caseSensitive, traverseHierarchy, parentsFirst );
- child = child->mNext;
- }
- }
- }
- //=============================================================================
- // GuiTreeViewCtrl::Item.
- //=============================================================================
- // MARK: ---- GuiTreeViewCtrl::Item ----
- //-----------------------------------------------------------------------------
- GuiTreeViewCtrl::Item::Item( GuiTreeViewCtrl* parent, GuiControlProfile *pProfile )
- {
- AssertFatal( pProfile != NULL , "Cannot create a tree item without a valid tree and control profile!");
- mParentControl = parent;
- mState = 0;
- mId = -1;
- mTabLevel = 0;
- mIcon = 0;
- mDataRenderWidth = 0;
- mParent = NULL;
- mChild = NULL;
- mNext = NULL;
- mPrevious = NULL;
- mProfile = pProfile;
- mScriptInfo.mNormalImage = BmpCon;
- mScriptInfo.mExpandedImage = BmpExp;
- mScriptInfo.mText = NULL;
- mScriptInfo.mValue = NULL;
- }
- //-----------------------------------------------------------------------------
- GuiTreeViewCtrl::Item::~Item()
- {
- _disconnectMonitors();
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::Item::_connectMonitors()
- {
- if( mInspectorInfo.mObject != NULL )
- {
- SimSet* set = dynamic_cast< SimSet* >( mInspectorInfo.mObject.getPointer() );
- if( set )
- set->getSetModificationSignal().notify( mParentControl, &GuiTreeViewCtrl::_onInspectorSetObjectModified );
- }
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::Item::_disconnectMonitors()
- {
- if( mInspectorInfo.mObject != NULL )
- {
- SimSet* set = dynamic_cast< SimSet* >( mInspectorInfo.mObject.getPointer() );
- if( set )
- set->getSetModificationSignal().remove( mParentControl, &GuiTreeViewCtrl::_onInspectorSetObjectModified );
- }
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::Item::setNormalImage(S8 id)
- {
- if(mState.test(InspectorData))
- {
- Con::errorf("Tried to set normal image %d for item %d, which is InspectorData!", id, mId);
- return;
- }
- mScriptInfo.mNormalImage = id;
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::Item::setExpandedImage(S8 id)
- {
- if(mState.test(InspectorData))
- {
- Con::errorf("Tried to set expanded image %d for item %d, which is InspectorData!", id, mId);
- return;
- }
- mScriptInfo.mExpandedImage = id;
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::Item::setText(StringTableEntry txt)
- {
- if(mState.test(InspectorData))
- {
- Con::errorf("Tried to set text for item %d, which is InspectorData!", mId);
- return;
- }
- mScriptInfo.mText = txt;
- // Update Render Data
- if( !mProfile.isNull() )
- mDataRenderWidth = getDisplayTextWidth( mProfile->mFont );
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::Item::setValue(StringTableEntry val)
- {
- if(mState.test(InspectorData))
- {
- Con::errorf("Tried to set value for item %d, which is InspectorData!", mId);
- return;
- }
- mScriptInfo.mValue = const_cast<char*>(val); // mValue really ought to be a StringTableEntry
- // Update Render Data
- if( !mProfile.isNull() )
- mDataRenderWidth = getDisplayTextWidth( mProfile->mFont );
- }
- //-----------------------------------------------------------------------------
- S8 GuiTreeViewCtrl::Item::getNormalImage() const
- {
- if(mState.test(InspectorData))
- {
- Con::errorf("Tried to get the normal image for item %d, which is InspectorData!", mId);
- return 0; // fail safe for width determinations
- }
- return mScriptInfo.mNormalImage;
- }
- //-----------------------------------------------------------------------------
- S8 GuiTreeViewCtrl::Item::getExpandedImage() const
- {
- if(mState.test(InspectorData))
- {
- Con::errorf("Tried to get the expanded image for item %d, which is InspectorData!", mId);
- return 0; // fail safe for width determinations
- }
- return mScriptInfo.mExpandedImage;
- }
- //-----------------------------------------------------------------------------
- StringTableEntry GuiTreeViewCtrl::Item::getText()
- {
- if(mState.test(InspectorData))
- {
- Con::errorf("Tried to get the text for item %d, which is InspectorData!", mId);
- return NULL;
- }
- return ( mScriptInfo.mText ) ? mScriptInfo.mText : StringTable->EmptyString();
- }
- //-----------------------------------------------------------------------------
- StringTableEntry GuiTreeViewCtrl::Item::getValue()
- {
- if(mState.test(InspectorData))
- {
- Con::errorf("Tried to get the value for item %d, which is InspectorData!", mId);
- return NULL;
- }
- return ( mScriptInfo.mValue ) ? mScriptInfo.mValue : StringTable->EmptyString();
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::Item::setObject(SimObject *obj)
- {
- if(!mState.test(InspectorData))
- {
- return;
- }
-
- _disconnectMonitors();
- mInspectorInfo.mObject = obj;
- _connectMonitors();
- // Update Render Data
- if( !mProfile.isNull() )
- mDataRenderWidth = getDisplayTextWidth( mProfile->mFont );
- }
- //-----------------------------------------------------------------------------
- SimObject *GuiTreeViewCtrl::Item::getObject()
- {
- if(!mState.test(InspectorData))
- {
- return NULL;
- }
- return mInspectorInfo.mObject;
- }
- //-----------------------------------------------------------------------------
- U32 GuiTreeViewCtrl::Item::getDisplayTextLength()
- {
- if( mState.test( InspectorData ) )
- {
- SimObject *obj = getObject();
- if( !obj )
- return 0;
- StringTableEntry name = obj->getName();
- StringTableEntry internalName = obj->getInternalName();
- StringTableEntry className = obj->getClassName();
- if( showInternalNameOnly() )
- {
- if( internalName && internalName[ 0 ] )
- return dStrlen( internalName );
- else
- return dStrlen( "(none)" );
- }
- else if( showObjectNameOnly() )
- {
- if( name && name[ 0 ] )
- return dStrlen( name );
- else if( mState.test( ShowClassNameForUnnamed ) )
- return dStrlen( className );
- else
- return dStrlen( "(none)" );
- }
- dsize_t len = 0;
- if( mState.test( ShowObjectId ) )
- len += dStrlen( obj->getIdString() ) + 2; // '<id>: '
- if( mState.test( ShowClassName ) )
- {
- if( name && name[ 0 ] )
- len += dStrlen( className ) + 3; // '<class> - '
- else
- len += dStrlen( className );
- }
- if( mState.test( ShowObjectName ) )
- {
- if( name && name[ 0 ] )
- len += dStrlen( name );
- else if( mState.test( ShowClassNameForUnnamed ) )
- len += dStrlen( className );
- }
- if( mState.test( ShowInternalName ) )
- {
- if( internalName && internalName[ 0 ] )
- len += dStrlen( internalName ) + 3; // ' [<internalname>]'
- }
- return len;
- }
- StringTableEntry pText = getText();
- if( pText == NULL )
- return 0;
- return dStrlen( pText );
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::Item::getDisplayText(U32 bufLen, char *buf)
- {
- FrameAllocatorMarker txtAlloc;
- //if we're doing the special case of forcing the item text, just skip the rest of this junk
- if (mState.test(ForceItemName))
- {
- StringTableEntry text = (mScriptInfo.mText) ? mScriptInfo.mText : StringTable->EmptyString();
- dStrncpy(buf, text, bufLen);
- return;
- }
- if( mState.test( InspectorData ) )
- {
- SimObject *pObject = getObject();
- if( pObject )
- {
- const char* pObjName = pObject->getName();
- const char* pInternalName = pObject->getInternalName();
- bool hasInternalName = pInternalName && pInternalName[0];
- bool hasObjectName = pObjName && pObjName[0];
- const char* pClassName = pObject->getClassName();
- if( showInternalNameOnly() )
- dSprintf( buf, bufLen, "%s", hasInternalName ? pInternalName : "(none)" );
- else if( showObjectNameOnly() )
- {
- if( !hasObjectName && mState.test( ShowClassNameForUnnamed ) )
- dSprintf( buf, bufLen, "%s", pClassName );
- else
- dSprintf( buf, bufLen, "%s", hasObjectName ? pObjName : "(none)" );
- }
- else
- {
- char* ptr = buf;
- int len = bufLen;
-
- if( mState.test( ShowObjectId ) )
- {
- S32 n = dSprintf( ptr, len, "%d: ", pObject->getId() );
- ptr += n;
- len -= n;
- }
-
- if( mState.test( ShowClassName ) )
- {
- S32 n;
- if( hasObjectName && mState.test( ShowObjectName ) )
- n = dSprintf( ptr, len, "%s - ", pClassName );
- else
- n = dSprintf( ptr, len, "%s", pClassName );
-
- ptr += n;
- len -= n;
- }
-
- if( mState.test( ShowObjectName ) )
- {
- S32 n = 0;
- if (hasObjectName)
- {
- //If it's been marked, reflect that
- if (mState.test(Item::Marked))
- n = dSprintf(ptr, len, "*%s", pObjName);
- else
- n = dSprintf(ptr, len, "%s", pObjName);
- }
- else if( mState.test( ShowClassNameForUnnamed ) )
- n = dSprintf( ptr, len, "%s", pClassName );
-
- ptr += n;
- len -= n;
- }
-
- if (hasInternalName && mState.test(ShowInternalName))
- {
- if (mState.test(Item::Marked))
- dSprintf(ptr, len, " *[%s]", pInternalName);
- else
- dSprintf(ptr, len, " [%s]", pInternalName);
- }
- }
- }
- else
- buf[ 0 ] = '\0';
- }
- else
- {
- // Script data! (copy it in)
- dStrncpy(buf, getText(), bufLen);
- }
- }
- //-----------------------------------------------------------------------------
- S32 GuiTreeViewCtrl::Item::getDisplayTextWidth(GFont *font)
- {
- if( !font )
- return 0;
- FrameAllocatorMarker txtAlloc;
- U32 bufLen = getDisplayTextLength();
- if( bufLen == 0 )
- return 0;
- // Add space for the string terminator and marker
- bufLen += 2;
- char *buf = (char*)txtAlloc.alloc(bufLen);
- getDisplayText(bufLen, buf);
- return font->getStrWidth(buf);
- }
- //-----------------------------------------------------------------------------
- bool GuiTreeViewCtrl::Item::hasObjectBasedTooltip()
- {
- if(mState.test(Item::InspectorData))
- {
- SimObject *pObject = getObject();
- if(pObject)
- {
- const char* pClassName = pObject->getClassName();
- // Retrieve custom tooltip string
- String method("GetTooltip");
- method += pClassName;
- if(mParentControl->isMethod(method.c_str()))
- {
- return true;
- }
- }
- }
- return false;
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::Item::getTooltipText(U32 bufLen, char *buf)
- {
- getDisplayText(bufLen, buf);
- if(mState.test(Item::InspectorData))
- {
- SimObject *pObject = getObject();
- if(pObject)
- {
- const char* pClassName = pObject->getClassName();
- // Retrieve custom tooltip string
- String method("GetTooltip");
- method += pClassName;
- if(mParentControl->isMethod(method.c_str()))
- {
- ConsoleValue cValue = Con::executef( mParentControl, method.c_str(), pObject->getIdString() );
- const char* tooltip = cValue.getString();
- dsize_t len = dStrlen(buf);
- S32 newBufLen = bufLen-len;
- if(dStrlen(tooltip) > 0 && newBufLen > 0)
- {
- dSprintf(buf+len, newBufLen, "\n%s", tooltip);
- }
- }
- }
- }
- }
- //-----------------------------------------------------------------------------
- bool GuiTreeViewCtrl::Item::isParent() const
- {
- if(mState.test(VirtualParent))
- {
- if( !isInspectorData() )
- return true;
- // Does our object have any children?
- if(mInspectorInfo.mObject)
- {
- SimSet *pSimSet = dynamic_cast<SimSet*>( (SimObject*)mInspectorInfo.mObject);
- if ( pSimSet != NULL && pSimSet->size() > 0)
- return pSimSet->size();
- }
- }
- // Otherwise, just return whether the child list is populated.
- return mChild;
- }
- //-----------------------------------------------------------------------------
- bool GuiTreeViewCtrl::Item::isExpanded() const
- {
- if(mState.test(InspectorData))
- return mInspectorInfo.mObject ? mInspectorInfo.mObject->isExpanded() : false;
- else
- return mState.test(Expanded);
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::Item::setExpanded(bool f)
- {
- if( mState.test(InspectorData) )
- {
- if( !mInspectorInfo.mObject.isNull() )
- mInspectorInfo.mObject->setExpanded(f);
- }
- else
- mState.set(Expanded, f);
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::Item::setVirtualParent( bool value )
- {
- mState.set(VirtualParent, value);
- }
- //-----------------------------------------------------------------------------
- GuiTreeViewCtrl::Item* GuiTreeViewCtrl::Item::findChildByName( const char* name )
- {
- Item* child = mChild;
- while( child )
- {
- if( dStricmp( child->mScriptInfo.mText, name ) == 0 )
- return child;
-
- child = child->mNext;
- }
-
- return NULL;
- }
- //-----------------------------------------------------------------------------
- GuiTreeViewCtrl::Item *GuiTreeViewCtrl::Item::findChildByValue(const SimObject *obj)
- {
- // Iterate over our children and try to find the given
- // SimObject
- Item *pResultObj = mChild;
- while(pResultObj)
- {
- // CodeReview this check may need to be removed
- // if we want to use the tree for data that
- // isn't related to SimObject based objects with
- // arbitrary values associated with them [5/5/2007 justind]
- // Skip non-inspector data stuff.
- if(pResultObj->mState.test(InspectorData))
- {
- if(pResultObj->getObject() == obj)
- break; // Whoa.
- }
- pResultObj = pResultObj->mNext;
- }
- // If the loop terminated we are NULL, otherwise we have the result in res.
- return pResultObj;
- }
- //-----------------------------------------------------------------------------
- GuiTreeViewCtrl::Item *GuiTreeViewCtrl::Item::findChildByValue( StringTableEntry Value )
- {
- // Iterate over our children and try to find the given Value
- // Note : This is a case-insensitive search
- Item *pResultObj = mChild;
- while(pResultObj)
- {
- // check the script value of the item against the specified value
- if( pResultObj->mScriptInfo.mValue != NULL && dStricmp( pResultObj->mScriptInfo.mValue, Value ) == 0 )
- return pResultObj;
- pResultObj = pResultObj->mNext;
- }
- // If the loop terminated we didn't find an item with the specified script value
- return NULL;
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::Item::sort( bool caseSensitive, bool traverseHierarchy, bool parentsFirst )
- {
- itemSortList( mChild, caseSensitive, traverseHierarchy, parentsFirst );
- }
- //=============================================================================
- // GuiTreeViewCtrl.
- //=============================================================================
- // MARK: ---- GuiTreeViewCtrl ----
- //-----------------------------------------------------------------------------
- GuiTreeViewCtrl::GuiTreeViewCtrl()
- {
- VECTOR_SET_ASSOCIATION(mItems);
- VECTOR_SET_ASSOCIATION(mVisibleItems);
- VECTOR_SET_ASSOCIATION(mSelectedItems);
- VECTOR_SET_ASSOCIATION(mSelected);
- mItemFreeList = NULL;
- mRoot = NULL;
- mItemCount = 0;
- mSelectedItem = 0;
- mStart = 0;
- mPossibleRenameItem = NULL;
- mRenamingItem = NULL;
- mTempItem = NULL;
- mRenameCtrl = NULL;
- mDraggedToItem = 0;
- mCurrentDragCell = 0;
- mPreviousDragCell = 0;
- mDragMidPoint = NomDragMidPoint;
- mMouseDragged = false;
- mDebug = false;
- // persist info..
- mTabSize = 16;
- mTextOffset = 2;
- mFullRowSelect = false;
- mItemHeight = 20;
- //
- setSize(Point2I(1, 0));
- // Set up default state
- mFlags.set(ShowTreeLines);
- mFlags.set(IsEditable, false);
- mDestroyOnSleep = true;
- mSupportMouseDragging = true;
- mMultipleSelections = true;
- mDeleteObjectAllowed = true;
- mDragToItemAllowed = true;
- mShowRoot = true;
- mUseInspectorTooltips = false;
- mTooltipOnWidthOnly = false;
- mCompareToObjectID = true;
- mShowObjectIds = true;
- mShowClassNames = true;
- mShowObjectNames = true;
- mShowInternalNames = true;
- mShowClassNameForUnnamedObjects = false;
- mFlags.set(RebuildVisible);
- mCanRenameObjects = true;
- mRenameInternal = false;
- mClearAllOnSingleSelection = true;
- mBitmapBase = StringTable->EmptyString();
- mTexRollover = NULL;
- mTexSelected = NULL;
-
- mRenderTooltipDelegate.bind( this, &GuiTreeViewCtrl::renderTooltip );
- mDoFilterChildren = true;
- }
- //-----------------------------------------------------------------------------
- GuiTreeViewCtrl::~GuiTreeViewCtrl()
- {
- _destroyTree();
- }
- //------------------------------------------------------------------------------
- void GuiTreeViewCtrl::initPersistFields()
- {
- docsURL;
- addGroup( "TreeView" );
- addField( "tabSize", TypeS32, Offset(mTabSize, GuiTreeViewCtrl));
- addField( "textOffset", TypeS32, Offset(mTextOffset, GuiTreeViewCtrl));
- addField( "fullRowSelect", TypeBool, Offset(mFullRowSelect, GuiTreeViewCtrl));
- addField( "itemHeight", TypeS32, Offset(mItemHeight, GuiTreeViewCtrl));
- addField( "destroyTreeOnSleep", TypeBool, Offset(mDestroyOnSleep, GuiTreeViewCtrl),
- "If true, the entire tree item hierarchy is deleted when the control goes to sleep." );
- addField( "mouseDragging", TypeBool, Offset(mSupportMouseDragging, GuiTreeViewCtrl));
- addField( "multipleSelections", TypeBool, Offset(mMultipleSelections, GuiTreeViewCtrl),
- "If true, multiple items can be selected concurrently." );
- addField( "deleteObjectAllowed", TypeBool, Offset(mDeleteObjectAllowed, GuiTreeViewCtrl));
- addField( "dragToItemAllowed", TypeBool, Offset(mDragToItemAllowed, GuiTreeViewCtrl));
- addField( "clearAllOnSingleSelection", TypeBool, Offset(mClearAllOnSingleSelection, GuiTreeViewCtrl));
- addField( "showRoot", TypeBool, Offset(mShowRoot, GuiTreeViewCtrl),
- "If true, the root item is shown in the tree." );
- addField( "useInspectorTooltips", TypeBool, Offset(mUseInspectorTooltips, GuiTreeViewCtrl));
- addField( "tooltipOnWidthOnly", TypeBool, Offset(mTooltipOnWidthOnly, GuiTreeViewCtrl));
- endGroup( "TreeView" );
-
- addGroup( "Inspector Trees" );
-
- addField( "showObjectIds", TypeBool, Offset( mShowObjectIds, GuiTreeViewCtrl ),
- "If true, item text labels for objects will include object IDs." );
- addField( "showClassNames", TypeBool, Offset( mShowClassNames, GuiTreeViewCtrl ),
- "If true, item text labels for objects will include class names." );
- addField( "showObjectNames", TypeBool, Offset( mShowObjectNames, GuiTreeViewCtrl ),
- "If true, item text labels for objects will include object names." );
- addField( "showInternalNames", TypeBool, Offset( mShowInternalNames, GuiTreeViewCtrl ),
- "If true, item text labels for obje ts will include internal names." );
- addField( "showClassNameForUnnamedObjects", TypeBool, Offset( mShowClassNameForUnnamedObjects, GuiTreeViewCtrl ),
- "If true, class names will be used as object names for unnamed objects." );
- addField( "compareToObjectID", TypeBool, Offset(mCompareToObjectID, GuiTreeViewCtrl));
- addField( "canRenameObjects", TypeBool, Offset(mCanRenameObjects, GuiTreeViewCtrl),
- "If true clicking on a selected item ( that is an object and not the root ) will allow you to rename it." );
- addField( "renameInternal", TypeBool, Offset(mRenameInternal, GuiTreeViewCtrl),
- "If true then object renaming operates on the internalName rather than the object name." );
- endGroup( "Inspector Trees" );
- Parent::initPersistFields();
- }
- //------------------------------------------------------------------------------
- GuiTreeViewCtrl::Item * GuiTreeViewCtrl::getItem(S32 itemId) const
- {
- if ( itemId > 0 && itemId <= mItems.size() )
- return mItems[itemId-1];
- return NULL;
- }
- //------------------------------------------------------------------------------
- GuiTreeViewCtrl::Item * GuiTreeViewCtrl::createItem(S32 icon)
- {
- Item * pNewItem = NULL;
- // grab from the free list?
- if( mItemFreeList )
- {
- pNewItem = mItemFreeList;
- mItemFreeList = pNewItem->mNext;
- // re-add to vector
- mItems[ pNewItem->mId - 1 ] = pNewItem;
- }
- else
- {
- pNewItem = new Item( this, mProfile );
- AssertFatal( pNewItem != NULL, "Fatal : unable to allocate tree item!");
- mItems.push_back( pNewItem );
- // set the id
- pNewItem->mId = mItems.size();
- }
- // reset
- if (icon)
- pNewItem->mIcon = icon;
- else
- pNewItem->mIcon = Default; //default icon to stick next to an item
- pNewItem->mState = Item::ShowObjectId | Item::ShowClassName | Item::ShowObjectName | Item::ShowInternalName;
- pNewItem->mTabLevel = 0;
- // Null out item pointers
- pNewItem->mNext = 0;
- pNewItem->mPrevious = 0;
- pNewItem->mChild = 0;
- pNewItem->mParent = 0;
- mItemCount++;
- return pNewItem;
- }
- //------------------------------------------------------------------------------
- void GuiTreeViewCtrl::_destroyChildren( Item* item, Item* parent, bool deleteObjects )
- {
- if ( !item || item == parent || !mItems[item->mId-1] )
- return;
- // destroy depth first, then siblings from last to first
- if ( item->isParent() && item->mChild )
- _destroyChildren(item->mChild, item, deleteObjects);
- if( item->mNext )
- _destroyChildren(item->mNext, parent, deleteObjects);
- // destroy the item
- _destroyItem( item, deleteObjects );
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::_destroyItem( Item* item, bool deleteObject )
- {
- if(!item)
- return;
- if(item->isInspectorData())
- {
- // make sure the SimObjectPtr is clean!
- SimObject *pObject = item->getObject();
- if( pObject && pObject->isProperlyAdded() )
- {
- bool skipDelete = !deleteObject;
- if( !skipDelete && isMethod( "onDeleteObject" ) )
- skipDelete = onDeleteObject_callback( pObject );
- if ( !skipDelete )
- pObject->deleteObject();
- }
- item->setObject( NULL );
- }
- // Remove item from the selection
- if (mSelectedItem == item->mId)
- mSelectedItem = 0;
- for ( S32 i = 0; i < mSelectedItems.size(); i++ )
- {
- if ( mSelectedItems[i] == item )
- {
- mSelectedItems.erase( i );
- break;
- }
- }
- item->mState.clear();
- // unlink
- if( item->mPrevious )
- item->mPrevious->mNext = item->mNext;
- if( item->mNext )
- item->mNext->mPrevious = item->mPrevious;
- if( item->mParent && ( item->mParent->mChild == item ) )
- item->mParent->mChild = item->mNext;
- // remove from vector
- mItems[item->mId-1] = 0;
- // set as root free item
- item->mNext = mItemFreeList;
- mItemFreeList = item;
- mItemCount--;
- }
- //------------------------------------------------------------------------------
- void GuiTreeViewCtrl::_deleteItem(Item *item)
- {
- removeItem(item->mId);
- }
- //------------------------------------------------------------------------------
- void GuiTreeViewCtrl::_destroyTree()
- {
- // clear the item list
- for(U32 i = 0; i < mItems.size(); i++)
- {
- Item *pFreeItem = mItems[ i ];
- if( pFreeItem != NULL )
- delete pFreeItem;
- }
- mItems.clear();
- // clear the free list
- while(mItemFreeList)
- {
- Item *next = mItemFreeList->mNext;
- delete mItemFreeList;
- mItemFreeList = next;
- }
- mVisibleItems.clear();
- mSelectedItems.clear();
- //
- mRoot = NULL;
- mItemFreeList = NULL;
- mItemCount = 0;
- mSelectedItem = 0;
- mDraggedToItem = 0;
- mRenamingItem = NULL;
- mTempItem = NULL;
- mPossibleRenameItem = NULL;
- }
- //------------------------------------------------------------------------------
- void GuiTreeViewCtrl::_onInspectorSetObjectModified( SetModification modification, SimSet* set, SimObject* object )
- {
- // Don't bother searching for the Item to see if it is actually visible and instead just
- // mark our tree state as dirty so we get a rebuild on the next render.
- mFlags.set( RebuildVisible );
- }
- //------------------------------------------------------------------------------
- GuiTreeViewCtrl::Item* GuiTreeViewCtrl::_findItemByAmbiguousId( S32 itemOrObjectId, bool buildVirtual )
- {
- Item* item = getItem( itemOrObjectId );
- if( item )
- return item;
- SimObject* object = Sim::findObject( itemOrObjectId );
- if( object )
- {
- // If we should expand virtual trees in order to find the item,
- // do so now.
- if( buildVirtual )
- {
- if( mFlags.test( RebuildVisible ) )
- buildVisibleTree();
- SimGroup* group = object->getGroup();
- if( group )
- _expandObjectHierarchy( group );
- }
- if( objectSearch( object, &item ) )
- return item;
- }
- return NULL;
- }
- //------------------------------------------------------------------------------
- void GuiTreeViewCtrl::_expandObjectHierarchy( SimGroup* group )
- {
- SimGroup* parent = group->getGroup();
- if( parent && !parent->isExpanded() )
- _expandObjectHierarchy( parent );
- if( !group->isExpanded() )
- {
- Item* item;
- if( objectSearch( group, &item ) )
- {
- item->setExpanded();
- onVirtualParentBuild( item, false );
- }
- }
- }
- //------------------------------------------------------------------------------
- void GuiTreeViewCtrl::_buildItem( Item* item, U32 tabLevel, bool bForceFullUpdate, bool skipFlter )
- {
- if (!item || !mActive || !isVisible() || !mProfile )
- return;
- // If it's inspector data, make sure we still have it, if not, kill it.
- if(item->isInspectorData() && !item->getObject() )
- {
- removeItem(item->mId);
- return;
- }
- // If it's a virtual parent, give a chance to update itself...
- if(item->mState.test( Item::VirtualParent) )
- {
- // If it returns false the item has been removed.
- if( !onVirtualParentBuild( item, bForceFullUpdate ) )
- return;
- }
- // If we have a filter pattern, sync the item's filtering status to it.
- if( !getFilterText().isEmpty() && !skipFlter)
- {
- // Determine the filtering status by looking for the filter
- // text in the item's display text.
- char displayText[ 2048 ];
- item->getDisplayText( sizeof( displayText ), displayText );
- if( !dStristr( displayText, mFilterText ) )
- {
- //Last check, see if we special-exception this item
- if (!mItemFilterExceptionList.contains(item->mId))
- item->mState.set(Item::Filtered);
- else
- item->mState.clear(Item::Filtered);
- // If it's not a parent, we're done. Otherwise, there may be children
- // that are not filtered so we need to process them first.
- if( !item->isParent() )
- return;
- }
- else
- {
- item->mState.clear(Item::Filtered);
- }
- }
- else
- item->mState.clear( Item::Filtered );
- //If the item should be hidden from view, check now
- if (mHiddenItemsList.contains(item->mId))
- item->mState.set(Item::Filtered);
- // Is this the root item?
- const bool isRoot = item == mRoot;
- // Add non-root items or the root if we're supposed to show it.
- if( ( mShowRoot || !isRoot ) &&
- !item->isFiltered() )
- {
- item->mTabLevel = tabLevel;
- mVisibleItems.push_back( item );
- if( mProfile != NULL )
- {
- mProfile->incLoadCount();
-
- S32 width = mTextOffset + ( mTabSize * item->mTabLevel ) + getInspectorItemIconsWidth( item ) + item->getDisplayTextWidth( mProfile->mFont );
- // check image
- S32 image = BmpChild;
- if ( item->isInspectorData() )
- image = item->isExpanded() ? BmpExp : BmpCon;
- else
- image = item->isExpanded() ? item->getExpandedImage() : item->getNormalImage();
- if ( ( image >= 0 ) && ( image < mProfile->mBitmapArrayRects.size() ) )
- width += mProfile->mBitmapArrayRects[image].extent.x;
- if ( width > mMaxWidth )
- mMaxWidth = width;
-
- mProfile->decLoadCount();
- }
- }
- // If expanded or a hidden root, add all the
- // children items as well.
- if ( item->isExpanded() ||
- bForceFullUpdate ||
- ( isRoot && !mShowRoot ) )
- {
- Item* child = item->mChild;
- while ( child )
- {
- // Bit of a hack so we can safely remove items as we
- // traverse.
- Item *pChildTemp = child;
- child = child->mNext;
- if (!mItemFilterExceptionList.contains(item->mId) && !mDoFilterChildren && !item->isFiltered())
- _buildItem( pChildTemp, tabLevel + 1, bForceFullUpdate, true );
- else
- _buildItem(pChildTemp, tabLevel + 1, bForceFullUpdate, false);
- }
- }
- }
- //------------------------------------------------------------------------------
- void GuiTreeViewCtrl::buildVisibleTree(bool bForceFullUpdate)
- {
- // Recursion Prevention.
- if( mFlags.test( BuildingVisTree ) )
- return;
- mFlags.set( BuildingVisTree, true );
- if( mDebug )
- Con::printf( "Rebuilding visible tree" );
- mMaxWidth = 0;
- mVisibleItems.clear();
- // If we're filtering, force a full update.
- if( !mFilterText.isEmpty() )
- bForceFullUpdate = true;
- // Update the flags.
- mFlags.clear(RebuildVisible);
- // build the root items
- Item *traverse = mRoot;
- while(traverse)
- {
- _buildItem(traverse, 0, bForceFullUpdate);
- traverse = traverse->mNext;
- }
- // adjust the GuiArrayCtrl
- mCellSize.set( mMaxWidth + mTextOffset, mItemHeight );
- setSize(Point2I(1, mVisibleItems.size()));
- syncSelection();
- // Done Recursing.
- mFlags.clear( BuildingVisTree );
- }
- //------------------------------------------------------------------------------
- bool GuiTreeViewCtrl::scrollVisible( S32 itemId )
- {
- Item* item = getItem(itemId);
- if(item)
- return scrollVisible(item);
- return false;
- }
- //-----------------------------------------------------------------------------
- bool GuiTreeViewCtrl::scrollVisible( Item *item )
- {
- // Now, make sure it's visible (ie, all parents expanded)
- Item *parent = item->mParent;
- if( !item->isInspectorData() && item->mState.test(Item::VirtualParent) )
- onVirtualParentExpand(item);
- while(parent)
- {
- parent->setExpanded(true);
- if( !parent->isInspectorData() && parent->mState.test(Item::VirtualParent) )
- onVirtualParentExpand(parent);
- parent = parent->mParent;
- }
- // Get our scroll-pappy, if any.
- GuiScrollCtrl *pScrollParent = dynamic_cast<GuiScrollCtrl*>( getParent() );
- if ( !pScrollParent )
- {
- Con::warnf("GuiTreeViewCtrl::scrollVisible - parent control is not a GuiScrollCtrl!");
- return false;
- }
- // And now, build the visible tree so we know where we have to scroll.
- if( mFlags.test( RebuildVisible ) )
- buildVisibleTree();
- // All done, let's figure out where we have to scroll...
- for(S32 i=0; i<mVisibleItems.size(); i++)
- {
- if(mVisibleItems[i] == item)
- {
- // Fetch X Details.
- const S32 xPos = pScrollParent->getChildRelPos().x;
- const S32 xWidth = ( mMaxWidth - xPos );
- // Scroll to View the Item.
- // Note: Delta X should be 0 so that we maintain the X axis position.
- pScrollParent->scrollRectVisible( RectI( xPos, i * mItemHeight, xWidth, mItemHeight ) );
- return true;
- }
- }
- // If we got here, it's probably bad...
- Con::errorf("GuiTreeViewCtrl::scrollVisible - was unable to find specified item in visible list!");
- return false;
- }
- //------------------------------------------------------------------------------
- S32 GuiTreeViewCtrl::insertItem(S32 parentId, const char * text, const char * value, const char * iconString, S16 normalImage, S16 expandedImage)
- {
- if( ( parentId < 0 ) || ( parentId > mItems.size() ) )
- {
- Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::insertItem: invalid parent id!");
- return 0;
- }
- if((parentId != 0) && (mItems[parentId-1] == 0))
- {
- Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::insertItem: parent item invalid!");
- return 0;
- }
- const char * pItemText = ( text != NULL ) ? text : "";
- const char * pItemValue = ( value != NULL ) ? value : "";
- S32 icon = getIcon(iconString);
- // create an item (assigns id)
- Item * pNewItem = createItem(icon);
- if( pNewItem == NULL )
- return 0;
- pNewItem->setText( StringTable->insert( pItemText, true ) );
- pNewItem->setValue( StringTable->insert( pItemValue, true ) );
-
- pNewItem->setNormalImage( normalImage );
- pNewItem->setExpandedImage( expandedImage );
- // root level?
- if(parentId == 0)
- {
- // insert back
- if( mRoot != NULL )
- {
- Item * pTreeTraverse = mRoot;
- while( pTreeTraverse != NULL && pTreeTraverse->mNext != NULL )
- pTreeTraverse = pTreeTraverse->mNext;
- pTreeTraverse->mNext = pNewItem;
- pNewItem->mPrevious = pTreeTraverse;
- }
- else
- mRoot = pNewItem;
- mFlags.set(RebuildVisible);
- }
- else if( mItems.size() >= ( parentId - 1 ) )
- {
- Item * pParentItem = mItems[parentId-1];
- // insert back
- if( pParentItem != NULL && pParentItem->mChild)
- {
- Item * pTreeTraverse = pParentItem->mChild;
- while( pTreeTraverse != NULL && pTreeTraverse->mNext != NULL )
- pTreeTraverse = pTreeTraverse->mNext;
- pTreeTraverse->mNext = pNewItem;
- pNewItem->mPrevious = pTreeTraverse;
- }
- else
- pParentItem->mChild = pNewItem;
- pNewItem->mParent = pParentItem;
- if( pParentItem->isExpanded() )
- mFlags.set(RebuildVisible);
- }
- return pNewItem->mId;
- }
- //------------------------------------------------------------------------------
- bool GuiTreeViewCtrl::removeItem( S32 itemId, bool deleteObjects )
- {
- if( isSelected( itemId ) )
- removeSelection( itemId );
-
- // tree?
- if(itemId == 0)
- {
- //RD: this does not delete objects and thus isn't coherent with the semantics of this method
-
- _destroyTree();
- return(true);
- }
- Item * item = getItem(itemId);
- if(!item)
- {
- //Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::removeItem: invalid item id!");
- return false;
- }
- // root?
- if(item == mRoot)
- mRoot = item->mNext;
- // Dispose of any children...
- if (item->mChild)
- _destroyChildren( item->mChild, item, deleteObjects );
- // Kill the item...
- _destroyItem( item, deleteObjects );
- // Update the rendered tree...
- mFlags.set(RebuildVisible);
- return true;
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::removeAllChildren(S32 itemId)
- {
- Item * item = getItem(itemId);
- if(item)
- {
- _destroyChildren(item->mChild, item);
- }
- }
- //------------------------------------------------------------------------------
- const S32 GuiTreeViewCtrl::getFirstRootItem() const
- {
- return (mRoot ? mRoot->mId : 0);
- }
- //------------------------------------------------------------------------------
- S32 GuiTreeViewCtrl::getChildItem(S32 itemId)
- {
- Item * item = getItem(itemId);
- if(!item)
- {
- Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::getChild: invalid item id!");
- return(0);
- }
- return(item->mChild ? item->mChild->mId : 0);
- }
- //-----------------------------------------------------------------------------
- S32 GuiTreeViewCtrl::getParentItem(S32 itemId)
- {
- Item * item = getItem(itemId);
- if(!item)
- {
- Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::getParent: invalid item id!");
- return(0);
- }
- return(item->mParent ? item->mParent->mId : 0);
- }
- //-----------------------------------------------------------------------------
- S32 GuiTreeViewCtrl::getNextSiblingItem(S32 itemId)
- {
- Item * item = getItem(itemId);
- if(!item)
- {
- Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::getNextSibling: invalid item id!");
- return(0);
- }
- return(item->mNext ? item->mNext->mId : 0);
- }
- //-----------------------------------------------------------------------------
- S32 GuiTreeViewCtrl::getPrevSiblingItem(S32 itemId)
- {
- Item * item = getItem(itemId);
- if(!item)
- {
- Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::getPrevSibling: invalid item id!");
- return(0);
- }
- return(item->mPrevious ? item->mPrevious->mId : 0);
- }
- //------------------------------------------------------------------------------
- bool GuiTreeViewCtrl::isValidDragTarget( Item* item )
- {
- bool isValid = true;
-
- // First, check if we're just going to override this from manually setting the ForceAllowDrag flag
- // If that's set, we're assuming special circumstances and will just let it go on it's way
- if (item->isDragTargetAllowed())
- return true;
-
- // If this is inspector data, first make sure the item accepts all
- // selected objects as children. This prevents bad surprises when
- // certain SimSet subclasses reject children and start shoving them
- // off to places of their own choosing.
- if( item->isInspectorData() )
- {
- if( mDebug )
- Con::printf( "Checking %i:%s as drag-parent",
- item->getObject()->getId(), item->getObject()->getClassName() );
-
- SimSet* set = dynamic_cast< SimSet*>( item->getObject() );
- if( set )
- {
- for( U32 i = 0; i < mSelectedItems.size(); ++ i )
- {
- Item* selectedItem = mSelectedItems[ i ];
-
- if( mDebug )
- Con::printf( "Checking %i:%s as drag-object",
- selectedItem->getObject()->getId(),
- selectedItem->getObject()->getClassName() );
-
- if( selectedItem->isInspectorData()
- && !set->acceptsAsChild( selectedItem->getObject() ) )
- return false;
- }
- }
- }
-
- if( isMethod( "isValidDragTarget" ) )
- {
- // We have a callback. Exclusively leave the decision whether
- // the item is a valid drag target to it.
-
- isValid = isValidDragTarget_callback( item->mId, getItemValue( item->mId ) );
- }
- else
- {
- // Make the item a valid drag target if it either already is
- // a parent (including VirtualParents) or if dragging to non-parent
- // items is explicitly allowed.
-
- isValid = item->isParent() || mDragToItemAllowed;
- }
-
- return isValid;
- }
- //------------------------------------------------------------------------------
- S32 GuiTreeViewCtrl::getItemCount()
- {
- return(mItemCount);
- }
- //-----------------------------------------------------------------------------
- S32 GuiTreeViewCtrl::getSelectedItem()
- {
- return mSelectedItem;
- }
- //------------------------------------------------------------------------------
- void GuiTreeViewCtrl::moveItemUp( S32 itemId )
- {
- GuiTreeViewCtrl::Item* pItem = getItem( itemId );
- if ( !pItem )
- {
- Con::errorf( ConsoleLogEntry::General, "GuiTreeViewCtrl::moveItemUp: invalid item id!");
- return;
- }
- Item * pParent = pItem->mParent;
- Item * pPrevItem = pItem->mPrevious;
- if ( pPrevItem == NULL || pParent == NULL )
- {
- Con::errorf( ConsoleLogEntry::General, "GuiTreeViewCtrl::moveItemUp: Unable to move item up, bad data!");
- return;
- }
- // Diddle the linked list!
- if ( pPrevItem->mPrevious )
- pPrevItem->mPrevious->mNext = pItem;
- else if ( pItem->mParent )
- pItem->mParent->mChild = pItem;
- if ( pItem->mNext )
- pItem->mNext->mPrevious = pPrevItem;
- pItem->mPrevious = pPrevItem->mPrevious;
- pPrevItem->mNext = pItem->mNext;
- pItem->mNext = pPrevItem;
- pPrevItem->mPrevious = pItem;
- // Update SimObjects if Appropriate.
- SimObject * pSimObject = NULL;
- SimSet * pParentSet = NULL;
- // Fetch Current Add Set
- if( pParent->isInspectorData() )
- pParentSet = dynamic_cast<SimSet*>( pParent->getObject() );
- else
- {
- // parent is probably script data so we search up the tree for a
- // set to put our object in
- Item * pTraverse = pItem->mParent;
- while ( pTraverse != NULL && !pTraverse->isInspectorData() )
- pTraverse = pTraverse->mParent;
- // found an ancestor who is an inspectorData?
- if (pTraverse != NULL)
- pParentSet = pTraverse->isInspectorData() ? dynamic_cast<SimSet*>( pTraverse->getObject() ) : NULL;
- }
- // Reorder the item and make sure that the children of the item get updated
- // correctly prev item may be script... so find a prevItem if there is.
- // We only need to reorder if there you move it above an inspector item.
- if ( pSimObject != NULL && pParentSet != NULL )
- {
- Item * pTraverse = pItem->mNext;
- while(pTraverse)
- {
- if (pTraverse->isInspectorData())
- break;
- pTraverse = pTraverse->mNext;
- }
- if (pTraverse && pItem->getObject() && pTraverse->getObject())
- pParentSet->reOrder(pItem->getObject(), pTraverse->getObject());
- }
- mFlags.set(RebuildVisible);
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::moveItemDown( S32 itemId )
- {
- GuiTreeViewCtrl::Item* item = getItem( itemId );
- if ( !item )
- {
- Con::errorf( ConsoleLogEntry::General, "GuiTreeViewCtrl::moveItemDown: invalid item id!");
- return;
- }
- Item* nextItem = item->mNext;
- if ( !nextItem )
- {
- Con::errorf( ConsoleLogEntry::General, "GuiTreeViewCtrl::moveItemDown: no next sibling?");
- return;
- }
- // Diddle the linked list!
- if ( nextItem->mNext )
- nextItem->mNext->mPrevious = item;
- if ( item->mPrevious )
- item->mPrevious->mNext = nextItem;
- else if ( item->mParent )
- item->mParent->mChild = nextItem;
- item->mNext = nextItem->mNext;
- nextItem->mPrevious = item->mPrevious;
- item->mPrevious = nextItem;
- nextItem->mNext = item;
- // And update the simobjects if apppropriate...
- SimObject * simobj = NULL;
- if (item->isInspectorData())
- simobj = item->getObject();
- SimSet *parentSet = NULL;
- // grab the current parentSet if there is any...
- if(item->mParent->isInspectorData())
- parentSet = dynamic_cast<SimSet*>(item->mParent->getObject());
- else
- {
- // parent is probably script data so we search up the tree for a
- // set to put our object in
- Item * temp = item->mParent;
- while (temp && !temp->isInspectorData())
- temp = temp->mParent;
- // found an ancestor who is an inspectorData?
- parentSet = (temp && temp->isInspectorData()) ? dynamic_cast<SimSet*>(temp->getObject()) : NULL;
- }
- // Reorder the item and make sure that the children of the item get updated
- // correctly prev item may be script... so find a prevItem if there is.
- // We only need to reorder if there you move it above an inspector item.
- if (simobj && parentSet)
- {
- Item * temp = item->mPrevious;
- while(temp)
- {
- if (temp->isInspectorData())
- break;
- temp = temp->mPrevious;
- }
- if (temp && item->getObject() && temp->getObject())
- parentSet->reOrder(temp->getObject(), item->getObject());
- }
- mFlags.set(RebuildVisible);
- }
- //------------------------------------------------------------------------------
- bool GuiTreeViewCtrl::onAdd()
- {
- if( !Parent::onAdd() )
- return false;
-
- // If we have dynamic fields, convert the "internalNamesOnly" and "objectNamesOnly"
- // legacy fields.
-
- if( getFieldDictionary() )
- {
- static StringTableEntry sInternalNamesOnly = StringTable->insert( "internalNamesOnly" );
- static StringTableEntry sObjectNamesOnly = StringTable->insert( "objectNamesOnly" );
-
- const char* internalNamesOnly = getDataField( sInternalNamesOnly, NULL );
- if( internalNamesOnly && internalNamesOnly[ 0 ] && dAtob( internalNamesOnly ) )
- {
- mShowObjectIds = false;
- mShowClassNames = false;
- mShowObjectNames = false;
- mShowInternalNames = true;
- }
- const char* objectNamesOnly = getDataField( sObjectNamesOnly, NULL );
- if( objectNamesOnly && objectNamesOnly[ 0 ] && dAtob( objectNamesOnly ) )
- {
- mShowObjectIds = false;
- mShowClassNames = false;
- mShowObjectNames = true;
- mShowInternalNames = false;
- }
- }
-
- return true;
- }
- //------------------------------------------------------------------------------
- bool GuiTreeViewCtrl::onWake()
- {
- if(!Parent::onWake() || !mProfile->constructBitmapArray())
- return false;
- // If destroy on sleep, then we have to give things a chance to rebuild.
- if(mDestroyOnSleep)
- {
- onDefineIcons_callback();
- }
- // Update the row height, if appropriate.
- if(mProfile->mAutoSizeHeight)
- {
- // make sure it's big enough for both bitmap AND font...
- mItemHeight = getMax((S32)mFont->getHeight(), (S32)mProfile->mBitmapArrayRects[0].extent.y);
- }
-
- mFlags.set(RebuildVisible);
- return true;
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::onSleep()
- {
- Parent::onSleep();
- // If appropriate, blast the tree. (We probably rebuild it on wake.)
- if( mDestroyOnSleep )
- _destroyTree();
- if ( mRenameCtrl )
- {
- mRenameCtrl->deleteObject();
- mRenameCtrl = NULL;
- }
- }
- //-----------------------------------------------------------------------------
- bool GuiTreeViewCtrl::buildIconTable(const char * icons)
- {
- // Icons should be designated by the bitmap/png file names (minus the file extensions)
- // and separated by colons (:). This list should be synchronized with the Icons enum.
- // Figure the size of the buffer we need...
- const char* temp = dStrchr( icons, '\t' );
- U32 textLen = temp ? ( temp - icons ) : dStrlen( icons );
- // Allocate temporary space.
- FrameAllocatorMarker txtBuff;
- char* drawText = (char*)txtBuff.alloc(sizeof(char) * (textLen + 4));
- dStrncpy( drawText, icons, textLen );
- drawText[textLen] = '\0';
- U32 numIcons = 0;
- char buf[ 1024 ];
- char* pos = drawText;
- // Count the number of icons and store them.
- while( *pos && numIcons < MaxIcons )
- {
- char* start = pos;
- while( *pos && *pos != ':' )
- pos ++;
-
- const U32 len = pos - start;
- if( len )
- {
- dStrncpy( buf, start, getMin( sizeof( buf ) / sizeof( buf[ 0 ] ) - 1, len ) );
- buf[ len ] = '\0';
-
- mIconTable[ numIcons ] = GFXTexHandle( buf, &GFXDefaultGUIProfile, avar( "%s() - mIconTable[%d] (line %d)", __FUNCTION__, numIcons, __LINE__ ) );
- }
- else
- mIconTable[ numIcons ] = GFXTexHandle();
-
- numIcons ++;
- if( *pos )
- pos ++;
- }
- return true;
- }
- //------------------------------------------------------------------------------
- void GuiTreeViewCtrl::onPreRender()
- {
- Parent::onPreRender();
- S32 nRootItemId = getFirstRootItem();
- if( nRootItemId == 0 )
- return;
- Item *pRootItem = getItem( nRootItemId );
- if( pRootItem == NULL )
- return;
- // Update every render in case new objects are added
- if(mFlags.test(RebuildVisible))
- {
- buildVisibleTree();
- mFlags.clear(RebuildVisible);
- }
- }
- //------------------------------------------------------------------------------
- bool GuiTreeViewCtrl::_hitTest(const Point2I & pnt, Item* & item, BitSet32 & flags)
- {
- // Initialize some things.
- const Point2I pos = globalToLocalCoord(pnt);
- flags.clear();
- item = 0;
- // get the hit cell
- Point2I cell((pos.x < 0 ? -1 : pos.x / mCellSize.x),
- (pos.y < 0 ? -1 : pos.y / mCellSize.y));
- // valid?
- if((cell.x < 0 || cell.x >= mSize.x) ||
- (cell.y < 0 || cell.y >= mSize.y))
- return false;
- flags.set(OnRow);
- // Grab the cell.
- if (cell.y >= mVisibleItems.size())
- return false; //Invalid cell, so don't do anything
- item = mVisibleItems[cell.y];
- S32 min = mTabSize * item->mTabLevel;
- // left of icon/text?
- if(pos.x < min)
- {
- flags.set(OnIndent);
- return true;
- }
- // check image
- S32 image = BmpChild;
- if(item->isInspectorData())
- image = item->isExpanded() ? BmpExp : BmpCon;
- else
- image = item->isExpanded() ? item->getExpandedImage() : item->getNormalImage();
- if((image >= 0) && (image < mProfile->mBitmapArrayRects.size()))
- min += mProfile->mBitmapArrayRects[image].extent.x;
- // Is it on the image?
- if(pos.x < min)
- {
- flags.set(OnImage);
- return(true);
- }
- // Check the icon.
- min += getInspectorItemIconsWidth( item );
- if ( pos.x < min )
- {
- flags.set(OnIcon);
- return true;
- }
- // Check the text.
- min += mProfile->mTextOffset.x;
- FrameAllocatorMarker txtAlloc;
- U32 bufLen = item->getDisplayTextLength() + 2;
- char *buf = (char*)txtAlloc.alloc(bufLen);
- item->getDisplayText(bufLen, buf);
- min += mProfile->mFont->getStrWidth(buf);
- if(pos.x < min)
- flags.set(OnText);
- return true;
- }
- //-----------------------------------------------------------------------------
- S32 GuiTreeViewCtrl::getInspectorItemIconsWidth(Item* & item)
- {
- S32 width = 0;
- if( item->isInspectorData() )
- {
- // Based on code in onRenderCell()
- S32 icon = Lock1;
- S32 icon2 = Hidden;
- if (item->getObject() && item->getObject()->isLocked())
- {
- if (mIconTable[icon])
- {
- width += mIconTable[icon].getWidth();
- }
- }
- if (item->getObject() && item->getObject()->isHidden())
- {
- if (mIconTable[icon2])
- {
- width += mIconTable[icon2].getWidth();
- }
- }
- GFXTexHandle iconHandle;
- if ( ( item->mIcon != -1 ) && mIconTable[item->mIcon] )
- iconHandle = mIconTable[item->mIcon];
- #ifdef TORQUE_TOOLS
- else
- iconHandle = gEditorIcons.findIcon( item->getObject() );
- #endif
- if ( iconHandle.isValid() )
- {
- width += iconHandle.getWidth();
- }
- }
- else
- {
- S32 icon = item->isExpanded() ? item->mScriptInfo.mExpandedImage : item->mScriptInfo.mNormalImage;
- if ( ( icon != -1 ) && mIconTable[icon] )
- {
- width += mIconTable[icon].getWidth();
- }
- }
- return width;
- }
- //-----------------------------------------------------------------------------
- bool GuiTreeViewCtrl::setAddGroup(SimObject * obj)
- {
- // make sure we're talking about a group.
- SimGroup * grp = dynamic_cast<SimGroup*>(obj);
- if(grp)
- {
- onAddGroupSelected_callback( grp );
- return true;
- }
- return false;
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::syncSelection()
- {
- // for each visible item check to see if it is on the mSelected list.
- // if it is then make sure that it is on the mSelectedItems list as well.
- for (S32 i = 0; i < mVisibleItems.size(); i++)
- {
- for (S32 j = 0; j < mSelected.size(); j++)
- {
- if (mVisibleItems[i]->mId == mSelected[j])
- {
- // check to see if it is on the visible items list.
- bool addToSelectedItems = true;
- for (S32 k = 0; k < mSelectedItems.size(); k++)
- {
- if (mSelected[j] == mSelectedItems[k]->mId)
- {
- // don't add it
- addToSelectedItems = false;
- }
- }
- if (addToSelectedItems)
- {
- mVisibleItems[i]->mState.set(Item::Selected, true);
- mSelectedItems.push_front(mVisibleItems[i]);
- break;
- }
- }
- else if (mVisibleItems[i]->isInspectorData())
- {
- if(mCompareToObjectID)
- {
- if (mVisibleItems[i]->getObject() && mVisibleItems[i]->getObject()->getId() == mSelected[j])
- {
- // check to see if it is on the visible items list.
- bool addToSelectedItems = true;
- for (S32 k = 0; k < mSelectedItems.size(); k++)
- {
- if (mSelectedItems[k]->isInspectorData() && mSelectedItems[k]->getObject() )
- {
- if (mSelected[j] == mSelectedItems[k]->getObject()->getId())
- {
- // don't add it
- addToSelectedItems = false;
- }
- }
- else
- {
- if (mSelected[j] == mSelectedItems[k]->mId)
- {
- // don't add it
- addToSelectedItems = false;
- }
- }
- }
- if (addToSelectedItems)
- {
- mVisibleItems[i]->mState.set(Item::Selected, true);
- mSelectedItems.push_front(mVisibleItems[i]);
- break;
- }
- }
- }
- }
- }
- }
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::removeSelection( S32 itemOrObjectId )
- {
- if (mDebug)
- Con::printf( "removeSelection %i", itemOrObjectId );
- Item* item = _findItemByAmbiguousId( itemOrObjectId, false );
- if (!item)
- return;
- // Make sure we have a true item ID even if we started with
- // an object ID.
- S32 itemId = item->getID();
- S32 objectId = -1;
- if ( item->isInspectorData() && item->getObject() )
- objectId = item->getObject()->getId();
- // Remove from vector of selected object ids if it exists there
- if ( objectId != -1 )
- {
- for ( S32 i = 0; i < mSelected.size(); i++ )
- {
- if ( objectId == mSelected[i] || itemId == mSelected[i] )
- {
- mSelected.erase( i );
- break;
- }
- }
- }
- else
- {
- for ( S32 i = 0; i < mSelected.size(); i++ )
- {
- if ( itemId == mSelected[i] )
- {
- mSelected.erase( i );
- break;
- }
- }
- }
- item->mState.set(Item::Selected, false);
-
- // Remove from vector of selected items if it exists there.
- for ( S32 i = 0; i < mSelectedItems.size(); i++ )
- {
- if ( mSelectedItems[i] == item )
- {
- mSelectedItems.erase( i );
- break;
- }
- }
- // Callback.
- onRemoveSelection( item );
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::addSelection( S32 itemOrObjectId, bool update, bool isLastSelection )
- {
- if (mDebug)
- Con::printf( "addSelection %i", itemOrObjectId );
- Item* item = _findItemByAmbiguousId( itemOrObjectId );
- // Add Item?
- if ( !item || isSelected( item ) || !canAddSelection( item ) )
- {
- // Nope.
- return;
- }
- const S32 itemId = item->getID();
-
- // Ok, we have an item to select which isn't already selected....
- // Do we want to allow more than one selected item?
- if( !mMultipleSelections )
- clearSelection();
- // Add this object id to the vector of selected objectIds
- // if it is not already.
- bool foundMatch = false;
- for ( S32 i = 0; i < mSelected.size(); i++)
- {
- if ( mSelected[i] == itemId )
- foundMatch = true;
- }
-
- if ( !foundMatch )
- mSelected.push_front(itemId);
- item->mState.set(Item::Selected, true);
- if( mSelected.size() == 1 )
- {
- onItemSelected( item );
- }
- // Callback Start
- // Set and add the selection to the selected items group
- item->mState.set(Item::Selected, true);
- mSelectedItems.push_front(item);
- if ( item->isInspectorData() &&
- item->getObject() )
- {
- SimObject *obj = item->getObject();
-
- onAddSelection_callback( obj->getId(), isLastSelection );
- }
- else
- {
- onAddSelection_callback( item->mId, isLastSelection );
- }
- // Callback end
- mFlags.set( RebuildVisible );
- if( update )
- {
- // Also make it so we can see it if we didn't already.
- scrollVisible( item );
- }
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::onItemSelected( Item *item )
- {
- mSelectedItem = item->getID();
- if (item->isInspectorData())
- {
- SimObject* object = item->getObject();
- if( object )
- onSelect_callback( object->getId() );
- if( !item->isParent() && object )
- onInspect_callback( object->getId() );
- }
- else
- {
- onSelect_callback( item->mId );
- if( !item->isParent() )
- onInspect_callback( item->mId );
- }
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::onRemoveSelection( Item *item )
- {
- S32 id = item->mId;
- if( item->isInspectorData() &&
- item->getObject() )
- {
- SimObject* obj = item->getObject();
- id = obj->getId();
- //obj->setSelected( false );
- }
- if( isMethod( "onRemoveSelection" ) )
- onRemoveSelection_callback( id );
- else
- onUnselect_callback( id );
- }
- //-----------------------------------------------------------------------------
- bool GuiTreeViewCtrl::setItemSelected(S32 itemId, bool select)
- {
- Item * item = getItem(itemId);
- if( isSelected( item ) == select )
- return true;
- if (select)
- {
- if (mDebug) Con::printf("setItemSelected called true");
- mSelected.push_front(itemId);
- }
- else
- {
- if (mDebug) Con::printf("setItemSelected called false");
- // remove it from the mSelected list
- for (S32 j = 0; j <mSelected.size(); j++)
- {
- if (item)
- {
- if (item->isInspectorData())
- {
- if (item->getObject())
- {
- if(item->getObject()->getId() == mSelected[j])
- {
- mSelected.erase(j);
- break;
- }
- }
- else
- {
- // Zombie, kill it!
- mSelected.erase(j);
- j--;
- break;
- }
- }
- }
- if (mSelected[j] == itemId)
- {
- mSelected.erase(j);
- break;
- }
- }
- }
- if(!item)
- {
- // maybe what we were passed wasn't an item id but an object id.
- for (S32 i = 0; i <mItems.size(); i++)
- {
- if (mItems[i] != 0)
- {
- if (mItems[i]->isInspectorData())
- {
- if (mItems[i]->getObject())
- {
- if(mItems[i]->getObject()->getId() == itemId)
- {
- item = mItems[i];
- break;
- }
- }
- else
- {
- // It's a zombie, blast it.
- mItems.erase(i);
- i--;
- }
- }
- }
- }
- if (!item)
- {
- //Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::setItemSelected: invalid item id! Perhaps it isn't visible yet.");
- return(false);
- }
- }
- mFlags.set( RebuildVisible );
- if(select)
- {
- addSelection( item->mId );
- onItemSelected( item );
- }
- else
- {
- // deselect the item, if it's present.
- item->mState.set(Item::Selected, false);
- if (item->isInspectorData() && item->getObject())
- onUnselect_callback( item->getObject()->getId() );
- else
- onUnselect_callback( item->mId );
- // remove it from the selected items list
- for (S32 i = 0; i < mSelectedItems.size(); i++)
- {
- if (mSelectedItems[i] == item)
- {
- mSelectedItems.erase(i);
- break;
- }
- }
- }
- setUpdate();
- return(true);
- }
- //-----------------------------------------------------------------------------
- // Given an item's index in the selection list, return its itemId
- S32 GuiTreeViewCtrl::getSelectedItem(S32 index)
- {
- if(index >= 0 && index < getSelectedItemsCount())
- {
- return mSelectedItems[index]->mId;
- }
- return -1;
- }
- //-----------------------------------------------------------------------------
- bool GuiTreeViewCtrl::setItemExpanded(S32 itemId, bool expand)
- {
- Item * item = getItem(itemId);
- if(!item)
- {
- Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::setItemExpanded: invalid item id!");
- return(false);
- }
- if(item->isExpanded() == expand)
- return(true);
- item->setExpanded(expand);
- // expand parents
- if(expand)
- {
- while (item)
- {
- if (!item->isInspectorData() && item->mState.test(Item::VirtualParent))
- onVirtualParentExpand(item);
- scrollVisible(item);
- item = item->mParent;
- }
- }
- else
- {
- if(item->mState.test(Item::VirtualParent))
- onVirtualParentCollapse(item);
- item->setExpanded(false);
- }
- //if (!item->isInspectorData() && item->mState.test(Item::VirtualParent))
- // onVirtualParentExpand(item);
- mFlags.set(RebuildVisible);
- return(true);
- }
- //-----------------------------------------------------------------------------
- bool GuiTreeViewCtrl::setItemValue(S32 itemId, StringTableEntry Value)
- {
- Item * item = getItem(itemId);
- if(!item)
- {
- Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::setItemValue: invalid item id!");
- return(false);
- }
- item->setValue( ( Value ) ? Value : "" );
- return(true);
- }
- //-----------------------------------------------------------------------------
- const char * GuiTreeViewCtrl::getItemText(S32 itemId)
- {
- Item * item = getItem(itemId);
- if(!item)
- {
- Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::getItemText: invalid item id!");
- return("");
- }
- return(item->getText() ? item->getText() : "");
- }
- //-----------------------------------------------------------------------------
- const char * GuiTreeViewCtrl::getItemValue(S32 itemId)
- {
- Item * item = getItem(itemId);
- if(!item)
- {
- Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::getItemValue: invalid item id!");
- return("");
- }
- if(item->mState.test(Item::InspectorData))
- {
- // If it's InspectorData, we let people use this call to get an object reference.
- return item->mInspectorInfo.mObject->getIdString();
- }
- else
- {
- // Just return the script value...
- return item->getValue();
- }
- }
- //-----------------------------------------------------------------------------
- S32 GuiTreeViewCtrl::getItemAtPosition(Point2I position)
- {
- BitSet32 hitFlags = 0;
- Item* item;
- if (_hitTest(position, item, hitFlags))
- return item->mId;
- else
- return -1;
- }
- //-----------------------------------------------------------------------------
- bool GuiTreeViewCtrl::editItem( S32 itemId, const char* newText, const char* newValue )
- {
- Item* item = getItem( itemId );
- if ( !item )
- {
- Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::editItem: invalid item id: %d!", itemId);
- return false;
- }
- if ( item->mState.test(Item::InspectorData) )
- {
- Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::editItem: item %d is inspector data and may not be modified!", itemId);
- return false;
- }
- item->setText( StringTable->insert( newText, true ) );
- item->setValue( StringTable->insert( newValue, true ) );
- // Update the widths and such:
- mFlags.set(RebuildVisible);
- return true;
- }
- //-----------------------------------------------------------------------------
- bool GuiTreeViewCtrl::markItem( S32 itemId, bool mark )
- {
- Item *item = getItem( itemId );
- if ( !item )
- {
- Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::markItem: invalid item id: %d!", itemId);
- return false;
- }
- item->mState.set(Item::Marked, mark);
- return true;
- }
- //-----------------------------------------------------------------------------
- bool GuiTreeViewCtrl::isItemSelected( S32 itemId )
- {
- for( U32 i = 0, num = mSelectedItems.size(); i < num; ++ i )
- if( mSelectedItems[ i ]->mId == itemId )
- return true;
-
- return false;
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::deleteSelection()
- {
- onDeleteSelection_callback();
- if (mSelectedItems.empty())
- {
- for (S32 i = 0; i < mSelected.size(); i++)
- {
- S32 objectId = mSelected[i];
- // find the object
- SimObject* obj = Sim::findObject(objectId);
- if ( !obj )
- continue;
- bool skipDelete = onDeleteObject_callback( obj );
- if ( !skipDelete )
- obj->deleteObject();
- }
- }
- else
- {
- Vector<Item*> delSelection;
- delSelection = mSelectedItems;
- mSelectedItems.clear();
- while (!delSelection.empty())
- {
- Item * item = delSelection.front();
- setItemSelected(item->mId,false);
- if ( item->mParent )
- _deleteItem( item );
-
- delSelection.pop_front();
- }
- }
- mSelected.clear();
- mSelectedItems.clear();
- mSelectedItem = 0;
- onObjectDeleteCompleted_callback();
- }
- //------------------------------------------------------------------------------
- // keyboard movement of items is restricted to just one item at a time
- // if more than one item is selected then movement operations are not performed
- bool GuiTreeViewCtrl::onKeyDown( const GuiEvent& event )
- {
- if ( !mVisible || !mActive || !mAwake )
- return false;
- // All the keyboard functionality requires a selected item, so if none exists...
- // Deal with enter and delete
- if ( event.modifier == 0 )
- {
- if ( event.keyCode == KEY_RETURN )
- {
- execAltConsoleCallback();
- return true;
- }
- if ( event.keyCode == KEY_DELETE && mDeleteObjectAllowed )
- {
- // Don't delete the root!
- if (mSelectedItems.empty())
- return true;
- //this may be fighting with the world editor delete
- deleteSelection();
- return true;
- }
-
- //call a generic bit of script that will let the subclass know that a key was pressed
- onKeyDown_callback( event.modifier, event.keyCode );
- }
- // only do operations if only one item is selected
- if ( mSelectedItems.empty() || (mSelectedItems.size() > 1))
- return false;
- Item* item = mSelectedItems.first();
- if ( !item )
- return false;
- // The Alt key lets you move items around!
- if ( mFlags.test(IsEditable) && event.modifier & SI_ALT )
- {
- switch ( event.keyCode )
- {
- case KEY_UP:
- // Move us up.
- if ( item->mPrevious )
- {
- moveItemUp( item->mId );
- scrollVisible(item);
- }
- return true;
- case KEY_DOWN:
- // Move the item under us up.
- if ( item->mNext )
- {
- moveItemUp( item->mNext->mId );
- scrollVisible(item);
- }
- return true;
- case KEY_LEFT:
- if ( item->mParent )
- {
- if ( item->mParent->mParent )
- {
- // Ok, we have both an immediate parent, and a grandparent.
- // The goal of left-arrow alt is to become the child of our
- // grandparent, ie, to become a sibling of our parent.
- // First, unlink item from its siblings.
- if ( item->mPrevious )
- item->mPrevious->mNext = item->mNext;
- else
- item->mParent->mChild = item->mNext;
- if ( item->mNext )
- item->mNext->mPrevious = item->mPrevious;
- // Now, relink as the next sibling of our parent.
- item->mPrevious = item->mParent;
- item->mNext = item->mParent->mNext;
- // If there was already a next sibling, deal with that case.
- if ( item->mNext )
- item->mNext->mPrevious = item;
- item->mParent->mNext = item;
- // Snag the current parent set if any...
- SimSet *parentSet = NULL;
- if(item->mParent->isInspectorData())
- parentSet = dynamic_cast<SimSet*>(item->mParent->getObject());
- else
- {
- // parent is probably script data so we search up the tree for a
- // set to put our object in
- Item * temp = item->mParent;
- while (!temp->isInspectorData())
- temp = temp->mParent;
- // found a ancestor who is an inspectorData
- if (temp->isInspectorData())
- parentSet = dynamic_cast<SimSet*>(temp->getObject());
- else parentSet = NULL;
- }
- // Get our active SimObject if any
- SimObject *simObj = NULL;
- if(item->isInspectorData())
- simObj = item->getObject();
- // Remove from the old parentset...
- if(simObj && parentSet) {
- if (parentSet->size()>0)
- {
- SimObject *lastObject = parentSet->last();
- parentSet->removeObject(simObj);
- parentSet->reOrder(lastObject);
- } else
- parentSet->removeObject(simObj);
- }
- // And finally, update our item
- item->mParent = item->mParent->mParent;
- // Snag the newparent set if any...
- SimSet *newParentSet = NULL;
- if(item->mParent->isInspectorData())
- newParentSet = dynamic_cast<SimSet*>(item->mParent->getObject());
- else
- {
- // parent is probably script data so we search up the tree for a
- // set to put our object in
- Item * temp = item->mParent;
- while (!temp->isInspectorData())
- temp = temp->mParent;
- // found a ancestor who is an inspectorData
- if (temp->isInspectorData())
- newParentSet = dynamic_cast<SimSet*>(temp->getObject());
- else newParentSet = NULL;
- }
- if(simObj && newParentSet)
- {
- newParentSet->addObject(simObj);
- Item * temp = item->mNext;
- // item->mNext may be script, so find an inspector item to reorder with if any
- if (temp) {
- do {
- if (temp->isInspectorData())
- break;
- temp = temp->mNext;
- } while (temp);
- if (temp && item->getObject() && temp->getObject()) //do we still have a item->mNext? If not then don't bother reordering
- newParentSet->reOrder(item->getObject(), temp->getObject());
- }
- } else if (!simObj&&newParentSet) {
- // our current item is script data. but it may have children who
- // is inspector data who need an updated set
- if (item->mChild)
- inspectorSearch(item->mChild, item, parentSet, newParentSet);
- }
- // And update everything hurrah.
- buildVisibleTree();
- scrollVisible(item);
- }
- }
- return true;
- case KEY_RIGHT:
- if ( item->mPrevious )
- {
- // Make the item the last child of its previous sibling.
- // First, unlink from the current position in the list
- item->mPrevious->mNext = item->mNext;
- if ( item->mNext )
- item->mNext->mPrevious = item->mPrevious;
- // Get the object we're poking with.
- SimObject *simObj = NULL;
- SimSet *parentSet = NULL;
- if(item->isInspectorData())
- simObj = item->getObject();
- if(item->mParent->isInspectorData())
- parentSet = dynamic_cast<SimSet*>(item->mParent->getObject());
- else {
- // parent is probably script data so we search up the tree for a
- // set to put our object in
- Item * temp = item->mParent;
- while (!temp->isInspectorData())
- temp = temp->mParent;
- // found an ancestor who is an inspectorData
- if (temp->isInspectorData())
- parentSet = dynamic_cast<SimSet*>(temp->getObject());
- }
- // If appropriate, remove from the current SimSet.
- if(parentSet && simObj) {
- if (parentSet->size()>0)
- {
- SimObject *lastObject = parentSet->last();
- parentSet->removeObject(simObj);
- parentSet->reOrder(lastObject);
- } else
- parentSet->removeObject(simObj);
- }
- // Now, make our previous sibling our parent...
- item->mParent = item->mPrevious;
- item->mNext = NULL;
- // And sink us down to the end of its siblings, if appropriate.
- if ( item->mParent->mChild )
- {
- Item* temp = item->mParent->mChild;
- while ( temp->mNext )
- temp = temp->mNext;
- temp->mNext = item;
- item->mPrevious = temp;
- }
- else
- {
- // only child...<sniff>
- item->mParent->mChild = item;
- item->mPrevious = NULL;
- }
- // Make sure the new parent is expanded:
- if ( !item->mParent->mState.test( Item::Expanded ) )
- setItemExpanded( item->mParent->mId, true );
- // Snag the new parent simset if any.
- SimSet *newParentSet = NULL;
- // new parent might be script. so figure out what set we need to add it to.
- if(item->mParent->isInspectorData())
- newParentSet = dynamic_cast<SimSet*>(item->mParent->getObject());
- else
- {
- // parent is probably script data so we search up the tree for a
- // set to put our object in
- if (mDebug) Con::printf("oh nos my parent is script!");
- Item * temp = item->mParent;
- while (!temp->isInspectorData())
- temp = temp->mParent;
- // found a ancestor who is an inspectorData
- if (temp->isInspectorData())
- newParentSet = dynamic_cast<SimSet*>(temp->getObject());
- else newParentSet = NULL;
- }
- // Add the item's SimObject to the new parent simset, at the end.
- if(newParentSet && simObj)
- newParentSet->addObject(simObj);
- else if (!simObj&&newParentSet&&parentSet) {
- // our current item is script data. but it may have children who
- // is inspector data who need an updated set
- if (item->mChild) {
- inspectorSearch(item->mChild, item, parentSet, newParentSet);
- }
- }
- scrollVisible(item);
- }
- return true;
-
- default:
- break;
- }
- }
- // Explorer-esque navigation...
- switch( event.keyCode )
- {
- case KEY_UP:
- // Select previous visible item:
- if ( item->mPrevious )
- {
- item = item->mPrevious;
- while ( item->isParent() && item->isExpanded() )
- {
- item = item->mChild;
- while ( item->mNext )
- item = item->mNext;
- }
- clearSelection();
- addSelection( item->mId );
- return true;
- }
- // or select parent:
- if ( item->mParent )
- {
- clearSelection();
- addSelection( item->mParent->mId );
- return true;
- }
- return false;
- break;
- case KEY_DOWN:
- // Selected child if it is visible:
- if ( item->isParent() && item->isExpanded() )
- {
- clearSelection();
- addSelection( item->mChild->mId );
- return true;
- }
- // or select next sibling (recursively):
- do
- {
- if ( item->mNext )
- {
- clearSelection();
- addSelection( item->mNext->mId );
- return true;
- }
- item = item->mParent;
- } while ( item );
- return false;
- break;
- case KEY_LEFT:
- // Contract current menu:
- if ( item->isExpanded() )
- {
- setItemExpanded( item->mId, false );
- scrollVisible(item);
- return true;
- }
- // or select parent:
- if ( item->mParent )
- {
- clearSelection();
- addSelection( item->mParent->mId );
- return true;
- }
- return false;
- break;
- case KEY_RIGHT:
- // Expand selected item:
- if ( item->isParent() )
- {
- if ( !item->isExpanded() )
- {
- setItemExpanded( item->mId, true );
- scrollVisible(item);
- return true;
- }
- // or select child:
- clearSelection();
- addSelection( item->mChild->mId );
- return true;
- }
- return false;
- break;
-
- default:
- break;
- }
- // Not processed, so pass the event on:
- return Parent::onKeyDown( event );
- }
- //------------------------------------------------------------------------------
- // on mouse up look at the current item and check to see if it is valid
- // to move the selected item(s) to it.
- void GuiTreeViewCtrl::onMouseUp(const GuiEvent &event)
- {
- if( !mActive || !mAwake || !mVisible )
- return;
-
- BitSet32 hitFlags = 0;
- if( isMethod("onMouseUp") )
- {
- Item* item;
-
- S32 hitItemId = -1;
- if( _hitTest( event.mousePoint, item, hitFlags ) )
- hitItemId = item->mId;
-
- onMouseUp_callback( hitItemId, event.mouseClickCount );
- }
- mouseUnlock();
- if ( mSelectedItems.empty())
- {
- mDragMidPoint = NomDragMidPoint;
- return;
- }
- hitFlags = 0;
- Item *hitItem;
- bool hitCheck = _hitTest( event.mousePoint, hitItem, hitFlags );
- mRenamingItem = NULL;
- if( hitCheck )
- {
- if ( event.mouseClickCount == 1 && !mMouseDragged && mPossibleRenameItem != NULL )
- {
- if (hitItem == mPossibleRenameItem )
- showItemRenameCtrl(hitItem);
- }
- else // If mouseUp occurs on the same item as mouse down
- {
- bool wasSelected = isSelected(hitItem);
- bool multiSelect = getSelectedItemsCount() > 1;
- if( wasSelected && multiSelect && hitItem == mTempItem )
- {
- clearSelection();
- addSelection( hitItem->mId );
- }
- }
- }
- mPossibleRenameItem = NULL;
-
- if (!mMouseDragged)
- return;
- Item* newItem = NULL;
- Item* newItem2 = NULL;
- if (mFlags.test(IsEditable))
- {
- Parent::onMouseMove( event );
-
- hitFlags = 0;
- if( !_hitTest( event.mousePoint, newItem2, hitFlags ) )
- {
- if( !mShowRoot )
- newItem2 = mRoot;
- else
- {
- if( mDebug )
- Con::printf( "Nothing hit" );
-
- mDragMidPoint = NomDragMidPoint;
- return;
- }
- }
- newItem2->mState.clear(Item::MouseOverBmp | Item::MouseOverText );
-
- // If the hit item is the visible root, make sure
- // we don't allow dragging above.
-
- if( newItem2 == mRoot && mDragMidPoint == AbovemDragMidPoint )
- {
- if( mDebug )
- Con::printf( "Rejecting to make child sibling of root" );
-
- mDragMidPoint = NomDragMidPoint;
- return;
- }
-
- // if the newItem isn't in the mSelectedItemList then continue.
- Vector<Item *>::iterator k;
- for(k = mSelectedItems.begin(); k != mSelectedItems.end(); k++)
- {
- newItem = newItem2;
-
- if (*(k) == newItem)
- {
- mDragMidPoint = NomDragMidPoint;
- return;
- }
- Item * temp = *(k);
- Item * grandpaTemp = newItem->mParent;
-
- // grandpa check, kick out if an item would be its own ancestor
- while (grandpaTemp)
- {
- if (temp == grandpaTemp)
- {
- if (mDebug)
- {
- Con::printf("grandpa check");
- if (temp->isInspectorData())
- Con::printf("temp's name: %s",temp->getObject()->getName());
- if (grandpaTemp->isInspectorData())
- Con::printf("grandpa's name: %s",grandpaTemp->getObject()->getName());
- }
- mDragMidPoint = NomDragMidPoint;
- return;
- }
- grandpaTemp = grandpaTemp->mParent;
- }
- }
-
- // Notify script for undo.
- onBeginReparenting_callback();
-
- // Reparent the items.
- reparentItems(mSelectedItems, newItem2);
-
- onEndReparenting_callback();
- // And update everything.
- scrollVisible(newItem);
- onDragDropped_callback();
- buildVisibleTree(false);
- }
- mDragMidPoint = NomDragMidPoint;
- }
- //------------------------------------------------------------------------------
- void GuiTreeViewCtrl::onMouseDragged(const GuiEvent &event)
- {
- if( mDragStartInSelection )
- onMouseDragged_callback();
-
- if(!mSupportMouseDragging)
- return;
-
- if( !mActive || !mAwake || !mVisible )
- return;
- if (mSelectedItems.size() == 0)
- return;
-
- //Check through to make sure all attempted dragged items even allow it
- for (U32 i = 0; i < mSelectedItems.size(); i++)
- if (!mSelectedItems[i]->isDragAllowed())
- return;
-
- // Give us a little delta before we actually start a mouse drag so that
- // if the user moves the mouse a little while clicking, he/she does not
- // accidentally trigger a drag.
-
- if( mFabs( ( mMouseDownPoint - event.mousePoint ).len() ) <= 4.f )
- return;
-
- Point2I pt = globalToLocalCoord(event.mousePoint);
- Parent::onMouseMove(event);
- mouseLock();
- mMouseDragged = true;
-
- // If the drag is outside of our visible area,
- // start scrolling.
-
- GuiScrollCtrl* scrollCtrl = dynamic_cast< GuiScrollCtrl* >( getParent() );
- if( scrollCtrl && !scrollCtrl->isPointVisible( pt ) )
- {
- S32 widthDelta = 0;
- S32 heightDelta = 0;
-
- if( pt.x < scrollCtrl->getChildRelPos().x )
- widthDelta = pt.x - scrollCtrl->getChildRelPos().x;
- else if( pt.x > scrollCtrl->getChildRelPos().x + scrollCtrl->getContentExtent().x )
- widthDelta = pt.x - scrollCtrl->getChildRelPos().x - scrollCtrl->getContentExtent().x;
- if( pt.y < scrollCtrl->getChildRelPos().y )
- heightDelta = pt.y - scrollCtrl->getChildRelPos().y;
- else if( pt.y > scrollCtrl->getChildRelPos().y + scrollCtrl->getContentExtent().y )
- heightDelta = pt.y - scrollCtrl->getChildRelPos().y - scrollCtrl->getContentExtent().y;
-
- const F32 SCROLL_RATIO = 0.5f;
- scrollCtrl->scrollDelta( S32( F32( widthDelta ) * SCROLL_RATIO ), S32( F32( heightDelta ) * SCROLL_RATIO ) );
- }
-
- // whats our mDragMidPoint?
- mCurrentDragCell = mMouseOverCell.y;
- S32 midpCell = mCurrentDragCell * mItemHeight + (mItemHeight/2);
- S32 currentY = pt.y;
- S32 yDiff = currentY-midpCell;
- S32 variance = (mItemHeight/5);
- if( mPreviousDragCell >= 0 && mPreviousDragCell < mVisibleItems.size() )
- mVisibleItems[mPreviousDragCell]->mState.clear( Item::MouseOverBmp | Item::MouseOverText | Item::MouseOverIcon );
- bool hoverItem = false;
- if (mAbs(yDiff) <= variance)
- {
- mDragMidPoint = NomDragMidPoint;
- // highlight the current item
- // hittest to detect whether we are on an item
- // ganked from onMouseMouse
- // used for tracking what our last cell was so we can clear it.
- mPreviousDragCell = mCurrentDragCell;
- if (mCurrentDragCell >= 0)
- {
- Item* item = NULL;
- BitSet32 hitFlags = 0;
- if ( !_hitTest( event.mousePoint, item, hitFlags ) )
- return;
-
- // If the item is a valid drag target, activate the item
- // highlighting.
- if( isValidDragTarget( item ) )
- {
- hoverItem = true;
- if ( hitFlags.test( OnImage ) )
- item->mState.set( Item::MouseOverBmp );
- if ( hitFlags.test( OnText ) )
- item->mState.set( Item::MouseOverText );
- if ( hitFlags.test( OnIcon ) )
- item->mState.set( Item::MouseOverIcon );
- // Always redraw the entire mouse over item, since we are distinguishing
- // between the bitmap and the text:
- setUpdateRegion( Point2I( mMouseOverCell.x * mCellSize.x, mMouseOverCell.y * mCellSize.y ), mCellSize );
- }
- }
- }
- if ( !hoverItem )
- {
- //above or below an item?
- if (yDiff < 0)
- mDragMidPoint = AbovemDragMidPoint;
- else
- mDragMidPoint = BelowmDragMidPoint;
- }
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::onMiddleMouseDown(const GuiEvent & event)
- {
- //for debugging items
- if (mDebug) {
- Item* item;
- BitSet32 hitFlags = 0;
- _hitTest( event.mousePoint, item, hitFlags );
- Con::printf("debugging %d", item->mId);
- Point2I pt = globalToLocalCoord(event.mousePoint);
- if (item->isInspectorData() && item->getObject()) {
- Con::printf("object data:");
- Con::printf("name:%s",item->getObject()->getName());
- Con::printf("className:%s",item->getObject()->getClassName());
- }
- Con::printf("contents of mSelectedItems:");
- for(S32 i = 0; i < mSelectedItems.size(); i++) {
- if (mSelectedItems[i]->isInspectorData()) {
- Con::printf("%d",mSelectedItems[i]->getObject()->getId());
- } else
- Con::printf("wtf %d", mSelectedItems[i]);
- }
- Con::printf("contents of mSelected");
- for (S32 j = 0; j < mSelected.size(); j++) {
- Con::printf("%d", mSelected[j]);
- }
- mCurrentDragCell = mMouseOverCell.y;
- S32 midpCell = (mCurrentDragCell) * mItemHeight + (mItemHeight/2);
- S32 currentY = pt.y;
- S32 yDiff = currentY-midpCell;
- Con::printf("cell info: (%d,%d) mCurrentDragCell=%d est=(%d,%d,%d) ydiff=%d",pt.x,pt.y,mCurrentDragCell,mCurrentDragCell*mItemHeight, midpCell, (mCurrentDragCell+1)*mItemHeight,yDiff);
- }
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::onMouseDown(const GuiEvent & event)
- {
- if( !mActive || !mAwake || !mVisible )
- {
- Parent::onMouseDown(event);
- return;
- }
- if ( mProfile->mCanKeyFocus )
- setFirstResponder();
- Item * item = 0;
- BitSet32 hitFlags;
- mDragMidPoint = NomDragMidPoint;
- mMouseDragged = false;
- mMouseDownPoint = event.mousePoint;
- //
- if(!_hitTest(event.mousePoint, item, hitFlags))
- return;
- mPossibleRenameItem = NULL;
- mRenamingItem = NULL;
- mTempItem = NULL;
-
- //
- if( event.modifier & SI_MULTISELECT )
- {
- bool selectFlag = item->mState.test(Item::Selected);
- if (selectFlag == true)
- {
- // already selected, so unselect it and remove it
- removeSelection(item->mId);
- }
- else
- {
- addSelection(item->mId);
- }
- }
- else if( event.modifier & SI_RANGESELECT && mMultipleSelections )
- {
- // is something already selected?
- S32 firstSelectedIndex = 0;
- Item * firstItem = NULL;
- if (!mSelectedItems.empty())
- {
- firstItem = mSelectedItems.front();
- for (S32 i = 0; i < mVisibleItems.size();i++)
- {
- if (mVisibleItems[i] == mSelectedItems.front())
- {
- firstSelectedIndex = i;
- break;
- }
- }
- mCurrentDragCell = mMouseOverCell.y;
- if (mVisibleItems[firstSelectedIndex] != firstItem )
- {
- /*
- Con::printf("something isn't right...");
- if (mVisibleItems[firstSelectedIndex]->isInspectorData())
- Con::printf("visibleItem %s",mVisibleItems[firstSelectedIndex]->getObject()->getName());
- if (firstItem->isInspectorData())
- Con::printf("firstItem %s",firstItem->getObject()->getName());
- */
- }
- else
- {
- // select the cells
- onAddMultipleSelectionBegin_callback();
- if ((mCurrentDragCell) < firstSelectedIndex)
- {
- //select up
- for (S32 j = (mCurrentDragCell); j < firstSelectedIndex; j++)
- {
- if( j != (firstSelectedIndex - 1) )
- addSelection(mVisibleItems[j]->mId, false, false);
- else
- addSelection(mVisibleItems[j]->mId, false);
- }
- }
- else
- {
- // select down
- for (S32 j = firstSelectedIndex+1; j < (mCurrentDragCell+1); j++)
- {
- if( j != mCurrentDragCell )
- addSelection(mVisibleItems[j]->mId, false, false);
- else
- addSelection(mVisibleItems[j]->mId, false);
- }
- }
- // Scroll to view the last selected cell.
- scrollVisible( mVisibleItems[mCurrentDragCell] );
- onAddMultipleSelectionEnd_callback();
- }
- }
- }
- else if ( event.modifier & SI_PRIMARY_ALT )
- {
- if ( item->isInspectorData() && item->getObject() )
- setAddGroup(item->getObject());
- }
- else if ( !hitFlags.test(OnImage) )
- {
- mTempItem = item;
- bool wasSelected = isSelected( item );
- bool multiSelect = getSelectedItemsCount() > 1;
-
- if( !wasSelected || !multiSelect )
- {
- if ( mClearAllOnSingleSelection )
- clearSelection();
- if ( !wasSelected || mClearAllOnSingleSelection )
- addSelection( item->mId );
- if ( wasSelected &&
- !multiSelect &&
- mCanRenameObjects &&
- hitFlags.test(OnText) &&
- mFlags.test(IsEditable) &&
- item->isInspectorData() &&
- item->getObject() &&
- item->getObject()->isNameChangeAllowed() &&
- item != mRoot &&
- event.mouseClickCount == 1 )
- {
- mPossibleRenameItem = item;
- if ( isMethod( "canRenameObject" ) )
- {
- if( canRenameObject_callback( item->getObject() ) )
- mPossibleRenameItem = NULL;
- }
- }
- }
-
- }
- if ( ( hitFlags.test( OnText ) || hitFlags.test( OnIcon ) ) &&
- event.mouseClickCount > 1 )
- execAltConsoleCallback();
- // For dragging, note if hit is in selection.
-
- mDragStartInSelection = isItemSelected( item->mId );
- if(!item->isParent())
- return;
- //
- if ( mFullRowSelect || hitFlags.test( OnImage ) )
- {
- item->setExpanded(!item->isExpanded());
- if( !item->isInspectorData() && item->mState.test(Item::VirtualParent) )
- onVirtualParentExpand(item);
-
- mFlags.set( RebuildVisible );
- scrollVisible(item);
- }
- }
- //------------------------------------------------------------------------------
- void GuiTreeViewCtrl::onMouseMove( const GuiEvent &event )
- {
- if ( mMouseOverCell.y >= 0 && mVisibleItems.size() > mMouseOverCell.y)
- mVisibleItems[mMouseOverCell.y]->mState.clear( Item::MouseOverBmp | Item::MouseOverText | Item::MouseOverIcon);
- Parent::onMouseMove( event );
- if ( mMouseOverCell.y >= 0 )
- {
- Item* item = NULL;
- BitSet32 hitFlags = 0;
- if ( !_hitTest( event.mousePoint, item, hitFlags ) )
- return;
- if ( hitFlags.test( OnImage ) )
- item->mState.set( Item::MouseOverBmp );
- if ( hitFlags.test( OnText ) )
- item->mState.set( Item::MouseOverText );
- if ( hitFlags.test( OnIcon ) )
- item->mState.set( Item::MouseOverIcon );
- // Always redraw the entire mouse over item, since we are distinguishing
- // between the bitmap and the text:
- setUpdateRegion( Point2I( mMouseOverCell.x * mCellSize.x, mMouseOverCell.y * mCellSize.y ), mCellSize );
- }
- }
- //------------------------------------------------------------------------------
- void GuiTreeViewCtrl::onMouseEnter( const GuiEvent &event )
- {
- Parent::onMouseEnter( event );
- onMouseMove( event );
- }
- //------------------------------------------------------------------------------
- void GuiTreeViewCtrl::onMouseLeave( const GuiEvent &event )
- {
- if ( mMouseOverCell.y >= 0 && mVisibleItems.size() > mMouseOverCell.y)
- mVisibleItems[mMouseOverCell.y]->mState.clear( Item::MouseOverBmp | Item::MouseOverText | Item::MouseOverIcon );
- Parent::onMouseLeave( event );
- }
- //------------------------------------------------------------------------------
- void GuiTreeViewCtrl::onRightMouseDown(const GuiEvent & event)
- {
- if(!mActive)
- {
- Parent::onRightMouseDown(event);
- return;
- }
- Item * item = NULL;
- BitSet32 hitFlags;
- //
- if(!_hitTest(event.mousePoint, item, hitFlags))
- return;
- //
- if (item->isInspectorData() && item->getObject())
- onRightMouseDown_callback( item->mId, event.mousePoint, item->getObject() );
- else
- onRightMouseDown_callback( item->mId, event.mousePoint );
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::onRightMouseUp(const GuiEvent & event)
- {
- Item *item = NULL;
- BitSet32 hitFlags;
- if ( !_hitTest( event.mousePoint, item, hitFlags ) )
- return;
- if ( hitFlags.test( OnText ) || hitFlags.test( OnIcon ) )
- {
- if ( !isItemSelected( item->getID() ) )
- {
- clearSelection();
- addSelection( item->getID() );
- }
- if (item->isInspectorData() && item->getObject())
- onRightMouseUp_callback( item->mId, event.mousePoint, item->getObject() );
- else
- onRightMouseUp_callback( item->mId, event.mousePoint );
- }
- else
- {
- clearSelection();
- }
- Parent::onRightMouseUp(event);
- }
- //------------------------------------------------------------------------------
- void GuiTreeViewCtrl::onRender(Point2I offset, const RectI &updateRect)
- {
- if ( !mRenamingItem && mRenameCtrl )
- {
- mRenameCtrl->deleteObject();
- mRenameCtrl = NULL;
- }
-
- // Get all our contents drawn!
- Parent::onRender(offset,updateRect);
- // Deal with drawing the drag & drop line, if any...
- GFX->setClipRect(updateRect);
- // only do it if we have a mDragMidPoint
- if (mDragMidPoint == NomDragMidPoint || !mSupportMouseDragging )
- return;
- ColorI greyLine(128,128,128);
- Point2F squarePt;
- // CodeReview: LineWidth is not supported in Direct3D. This is lame. [5/10/2007 Pat]
- // draw mDragMidPoint lines with a diamond
- if (mDragMidPoint == AbovemDragMidPoint)
- {
- S32 tempY = mItemHeight*mCurrentDragCell+offset.y ;
- squarePt.y = (F32)tempY;
- squarePt.x = 125.f+offset.x;
- GFX->getDrawUtil()->drawLine(0+offset.x, tempY, 250+offset.x, tempY,greyLine);
- GFX->getDrawUtil()->draw2DSquare(squarePt, 6, 90 );
- }
- if (mDragMidPoint == BelowmDragMidPoint)
- {
- S32 tempY2 = mItemHeight*(mCurrentDragCell+1) +offset.y;
- squarePt.y = (F32)tempY2;
- squarePt.x = 125.f+offset.x;
- GFX->getDrawUtil()->drawLine(0+offset.x, tempY2, 250+offset.x, tempY2,greyLine);
- GFX->getDrawUtil()->draw2DSquare(squarePt,6, 90 );
- }
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::onRenderCell(Point2I offset, Point2I cell, bool, bool )
- {
- if( !mVisibleItems.size() )
- return;
- // Do some sanity checking and data retrieval.
- AssertFatal(cell.y < mVisibleItems.size(), "GuiTreeViewCtrl::onRenderCell: invalid cell");
- Item * item = mVisibleItems[cell.y];
- // If there's no object, deal with it.
- if(item->isInspectorData())
- if(!item->getObject())
- return;
- RectI drawRect( offset, mCellSize );
- GFXDrawUtil *drawer = GFX->getDrawUtil();
- drawer->clearBitmapModulation();
- FrameAllocatorMarker txtBuff;
-
- // Ok, we have the item. There are a few possibilities at this point:
- // - We need to draw inheritance lines and a treeview-chosen icon
- // OR
- // - We have to draw an item-dependent icon
- // - If we're mouseover, we have to highlight it.
- //
- // - We have to draw the text for the item
- // - Taking into account various mouseover states
- // - Taking into account the value (set or not)
- // - If it's an inspector data, we have to do some custom rendering
- // - ADDED: If it is being renamed, we also have custom rendering.
- // Ok, first draw the tab and icon.
- // Do we draw the tree lines?
- if( mFlags.test(ShowTreeLines) )
- {
- drawRect.point.x += ( mTabSize * item->mTabLevel );
- Item* parent = item->mParent;
- for ( S32 i = item->mTabLevel; ( parent && i > 0 ); i-- )
- {
- drawRect.point.x -= mTabSize;
- if ( parent->mNext )
- drawer->drawBitmapSR( mProfile->mBitmap, drawRect.point, mProfile->mBitmapArrayRects[BmpLine] );
- parent = parent->mParent;
- }
- }
- // Now, the icon...
- drawRect.point.x = offset.x + mTabSize * item->mTabLevel;
- // First, draw the rollover glow, if it's an inner node.
- if ( item->isParent() && item->mState.test( Item::MouseOverBmp ) )
- drawer->drawBitmapSR( mProfile->mBitmap, drawRect.point, mProfile->mBitmapArrayRects[BmpGlow] );
- // Now, do we draw a treeview-selected item or an item dependent one?
- S32 newOffset = 0; // This is stored so we can render glow, then update render pos.
- S32 bitmap = 0;
- // Ok, draw the treeview lines as appropriate.
-
- bool drawBitmap = true;
- if ( !item->isParent() )
- {
- if( mFlags.test( ShowTreeLines ) )
- {
- if( ( item->mNext && item->mPrevious )
- || ( item->mNext && item->mParent && ( !_isRootLevelItem( item ) || mShowRoot ) ) )
- bitmap = BmpChild;
- else if( item->mNext && ( !item->mParent || !mShowRoot ) )
- bitmap = BmpFirstChild;
- else if( item->mPrevious || ( item->mParent && !_isRootLevelItem( item ) ) )
- bitmap = BmpLastChild;
- else
- drawBitmap = false;
- }
- else
- drawBitmap = false;
- }
- else
- {
- bitmap = item->isExpanded() ? BmpExp : BmpCon;
- if( mFlags.test( ShowTreeLines ) )
- {
- // Shift indices to show versions with tree lines.
-
- if ( item->mParent || item->mPrevious )
- bitmap += ( item->mNext ? 3 : 2 );
- else
- bitmap += ( item->mNext ? 1 : 0 );
- }
- }
- if( ( bitmap >= 0 ) && ( bitmap < mProfile->mBitmapArrayRects.size() ) )
- {
- if( drawBitmap )
- drawer->drawBitmapSR( mProfile->getBitmapResource(), drawRect.point, mProfile->mBitmapArrayRects[bitmap] );
- newOffset = mProfile->mBitmapArrayRects[bitmap].extent.x;
- }
- if(item->isInspectorData())
- {
- // draw lock icon if need be
- S32 icon = Lock1;
- S32 icon2 = Hidden;
- if (item->getObject() && item->getObject()->isLocked())
- {
- if (mIconTable[icon])
- {
- //drawRect.point.x = offset.x + mTabSize * item->mTabLevel + mIconTable[icon].getWidth();
- drawRect.point.x += mIconTable[icon].getWidth();
- drawer->drawBitmap( mIconTable[icon], drawRect.point );
- }
- }
- if (item->getObject() && item->getObject()->isHidden())
- {
- if (mIconTable[icon2])
- {
- //drawRect.point.x = offset.x + mTabSize * item->mTabLevel + mIconTable[icon].getWidth();
- drawRect.point.x += mIconTable[icon2].getWidth();
- drawer->drawBitmap( mIconTable[icon2], drawRect.point );
- }
- }
- SimObject * pObject = item->getObject();
- SimGroup * pGroup = ( pObject == NULL ) ? NULL : dynamic_cast<SimGroup*>( pObject );
- // If this item is a VirtualParent we can use the generic SimGroup123 icons.
- // However if there is already an icon in the EditorIconRegistry for this
- // exact class (not counting parent class icons) we want to use that instead.
- bool hasClassIcon = false;
- #ifdef TORQUE_TOOLS
- hasClassIcon = gEditorIcons.hasIconNoRecurse( pObject );
- #endif
- // draw the icon associated with the item
- if ( !hasClassIcon && item->mState.test(Item::VirtualParent))
- {
- if ( pGroup != NULL)
- {
- //Check if we're a SceneObject, and pick the default icon as appropriate
-
- if (pObject->getClassName() != StringTable->insert("SimGroup"))
- {
- item->mIcon = Icon31;
- }
- else
- {
- //If we're purely a SimGroup, pick our icon.
- if (item->isExpanded())
- item->mIcon = SimGroup1;
- else
- item->mIcon = SimGroup2;
- }
- }
- else
- item->mIcon = SimGroup2;
- }
-
- if ( !hasClassIcon && item->mState.test(Item::Marked))
- {
- if (item->isInspectorData())
- {
- if ( pGroup != NULL )
- {
- if (item->isExpanded())
- item->mIcon = SimGroup3;
- else
- item->mIcon = SimGroup4;
- }
- }
- }
- GFXTexHandle iconHandle;
- if ( ( item->mIcon != -1 ) && mIconTable[item->mIcon] )
- iconHandle = mIconTable[item->mIcon];
- #ifdef TORQUE_TOOLS
- else
- iconHandle = gEditorIcons.findIcon( item->getObject() );
- #endif
- if ( iconHandle.isValid() )
- {
- S32 iconHeight = (mItemHeight - iconHandle.getHeight()) / 2;
- S32 oldHeight = drawRect.point.y;
- if(iconHeight > 0)
- drawRect.point.y += iconHeight;
- drawRect.point.x += iconHandle.getWidth();
- drawer->drawBitmap( iconHandle, drawRect.point );
- drawRect.point.y = oldHeight;
- }
- }
- else
- {
- S32 icon = item->isExpanded() ? item->mScriptInfo.mExpandedImage : item->mScriptInfo.mNormalImage;
- if ( icon )
- {
- if (mIconTable[icon])
- {
- S32 iconHeight = (mItemHeight - mIconTable[icon].getHeight()) / 2;
- S32 oldHeight = drawRect.point.y;
- if(iconHeight > 0)
- drawRect.point.y += iconHeight;
- drawRect.point.x += mIconTable[icon].getWidth();
- drawer->drawBitmap( mIconTable[icon], drawRect.point );
- drawRect.point.y = oldHeight;
- }
- }
- }
- // Ok, update offset so we can render some text!
- drawRect.point.x += newOffset;
- // Ok, now we're off to rendering the actual data for the treeview item.
- U32 bufLen = 1024; //item->mDataRenderWidth + 1;
- char *displayText = (char *)txtBuff.alloc(bufLen);
- displayText[bufLen-1] = 0;
- item->getDisplayText(bufLen, displayText);
- // Draw the rollover/selected bitmap, if one was specified.
- drawRect.extent.x = mProfile->mFont->getStrWidth( displayText ) + ( 2 * mTextOffset );
- if ( item->mState.test( Item::Selected ) && mTexSelected )
- drawer->drawBitmapStretch( mTexSelected, drawRect );
- else if ( item->mState.test( Item::MouseOverText ) && mTexRollover )
- drawer->drawBitmapStretch( mTexRollover, drawRect );
- // Offset a bit so as to space text properly.
- drawRect.point.x += mTextOffset;
- // Determine what color the font should be.
- ColorI fontColor;
- fontColor = item->mState.test( Item::Selected ) ? mProfile->mFontColorSEL :
- ( item->mState.test( Item::MouseOverText ) ? mProfile->mFontColorHL : mProfile->mFontColor );
- if (item->mState.test(Item::Selected))
- {
- drawer->drawRectFill(drawRect, mProfile->mFillColorSEL);
- }
- else if (item->mState.test(Item::MouseOverText))
- {
- drawer->drawRectFill(drawRect, mProfile->mFillColorHL);
- }
- if( item->mState.test(Item::MouseOverText) )
- {
- fontColor = mProfile->mFontColorHL;
- }
- drawer->setBitmapModulation( fontColor );
- // Center the text horizontally.
- S32 height = (mItemHeight - mProfile->mFont->getHeight()) / 2;
- if(height > 0)
- drawRect.point.y += height;
- // JDD - offset by two pixels or so to keep the text from rendering RIGHT ONTOP of the outline
- drawRect.point.x += 2;
- drawer->drawText( mProfile->mFont, drawRect.point, displayText, mProfile->mFontColors );
- if ( mRenamingItem == item && mRenameCtrl )
- {
- Point2I ctrPos = globalToLocalCoord( drawRect.point );
- ctrPos.y -= height;
- ctrPos.x -= 2;
- Point2I ctrExtent( getWidth() - ctrPos.x, drawRect.extent.y );
- mRenameCtrl->setPosition( ctrPos );
- mRenameCtrl->setExtent( ctrExtent );
- mRenameCtrl->setVisible( true );
- }
- }
- //------------------------------------------------------------------------------
- bool GuiTreeViewCtrl::renderTooltip( const Point2I &hoverPos, const Point2I& cursorPos, const char* tipText )
- {
- Item* item;
- BitSet32 flags = 0;
- if( _hitTest( cursorPos, item, flags ) && (!item->mTooltip.isEmpty() || mUseInspectorTooltips) )
- {
- bool render = true;
- if( mTooltipOnWidthOnly && !item->hasObjectBasedTooltip() )
- {
- // Only render tooltip if the item's text is cut off with its
- // parent scroll control, unless there is custom object-based
- // tooltip information.
- GuiScrollCtrl *pScrollParent = dynamic_cast<GuiScrollCtrl*>( getParent() );
- if ( pScrollParent )
- {
- Point2I textStart;
- Point2I textExt;
- const Point2I pos = globalToLocalCoord(cursorPos);
- textStart.y = pos.y / mCellSize.y;
- textStart.y *= mCellSize.y;
- // The following is taken from _hitTest()
- textStart.x = mTabSize * item->mTabLevel;
- S32 image = BmpChild;
- if((image >= 0) && (image < mProfile->mBitmapArrayRects.size()))
- textStart.x += mProfile->mBitmapArrayRects[image].extent.x;
- textStart.x += mTextOffset;
- textStart.x += getInspectorItemIconsWidth( item );
- FrameAllocatorMarker txtAlloc;
- U32 bufLen = item->getDisplayTextLength() + 1;
- char *buf = (char*)txtAlloc.alloc(bufLen);
- item->getDisplayText(bufLen, buf);
- textExt.x = mProfile->mFont->getStrWidth(buf);
- textExt.y = mProfile->mFont->getHeight();
- if( pScrollParent->isRectCompletelyVisible(RectI(textStart, textExt)) )
- render = false;
- }
- }
- if( render )
- {
- if( mUseInspectorTooltips )
- {
- char buf[2048];
- item->getTooltipText( sizeof( buf ), buf );
- tipText = buf;
- }
- else
- {
- tipText = item->mTooltip.c_str();
- }
- }
- }
-
- return defaultTooltipRender( cursorPos, cursorPos, tipText );
- }
- //------------------------------------------------------------------------------
- void GuiTreeViewCtrl::clearSelection()
- {
- if( mDebug ) Con::printf( "clearSelection called" );
-
- while ( !mSelectedItems.empty() )
- {
- removeSelection( mSelectedItems.last()->mId );
- }
- mSelectedItems.clear();
- mSelected.clear();
- onClearSelection();
- onClearSelection_callback();
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::lockSelection(bool lock)
- {
- for(U32 i = 0; i < mSelectedItems.size(); i++)
- {
- if(mSelectedItems[i]->isInspectorData())
- mSelectedItems[i]->getObject()->setLocked(lock);
- }
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::hideSelection(bool hide)
- {
- for(U32 i = 0; i < mSelectedItems.size(); i++)
- {
- if(mSelectedItems[i]->isInspectorData())
- mSelectedItems[i]->getObject()->setHidden(hide);
- }
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::toggleLockSelection()
- {
- for(U32 i = 0; i < mSelectedItems.size(); i++)
- {
- if( mSelectedItems[i]->isInspectorData() )
- {
- SimObject* object = mSelectedItems[ i ]->getObject();
- object->setLocked( !object->isLocked() );
- }
- }
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::toggleHideSelection()
- {
- for(U32 i = 0; i < mSelectedItems.size(); i++)
- {
- if( mSelectedItems[i]->isInspectorData() )
- {
- SimObject* object = mSelectedItems[ i ]->getObject();
- object->setHidden( !object->isHidden() );
- }
- }
- }
- //------------------------------------------------------------------------------
- // handles icon assignments
- S32 GuiTreeViewCtrl::getIcon(const char * iconString)
- {
- return -1;
- }
- //-----------------------------------------------------------------------------
- GuiTreeViewCtrl::Item* GuiTreeViewCtrl::addInspectorDataItem(Item *parent, SimObject *obj)
- {
- S32 icon = getIcon(obj->getClassName());
- Item *item = createItem(icon);
- item->mState.set(Item::InspectorData);
- // Set the item text label flags.
-
- if( !mShowObjectIds )
- item->mState.clear( Item::ShowObjectId );
- else
- item->mState.set( Item::ShowObjectId );
- if( !mShowClassNames )
- item->mState.clear( Item::ShowClassName );
- else
- item->mState.set( Item::ShowClassName );
- if( !mShowObjectNames )
- item->mState.clear( Item::ShowObjectName );
- else
- item->mState.set( Item::ShowObjectName );
- if( !mShowInternalNames )
- item->mState.clear( Item::ShowInternalName );
- else
- item->mState.set( Item::ShowInternalName );
- if( mShowClassNameForUnnamedObjects )
- item->mState.set( Item::ShowClassNameForUnnamed );
- // Deal with child objects...
- if(dynamic_cast<SimSet*>(obj))
- item->mState.set(Item::VirtualParent);
- // Actually store the data!
- item->setObject(obj);
- // Now add us to the data structure...
- if(parent)
- {
- // Add as child of parent.
- if(parent->mChild)
- {
- Item * traverse = parent->mChild;
- while(traverse->mNext)
- traverse = traverse->mNext;
- traverse->mNext = item;
- item->mPrevious = traverse;
- }
- else
- parent->mChild = item;
- item->mParent = parent;
- }
- else
- {
- // If no parent, add to root.
- item->mNext = mRoot;
- mRoot = item;
- item->mParent = NULL;
- }
- mFlags.set(RebuildVisible);
- return item;
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::unlinkItem(Item * item)
- {
- if (item->mPrevious)
- item->mPrevious->mNext = item->mNext;
- if (item->mNext)
- item->mNext->mPrevious = item->mPrevious;
- }
- //-----------------------------------------------------------------------------
- bool GuiTreeViewCtrl::childSearch(Item * item, SimObject *obj, bool yourBaby)
- {
- Item * temp = item->mChild;
- while (temp)
- {
- //do you have my baby?
- if (temp->isInspectorData())
- {
- if (temp->getObject() == obj)
- yourBaby = false; //probably a child of an inner script
- }
- yourBaby = childSearch(temp,obj, yourBaby);
- temp = temp->mNext;
- }
- return yourBaby;
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::inspectorSearch(Item * item, Item * parent, SimSet * parentSet, SimSet * newParentSet)
- {
- if (!parentSet||!newParentSet)
- return;
- if (item == parent->mNext)
- return;
- if (item)
- {
- if (item->isInspectorData())
- {
- // remove the object from the parentSet and add it to the newParentSet
- SimObject* simObj = item->getObject();
- if (parentSet->size())
- {
- SimObject *lastObject = parentSet->last();
- parentSet->removeObject(simObj);
- parentSet->reOrder(lastObject);
- }
- else
- parentSet->removeObject(simObj);
- newParentSet->addObject(simObj);
- if (item->mNext)
- {
- inspectorSearch(item->mNext, parent, parentSet, newParentSet);
- return;
- }
- else
- {
- // end of children so backing up
- if (item->mParent == parent)
- return;
- else
- {
- inspectorSearch(item->mParent->mNext, parent, parentSet, newParentSet);
- return;
- }
- }
- }
- if (item->mChild)
- {
- inspectorSearch(item->mChild, parent, parentSet, newParentSet);
- return;
- }
- if (item->mNext)
- {
- inspectorSearch(item->mNext, parent, parentSet, newParentSet);
- return;
- }
- }
- }
- //-----------------------------------------------------------------------------
- bool GuiTreeViewCtrl::objectSearch( const SimObject *object, Item **item )
- {
- for ( U32 i = 0; i < mItems.size(); i++ )
- {
- Item *pItem = mItems[i];
- if ( !pItem )
- continue;
- //A bit hackish, but we make a special exception here for items that are named 'Components', as they're merely
- //virtual parents to act as a container to an Entity's components
- if (pItem->mScriptInfo.mText == StringTable->insert("Components"))
- continue;
- SimObject *pObj = pItem->getObject();
- if ( pObj && pObj == object )
- {
- *item = pItem;
- return true;
- }
- }
- return false;
- }
- //-----------------------------------------------------------------------------
- bool GuiTreeViewCtrl::onVirtualParentBuild(Item *item, bool bForceFullUpdate)
- {
- if(!item->mState.test(Item::InspectorData))
- return true;
- // Blast an item if it doesn't have a corresponding SimObject...
- if(item->mInspectorInfo.mObject == NULL)
- {
- removeItem(item->mId);
- return false;
- }
- // Skip the next stuff unless we're expanded...
- if(!item->isExpanded() && !bForceFullUpdate && !( item == mRoot && !mShowRoot ) )
- return true;
- // Verify that we have all the kids we should in here...
- SimSet *srcObj = dynamic_cast<SimSet*>(&(*item->mInspectorInfo.mObject));
- // If it's not a SimSet... WTF are we doing here?
- if(!srcObj)
- return true;
- // This is slow but probably ok.
- for( SimSet::iterator i = srcObj->begin(); i != srcObj->end(); ++ i )
- {
- SimObject *obj = *i;
- // If we can't find it, add it.
- // unless it has a parent that is a child that is a script
- Item *res = item->findChildByValue(obj);
- bool foundChild = true;
- // search the children. if any of them are the parent of the object then don't add it.
- foundChild = childSearch(item,obj,foundChild);
- if(!res && foundChild)
- {
- if (mDebug) Con::printf( "adding object %i to item %i", obj->getId(), item->mId );
- res = addInspectorDataItem(item, obj);
- }
-
- if( res )
- res->mState.set( Item::RebuildVisited );
- }
-
- // Go through our items and purge those that have disappeared from
- // the set.
- for( Item* ptr = item->mChild; ptr != NULL; )
- {
- Item* next = ptr->mNext;
- if( !ptr->mState.test( Item::RebuildVisited ) )
- {
- if( mDebug ) Con::printf( "removing item %i for object %i that is no longer in the set",
- ptr->mId, ptr->getObject()->getId() );
-
- removeItem( ptr->mId, false );
- }
- else
- ptr->mState.clear( Item::RebuildVisited );
-
- ptr = next;
- }
- return true;
- }
- //-----------------------------------------------------------------------------
- bool GuiTreeViewCtrl::onVirtualParentExpand(Item *item)
- {
- // Do nothing...
- return true;
- }
- //-----------------------------------------------------------------------------
- bool GuiTreeViewCtrl::onVirtualParentCollapse(Item *item)
- {
- // Do nothing...
- return true;
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::inspectObject( SimObject* obj, bool okToEdit )
- {
- _destroyTree();
- mFlags.set( IsEditable, okToEdit );
- mFlags.set( IsInspector );
- onDefineIcons_callback();
- addInspectorDataItem( NULL, obj );
- }
- //-----------------------------------------------------------------------------
- S32 GuiTreeViewCtrl::insertObject( S32 parent, SimObject* obj, bool okToEdit )
- {
- mFlags.set( IsEditable, okToEdit );
- mFlags.set( IsInspector );
- //onDefineIcons_callback();
- GuiTreeViewCtrl::Item *item = addInspectorDataItem( getItem(parent), obj );
- return item->getID();
- }
- //-----------------------------------------------------------------------------
- S32 GuiTreeViewCtrl::findItemByName(const char *name)
- {
- for (S32 i = 0; i < mItems.size(); i++)
- {
- if ( !mItems[i] )
- continue;
- if( mItems[i]->mState.test( Item::InspectorData ) )
- continue;
- if (mItems[i] && String::compare(mItems[i]->getText(),name) == 0)
- return mItems[i]->mId;
- }
- return 0;
- }
- //-----------------------------------------------------------------------------
- S32 GuiTreeViewCtrl::findItemByValue(const char *name)
- {
- for (S32 i = 0; i < mItems.size(); i++)
- {
- if (!mItems[i])
- continue;
- if( mItems[i]->mState.test( Item::InspectorData ) )
- continue;
- if (mItems[i] && String::compare(mItems[i]->getValue(),name) == 0)
- return mItems[i]->mId;
- }
- return 0;
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::sortTree( bool caseSensitive, bool traverseHierarchy, bool parentsFirst )
- {
- itemSortList( mRoot, caseSensitive, traverseHierarchy, parentsFirst );
- }
- //-----------------------------------------------------------------------------
- StringTableEntry GuiTreeViewCtrl::getTextToRoot( S32 itemId, const char * delimiter )
- {
- Item * item = getItem(itemId);
- if(!item)
- {
- Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::getTextToRoot: invalid start item id!");
- return StringTable->EmptyString();
- }
- if(item->isInspectorData())
- {
- Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::getTextToRoot: cannot get text to root of inspector data items");
- return StringTable->EmptyString();
- }
- char bufferOne[1024];
- char bufferTwo[1024];
- char bufferNodeText[128];
- dMemset( bufferOne, 0, sizeof(bufferOne) );
- dMemset( bufferTwo, 0, sizeof(bufferTwo) );
- dStrcpy( bufferOne, item->getText(), 1024 );
- Item *prevNode = item->mParent;
- while ( prevNode )
- {
- dMemset( bufferNodeText, 0, sizeof(bufferNodeText) );
- dStrcpy( bufferNodeText, prevNode->getText(), 128 );
- dSprintf( bufferTwo, 1024, "%s%s%s",bufferNodeText, delimiter, bufferOne );
- dStrcpy( bufferOne, bufferTwo, 1024 );
- dMemset( bufferTwo, 0, sizeof(bufferTwo) );
- prevNode = prevNode->mParent;
- }
- // Return the result, StringTable-ized.
- return StringTable->insert( bufferOne, true );
- }
- //-----------------------------------------------------------------------------
- void GuiTreeViewCtrl::setFilterText( const String& text )
- {
- mFilterText = text;
- // Trigger rebuild.
- mFlags.set( RebuildVisible );
- }
- void GuiTreeViewCtrl::setItemFilterException(U32 item, bool isExempted)
- {
- if (isExempted)
- {
- mItemFilterExceptionList.push_back(item);
- }
- else
- {
- mItemFilterExceptionList.remove(item);
- }
- }
- void GuiTreeViewCtrl::setItemHidden(U32 item, bool isHidden)
- {
- if (isHidden)
- {
- mHiddenItemsList.push_back(item);
- }
- else
- {
- mHiddenItemsList.remove(item);
- }
- }
- void GuiTreeViewCtrl::reparentItems(Vector<Item*> selectedItems, Item* newParent)
- {
- for (S32 i = 0; i < selectedItems.size(); i++)
- {
- Item* item = selectedItems[i];
- if (mDebug)
- Con::printf("----------------------------");
- // clear old highlighting of the item
- item->mState.clear(Item::MouseOverBmp | Item::MouseOverText);
- // move the selected item to the newParent
- Item * oldParent = item->mParent;
- // Snag the current parent set if any for future reference
- SimSet * parentSet = NULL;
- if (oldParent != nullptr && oldParent->isInspectorData())
- {
- parentSet = dynamic_cast<SimSet*>(oldParent->getObject());
- }
- else
- {
- // parent is probably script data so we search up the tree for a
- // set to put our object in
- Item* temp = oldParent;
- while (temp)
- {
- if (temp->isInspectorData())
- break;
- temp = temp->mParent;
- }
- // found an ancestor who is an inspectorData
- if (temp)
- {
- if (temp->isInspectorData())
- parentSet = dynamic_cast<SimSet*>(temp->getObject());
- }
- }
- // unlink from the current position in the list
- unlinkItem(item);
- // update the parent's children
- // check if we an only child
- if (item->mParent && item->mParent->mChild == item)
- {
- if (item->mNext)
- item->mParent->mChild = item->mNext;
- else
- item->mParent->mChild = NULL;
- }
- if (mDragMidPoint != NomDragMidPoint)
- {
- //if it is below an expanded tree, place as last item in the tree
- //if it is below a parent who isn't expanded put below it
- // position the item above or below another item
- if (mDragMidPoint == AbovemDragMidPoint)
- {
- // easier to treat everything as "Below the mDragMidPoint" so make some adjustments
- if (mDebug)
- Con::printf("adding item above mDragMidPoint");
- // above the mid point of an item, so grab either the parent
- // or the previous sibling
- // does the item have a previous sibling?
- if (newParent->mPrevious)
- {
- newParent = newParent->mPrevious;
- if (mDebug)
- Con::printf("treating as if below an item that isn't expanded");
- // otherwise add below that item as a sibling
- item->mParent = newParent->mParent;
- item->mPrevious = newParent;
- item->mNext = newParent->mNext;
- if (newParent->mNext)
- newParent->mNext->mPrevious = item;
- newParent->mNext = item;
- }
- else
- {
- if (mDebug)
- Con::printf("treating as if adding below the parent of the item");
- // instead we add as the first item below the newParent's parent
- item->mParent = newParent->mParent;
- item->mNext = newParent;
- item->mPrevious = NULL;
- newParent->mPrevious = item;
- item->mParent->mChild = item;
- }
- }
- else if (mDragMidPoint == BelowmDragMidPoint)
- {
- if ((newParent->isParent()) && (newParent->isExpanded()))
- {
- if (mDebug)
- Con::printf("adding item to an expanded parent below the mDragMidPoint");
- item->mParent = newParent;
- // then add the new item as a child
- item->mNext = newParent->mChild;
- if (newParent->mChild)
- newParent->mChild->mPrevious = item;
- item->mParent->mChild = item;
- item->mPrevious = NULL;
- }
- else if ((!newParent->mNext) && (newParent->mParent) && (newParent->mParent->mParent))
- {
- // add below it's parent.
- if (mDebug)
- Con::printf("adding below a tree");
- item->mParent = newParent->mParent->mParent;
- item->mNext = newParent->mParent->mNext;
- item->mPrevious = newParent->mParent;
- if (newParent->mParent->mNext)
- newParent->mParent->mNext->mPrevious = item;
- newParent->mParent->mNext = item;
- }
- else
- {
- // adding below item not as a child
- if (mDebug)
- Con::printf("adding item below the mDragMidPoint of an item");
- item->mParent = newParent->mParent;
- // otherwise the item is a sibling
- if (newParent->mNext)
- newParent->mNext->mPrevious = item;
- item->mNext = newParent->mNext;
- item->mPrevious = newParent;
- newParent->mNext = item;
- }
- }
- }
- // if we're not allowed to add to items, then try to add to the parent of the hit item.
- // if we are, just add to the item we hit.
- else
- {
- if (mDebug)
- {
- if (item->isInspectorData() && item->getObject())
- Con::printf("Item: %i", item->getObject()->getId());
- if (newParent->isInspectorData() && newParent->getObject())
- Con::printf("Parent: %i", newParent->getObject()->getId());
- Con::printf("dragged onto an item");
- }
- // If the hit item is not a valid drag target,
- // then try to add to the parent.
- if (!isValidDragTarget(newParent))
- {
- // add to the item's parent.
- if (!newParent->mParent || !newParent->mParent->isParent())
- {
- if (mDebug)
- Con::printf("could not find the parent of that item. dragging to an item is not allowed, kicking out.");
- mDragMidPoint = NomDragMidPoint;
- continue;
- }
- newParent = newParent->mParent;
- }
- // new parent is the item in the current cell
- item->mParent = newParent;
- // adjust children if any
- if (newParent->mChild)
- {
- if (mDebug) Con::printf("not the first child");
- // put it at the top of the list (easier to find if there are many children)
- if (newParent->mChild)
- newParent->mChild->mPrevious = item;
- item->mNext = newParent->mChild;
- newParent->mChild = item;
- item->mPrevious = NULL;
- }
- else
- {
- if (mDebug) Con::printf("first child");
- // only child
- newParent->mChild = item;
- item->mNext = NULL;
- item->mPrevious = NULL;
- }
- }
- // expand the item we added to, if it isn't expanded already
- if (!item->mParent->mState.test(Item::Expanded))
- setItemExpanded(item->mParent->mId, true);
- //----------------------------------------------------------------
- // handle objects
- // Get our active SimObject if any
- SimObject* simObj = NULL;
- if (item->isInspectorData())
- {
- simObj = item->getObject();
- }
- // Remove from the old parentset
- if ((simObj && parentSet) && (oldParent != item->mParent))
- {
- if (mDebug)
- Con::printf("removing item from old parentset");
- // hack to get around the way removeObject takes the last item of the set
- // and moves it into the place of the object we removed
- if (parentSet->size() > 0)
- {
- SimObject* lastObject = parentSet->last();
- parentSet->removeObject(simObj);
- parentSet->reOrder(lastObject);
- }
- else
- {
- parentSet->removeObject(simObj);
- }
- }
- // Snag the newparent set if any...
- SimSet* newParentSet = NULL;
- if (item->mParent->isInspectorData())
- {
- if (mDebug)
- Con::printf("getting a new parent set");
- SimObject* tmpObj = item->mParent->getObject();
- newParentSet = dynamic_cast<SimSet*>(tmpObj);
- }
- else
- {
- // parent is probably script data so we search up the tree for a
- // set to put our object in
- if (mDebug)
- Con::printf("oh nos my parent is script!");
- Item* temp = item->mParent;
- while (temp)
- {
- if (temp->isInspectorData())
- break;
- temp = temp->mParent;
- }
- // found a ancestor who is an inspectorData
- if (temp)
- {
- if (temp->isInspectorData())
- newParentSet = dynamic_cast<SimSet*>(temp->getObject());
- }
- else
- {
- newParentSet = NULL;
- }
- }
- if (simObj && newParentSet)
- {
- if (mDebug)
- Con::printf("simobj and new ParentSet");
- if (oldParent != item->mParent)
- newParentSet->addObject(simObj);
- //order the objects in the simset according to their
- //order in the tree view control
- if (!item->mNext)
- {
- if (item->mPrevious)
- {
- //bring to the end of the set
- SimObject* prevObject = item->mPrevious->getObject();
- if (prevObject && item->getObject())
- {
- newParentSet->reOrder(item->getObject(), prevObject);
- }
- }
- }
- else
- {
- //reorder within the set
- SimObject* nextObject = item->mNext->getObject();
- if (nextObject && item->getObject())
- {
- newParentSet->reOrder(item->getObject(), nextObject);
- }
- }
- }
- else if (!simObj && newParentSet)
- {
- // our current item is script data. but it may have children who
- // is inspector data who need an updated set
- if (mDebug)
- Con::printf("no simobj but new parentSet");
- if (item->mChild)
- inspectorSearch(item->mChild, item, parentSet, newParentSet);
- }
- else if (simObj && !newParentSet)
- {
- if (mDebug)
- Con::printf("simobject and no new parent set");
- }
- else
- if (mDebug)
- Con::printf("no simobject and no new parent set");
- // Notify script.
- if (item->isInspectorData())
- {
- if (item->getObject() && (oldParent && oldParent->getObject()) && item->mParent->getObject())
- onReparent_callback(
- item->getObject()->getId(),
- oldParent->getObject()->getId(),
- item->mParent->getObject()->getId()
- );
- }
- else
- {
- onReparent_callback(
- item->mId,
- oldParent->mId,
- item->mParent->mId
- );
- }
- }
- }
- S32 GuiTreeViewCtrl::getTabLevel(S32 itemId)
- {
- Item* item = getItem(itemId);
- if (item != nullptr)
- {
- return item->mTabLevel;
- }
- return 0;
- }
- //=============================================================================
- // Console Methods.
- //=============================================================================
- // MARK: ---- Console Methods ----
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTreeViewCtrl, findItemByName, S32, ( const char* text ),,
- "Get the ID of the item whose text matches the given @a text.\n\n"
- "@param text Item text to match.\n"
- "@return ID of the item or -1 if no item matches the given text." )
- {
- return object->findItemByName( text );
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTreeViewCtrl, findItemByValue, S32, ( const char* value ),,
- "Get the ID of the item whose value matches @a value.\n\n"
- "@param value Value text to match.\n"
- "@return ID of the item or -1 if no item has the given value." )
- {
- return object->findItemByValue( value );
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTreeViewCtrl, findChildItemByName, S32, ( S32 parentId, const char* childName ),,
- "Get the child item of the given parent item whose text matches @a childName.\n\n"
- "@param parentId Item ID of the parent in which to look for the child.\n"
- "@param childName Text of the child item to find.\n"
- "@return ID of the child item or -1 if no child in @a parentId has the given text @a childName.\n\n"
- "@note This method does not recurse, i.e. it only looks for direct children." )
- {
- if( parentId == 0 )
- {
- if( !object->getRootItem() )
- return 0;
-
- GuiTreeViewCtrl::Item* root = object->getRootItem();
- while( root )
- {
- if( dStricmp( root->getText(), childName ) == 0 )
- return root->getID();
-
- root = root->mNext;
- }
-
- return 0;
- }
- else
- {
- GuiTreeViewCtrl::Item* item = object->getItem( parentId );
-
- if( !item )
- {
- Con::errorf( "GuiTreeViewCtrl.findChildItemByName - invalid parent ID '%i'", parentId );
- return 0;
- }
-
- GuiTreeViewCtrl::Item* child = item->findChildByName( childName );
- if( !child )
- return 0;
-
- return child->mId;
- }
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTreeViewCtrl, insertItem, S32, ( S32 parentId, const char* text, const char* value, const char* icon, S32 normalImage, S32 expandedImage ), ( "", "", 0, 0 ),
- "Add a new item to the tree.\n\n"
- "@param parentId Item ID of parent to which to add the item as a child. 0 is root item.\n"
- "@param text Text to display on the item in the tree.\n"
- "@param value Behind-the-scenes value of the item.\n"
- "@param icon\n"
- "@param normalImage\n"
- "@param expandedImage\n"
- "@return The ID of the newly added item." )
- {
- return object->insertItem( parentId, text, value, icon, normalImage, expandedImage );
- }
- DefineEngineMethod( GuiTreeViewCtrl, insertObject, S32, ( S32 parentId, SimObject* obj, bool OKToEdit ), (false), "Inserts object as a child to the given parent." )
- {
- return object->insertObject(parentId, obj, OKToEdit);
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTreeViewCtrl, lockSelection, void, ( bool lock ), ( true ),
- "Set whether the current selection can be changed by the user or not.\n\n"
- "@param lock If true, the current selection is frozen and cannot be changed. If false, "
- "the selection may be modified." )
- {
- object->lockSelection( lock );
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTreeViewCtrl, hideSelection, void, ( bool state ), ( true ),
- "Call SimObject::setHidden( @a state ) on all objects in the current selection.\n\n"
- "@param state Visibility state to set objects in selection to." )
- {
- object->hideSelection( state );
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTreeViewCtrl, toggleLockSelection, void, (),,
- "Toggle the locked state of all objects in the current selection." )
- {
- object->toggleLockSelection();
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTreeViewCtrl, toggleHideSelection, void, (),,
- "Toggle the hidden state of all objects in the current selection." )
- {
- object->toggleHideSelection();
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTreeViewCtrl, clearSelection, void, (),,
- "Unselect all currently selected items." )
- {
- object->clearSelection();
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTreeViewCtrl, deleteSelection, void, (),,
- "Delete all items/objects in the current selection." )
- {
- object->deleteSelection();
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTreeViewCtrl, addSelection, void, ( S32 id, bool isLastSelection ), ( true ),
- "Add an item/object to the current selection.\n\n"
- "@param id ID of item/object to add to the selection.\n"
- "@param isLastSelection Whether there are more pending items/objects to be added to the selection. If false, "
- "the control will defer refreshing the tree and wait until addSelection() is called with this parameter set "
- "to true." )
- {
- object->addSelection( id, isLastSelection, isLastSelection );
- }
- DefineEngineMethod( GuiTreeViewCtrl, addChildSelectionByValue, void, ( S32 parentId, const char* value), ,
- "Add a child selection by it's value.\n\n"
- "@param parentId Parent TreeItemId.\n"
- "@param value Value to search for.\n")
- {
- GuiTreeViewCtrl::Item* parentItem = object->getItem(parentId);
- GuiTreeViewCtrl::Item* child = parentItem->findChildByValue(value);
- object->addSelection(child->getID());
- }
- DefineEngineMethod( GuiTreeViewCtrl, removeSelection, void, ( S32 itemId), ,
- "Deselect an item or remove it from the selection.\n\n"
- "@param itemId Item Id to deselect.\n")
- {
- object->removeSelection(itemId);
- }
- DefineEngineMethod( GuiTreeViewCtrl, removeChildSelectionByValue, void, ( S32 parentId, const char* value), ,
- "Deselect a child item or remove it from the selection based on its parent and its value.\n\n"
- "@param parentId Parent TreeItemId.\n"
- "@param value Value to search for.\n"
- "@param performCallback True to notify script of the change, false to not.\n")
- {
- GuiTreeViewCtrl::Item* parentItem = object->getItem(parentId);
- if(parentItem)
- {
- GuiTreeViewCtrl::Item* child = parentItem->findChildByValue(value);
- if(child)
- {
- object->removeSelection(child->getID());
- }
- }
- }
- DefineEngineMethod( GuiTreeViewCtrl, selectItem, bool, ( S32 itemID, bool select), (true) ,
- "Select or deselect and item.\n\n"
- "@param itemID TreeItemId of item to select or deselect.\n"
- "@param select True to select the item, false to deselect it.\n"
- "@return True if it was successful, false if not.")
- {
- return object->setItemSelected(itemID, select);
- }
- DefineEngineMethod( GuiTreeViewCtrl, expandItem, bool, ( S32 itemID, bool expand), (true) ,
- "Expand/contract item, item's sub-tree.\n\n"
- "@param itemID TreeItemId of item to expand or contract.\n"
- "@param expand True to expand the item, false to contract it.\n"
- "@return True if it was successful, false if not.")
- {
- return(object->setItemExpanded(itemID, expand));
- }
- DefineEngineMethod( GuiTreeViewCtrl, markItem, bool, ( S32 itemID, bool mark), (true) ,
- "Mark/unmark item.\n\n"
- "@param itemID TreeItemId of item to Mark or unmark.\n"
- "@param mark True to Mark the item, false to unmark it.\n"
- "@return True if it was successful, false if not.")
- {
- return object->markItem(itemID, mark);
- }
- DefineEngineMethod( GuiTreeViewCtrl, scrollVisible, bool, ( S32 itemID), ,
- "Make the given item visible.\n\n"
- "@param itemID TreeItemId of item to scroll to/make visible.\n"
- "@return True if it was successful, false if not.")
- {
- return object->scrollVisible(itemID);
- }
- DefineEngineMethod( GuiTreeViewCtrl, buildIconTable, bool, ( const char* icons), ,
- "Builds an icon table.\n\n"
- "@param icons Name of icons to build, Icons should be designated by the bitmap/png file names (minus the file extensions)"
- "and separated by colons (:). This list should be synchronized with the Icons enum\n"
- "@return True if it was successful, false if not.")
- {
- return object->buildIconTable(icons);
- }
- DefineEngineMethod( GuiTreeViewCtrl, open, void, ( const char * objName, bool okToEdit), (true),
- "Set the root of the tree view to the specified object, or to the root set.\n\n"
- "@param objName Name or id of SimSet or object to set the tree root equal to.\n")
- {
- SimSet *treeRoot = NULL;
- SimObject* target = Sim::findObject(objName);
- if (target)
- treeRoot = dynamic_cast<SimSet*>(target);
- if (! treeRoot)
- Sim::findObject(RootGroupId, treeRoot);
- object->inspectObject(treeRoot,okToEdit);
- }
- DefineEngineMethod( GuiTreeViewCtrl, setItemTooltip, bool, ( S32 itemId, const char* tooltip), ,
- "Set the tooltip to show for the given item.\n\n"
- "@param itemId TreeItemID of item to set the tooltip for.\n"
- "@param tooltip String tooltip to set for the item."
- "@return True if successfully found the item, false if not")
- {
- GuiTreeViewCtrl::Item* item = object->getItem( itemId );
- if( !item )
- {
- Con::errorf( "GuiTreeViewCtrl::setTooltip() - invalid item id '%i'", itemId );
- return false;
- }
- item->mTooltip = tooltip;
- return true;
- }
- DefineEngineMethod( GuiTreeViewCtrl, setItemImages, void, ( S32 itemId, S8 normalImage, S8 expandedImage ), ,
- "Sets the normal and expanded images to show for the given item.\n\n"
- "@param itemId TreeItemID of item to set images for.\n"
- "@param normalImage Normal image to set for the given item."
- "@param expandedImage Expanded image to set for the given item.")
- {
- GuiTreeViewCtrl::Item* item = object->getItem( itemId );
- if( !item )
- {
- Con::errorf( "GuiTreeViewCtrl::setItemImages() - invalid item id '%i'", itemId );
- return;
- }
- item->setNormalImage(normalImage);
- item->setExpandedImage(expandedImage);
- }
- DefineEngineMethod( GuiTreeViewCtrl, isParentItem, bool, ( S32 itemId ), ,
- "Returns true if the given item contains child items.\n\n"
- "@param itemId TreeItemID to check for children.\n"
- "@return True if the given item contains child items, false if not.")
- {
- if( !itemId && object->getItemCount() )
- return true;
-
- GuiTreeViewCtrl::Item* item = object->getItem( itemId );
- if( !item )
- {
- Con::errorf( "GuiTreeViewCtrl::isParentItem - invalid item id '%i'", itemId );
- return false;
- }
-
- return item->isParent();
- }
- DefineEngineMethod( GuiTreeViewCtrl, getItemText, const char *, ( S32 itemId ), ,
- "Gets the text for a given item.\n\n"
- "@param itemId TreeItemID to get text of.\n"
- "@return Text for a given item.")
- {
- return(object->getItemText(itemId));
- }
- DefineEngineMethod( GuiTreeViewCtrl, getItemValue, const char *, ( S32 itemId ), ,
- "Gets the value for a given item.\n\n"
- "@param itemId TreeItemID to get value of.\n"
- "@return Value for a given item.")
- {
- return object->getItemValue(itemId);
- }
- DefineEngineMethod( GuiTreeViewCtrl, editItem, bool, ( S32 itemId, const char* newText, const char* newValue ), ,
- "Edits the text and value for a given tree item.\n\n"
- "@param itemId TreeItemID to edit.\n"
- "@return True if successful, false if not.")
- {
- return(object->editItem(itemId, newText, newValue));
- }
- DefineEngineMethod( GuiTreeViewCtrl, removeItem, bool, (S32 itemId, bool deleteObjects), (0, true),
- "Remove an item from the tree with the given id.\n\n"
- "@param itemId TreeItemID of item to remove.\n"
- "@param deleteObjects Whether the object on the item is deleted when the item is.\n"
- "@return True if successful, false if not.")
- {
- return(object->removeItem(itemId, deleteObjects));
- }
- DefineEngineMethod( GuiTreeViewCtrl, removeAllChildren, void, (S32 itemId), ,
- "Remove all children of an item from the tree with the given id.\n\n"
- "@param itemId TreeItemID of item that has children we should remove.\n")
- {
- object->removeAllChildren(itemId);
- }
- DefineEngineMethod( GuiTreeViewCtrl, clear, void, (), ,
- "Empty the tree.\n")
- {
- object->removeItem(0);
- }
- DefineEngineMethod( GuiTreeViewCtrl, getFirstRootItem, S32, (), ,
- "Get id for root item.\n"
- "@return Id for root item.")
- {
- return(object->getFirstRootItem());
- }
- DefineEngineMethod( GuiTreeViewCtrl, getChild, S32, (S32 itemId), ,
- "Get the child of the parent with the given id.\n\n"
- "@param itemId TreeItemID of item that a child we should get.\n"
- "@return Id of child of given item.")
- {
- return(object->getChildItem(itemId));
- }
- DefineEngineMethod( GuiTreeViewCtrl, buildVisibleTree, void, (bool forceFullUpdate), (false),
- "Build the visible tree.\n\n"
- "@param forceFullUpdate True to force a full update of the tree, false to only update the new stuff.\n")
- {
- object->buildVisibleTree( forceFullUpdate );
- }
- //FIXME: [rene 11/09/09 - This clashes with GuiControl.getParent(); bad thing; should be getParentItem]
- DefineEngineMethod( GuiTreeViewCtrl, getParentItem, S32, (S32 itemId), ,
- "Get the parent of a given id in the tree.\n\n"
- "@param itemId TreeItemID of item that has a parent we should get.\n"
- "@return Id of parent of given item.")
- {
- return(object->getParentItem(itemId));
- }
- DefineEngineMethod( GuiTreeViewCtrl, getNextSibling, S32, (S32 itemId), ,
- "Get the next sibling of the given item id in the tree.\n\n"
- "@param itemId TreeItemID of item that we want the next sibling of.\n"
- "@return Id of next sibling of the given item.")
- {
- return(object->getNextSiblingItem(itemId));
- }
- DefineEngineMethod( GuiTreeViewCtrl, getPrevSibling, S32, (S32 itemId), ,
- "Get the previous sibling of the given item id in the tree.\n\n"
- "@param itemId TreeItemID of item that we want the previous sibling of.\n"
- "@return Id of previous sibling of the given item.")
- {
- return(object->getPrevSiblingItem(itemId));
- }
- DefineEngineMethod( GuiTreeViewCtrl, getItemCount, S32, (), ,
- "Get the total number of items in the tree or item count.\n\n"
- "@return total number of items in the tree.")
- {
- return(object->getItemCount());
- }
- DefineEngineMethod( GuiTreeViewCtrl, getSelectedItem, S32, (S32 index), (0),
- "Return the selected item at the given index.\n\n"
- "@param index Given index to look for selected item."
- "@return selected item at the given index.")
- {
- return ( object->getSelectedItem( index ) );
- }
- DefineEngineMethod( GuiTreeViewCtrl, getSelectedObject, S32, (S32 index), (0),
- "Return the currently selected SimObject at the given index in inspector mode or -1.\n\n"
- "@param index Given index to look for selected object."
- "@return currently selected SimObject at the given index in inspector mode or -1.")
- {
- GuiTreeViewCtrl::Item *item = object->getItem( object->getSelectedItem( index ) );
- if( item != NULL && item->isInspectorData() )
- {
- SimObject *obj = item->getObject();
- if( obj != NULL )
- return obj->getId();
- }
- return -1;
- }
- const char* GuiTreeViewCtrl::getSelectedObjectList()
- {
- static const U32 bufSize = 1024;
- char* buff = Con::getReturnBuffer(bufSize);
- dSprintf(buff,bufSize,"");
- const Vector< GuiTreeViewCtrl::Item* > selectedItems = this->getSelectedItems();
- for(S32 i = 0; i < selectedItems.size(); i++)
- {
- GuiTreeViewCtrl::Item *item = selectedItems[i];
- if ( item->isInspectorData() && item->getObject() )
- {
- S32 id = item->getObject()->getId();
- //get the current length of the buffer
- U32 len = dStrlen(buff);
- //the start of the buffer where we want to write
- char* buffPart = buff+len;
- //the size of the remaining buffer (-1 cause dStrlen doesn't count the \0)
- S32 size = bufSize-len-1;
- //write it:
- if(size < 1)
- {
- Con::errorf("GuiTreeViewCtrl::getSelectedItemList - Not enough room to return our object list");
- return buff;
- }
- dSprintf(buffPart,size,"%d ", id);
- }
- }
- return buff;
- }
- DefineEngineMethod( GuiTreeViewCtrl, getSelectedObjectList, const char*, (), ,
- "Returns a space separated list of all selected object ids.\n\n"
- "@return space separated list of all selected object ids.")
- {
- return object->getSelectedObjectList();
- }
- DefineEngineMethod( GuiTreeViewCtrl, moveItemUp, void, (S32 itemId), ,
- "Move the specified item up in the tree.\n\n"
- "@param itemId TreeItemId of item to move up in the tree.")
- {
- object->moveItemUp( itemId );
- }
- DefineEngineMethod( GuiTreeViewCtrl, getSelectedItemsCount, S32, (), ,
- "Get the selected number of items.\n\n"
- "@return number of selected items.")
- {
- return ( object->getSelectedItemsCount() );
- }
- DefineEngineMethod( GuiTreeViewCtrl, moveItemDown, void, (S32 itemId), ,
- "Move the specified item down in the tree.\n\n"
- "@param itemId TreeItemId of item to move down in the tree.")
- {
- object->moveItemDown( itemId );
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTreeViewCtrl, getTextToRoot, const char*, (S32 itemId, const char* delimiter), (""),
- "Gets the text from the current node to the root, concatenating at each branch upward, with a specified delimiter optionally.\n\n"
- "@param itemId TreeItemId of node to start at."
- "@param delimiter (Optional) delimiter to use between each branch concatenation."
- "@return text from the current node to the root.")
- {
- if (!String::compare(delimiter, "" ))
- {
- Con::warnf("GuiTreeViewCtrl::getTextToRoot - Invalid number of arguments!");
- return ("");
- }
- return object->getTextToRoot( itemId, delimiter );
- }
- DefineEngineMethod( GuiTreeViewCtrl, getSelectedItemList, const char*, (), ,
- "Returns a space separated list if ids of all selected items.\n\n"
- "@return space separated list of selected item ids.")
- {
- const U32 bufSize = 1024;
- char* buff = Con::getReturnBuffer(bufSize);
- dSprintf(buff, bufSize, "");
- const Vector< S32 >& selected = object->getSelected();
- for(int i = 0; i < selected.size(); i++)
- {
- S32 id = selected[i];
- //get the current length of the buffer
- U32 len = dStrlen(buff);
- //the start of the buffer where we want to write
- char* buffPart = buff+len;
- //the size of the remaining buffer (-1 cause dStrlen doesn't count the \0)
- S32 size = bufSize-len-1;
- //write it:
- if(size < 1)
- {
- Con::errorf("GuiTreeViewCtrl::getSelectedItemList - Not enough room to return our object list");
- return buff;
- }
- dSprintf(buffPart,size,"%d ", id);
- }
- //mSelected
- return buff;
- }
- S32 GuiTreeViewCtrl::findItemByObjectId(S32 iObjId)
- {
- for (S32 i = 0; i < mItems.size(); i++)
- {
- if ( !mItems[i] )
- continue;
- SimObject* pObj = mItems[i]->getObject();
- if( pObj && pObj->getId() == iObjId )
- return mItems[i]->mId;
- }
- return -1;
- }
- //------------------------------------------------------------------------------
- DefineEngineMethod( GuiTreeViewCtrl, findItemByObjectId, S32, (S32 objectId), ,
- "Find an item by its object id and returns the Tree Item ID for it.\n\n"
- "@param objectId Object id you want the item id for."
- "@return Tree Item Id for the given object ID.")
- {
- return(object->findItemByObjectId(objectId));
- }
- //------------------------------------------------------------------------------
- S32 GuiTreeViewCtrl::getItemObject(S32 itemId)
- {
- GuiTreeViewCtrl::Item* item = getItem(itemId);
- if (!item)
- {
- return 0;
- }
- SimObject* pObj = item->getObject();
- if (pObj)
- return pObj->getId();
- return 0;
- }
- //------------------------------------------------------------------------------
- DefineEngineMethod(GuiTreeViewCtrl, getItemObject, S32, (S32 itemId), ,
- "Gets the object for a particular item.\n\n"
- "@param itemId Item id you want the object id for."
- "@return Object Id for the given tree item ID.")
- {
- return(object->getItemObject(itemId));
- }
- //------------------------------------------------------------------------------
- bool GuiTreeViewCtrl::scrollVisibleByObjectId(S32 objID)
- {
- S32 itemID = findItemByObjectId(objID);
- if(itemID == -1)
- {
- // we did not find the item in our current items
- // we should try to find and show the parent of the item.
- SimObject *obj = Sim::findObject(objID);
- if(!obj || !obj->getGroup())
- return false;
-
- // if we can't show the parent, we fail.
- if(! scrollVisibleByObjectId(obj->getGroup()->getId()) )
- return false;
-
- // get the parent. expand the parent. rebuild the tree. this ensures that
- // we'll be able to find the child item we're targeting.
- S32 parentID = findItemByObjectId(obj->getGroup()->getId());
- AssertFatal(parentID != -1, "We were able to show the parent, but could not then find the parent. This should not happen.");
- Item *parentItem = getItem(parentID);
- parentItem->setExpanded(true);
- buildVisibleTree();
-
- // NOW we should be able to find the object. if not... something's wrong.
- itemID = findItemByObjectId(objID);
- AssertWarn(itemID != -1,"GuiTreeViewCtrl::scrollVisibleByObjectId() found the parent, but can't find it's immediate child. This should not happen.");
- if(itemID == -1)
- return false;
- }
-
- // ok, item found. scroll to it.
- mFlags.set( RebuildVisible );
- scrollVisible(itemID);
-
- return true;
- }
- //------------------------------------------------------------------------------
- DefineEngineMethod( GuiTreeViewCtrl, scrollVisibleByObjectId, S32, (S32 objectId), ,
- "Show item by object id.\n\n"
- "@param objectId Object id you want to scroll to."
- "@return True if successful, false if not.")
- {
- return(object->scrollVisibleByObjectId(objectId));
- }
- //------------------------------------------------------------------------------
- //FIXME: this clashes with SimSet.sort()
- DefineEngineMethod( GuiTreeViewCtrl, sort, void, (S32 parentId, bool traverseHierarchy, bool parentsFirst, bool caseSensitive), (0, false, false, true),
- "Sorts all items of the given parent (or root). With 'hierarchy', traverses hierarchy."
- "@param parentId TreeItemID of parent/root to sort all the items under. Use 0 to sort the entire tree."
- "@param traverseHierarchy True to traverse the hierarchy, false to not."
- "@param parentsFirst True to sort the parents first."
- "@param caseSensitive True to pay attention to case, false to ignore it.")
- {
-
- if( !parentId )
- object->sortTree( caseSensitive, traverseHierarchy, parentsFirst );
- else
- {
- GuiTreeViewCtrl::Item* item = object->getItem( parentId );
- if( !item )
- {
- Con::errorf( "GuiTreeViewCtrl::sort - no item '%i' in tree", parentId );
- return;
- }
-
- item->sort( caseSensitive, traverseHierarchy, parentsFirst );
- }
- }
- void GuiTreeViewCtrl::cancelRename()
- {
- if ( !mRenamingItem || !mRenameCtrl )
- return;
- mRenamingItem = NULL;
- if ( mRenameCtrl )
- mRenameCtrl->clearFirstResponder();
- }
- void GuiTreeViewCtrl::onRenameValidate()
- {
- if ( !mRenamingItem || !mRenameCtrl )
- return;
- char data[ GuiTextCtrl::MAX_STRING_LENGTH+1 ];
- mRenameCtrl->getText( data );
- SimObject *obj = mRenamingItem->getObject();
- mRenamingItem = NULL;
- // Object could have been deleted in the interum.
- if ( !obj )
- return;
-
- if( isMethod( "handleRenameObject" ) && handleRenameObject_callback( data, obj ) )
- return;
- if ( mRenameInternal )
- obj->setInternalName( data );
- else
- #ifdef TORQUE_TOOLS
- if ( validateObjectName( data, obj ) )
- #endif
- obj->assignName( data );
- }
- void GuiTreeViewCtrl::showItemRenameCtrl( Item* item )
- {
- SimObject *renameObj = item->getObject();
-
- mRenamingItem = item;
-
- if ( !mRenameCtrl )
- {
- mRenameCtrl = new GuiTextEditCtrl;
- mRenameCtrl->registerObject();
- addObject( mRenameCtrl );
-
- if ( mRenameInternal )
- mRenameCtrl->setText( renameObj->getInternalName() );
- else
- mRenameCtrl->setText( renameObj->getName() );
- mRenameCtrl->setFirstResponder();
- mRenameCtrl->setSinkAllKeys(true);
- mRenameCtrl->selectAllText();
- mRenameCtrl->setCursorPos(0);
-
- char cmd[256];
- dSprintf( cmd, 256, "%i.onRenameValidate();", getId() );
- mRenameCtrl->setField( "validate", cmd );
- dSprintf( cmd, 256, "%i.cancelRename();", getId() );
- mRenameCtrl->setField( "escapeCommand", cmd );
- }
- }
- DefineEngineMethod( GuiTreeViewCtrl, cancelRename, void, (), , "Cancel renaming an item (For internal use).")
- {
- object->cancelRename();
- }
- DefineEngineMethod( GuiTreeViewCtrl, onRenameValidate, void, (), , "Validate the new name for an object (For internal use).")
- {
- object->onRenameValidate();
- }
- DefineEngineMethod( GuiTreeViewCtrl, showItemRenameCtrl, void, (S32 itemId), ,
- "Show the rename text field for the given item (only one at a time)."
- "@param itemId TreeItemId of item to show rename text field for.")
- {
- GuiTreeViewCtrl::Item* item = object->getItem( itemId );
- if( !item )
- {
- Con::errorf( "GuiTreeViewCtrl::showItemRenameCtrl - invalid item id '%i'", itemId );
- return;
- }
-
- object->showItemRenameCtrl( item );
- }
- DefineEngineMethod( GuiTreeViewCtrl, setDebug, void, (bool value), (true),
- "Enable/disable debug output."
- "@param value True to enable debug output, false to disable it.")
- {
-
- object->setDebug( value );
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTreeViewCtrl, isItemSelected, bool, ( S32 id ),,
- "Check whether the given item is currently selected in the tree.\n\n"
- "@param id Item/object ID.\n"
- "@return True if the given item/object is currently selected in the tree." )
- {
- const Vector< GuiTreeViewCtrl::Item* >& selectedItems = object->getSelectedItems();
- for( S32 i = 0; i < selectedItems.size(); ++ i )
- if( selectedItems[ i ]->mId == id )
- return true;
-
- return false;
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTreeViewCtrl, getFilterText, const char*, (),,
- "Get the current filter expression. Only tree items whose text matches this expression "
- "are displayed. By default, the expression is empty and all items are shown.\n\n"
- "@return The current filter pattern or an empty string if no filter pattern is currently active.\n\n"
- "@see setFilterText\n"
- "@see clearFilterText" )
- {
- return object->getFilterText();
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTreeViewCtrl, setFilterText, void, ( const char* pattern ),,
- "Set the pattern by which to filter items in the tree. Only items in the tree whose text "
- "matches this pattern are displayed.\n\n"
- "@param pattern New pattern based on which visible items in the tree should be filtered. If empty, all items become visible.\n\n"
- "@see getFilterText\n"
- "@see clearFilterText" )
- {
- object->setFilterText( pattern );
- }
- DefineEngineMethod(GuiTreeViewCtrl, setFilterChildren, void, (bool doFilterChildren), (true),
- "Set the pattern by which to filter items in the tree. Only items in the tree whose text "
- "matches this pattern are displayed.\n\n"
- "@param pattern New pattern based on which visible items in the tree should be filtered. If empty, all items become visible.\n\n"
- "@see getFilterText\n"
- "@see clearFilterText")
- {
- object->setFilterChildren(doFilterChildren);
- }
- DefineEngineMethod(GuiTreeViewCtrl, setItemFilterException, void, (U32 item, bool isExempt), (0, true),
- "Set the pattern by which to filter items in the tree. Only items in the tree whose text "
- "matches this pattern are displayed.\n\n"
- "@param pattern New pattern based on which visible items in the tree should be filtered. If empty, all items become visible.\n\n"
- "@see getFilterText\n"
- "@see clearFilterText")
- {
- object->setItemFilterException(item, isExempt);
- }
- DefineEngineMethod(GuiTreeViewCtrl, setItemHidden, void, (U32 item, bool hidden), (0, true),
- "Set the pattern by which to filter items in the tree. Only items in the tree whose text "
- "matches this pattern are displayed.\n\n"
- "@param pattern New pattern based on which visible items in the tree should be filtered. If empty, all items become visible.\n\n"
- "@see getFilterText\n"
- "@see clearFilterText")
- {
- object->setItemHidden(item, hidden);
- }
- DefineEngineMethod(GuiTreeViewCtrl, clearHiddenItems, void, (),,
- "Set the pattern by which to filter items in the tree. Only items in the tree whose text "
- "matches this pattern are displayed.\n\n"
- "@param pattern New pattern based on which visible items in the tree should be filtered. If empty, all items become visible.\n\n"
- "@see getFilterText\n"
- "@see clearFilterText")
- {
- object->clearHiddenItems();
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTreeViewCtrl, clearFilterText, void, (),,
- "Clear the current item filtering pattern.\n\n"
- "@see setFilterText\n"
- "@see getFilterText" )
- {
- object->clearFilterText();
- }
- DefineEngineMethod(GuiTreeViewCtrl, getItemAtPosition, S32, (Point2I position), (Point2I::Zero),
- "Get the tree item at the passed in position.\n\n"
- "@param position The position to check for what item is below it.\n"
- "@return The id of the item under the position.")
- {
- return object->getItemAtPosition(position);
- }
- DefineEngineMethod(GuiTreeViewCtrl, reparentItem, void, (S32 itemId, S32 parentId), (0, 0),
- "Check whether the given item is currently selected in the tree.\n\n"
- "@param id Item/object ID.\n"
- "@return True if the given item/object is currently selected in the tree.")
- {
- if (itemId == parentId || itemId < 0 || parentId < 0)
- return;
- const Vector< GuiTreeViewCtrl::Item* > & selectedItems = object->getItems();
- Vector<GuiTreeViewCtrl::Item*> items;
- GuiTreeViewCtrl::Item * parent = nullptr;
- for (S32 i = 0; i < selectedItems.size(); ++i)
- {
- if (selectedItems[i]->mId == itemId)
- {
- items.push_back(selectedItems[i]);
- }
- if (selectedItems[i]->mId == parentId)
- {
- parent = selectedItems[i];
- }
- }
- if (!items.empty() && parent != nullptr)
- {
- object->reparentItems(items, parent);
- }
- }
- DefineEngineMethod(GuiTreeViewCtrl, getTabLevel, S32, (S32 itemId), (0),
- "Get the tree item at the passed in position.\n\n"
- "@param position The position to check for what item is below it.\n"
- "@return The id of the item under the position.")
- {
- return object->getTabLevel(itemId);
- }
|